//工作子线程读管道有数据到来,thread_libevent_process从读管道读取到信息 //对应的主线程写管道在dispatch_conn_new或者switch_item_lock_type static void thread_libevent_process(int fd, short which, void *arg) { LIBEVENT_THREAD *me = arg; CQ_ITEM *item; char buf[1]; if (read(fd, buf, 1) != 1) if (settings.verbose > 0) fprintf(stderr, "Can't read from libevent pipe\n"); switch (buf[0]) { case 'c': //dispatch_conn_new //从CQ队列中读取一个item,因为是pop所以读取后,CQ队列会把这个item从队列中删除 item = cq_pop(me->new_conn_queue); if (NULL != item) { //为sfd分配一个conn结构体,并且为这个sfd建立一个event,然后让base监听这个event //这个sfd的事件回调函数是event_handler conn *c = conn_new(item->sfd, item->init_state, item->event_flags, item->read_buffer_size, item->transport, me->base); if (c == NULL) { if (IS_UDP(item->transport)) { fprintf(stderr, "Can't listen for events on UDP socket\n"); exit(1); } else { if (settings.verbose > 0) { fprintf(stderr, "Can't listen for events on fd %d\n", item->sfd); } close(item->sfd); } } else { c->thread = me; } cqi_free(item); } break; //switch_item_lock_type触发走到这里 /* we were told to flip the lock type and report in */ case 'l': //参考switch_item_lock_type //切换item到段级别 //唤醒睡眠在init_cond条件变量上的迁移线程 me->item_lock_type = ITEM_LOCK_GRANULAR; register_thread_initialized(); break; case 'g'://切换item锁到全局级别 me->item_lock_type = ITEM_LOCK_GLOBAL; register_thread_initialized(); break; } }
//worker线程的事件处理函数 //主线程分发client_fd给worker线程后,向管道写入字符,唤醒worker线程调用此函数 static void thread_libevent_process(int fd, short which, void *arg) { LIBEVENT_THREAD *me = arg; CQ_ITEM *item; char buf[1]; if (read(fd, buf, 1) != 1) if (settings.verbose > 0) fprintf(stderr, "Can't read from libevent pipe\n"); switch (buf[0]) { case 'c': //从队列中取出主线程放入的CQ_ITEM item = cq_pop(me->new_conn_queue); if (NULL != item) { //创建监听事件,把worker线程传过来的client_fd加入监听事件,使用的是worker线程的libevent //worker线程监听两种fd,一是管道接收fd,一是client_fd conn *c = conn_new(item->sfd, item->init_state, item->event_flags, item->read_buffer_size, item->transport, me->base); if (c == NULL) { if (IS_UDP(item->transport)) { fprintf(stderr, "Can't listen for events on UDP socket\n"); exit(1); } else { if (settings.verbose > 0) { fprintf(stderr, "Can't listen for events on fd %d\n", item->sfd); } close(item->sfd); } } else { //设置监听连接的线程为当前worker线程 c->thread = me; } cqi_free(item); } break; /* we were told to flip the lock type and report in */ case 'l': me->item_lock_type = ITEM_LOCK_GRANULAR; register_thread_initialized(); break; case 'g': me->item_lock_type = ITEM_LOCK_GLOBAL; register_thread_initialized(); break; } }
/* * Processes an incoming "handle a new connection" item. This is called when * input arrives on the libevent wakeup pipe. * * 当管道有数据可读的时候会触发此函数的调用 */ static void thread_libevent_process(int fd, short which, void *arg) { LIBEVENT_THREAD *me = arg; CQ_ITEM *item; char buf[1]; if (read(fd, buf, 1) != 1) if (settings.verbose > 0) fprintf(stderr, "Can't read from libevent pipe\n"); switch (buf[0]) { case 'c': // 取出一个任务 item = cq_pop(me->new_conn_queue); if (NULL != item) { // 为新的请求建立一个连接结构体. 连接其实已经建立, 这里只是为了填充连接结构体. 最关键的动作是在 libevent 中注册了事件, 回调函数是 event_handler() conn *c = conn_new(item->sfd, item->init_state, item->event_flags, item->read_buffer_size, item->transport, me->base); if (c == NULL) { if (IS_UDP(item->transport)) { fprintf(stderr, "Can't listen for events on UDP socket\n"); exit(1); } else { if (settings.verbose > 0) { fprintf(stderr, "Can't listen for events on fd %d\n", item->sfd); } close(item->sfd); } } else { c->thread = me; } cqi_free(item); } break; /* we were told to flip the lock type and report in */ case 'l': me->item_lock_type = ITEM_LOCK_GRANULAR; register_thread_initialized(); break; case 'g': me->item_lock_type = ITEM_LOCK_GLOBAL; register_thread_initialized(); break; } }
/* * Worker thread: main event loop */ static void *worker_libev(void *arg) { printf(">%s on thread %d\n", __FUNCTION__, pthread_self()); LIBEV_THREAD *me = arg; printf("me->tcp_sd=%d me->udp_sd=%d\n", me->tcp_sd, me->udp_sd); /* Any per-thread setup can happen here; thread_init() will block until * all threads have finished initializing. */ /* set an indexable thread-specific memory item for the lock type. * this could be unnecessary if we pass the conn *c struct through * all item_lock calls... */ //me->item_lock_type = ITEM_LOCK_GRANULAR; //pthread_setspecific(item_lock_type_key, &me->item_lock_type); me->thread_id = pthread_self(); register_thread_initialized(); //memory leak... me->w_general = (struct ev_io*) malloc (sizeof(struct ev_io)); //me->w_general->fd = me->udp_sd; //event_base_loop(me->base, 0); ev_io_init(me->w_general, worker_cb, me->udp_sd, EV_READ); ev_io_start(me->loop, me->w_general); return NULL; }
static void *worker_libevent(void *arg) { LIBEVENT_THREAD *me = (LIBEVENT_THREAD *)arg; register_thread_initialized(); event_base_dispatch(me->base); return NULL; }
static void *thread_run(void *arg) { P_THREAD_OBJ me = (P_THREAD_OBJ)arg; register_thread_initialized(); event_base_loop(me->base, 0); return NULL; }
static void *worker_thread_loop(void *arg) { void *ret = NULL; struct zhw_worker_t *worker = (struct zhw_worker_t *)arg; register_thread_initialized(worker->pool); ZHW_LOG_INFO("worker thread in pool: %ld start", (long)worker->id); ret = worker_walk_task(worker); ZHW_LOG_INFO("worker thread in pool: %ld exit", (long)worker->id); pthread_exit(NULL); return ret; }
/* * Worker thread: main event loop */ static void *worker_libevent(void *arg) { LIBEVENT_THREAD *me = arg; /* Any per-thread setup can happen here; memcached_thread_init() will block until * all threads have finished initializing. */ register_thread_initialized(); event_base_loop(me->base, 0); return NULL; }
/* * Processes an incoming "handle a new connection" item. This is called when * input arrives on the libevent wakeup pipe. */ static void thread_libevent_process(int fd, short which, void *arg) { LIBEVENT_THREAD *me = arg; CQ_ITEM *item; char buf[1]; unsigned int timeout_fd; if (read(fd, buf, 1) != 1) { if (settings.verbose > 0) fprintf(stderr, "Can't read from libevent pipe\n"); return; } switch (buf[0]) { case 'c': item = cq_pop(me->new_conn_queue); if (NULL != item) { conn *c = conn_new(item->sfd, item->init_state, item->event_flags, item->read_buffer_size, item->transport, me->base); if (c == NULL) { if (IS_UDP(item->transport)) { fprintf(stderr, "Can't listen for events on UDP socket\n"); exit(1); } else { if (settings.verbose > 0) { fprintf(stderr, "Can't listen for events on fd %d\n", item->sfd); } close(item->sfd); } } else { c->thread = me; } cqi_free(item); } break; /* we were told to pause and report in */ case 'p': register_thread_initialized(); break; /* a client socket timed out */ case 't': if (read(fd, &timeout_fd, sizeof(timeout_fd)) != sizeof(timeout_fd)) { if (settings.verbose > 0) fprintf(stderr, "Can't read timeout fd from libevent pipe\n"); return; } conn_close_idle(conns[timeout_fd]); break; } }
/* * Worker thread: main event loop */ static void *worker_libevent(void *arg) { LIBEVENT_THREAD *me = arg; /* Any per-thread setup can happen here; thread_init() will block until * all threads have finished initializing. */ /* set an indexable thread-specific memory item for the lock type. * this could be unnecessary if we pass the conn *c struct through * all item_lock calls... */ me->item_lock_type = ITEM_LOCK_GRANULAR; pthread_setspecific(item_lock_type_key, &me->item_lock_type); register_thread_initialized(); event_base_loop(me->base, 0); return NULL; }
/* * Processes an incoming "handle a new connection" item. This is called when * input arrives on the libevent wakeup pipe. */ static void thread_libevent_process(int fd, short which, void *arg) { LIBEVENT_THREAD *me = arg; CQ_ITEM *item; char buf[1]; //响应pipe可读事件,读取主线程向管道内写的1字节数据(见dispatch_conn_new()函数) if (read(fd, buf, 1) != 1) if (settings.verbose > 0) fprintf(stderr, "Can't read from libevent pipe\n"); switch (buf[0]) { case 'c': //从链接队列中取出一个conn item = cq_pop(me->new_conn_queue); if (NULL != item) { //使用conn创建新的任务,并注册事件 conn *c = conn_new(item->sfd, item->init_state, item->event_flags, item->read_buffer_size, item->transport, me->base); if (c == NULL) { if (IS_UDP(item->transport)) { fprintf(stderr, "Can't listen for events on UDP socket\n"); exit(1); } else { if (settings.verbose > 0) { fprintf(stderr, "Can't listen for events on fd %d\n", item->sfd); } close(item->sfd); } } else { c->thread = me; } cqi_free(item); } break; /* we were told to pause and report in */ case 'p': register_thread_initialized(); break; } }
/* * Worker thread: main event loop */ static void *worker_libevent(void *arg) { LIBEVENT_THREAD *me = arg; /* Any per-thread setup can happen here; memcached_thread_init() will block until * all threads have finished initializing. */ me->l = logger_create(); me->lru_bump_buf = item_lru_bump_buf_create(); if (me->l == NULL || me->lru_bump_buf == NULL) { abort(); } if (settings.drop_privileges) { drop_worker_privileges(); } register_thread_initialized(); event_base_loop(me->base, 0); return NULL; }
/* * Worker thread: main event loop */ static void *worker_libevent(void *arg) { LIBEVENT_THREAD *me = arg; /* Any per-thread setup can happen here; thread_init() will block until * all threads have finished initializing. */ /* set an indexable thread-specific memory item for the lock type. * this could be unnecessary if we pass the conn *c struct through * all item_lock calls... */ me->item_lock_type = ITEM_LOCK_GRANULAR;//初试状态使用段级别锁 //为workers线程设置线程私有数据 //因为所有的workers线程都会调用这个函数,所以所有的workers线程都设置了相同键值的 //线程私有数据 pthread_setspecific(item_lock_type_key, &me->item_lock_type); register_thread_initialized(); event_base_loop(me->base, 0); //等待事件到来触发setup_thread中的thread_libevent_process执行 return NULL; }