标签:
说明:本文章重点关注事件处理模型,顺便介绍相关的结构体,其他的结构体不做介绍。有兴趣的同学可以去http://tengine.taobao.org/book/查找更多资料。Tengine应该是淘宝基于Nginx自己做的修改。这个地址的文档还在不断的完善更新中。
程序流程图:
说明:
一、进程生成顺序
1.main(src/core/nginx.c)函数启动ngx_master_process_cycle,启动主服务进程。
2.ngx_master_process_cycle(src/os/unix/ngx_process_cycle.c)里面调用ngx_start_worker_processes.
3.ngx_start_worker_processes(src/os/unix/ngx_process_cycle.c)里面循环执行生成特定数量的进程池。
4.ngx_spawn_process(src/os/unix/ngx_process.c)根据指定的respawn选项fork子进程,相关子进程信息保存在全部ngx_processes数组(ngx_process_t ngx_processes[NGX_MAX_PROCESSES])中,子进程的运行过程通过参数proc指定,这里是ngx_worker_process_cycle(src/os/unix/ngx_process_cycle.c)。在fork之前先通过socketpair生成master process和worker process间进行通信的channel[2]。
master_process进程作为Nginx的服务主进程,管理其他子进程的生存周期,包括cache_manager_processes子进程,全部worker_processes,信号处理,timer等。
二、timer定时器超时处理机制
上图中的左侧红色1,2,3步构成了timer和select/poll/epoll_wait等等待函数配合使用的基本流程,libevent里面的timer处理机制也是一样的,即:
1.从timer最小堆(一般使用红黑树代替)中取出最小的timer;
2.传入epoll_wait等I/O复用函数;
3.处理堆中的timer超时事件。
三、worker process I/O处理流程
每个worker process的运行过程ngx_worker_process_cycle如下:
1 static void 2 ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data) 3 { 4 ngx_int_t worker = (intptr_t) data; 5 6 ngx_process = NGX_PROCESS_WORKER; 7 ngx_worker = worker; 8 9 ngx_worker_process_init(cycle, worker); 10 11 ngx_setproctitle("worker process"); 12 13 for ( ;; ) { 14 15 if (ngx_exiting) { 16 ngx_event_cancel_timers(); 17 18 if (ngx_event_timer_rbtree.root == ngx_event_timer_rbtree.sentinel) 19 { 20 ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting"); 21 22 ngx_worker_process_exit(cycle); 23 } 24 } 25 26 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "worker cycle"); 27 28 ngx_process_events_and_timers(cycle); 29 30 if (ngx_terminate) { 31 ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting"); 32 33 ngx_worker_process_exit(cycle); 34 } 35 36 if (ngx_quit) { 37 ngx_quit = 0; 38 ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, 39 "gracefully shutting down"); 40 ngx_setproctitle("worker process is shutting down"); 41 42 if (!ngx_exiting) { 43 ngx_exiting = 1; 44 ngx_close_listening_sockets(cycle); 45 ngx_close_idle_connections(cycle); 46 } 47 } 48 49 if (ngx_reopen) { 50 ngx_reopen = 0; 51 ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs"); 52 ngx_reopen_files(cycle, -1); 53 } 54 } 55 }
可以看出,里面除了exiting,terminate,quit和reopen等控制操作外,只有ngx_process_events_and_timers(src/event/ngx_event.c)。再看ngx_process_events_and_timers函数:
1 void 2 ngx_process_events_and_timers(ngx_cycle_t *cycle) 3 { 4 ngx_uint_t flags; 5 ngx_msec_t timer, delta; 6 7 if (ngx_timer_resolution) { 8 timer = NGX_TIMER_INFINITE; 9 flags = 0; 10 11 } else { 12 timer = ngx_event_find_timer(); 13 flags = NGX_UPDATE_TIME; 14 15 #if (NGX_WIN32) 16 17 /* handle signals from master in case of network inactivity */ 18 19 if (timer == NGX_TIMER_INFINITE || timer > 500) { 20 timer = 500; 21 } 22 23 #endif 24 } 25 26 if (ngx_use_accept_mutex) { 27 if (ngx_accept_disabled > 0) { 28 ngx_accept_disabled--; 29 30 } else { 31 if (ngx_trylock_accept_mutex(cycle) == NGX_ERROR) { 32 return; 33 } 34 35 if (ngx_accept_mutex_held) { 36 flags |= NGX_POST_EVENTS; 37 38 } else { 39 if (timer == NGX_TIMER_INFINITE 40 || timer > ngx_accept_mutex_delay) 41 { 42 timer = ngx_accept_mutex_delay; 43 } 44 } 45 } 46 } 47 48 delta = ngx_current_msec; 49 50 (void) ngx_process_events(cycle, timer, flags); 51 52 delta = ngx_current_msec - delta; 53 54 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, 55 "timer delta: %M", delta); 56 57 ngx_event_process_posted(cycle, &ngx_posted_accept_events); 58 59 if (ngx_accept_mutex_held) { 60 ngx_shmtx_unlock(&ngx_accept_mutex); 61 } 62 63 if (delta) { 64 ngx_event_expire_timers(); 65 } 66 67 ngx_event_process_posted(cycle, &ngx_posted_events); 68 }
1.函数开头7-24行计算定时器timer,用于后面的ngx_process_events(50行)函数,最终用于各种I/O复用函数的timeout参数,如epoll_wait的timeout参数。ngx_process_events是一个宏,#define ngx_process_events ngx_event_actions.process_events(src/event/ngx_event.h)。全局变量ngx_event_actions在各个event module的init方法里面设置,如ngx_epoll_init(src/event/modules/ngx_epoll_module.c)中ngx_event_actions = ngx_epoll_module_ctx.actions;。而各个module的init方法的调用需要通过Nginx指定使用哪种类型的module来设置。相关初始设置在ngx_event_core_init_conf(src/event/ngx_event.c)里面指定。
2.63-65行处理timer超时事件。
以epoll module为例,ngx_process_events最终指向ngx_epoll_process_events(src/event/modules/ngx_epoll_module.c)。
1 static ngx_int_t 2 ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags) 3 { 4 int events; 5 uint32_t revents; 6 ngx_int_t instance, i; 7 ngx_uint_t level; 8 ngx_err_t err; 9 ngx_event_t *rev, *wev; 10 ngx_queue_t *queue; 11 ngx_connection_t *c; 12 13 /* NGX_TIMER_INFINITE == INFTIM */ 14 15 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, 16 "epoll timer: %M", timer); 17 18 events = epoll_wait(ep, event_list, (int) nevents, timer); 19 20 err = (events == -1) ? ngx_errno : 0; 21 22 if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) { 23 ngx_time_update(); 24 } 25 26 if (err) { 27 if (err == NGX_EINTR) { 28 29 if (ngx_event_timer_alarm) { 30 ngx_event_timer_alarm = 0; 31 return NGX_OK; 32 } 33 34 level = NGX_LOG_INFO; 35 36 } else { 37 level = NGX_LOG_ALERT; 38 } 39 40 ngx_log_error(level, cycle->log, err, "epoll_wait() failed"); 41 return NGX_ERROR; 42 } 43 44 if (events == 0) { 45 if (timer != NGX_TIMER_INFINITE) { 46 return NGX_OK; 47 } 48 49 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, 50 "epoll_wait() returned no events without timeout"); 51 return NGX_ERROR; 52 } 53 54 for (i = 0; i < events; i++) { 55 c = event_list[i].data.ptr; 56 57 instance = (uintptr_t) c & 1; 58 c = (ngx_connection_t *) ((uintptr_t) c & (uintptr_t) ~1); 59 60 rev = c->read; 61 62 if (c->fd == -1 || rev->instance != instance) { 63 64 /* 65 * the stale event from a file descriptor 66 * that was just closed in this iteration 67 */ 68 69 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, 70 "epoll: stale event %p", c); 71 continue; 72 } 73 74 revents = event_list[i].events; 75 76 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0, 77 "epoll: fd:%d ev:%04XD d:%p", 78 c->fd, revents, event_list[i].data.ptr); 79 80 if (revents & (EPOLLERR|EPOLLHUP)) { 81 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0, 82 "epoll_wait() error on fd:%d ev:%04XD", 83 c->fd, revents); 84 } 85 86 #if 0 87 if (revents & ~(EPOLLIN|EPOLLOUT|EPOLLERR|EPOLLHUP)) { 88 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, 89 "strange epoll_wait() events fd:%d ev:%04XD", 90 c->fd, revents); 91 } 92 #endif 93 94 if ((revents & (EPOLLERR|EPOLLHUP)) 95 && (revents & (EPOLLIN|EPOLLOUT)) == 0) 96 { 97 /* 98 * if the error events were returned without EPOLLIN or EPOLLOUT, 99 * then add these flags to handle the events at least in one 100 * active handler 101 */ 102 103 revents |= EPOLLIN|EPOLLOUT; 104 } 105 106 if ((revents & EPOLLIN) && rev->active) { 107 108 #if (NGX_HAVE_EPOLLRDHUP) 109 if (revents & EPOLLRDHUP) { 110 rev->pending_eof = 1; 111 } 112 #endif 113 114 rev->ready = 1; 115 116 if (flags & NGX_POST_EVENTS) { 117 queue = rev->accept ? &ngx_posted_accept_events 118 : &ngx_posted_events; 119 120 ngx_post_event(rev, queue); 121 122 } else { 123 rev->handler(rev); 124 } 125 } 126 127 wev = c->write; 128 129 if ((revents & EPOLLOUT) && wev->active) { 130 131 if (c->fd == -1 || wev->instance != instance) { 132 133 /* 134 * the stale event from a file descriptor 135 * that was just closed in this iteration 136 */ 137 138 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, 139 "epoll: stale event %p", c); 140 continue; 141 } 142 143 wev->ready = 1; 144 145 if (flags & NGX_POST_EVENTS) { 146 ngx_post_event(wev, &ngx_posted_events); 147 148 } else { 149 wev->handler(wev); 150 } 151 } 152 } 153 154 return NGX_OK; 155 }
可以看出,前面计算得到的timer传进了epoll_wait里面。其实这个timer的值是通过函数 ngx_event_find_timer从全部的timer组成的最小堆(Nginx里面使用RB tree实现,我猜是红黑树查询插入删除开销比堆小)里面取出来的最小timer值。 epoll_wait之后就是常见的事件处理了。可以对事件立即处理(调用handler)或者将事件插入请求队列(调用ngx_post_event)。
注:引用本人文章请注明出处,谢谢。
标签:
原文地址:http://www.cnblogs.com/NerdWill/p/4989859.html