nginx源码初读(8)--让烦恼从数据结构开始(ngx_event)
生活随笔
收集整理的這篇文章主要介紹了
nginx源码初读(8)--让烦恼从数据结构开始(ngx_event)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
nginx中的事件模塊是一個很重要的模塊,但這里作為初讀,我們只簡單看一下ngx_event的數據結構,至于模塊和機制,留作之后再分析。
下面是結構體ngx_event_t的代碼:
typedef struct ngx_event_s ngx_event_t; struct ngx_event_s {void *data;/* 事件上下文數據,通常data都是指向ngx_connection_t連接對象。* 開啟文件異步I/O時,它可能會指向ngx_event_aio_t結構體。* ... ngx_int_t ngx_handle_write_event(ngx_event_t *wev, size_t lowat) {ngx_connection_t *c;if (lowat) {c = wev->data; // 在這里event的data就指向了connection_t,直接用指針獲取if (ngx_send_lowat(c, lowat) == NGX_ERROR) {return NGX_ERROR;}}...} ...unsigned write:1; /* 標志位,為1時表示事件是可寫的。通常它表示對應的TCP連接可寫,也就是連接處于可以發送網絡包的狀態。*/unsigned accept:1; /* 標志位,為1時表示為此事件可以建立新的連接。通常在ngx_cycle_t中的listening動態數組中,每一個監聽對象ngx_listening_t,對應的讀事件中的accept標志位才會是1。*/unsigned instance:1;/* used to detect the stale events in kqueue, rtsig, and epoll* 這個標志位用于區分當前事件是否過期,它僅僅是給事件驅動模塊使用的,而事件消費模塊可不用關心。* 為什么需要這個標志位呢?當開始處理一批事件時,處理前面的事件可能會關閉一些連接,而這些連接有可能影響這批事件中還未處理到的后面的事件,這時可通過instance來避免處理后面的過期事件。*/unsigned active:1;/* the event was passed or would be passed to a kernel;* in aio mode - operation was posted.* 標志位,為1表示當前事件是活躍的,為0表示事件是不活躍的。* 這個狀態對應著事件驅動模塊處理方式的不同。例如,在添加事件,刪除事件和處理事件時,active標志位的不同都會對應著不同的處理方式。在使用事件時,一般不會直接改變active標志位。* ... if (!rev->delayed) {if (rev->active && !rev->ready) {ngx_add_timer(rev, p->read_timeout);} else if (rev->timer_set) {ngx_del_timer(rev);} } ...*/unsigned disabled:1;/* 標志位,為1表示禁用事件,僅在kqueue或者rtsig事件驅動模塊中有效,對于epoll事件驅動模塊則沒有意義。* ... if (c->read->active || c->read->disabled) { ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT);} ... // 位于close_connection函數中*//unsigned ready:1;/* the ready event; in aio mode 0 means that no operation can be posted * 標志位,為1表示當前事件準備就緒,也就是說,允許這個事件的handler處理這個事件。* 在HTTP框架中,經常會檢查事件的ready標志位,以確定是否可以接收請求或者發送相應。* ... if (rev->ready) {if (ngx_use_accept_mutex) {ngx_post_event(rev, &ngx_posted_events);return;}rev->handler(rev);return;} ...*/ unsigned oneshot:1;/* 該標志位僅對kqueue,eventport等模塊有意義,而對于linux上的epoll事件驅動模塊則是無意義的。*/unsigned complete:1;/* aio operation is complete* 用于異步aio事件的處理 */unsigned eof:1;unsigned error:1;/* 標志位,eof表示當前處理的字符流已經結束,error表示事件處理過程出錯了。 * ... flags = (rev->eof || rev->error) ? NGX_CLOSE_EVENT : 0; ...*/unsigned timedout:1;/* 標志位,為1表示這個事件超時,用以提示handler做超時處理,它與timer_set都用了定時器 * ... if (wev->timedout) {wev->timedout = 0;ngx_http_perl_handle_request(r);return;} ...*/unsigned timer_set:1;/* 標志位,為1表示這個事件存在于定時器中* ... if (!ngx_cleaner_event.timer_set) {ngx_add_timer(&ngx_cleaner_event, 30000);ngx_cleaner_event.timer_set = 1;} ...*/ unsigned delayed:1;/* 標志位,delayed為1表示需要延遲處理這個事件,它僅用于限速功能 */unsigned deferred_accept:1;/* 標志位,為1表示延遲建立TCP連接,也就是TCP三次握手后并不建立連接,而是等到真正收到數據包后才建連接 */unsigned pending_eof:1;/* the pending eof reported by kqueue, epoll or in aio chain operation * 標志位,為1表示等待字符流結束,它只與kqueue和aio事件驅動機制有關 */unsigned posted:1;#if (NGX_WIN32)/* setsockopt(SO_UPDATE_ACCEPT_CONTEXT) was successful */unsigned accept_context_updated:1; #endif// 下面這部分都是因不同事件管理機制而不同的,先不看了 #if (NGX_HAVE_KQUEUE)unsigned kq_vnode:1;/* the pending errno reported by kqueue */int kq_errno; #endif/** kqueue only:* accept: number of sockets that wait to be accepted* read: bytes to read when event is ready* or lowat when event is set with NGX_LOWAT_EVENT flag* write: available space in buffer when event is ready* or lowat when event is set with NGX_LOWAT_EVENT flag** iocp: TODO** otherwise:* accept: 1 if accept many, 0 otherwise*/#if (NGX_HAVE_KQUEUE) || (NGX_HAVE_IOCP)int available; #elseunsigned available:1; #endifngx_event_handler_pt handler;/* 這個事件發生時的處理方法,每個事件處理模塊都會重新實現它 */#if (NGX_HAVE_AIO)// win下的一種事件驅動模型 #if (NGX_HAVE_IOCP) ngx_event_ovlp_t ovlp; #else // 在linux中定義的aio結構體 struct aiocb aiocb; #endif#endifngx_uint_t index;/* epoll 事件驅動方式不使用index */ngx_log_t *log;/* 記錄當前event的log對象 */ngx_rbtree_node_t timer; /* 定時器節點,用于定時器紅黑樹中 *//* the posted queue */ngx_queue_t queue;unsigned closed:1;/* to test on worker exit */unsigned channel:1;unsigned resolver:1;unsigned cancelable:1;#if 0/* the threads support *//** the event thread context, we store it here* if $(CC) does not understand __thread declaration* and pthread_getspecific() is too costly*/void *thr_ctx;#if (NGX_EVENT_T_PADDING)/* event should not cross cache line in SMP */uint32_t padding[NGX_EVENT_T_PADDING]; #endif #endif };我們再看一下event.h里一個數據結構:
typedef struct {ngx_int_t (*add)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags); ngx_int_t (*del)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);/* 添加/移出事件方法,負責把事件添加/移出到操作系統提供的事件驅動機制(如epoll,kqueue等)中,這樣在事件發生之后,將可以/無法調用下面的process_envets時獲取這個事件。*/ngx_int_t (*enable)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);ngx_int_t (*disable)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);/* 啟用/禁用一個事件,目前事件框架不會調用,大部分事件驅動模塊對該方法的實現都與add/del完全一致 */ngx_int_t (*add_conn)(ngx_connection_t *c);ngx_int_t (*del_conn)(ngx_connection_t *c, ngx_uint_t flags);/* 向事件驅動機制中添加/移除一個新的連接,這意味著連接上的讀寫事件都添加到/移出事件驅動機制中了 */ngx_int_t (*process_events)(ngx_cycle_t *cycle, ngx_msec_t timer,ngx_uint_t flags);/* 在正常的工作循環中,將通過調用process_events方法來處理事件。* 這個方法僅在ngx_process_events_and_timers方法中調用,它是處理分發事件的核心。*/ngx_int_t (*init)(ngx_cycle_t *cycle, ngx_msec_t timer);void (*done)(ngx_cycle_t *cycle);/* 初始化和退出事件驅動模塊的方法 */ } ngx_event_actions_t;extern ngx_event_actions_t ngx_event_actions;作為nginx中比較重要的一個驅動,event當然是很復雜的,第一遍看反正怎么也不容易懂,后續刨析了nginx的各種機制和流程應該就很容易懂了,先放過它,繼續往下看。
貼個鏈接:https://segmentfault.com/a/1190000002715203
--------------------- 本文來自 醇霧 的CSDN 博客 ,全文地址請點擊:https://blog.csdn.net/wuchunlai_2012/article/details/50731037?utm_source=copy
總結
以上是生活随笔為你收集整理的nginx源码初读(8)--让烦恼从数据结构开始(ngx_event)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: nginx 源码学习笔记(二十一)——
- 下一篇: 关于ngx_trylock_accept