成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專(zhuān)欄INFORMATION COLUMN

nginx 事件模塊簡(jiǎn)單剖析

huayeluoliuhen / 1321人閱讀

摘要:我們這里以單進(jìn)程啟動(dòng)為例中的函數(shù)調(diào)用這個(gè)函數(shù)回循環(huán)調(diào)用中的事件循環(huán)的核心函數(shù)是。這個(gè)方法僅在方法中調(diào)用,它是處理,分發(fā)事件的核心初始化事件驅(qū)動(dòng)模塊的方法退出事件驅(qū)動(dòng)模塊前調(diào)用的方法。讀事件的回調(diào)函數(shù)是這樣就進(jìn)入了框架處理流程

我們這里以單進(jìn)程啟動(dòng)為例
nginx.c中的main 函數(shù)調(diào)用ngx_single_process_cycle

這個(gè)函數(shù)回循環(huán)調(diào)用

ngx_process_cycle.c 中的

for ( ;; ) {
  ....
  ngx_process_events_and_timers
  ....
}

事件循環(huán)的核心函數(shù)是 ngx_process_events_and_timers 。這個(gè)函數(shù)主要干了四件 事情:搶占 accept mutex,等待并分發(fā)事件,處理 accept 事件,處理其他io事件

我們這里只介紹等待分發(fā)事件
ngx_event.c 中的

    (void) ngx_process_events(cycle, timer, flags);

這里開(kāi)始 wait并分發(fā)事件, 我們來(lái)可以來(lái)看一下這個(gè)函數(shù)
可以看到在 ngx_event.h 中的一個(gè)宏

#define ngx_process_events   ngx_event_actions.process_events

我們來(lái)看一下 ngx_event_actions 這個(gè)數(shù)據(jù)結(jié)構(gòu)

typedef struct {
    /*
    添加事件方法,它將負(fù)責(zé)把1個(gè)感興趣的事件添加到操作系統(tǒng)提供的事件驅(qū)動(dòng)機(jī)制(如epoll,kqueue等)中,
    這樣,在事件發(fā)生之后,將可以在調(diào)用下面的process_envets時(shí)獲取這個(gè)事件。
    */
    ngx_int_t  (*add)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);
    /*
    刪除事件方法,它將一個(gè)已經(jīng)存在于事件驅(qū)動(dòng)機(jī)制中的事件一出,這樣以后即使這個(gè)事件發(fā)生,調(diào)用process_events方法時(shí)也無(wú)法再獲取這個(gè)事件
    */
    ngx_int_t  (*del)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);

    /*
    啟用一個(gè)事件,目前事件框架不會(huì)調(diào)用這個(gè)方法,大部分事件驅(qū)動(dòng)模塊對(duì)于該方法的實(shí)現(xiàn)都是與上面的add方法完全一致的
    */
    ngx_int_t  (*enable)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);
    /*
    禁用一個(gè)事件,目前事件框架不會(huì)調(diào)用這個(gè)方法,大部分事件驅(qū)動(dòng)模塊對(duì)于該方法的實(shí)現(xiàn)都是與上面的del方法一致
    */
    ngx_int_t  (*disable)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);

    /*
    向事件驅(qū)動(dòng)機(jī)制中添加一個(gè)新的連接,這意味著連接上的讀寫(xiě)事件都添加到事件驅(qū)動(dòng)機(jī)制中了
    */
    ngx_int_t  (*add_conn)(ngx_connection_t *c);
    // 從事件驅(qū)動(dòng)機(jī)制中一出一個(gè)連續(xù)的讀寫(xiě)事件
    ngx_int_t  (*del_conn)(ngx_connection_t *c, ngx_uint_t flags);

    // 僅在多線(xiàn)程環(huán)境下會(huì)被調(diào)用,目前,nginx在產(chǎn)品環(huán)境下還不會(huì)以多線(xiàn)程方式運(yùn)行。
    ngx_int_t  (*process_changes)(ngx_cycle_t *cycle, ngx_uint_t nowait);
    // 在正常的工作循環(huán)中,將通過(guò)調(diào)用process_events方法來(lái)處理事件。
    // 這個(gè)方法僅在ngx_process_events_and_timers方法中調(diào)用,它是處理,分發(fā)事件的核心
    ngx_int_t  (*process_events)(ngx_cycle_t *cycle, ngx_msec_t timer,
                   ngx_uint_t flags);

    // 初始化事件驅(qū)動(dòng)模塊的方法
    ngx_int_t  (*init)(ngx_cycle_t *cycle, ngx_msec_t timer);
    // 退出事件驅(qū)動(dòng)模塊前調(diào)用的方法。
    void       (*done)(ngx_cycle_t *cycle);
} ngx_event_actions_t;


extern ngx_event_actions_t   ngx_event_actions;

這個(gè)數(shù)據(jù)結(jié)構(gòu)中定義了很多函數(shù)指針,

這里我們的配置是

events { 
    use epoll; 
    worker_connections 1024;     #所以nginx支持的總連接數(shù)就等于worker_processes * worker_connections 
} 

使用的是 epoll 事件模塊,在epoll 模塊初始化的時(shí)候調(diào)用

ngx_epoll_module.c 中的ngx_epoll_init的函數(shù)

其中給ngx_event_actions賦值

ngx_event_actions = ngx_epoll_module_ctx.actions 

我們來(lái)看下 ngx_epoll_module_ctx
結(jié)構(gòu)類(lèi)型是


typedef struct { // 事件模塊的名稱(chēng) ngx_str_t *name; // 在解析配置項(xiàng)前,這個(gè)回調(diào)方法用于創(chuàng)建存儲(chǔ)配置項(xiàng)參數(shù)的結(jié)構(gòu)體 void *(*create_conf)(ngx_cycle_t *cycle); // 在解析配置項(xiàng)完成后,init_conf方法會(huì)被調(diào)用,用于綜合處理當(dāng)前事件模塊感興趣的全部配置項(xiàng)。 char *(*init_conf)(ngx_cycle_t *cycle, void *conf); // 對(duì)于事件驅(qū)動(dòng)機(jī)制,每個(gè)事件模塊需要實(shí)現(xiàn)的10個(gè)抽象方法 ngx_event_actions_t actions; } ngx_event_module_t;

初始化

//epoll是個(gè)event模塊
ngx_event_module_t  ngx_epoll_module_ctx = {
    &epoll_name,
    ngx_epoll_create_conf,               /* create configuration */
    ngx_epoll_init_conf,                 /* init configuration */

    {
        ngx_epoll_add_event,             /* add an event */
        ngx_epoll_del_event,             /* delete an event */
        ngx_epoll_add_event,             /* enable an event */
        ngx_epoll_del_event,             /* disable an event */
        ngx_epoll_add_connection,        /* add an connection */
        ngx_epoll_del_connection,        /* delete an connection */
        NULL,                            /* process the changes */
        ngx_epoll_process_events,        /* process the events */
        ngx_epoll_init,                  /* init the events */
        ngx_epoll_done,                  /* done the events */
    }
};


這些事件處理函數(shù)都在 ngx_epoll_module.c 這個(gè)文件中,大家可以看一下源碼

綜上,根據(jù)我們的配置, ngx_event.c 中的 ngx_process_events
實(shí)際調(diào)用的是 ngx_epoll_module.c 中的 ngx_epoll_process_events

這個(gè)函數(shù)有點(diǎn)長(zhǎng),我們找些關(guān)鍵的點(diǎn)看一下,

 //一開(kāi)始就是等待事件,最長(zhǎng)等待時(shí)間為timer;nginx為事件專(zhuān)門(mén)用紅黑樹(shù)維護(hù)了一個(gè)計(jì)時(shí)器
    events = epoll_wait(ep, event_list, (int) nevents, timer);

所有收集到的事件都放在了event_list 中,我們來(lái)看一下這個(gè)event_list

static struct epoll_event  *event_list;

struct epoll_event {
    uint32_t      events;
    epoll_data_t  data;
};


typedef union epoll_data {
    void         *ptr;
    int           fd;
    uint32_t      u32;
    uint64_t      u64;
} epoll_data_t;


下面就開(kāi)始對(duì)這些事件就行處理, 先加鎖,

 ngx_mutex_lock(ngx_posted_events_mutex);
    //循環(huán)開(kāi)始處理收到的所有事件
    for (i = 0; i < events; i++) {
        c = event_list[i].data.ptr;

        instance = (uintptr_t) c & 1;
        c = (ngx_connection_t *) ((uintptr_t) c & (uintptr_t) ~1);

        rev = c->read;

        if (c->fd == -1 || rev->instance != instance) {

            /*
             * the stale event from a file descriptor
             * that was just closed in this iteration
             */

            ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                           "epoll: stale event %p", c);
            continue;
        }
        //取得發(fā)生一個(gè)事件
        revents = event_list[i].events;

        ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                       "epoll: fd:%d ev:%04XD d:%p",
                       c->fd, revents, event_list[i].data.ptr);
        //記錄wait的錯(cuò)誤返回狀態(tài)
        if (revents & (EPOLLERR|EPOLLHUP)) {
            ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                           "epoll_wait() error on fd:%d ev:%04XD",
                           c->fd, revents);
        }

#if 0
        if (revents & ~(EPOLLIN|EPOLLOUT|EPOLLERR|EPOLLHUP)) {
            ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                          "strange epoll_wait() events fd:%d ev:%04XD",
                          c->fd, revents);
        }
#endif
        //該事件是一個(gè)讀事件,并該連接上注冊(cè)的讀事件是active的
        if ((revents & (EPOLLERR|EPOLLHUP))
             && (revents & (EPOLLIN|EPOLLOUT)) == 0)
        {
            /*
             * if the error events were returned without EPOLLIN or EPOLLOUT,
             * then add these flags to handle the events at least in one
             * active handler
             */

            revents |= EPOLLIN|EPOLLOUT;
        }

        if ((revents & EPOLLIN) && rev->active) {

            if ((flags & NGX_POST_THREAD_EVENTS) && !rev->accept) {
                rev->posted_ready = 1;

            } else {
                rev->ready = 1;
            }
            //事件放入到相應(yīng)的隊(duì)列中
            if (flags & NGX_POST_EVENTS) {
                queue = (ngx_event_t **) (rev->accept ?
                               &ngx_posted_accept_events : &ngx_posted_events);

                ngx_locked_post_event(rev, queue);

            } else {
                rev->handler(rev);
            }
        }

        wev = c->write;

        if ((revents & EPOLLOUT) && wev->active) {

            if (c->fd == -1 || wev->instance != instance) {

                /*
                 * the stale event from a file descriptor
                 * that was just closed in this iteration
                 */

                ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                               "epoll: stale event %p", c);
                continue;
            }

            if (flags & NGX_POST_THREAD_EVENTS) {
                wev->posted_ready = 1;

            } else {
                wev->ready = 1;
            }

            if (flags & NGX_POST_EVENTS) {
                ngx_locked_post_event(wev, &ngx_posted_events);

            } else {
                wev->handler(wev);
            }
        }
    }

    ngx_mutex_unlock(ngx_posted_events_mutex);

先加鎖,對(duì)event_list 中的事件循環(huán)處理,
在每個(gè)循環(huán)中,
先獲取這個(gè)事件所在的連接, 然后判斷是讀事件還是寫(xiě)事件, 然后調(diào)用注冊(cè)在這個(gè)事件上的的回調(diào)函數(shù)。 讀事件的回調(diào)函數(shù)是
ngx_http_init_connection 這樣就進(jìn)入了 HTTP框架處理流程

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/39136.html

相關(guān)文章

  • nginx架構(gòu)

    摘要:反向代理反向代理反向代理負(fù)載均衡鑒權(quán)限流等邏輯架構(gòu)在邏輯上分為入口層,模塊化的功能處理層,系統(tǒng)調(diào)用層。多個(gè)共同監(jiān)聽(tīng)事件并處理,反向代理會(huì)把請(qǐng)求轉(zhuǎn)發(fā)給后端服務(wù)。 一.概述 本文將深入剖析nginx的架構(gòu)。 第一部分介紹nginx現(xiàn)有框架,用典型的4+1視圖闡述,包括邏輯架構(gòu),開(kāi)發(fā)架構(gòu),運(yùn)行架構(gòu),物理架構(gòu),功能用例,nginx為單機(jī)服務(wù),不考慮物理架構(gòu)。其中功能用例概述nginx功能;邏輯...

    smartlion 評(píng)論0 收藏0
  • nginx架構(gòu)

    摘要:反向代理反向代理反向代理負(fù)載均衡鑒權(quán)限流等邏輯架構(gòu)在邏輯上分為入口層,模塊化的功能處理層,系統(tǒng)調(diào)用層。多個(gè)共同監(jiān)聽(tīng)事件并處理,反向代理會(huì)把請(qǐng)求轉(zhuǎn)發(fā)給后端服務(wù)。 一.概述 本文將深入剖析nginx的架構(gòu)。 第一部分介紹nginx現(xiàn)有框架,用典型的4+1視圖闡述,包括邏輯架構(gòu),開(kāi)發(fā)架構(gòu),運(yùn)行架構(gòu),物理架構(gòu),功能用例,nginx為單機(jī)服務(wù),不考慮物理架構(gòu)。其中功能用例概述nginx功能;邏輯...

    fuyi501 評(píng)論0 收藏0
  • Swoft 源碼剖析 - Swoole和Swoft的那些事 (Http/Rpc服務(wù)篇)

    摘要:和服務(wù)關(guān)系最密切的進(jìn)程是中的進(jìn)程組,絕大部分業(yè)務(wù)處理都在該進(jìn)程中進(jìn)行。隨后觸發(fā)一個(gè)事件各組件通過(guò)該事件進(jìn)行配置文件加載路由注冊(cè)。事件每個(gè)請(qǐng)求到來(lái)時(shí)僅僅會(huì)觸發(fā)事件。服務(wù)器生命周期和服務(wù)基本一致,詳情參考源碼剖析功能實(shí)現(xiàn) 作者:bromine鏈接:https://www.jianshu.com/p/4c0...來(lái)源:簡(jiǎn)書(shū)著作權(quán)歸作者所有,本文已獲得作者授權(quán)轉(zhuǎn)載,并對(duì)原文進(jìn)行了重新的排版。S...

    張漢慶 評(píng)論0 收藏0
  • epoll LT/ET 深入剖析

    摘要:深入剖析事件有兩種模型水平觸發(fā)接收緩沖區(qū)不為空有數(shù)據(jù)可讀讀事件一直觸發(fā)發(fā)送緩沖區(qū)不滿(mǎn)可以繼續(xù)寫(xiě)入數(shù)據(jù)寫(xiě)事件一直觸發(fā)符合思維習(xí)慣,返回的事件就是的狀態(tài)邊沿觸發(fā)的接收緩沖區(qū)狀態(tài)變化時(shí)觸發(fā)讀事件,即空的接收緩沖區(qū)剛接收到數(shù)據(jù)時(shí)觸發(fā)讀事件的發(fā)送緩沖 epoll LT/ET 深入剖析 EPOLL事件有兩種模型: Level Triggered (LT) 水平觸發(fā).socket接收緩沖區(qū)不為空 有...

    microelec 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<