首先繼續回憶下,之前子執行緒執行操作裡面有一個未涉及的內容ngx_process_events_and_timers,今天我們就來研究下這個函數。
這篇文章來自於:http://blog.csdn.net/lengzijian/article/details/7601730
先來看看第十九節
今天主要講解的就是事件驅動函數,圖中的紅色部分:
[cpppp
plaincopyprint?
- src/event/ngx_event.c
-
-
timers(ngx_cycle_t *cycle) {
-
ng
ngx_msec_t timer, delta; -
timer = NGX_TIMER_INFINITE;
-
- } else {
- timer = ngx_event_find_timer(); _TIME;
- }
-
ngx_use_accept_mutex變數代表是否使用accept互斥體
- 預設使用,可透過accept_mutex off;指令關閉;
*/-
-
if-
(ngx_use_accept_mutex) {
/*-
ngx_accept_disabled變數在ngx_event_accept函數中計算。 -
如果ngx_accept_disabled大於0,並表示此程序接受的連結過多,- 同時將自己減一。
- 然後,並繼續處理已連結上的事件。
- nginx利用這一點實現了繼承關於連接的基本負載平衡。 */
- 0) {
-
ngx_accep t_disable else
- {
- /*
-
- 因此,而確保了只有一個程序擁有監聽套接口,故 才不會驚群現象。
- */ (ngx_trylock_accept_mutex(cycle) == NGX_ERROR) {
- }
- if
(ngx_accept_mutex_held) { - /*
-
- ‧
- 因為,以處理時間可能會很耗時,且不先施放鎖、除霸鎖 導致其他流程無法取得鎖定,且有accept的效率就低了。
-
*/ flags |= NGX_POST_EVENTS;
-
- /*
- 所得進程,當然不需要NGX_POST_EVENTS標誌。
- 但為要設定延遲時多久,且再去爭搶。
- */ if
(timer == NGX_TIMER_INFINITE -
- { accept_mutex_delay;
- }
-
}
-
}
-
}
-
-
delta = ngx_current_msec;
-
-
/*接下來,epoll要開始wait事件, -
- ngx_process_events的具體實作是對應epoll模組中的ngx_epoll_process_events函數 之後
- */
- (void
) ngx_process_events(cycle, timer, flags); - delta = ngx_current_msec - delta;
- ngx_log_debug1 (NGX_LOG_DEBUG_EVENT, cycle->log, 0,
-
-
/*-
post- 佇列,暫存epoll從監聽套介面wait到的accept事件。
- 前文提到的NGX_POST_EVENTS標誌使用後,將所有的accept事件暫存到這個隊列
- if (ngx_posted_accept_events ) {
- ngx_event_process_posted(cycle, &ngx_posted_accept_eventH); //所有accept事件處理完後,如果持有鎖的話,就釋放掉。
- if (ngx_accept_mutex_held) &ngx_accept_mutex);
- }
- delta是之前統計的耗時,存在毫秒級的耗時,就對所有時間的timer進行檢查,
- 如果timeout 就從time rbtree中刪除到期的timer,同時調用相應事件的handler函數處理相應事件的handler函數處理? */
-
- if (delta) {
- ngx_event_expire_timers(); }
- ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle-> log, 0,
-
》,ed
- /*
-
處理普通事件中所獲得的寫字事件),
- 因為每個事件都有自己的handler方法,
-
if
- (ngx_posted_events) {
- if (ngx_threaded) {
- ngx_wakeup_worker_thread(cycle);
-
} else {
- ngx_event_process_posted(cycle, &ngx_posted_events);
} - }
}
-
之前有說過accept事件,其實他就是監聽套介面上是否有新來的事件,下面介紹下accept時間的
- [cpp] view
plaincopyprint?
- src/event/ngx_event_accept.c
-
- void x_event_t * ev)
{ socklen_t - ngx_err_t ngx_socket_t s;
- ngx_event_t *ls;
- ngx_connection_t *c, *lc;
- ngx_event_conf_t *ecf;
- u_char
-
//省略部分代碼
-
-
ls = lc->聽;
-
ev->準備=0; bug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
-
, 準備:%d"
- ,&ls->addr_text,ev->可用);
- socklen = NGX_SOCKADDRLEN;
- / /接受一個新的連線
- s = accept(lc->fd, (
- //簡潔部分程式碼
-
- 重新計算ngx_accept_disabled的值, 主要是為了做負載平衡,且之前有提及。
- 「連接數八分之一 - 剩餘的連結數「
- 指每個行程設定的再最大連線數,這個數字可以設定檔中指定。
-
-
-
-
-
ngx_accept_disabled - ngx_cycle->free_connection_n;
//取得connection-
-
c= ngx_get_connection(s, ev->log);
-
- //連接關閉的時候,才釋放pool
-
- c->pool = if (c->pool == NULL) {
- ngx_close_accepted_connection(c); return🎠
-
-
c->sockaddr = ng if
- (c->sockaddr == NULL) { ngx_close_accepted_connection(c);
-
return
- ; }
-
- ngx_memcpy(c->sockaddr , sa, socklen);
-
-
log if
- (log == NULL) {
- ngx_close_accepted_connection(c);
- }
-
- /* 為aio設定阻塞模式,並設定非阻塞模式 if
(ngx_inherited_nonblocking) {
- if (ngx_event_flags & NGX_USE_AIO_EVENT) {
- == -1) {
- 「失敗」);
- 回復;
- }
-
{ -
//我們使用epoll if
- (!(ngx_event_flags & (NGX_USE_AIO_EVENT|NGX_USE_RTSIG_EVENT))) { if
- (ngx_nonblocking(s) == ngx_log_error(NGX_LOG_ALERT, ev-> ;log, ngx_socket_errno,
ngx_nonblocking_n - 「失敗」);
-
ngx_close_accepted_connection(c); 🎠 回;
-
}-
-
*log = ls->log;
- c->recv = ngx_recv;
ngx_send; c->recv_chain = ngx_recv_chain; -
-
- c->log = log; = log;
-
- c->socklen = s
- c->local_sockaddr = ls->sockaddr;
- c->unexpected_eof = 1;
-
- 🎠
if- (c->sockaddr->sa_家 == AF_UNIX) {
-
c->tcp_nopush = NGX_TCP_NOPUSH_DISABLED;
_NODELAY_DISABLED;
- #if (NGX_SOLARIS)
- _INET及AF_INET6 */
- c->sendfile = }
- #endif
- rev = c->閱讀;
- wev = 我們->準備= 1;
- (NGX_USE_AIO_EVENT|NGX_USE_RTSIG_EVENT)) { /* rtsig、 aio、 iocp */
-
- rev->就緒= 1; }
-
- if (ev->deferred_accept) {
- 轉速UE)
- rev->可用 = 1;
-
#endif-
-
}
-
- rev->log = log;
-
- /*
- ()
- * *
- * TODO: MP: - 分配在共享記憶體中 * TODO: MP: - 分配在共享記憶體中 * TODO: MP: - 分配在共享記憶體中
- * - ngx_atomic_fetch_add() 或透過臨界區域或輕斥體保護
- */ c->number = ngx_atomic_fetch_add (ngx_connection_counter, 1);
- _flags & NGX_USE_EPOLL_EVENT) == 0) {
-
- ngx_close_accepted_connection 回;
- }
-
-
- ->handler = NULL;
- 這裡聽 handler 非常重要,它完成了新連結的最後一個初始化工作,
同時接受新的連結到epoll;掛在這個handler上的函數,-
-
就是ngx_http_init_connection */
- ls->handler(c );
-
- if
(ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
- ev->ava不可以——;
- }
- }
while - (ev->可用);
- }
- accpt事件的handler方法就這樣了。之後就是每個連接的讀寫器事件handler方法,這部分會直接將我們引入http模組,我們不著急,還要學習下nginx經典模組epoll。
以上就介紹了nginx 原始碼學習筆記(二十一)—— event 模組二 ——事件驅動核心ngx_process_events_and_timers,包括了隊列方面的內容,希望對PHP教程有興趣的朋友有所幫助。