/* * Dispatches a new connection to another thread. This is only ever called * from the main thread, either during initialization (for UDP) or because * of an incoming connection. */ void dispatch_conn_new(int sfd, enum conn_states init_state, int event_flags, int read_buffer_size, enum network_transport transport) { CQ_ITEM *item = cqi_new(); char buf[1]; if (item == NULL) { close(sfd); /* given that malloc failed this may also fail, but let's try */ fprintf(stderr, "Failed to allocate memory for connection object\n"); return ; } int tid = (last_thread + 1) % settings.num_threads; LIBEVENT_THREAD *thread = threads + tid; last_thread = tid; item->sfd = sfd; item->init_state = init_state; item->event_flags = event_flags; item->read_buffer_size = read_buffer_size; item->transport = transport; item->mode = queue_new_conn; cq_push(thread->new_conn_queue, item); MEMCACHED_CONN_DISPATCH(sfd, thread->thread_id); buf[0] = 'c'; if (write(thread->notify_send_fd, buf, 1) != 1) { perror("Writing to thread notify pipe"); } }
void dispatch_conn_new_to_thread(int tid, int sfd, enum conn_states init_state, int event_flags, int read_buffer_size, enum protocol prot, enum network_transport transport, conn_funcs *funcs, void *extra) { assert(tid > 0); assert(tid < settings.num_threads); LIBEVENT_THREAD *thread = threads + tid; CQ_ITEM *cq_item = cqi_new(); cq_item->sfd = sfd; cq_item->init_state = init_state; cq_item->event_flags = event_flags; cq_item->read_buffer_size = read_buffer_size; cq_item->protocol = prot; cq_item->transport = transport; cq_item->funcs = funcs; cq_item->extra = extra; cq_push(thread->new_conn_queue, cq_item); MEMCACHED_CONN_DISPATCH(sfd, thread->thread_id); if (write(thread->notify_send_fd, "", 1) != 1) { perror("Writing to thread notify pipe"); } }
/* * Dispatches a new connection to another thread. This is only ever called * from the main thread, either during initialization (for UDP) or because * of an incoming connection. */ void dispatch_conn_new(int sfd, enum conn_states init_state, int event_flags, int read_buffer_size, enum network_transport transport) { CQ_ITEM *item = cqi_new(); char buf[1]; int tid = (last_thread + 1) % g_settings.num_threads; LIBEVENT_THREAD *thread = threads + tid; last_thread = tid; item->sfd = sfd; item->init_state = init_state; item->event_flags = event_flags; item->read_buffer_size = read_buffer_size; item->transport = transport; cq_push(thread->new_conn_queue, item); buf[0] = 'c'; if (write(thread->notify_send_fd, buf, 1) != 1) { log_debug(LOG_ERR, "Writing to thread notify pipe, error:%s\n", strerror(errno)); } }
/* * Dispatches a new connection to another thread. This is only ever called * from the main thread, either during initialization (for UDP) or because * of an incoming connection. * * 分发新的连接到线程池中的一个线程中, 其实就是在一个线程的工作队列中加入一个 * 工作任务, 并通过管道给相应的线程发送信号 * */ void dispatch_conn_new(int sfd, enum conn_states init_state, int event_flags, int read_buffer_size, enum network_transport transport) { // CQ_ITEM connection queue item CQ_ITEM *item = cqi_new(); char buf[1]; // 线程池中有多个线程, 每个线程都有一个工作队列, 线程所需要做的就是从工作队列中取出工作任务并执行, 只要队列为空线程就可以进入等待状态 // 计算线程信息下标 int tid = (last_thread + 1) % settings.num_threads; // LIBEVENT_THREAD threads 是一个全局数组变量 LIBEVENT_THREAD *thread = threads + tid; // 定位到下一个线程信息,通过简单地轮放方式 last_thread = tid; item->sfd = sfd; item->init_state = init_state; item->event_flags = event_flags; item->read_buffer_size = read_buffer_size; item->transport = transport; // 将工作任务放入对应线程的工作队列中 cq_push(thread->new_conn_queue, item); MEMCACHED_CONN_DISPATCH(sfd, thread->thread_id); // 有意思, 这里向一个熟睡的线程写了一个字符: char buf[1] // 当管道中被写入数据后, libevent 中的注册事件会被触发, thread_libevent_process() 函数会被调用. 因为在 setup_thread() 中线程中管道描述符被设置到 event 中, 并注册到 libevent 中 buf[0] = 'c'; if (write(thread->notify_send_fd, buf, 1) != 1) { perror("Writing to thread notify pipe"); } }
/* * Dispatches a new connection to another thread. This is only ever called * from the main thread, either during initialization (for UDP) or because * of an incoming connection. */ void dispatch_conn_new(int sfd, enum conn_states init_state, int event_flags, int read_buffer_size, enum network_transport transport) { CQ_ITEM *item = cqi_new(); char buf[1]; if (item == NULL) { close(sfd); /* given that malloc failed this may also fail, but let's try */ fprintf(stderr, "Failed to allocate memory for connection object\n"); return ; } int tid = (last_thread + 1) % settings.num_threads; LIBEVENT_THREAD *thread = threads + tid; last_thread = tid; #ifdef DUP_AWARE fprintf(stderr, "last_thread = %d, tid = %d\n", last_thread, tid); #endif item->sfd = sfd; item->init_state = init_state; item->event_flags = event_flags; item->read_buffer_size = read_buffer_size; item->transport = transport; item->priority = -1; // ignored unless DUP_AWARE #ifdef DUP_AWARE if (!IS_UDP(transport)) { if (settings.num_threads != NUM_THREADS) { fprintf(stderr, "settings.num_threads must be %d for duplicate awareness" "to work in its current implementation. You specified %d " "threads.", NUM_THREADS, settings.num_threads); exit(1); } static int is_priority = NUM_THREADS; // The first set of `num_thread` connections will all be primary, while any // subsequent will be duplicate. item->priority = (is_priority-- > 0) ? PRIMARY : DUPLICATE; fprintf(stderr, "<%d item->priority is %s\n", sfd, (item->priority == PRIMARY) ? "PRIMARY" : "DUPLICATE"); } #endif cq_push(thread->new_conn_queue, item); MEMCACHED_CONN_DISPATCH(sfd, thread->thread_id); buf[0] = 'c'; if (write(thread->notify_send_fd, buf, 1) != 1) { perror("Writing to thread notify pipe"); } }
void print_levelbylevel(ptr_rbnode root) { CircularQueue *cq; cq_init(cq, ELEMENT_MAX); cq_push(cq, root); int depth_cnt = -1; while ((depth_cnt = cq->capacity)) { while (depth_cnt--) { cq_element_t current_node = cq_front(cq); cq_pop(cq); if (current_node->nil) { printf("N "); } else { printf("%d%s ", current_node->val, current_node->color ? "(B)" : "(R)"); cq_push(cq, current_node->left); cq_push(cq, current_node->right); } } printf("\n"); } cq_destroy(cq); }
static inline int __op_fetch_disk (uint64_t id, uint64_t offset, struct __arc_object *_obj) { CQ_ITEM *item = cqi_new (); item->fops = READ_COMMAND; item->offset = offset; item->fid = id; item->obj = _obj; // lfs_printf("readstate =%d",_obj->read_state); assert (_obj->read_state == READ_STATE); /* * cq is aio queue. */ cq_push (RFS_AIOQ, item); return 1; }
/* * Dispatches a new connection to another thread. This is only ever called * from the main thread, either during initialization (for UDP) or because * of an incoming connection. */ void dispatch_conn_new(int sfd, int init_state, int event_flags, int read_buffer_size, int is_udp) { CQ_ITEM *item = cqi_new(); int thread = (last_thread + 1) % settings.num_threads; last_thread = thread; item->sfd = sfd; item->init_state = init_state; item->event_flags = event_flags; item->read_buffer_size = read_buffer_size; item->is_udp = is_udp; cq_push(&threads[thread].new_conn_queue, item); if (write(threads[thread].notify_send_fd, "", 1) != 1) { perror("Writing to thread notify pipe"); } }
/* * Dispatches a new connection to another thread. This is only ever called * from the main thread, either during initialization (for UDP) or because * of an incoming connection. */ void dispatch_conn_new(SOCKET sfd, STATE_FUNC init_state, int event_flags, int read_buffer_size, enum network_transport transport) { CQ_ITEM *item = cqi_new(); int tid = (last_thread + 1) % settings.num_threads; LIBEVENT_THREAD *thread = threads + tid; last_thread = tid; item->sfd = sfd; item->init_state = init_state; item->event_flags = event_flags; item->read_buffer_size = read_buffer_size; item->transport = transport; cq_push(thread->new_conn_queue, item); MEMCACHED_CONN_DISPATCH(sfd, (uintptr_t)thread->thread_id); notify_thread(thread); }
void dispath_conn(int anewfd,struct sockaddr_in asin) { // set the new connect item CQ_ITEM *lpNewItem = calloc(1,sizeof(CQ_ITEM)); if (! lpNewItem) { perror("Can't allocate connection item\n"); exit(1); } lpNewItem->sfd = anewfd; strcpy(lpNewItem->szAddr,(char*)inet_ntoa(asin.sin_addr)); lpNewItem->port = asin.sin_port; // libev default loop, accept the new connection, round-robin // dispath to a work_thread. int robin = round_robin%init_count; cq_push(work_threads[robin].new_conn_queue,lpNewItem); ev_async_send(work_threads[robin].loop, &(work_threads[robin].async_watcher)); round_robin++; }
/* * Dispatches a new connection to another thread. This is only ever called * from the main thread, either during initialization (for UDP) or because * of an incoming connection. */ void dispatch_conn_new(int sfd, enum conn_states init_state, int event_flags, int read_buffer_size, enum network_transport transport) { CQ_ITEM *item = cqi_new(); int tid = (last_thread + 1) % settings.num_threads; LIBEVENT_THREAD *thread = threads + tid; last_thread = tid; item->sfd = sfd; item->init_state = init_state; item->event_flags = event_flags; item->read_buffer_size = read_buffer_size; item->transport = transport; cq_push(thread->new_conn_queue, item); MEMCACHED_CONN_DISPATCH(sfd, thread->thread_id); if (write(thread->notify_send_fd, "", 1) != 1) { perror("Writing to thread notify pipe"); } }
/* * Re-dispatches a connection back to the original thread. Can be called from * any side thread borrowing a connection. */ void redispatch_conn(conn *c) { CQ_ITEM *item = cqi_new(); char buf[1]; if (item == NULL) { /* Can't cleanly redispatch connection. close it forcefully. */ c->state = conn_closed; close(c->sfd); return; } LIBEVENT_THREAD *thread = c->thread; item->sfd = c->sfd; item->init_state = conn_new_cmd; item->c = c; item->mode = queue_redispatch; cq_push(thread->new_conn_queue, item); buf[0] = 'c'; if (write(thread->notify_send_fd, buf, 1) != 1) { perror("Writing to thread notify pipe"); } }
//将主线程的连接分发给worker线程 void dispatch_conn_new(int sfd, enum conn_states init_state, int event_flags, int read_buffer_size, enum network_transport transport) { //创建CQ_ITEM对象,封装了client_fd以及一些client连接信息 CQ_ITEM *item = cqi_new(); char buf[1]; if (item == NULL) { close(sfd); /* given that malloc failed this may also fail, but let's try */ fprintf(stderr, "Failed to allocate memory for connection object\n"); return ; } //通过轮询的方式选择worker线程 int tid = (last_thread + 1) % settings.num_threads; LIBEVENT_THREAD *thread = threads + tid; last_thread = tid; //初始化CQ_ITEM对象 item->sfd = sfd; item->init_state = init_state; item->event_flags = event_flags; item->read_buffer_size = read_buffer_size; item->transport = transport; //将CQ_ITEM放入所选择的worker线程的CQ_ITEM队列中 cq_push(thread->new_conn_queue, item); MEMCACHED_CONN_DISPATCH(sfd, thread->thread_id); buf[0] = 'c'; //主线程向所选择的worker线程的管道中写入一个'c'字符, //由于worker线程会监听管道的receive_fd, 于是会收到事件通知 //触发worker线程的事件处理函数thread_libevent_process if (write(thread->notify_send_fd, buf, 1) != 1) { perror("Writing to thread notify pipe"); } }
static int __op_fetch (struct __arc_object *e) { uint64_t offset, id; struct object *obj = __arc_list_entry (e, struct object, entry); obj->obj_data = cache_alloc_shm (lfs_n.lfs_cache); offset = obj->offset; id = obj->id; #ifdef LFS_DEBUG lfs_printf ("\n2:cache_alloc obj=%p,id=%" PRIu64 ",offset=%" PRIu64 "", &obj->entry, id, offset); #endif CQ_ITEM *item = cqi_new (); item->fops = READ_COMMAND; item->offset = offset; item->fid = id; item->obj = e; lfs_printf (" 2ci fetch begin id=%d\n", id); if (id < 0 || id > lfs_n.max_files) return -1; cq_push (RFS_AIOQ, item); return 0; }
/* * Dispatches a new connection to another thread. This is only ever called * from the main thread, either during initialization (for UDP) or because * of an incoming connection. */ void dispatch_conn_new(int sfd, STATE_FUNC init_state, int event_flags, int read_buffer_size, enum network_transport transport) { CQ_ITEM *item = cqi_new(); int tid = (last_thread + 1) % settings.num_threads; LIBEVENT_THREAD *thread = threads + tid; last_thread = tid; item->sfd = sfd; item->init_state = init_state; item->event_flags = event_flags; item->read_buffer_size = read_buffer_size; item->transport = transport; cq_push(thread->new_conn_queue, item); MEMCACHED_CONN_DISPATCH(sfd, (uintptr_t)thread->thread_id); if (write(thread->notify_send_fd, "", 1) != 1) { mc_logger->log(EXTENSION_LOG_WARNING, NULL, "Writing to thread notify pipe: %s", strerror(errno)); } }
void dispatch_conn_new(int fd, char key, void *arg) { if ('k' == key) { for (int i = 0; i < num_threads; i++) { LIBEVENT_THREAD *thread = threads + i; char buf[1]; buf[0] = key; if (write(thread->notify_send_fd, buf, 1) != 1) { merror("writing to thread notify pipe failed!"); } } } else { CQ_ITEM *item = cqi_new(); if (NULL == item) { merror("cqi_new failed!"); return; } char buf[1]; int tid = (last_thread + 1) % num_threads; LIBEVENT_THREAD *thread = threads + tid; last_thread = tid; item->fd = fd; item->data = arg; cq_push(thread->new_conn_queue, item); buf[0] = key; if (write(thread->notify_send_fd, buf, 1) != 1) { merror("writing to thread notify pipe failed!"); } } }