• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            Just enjoy programming

            Nginx源碼分析-Epoll模塊(轉載)

            轉載自:http://www.tbdata.org/archives/1296


            Nginx源碼分析-Epoll模塊

            3 comments 十二月 26th, 2010 | by yixiao in 高性能服務器

            Linux平臺上,Nginx使用epoll完成事件驅動,實現高并發;本文將不對epoll本身進行介紹(網上一堆一堆的文章介紹epoll的原理及使用方法,甚至源碼分析等),僅看一下Nginx是如何使用epoll的。

            Nginx在epoll模塊中定義了好幾個函數,這些函數基本都是作為回調注冊到事件抽象層的對應接口上,從而實現了事件驅動的具體化,我們看如下的一段代碼:

            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 */
                }
            };
            


            這段代碼就是epoll的相關函數注冊到事件抽象層,這里所謂的事件抽象層在前面的博文中有提過,就是Nginx為了方便支持和開發具體的I/O模型,從而實現的一層抽象。代碼后面的注釋將功能說明得很詳細了,本文就只重點關注ngx_epoll_init和ngx_epoll_process_events兩個函數,其他幾個函數就暫且忽略了。

            ngx_epoll_init主要是完成epoll的相關初始化工作,代碼分析如下:

            static ngx_int_t
            ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
            {
                ngx_epoll_conf_t  *epcf;
            	/*取得epoll模塊的配置結構*/
                epcf = ngx_event_get_conf(cycle->conf_ctx, ngx_epoll_module);
            	/*ep是epoll模塊定義的一個全局變量,初始化為-1*/
                if (ep == -1) {
                	/*創一個epoll對象,容量為總連接數的一半*/
                    ep = epoll_create(cycle->connection_n / 2);
                    if (ep == -1) {
                        ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                                      "epoll_create() failed");
                        return NGX_ERROR;
                    }
                }
            	/*nevents也是epoll模塊定義的一個全局變量,初始化為0*/
                if (nevents events) {
                    if (event_list) {
                        ngx_free(event_list);
                    }
            
            		/*event_list存儲產生事件的數組*/
                    event_list = ngx_alloc(sizeof(struct epoll_event) * epcf->events,
                                           cycle->log);
                    if (event_list == NULL) {
                        return NGX_ERROR;
                    }
                }
                nevents = epcf->events;
            	/*初始化全局變量ngx_io, ngx_os_is定義為:
            		ngx_os_io_t ngx_os_io = {
                		ngx_unix_recv,
                		ngx_readv_chain,
                		ngx_udp_unix_recv,
                		ngx_unix_send,
                		ngx_writev_chain,
                		0
            		};(位于src/os/unix/ngx_posix_init.c)
            	*/
                ngx_io = ngx_os_io;
            	/*這里就是將epoll的具體接口函數注冊到事件抽象層接口ngx_event_actions上。
            	具體是上文提到的ngx_epoll_module_ctx中封裝的如下幾個函數
                    ngx_epoll_add_event,
                    ngx_epoll_del_event,
                    ngx_epoll_add_event,
                    ngx_epoll_del_event,
                    ngx_epoll_add_connection,
                    ngx_epoll_del_connection,
                    ngx_epoll_process_events,
                    ngx_epoll_init,
                    ngx_epoll_done,
            	*/
                ngx_event_actions = ngx_epoll_module_ctx.actions;
            #if (NGX_HAVE_CLEAR_EVENT)
            	/*epoll將添加這個標志,主要為了實現邊緣觸發*/
                ngx_event_flags = NGX_USE_CLEAR_EVENT
            #else
            	/*水平觸發*/
                ngx_event_flags = NGX_USE_LEVEL_EVENT
            #endif
                                  |NGX_USE_GREEDY_EVENT /*io的時候,直到EAGAIN為止*/
                                  |NGX_USE_EPOLL_EVENT; /*epoll標志*/
                return NGX_OK;
            }
            

            epoll初始化工作沒有想象中的復雜,和我們平時使用epoll都一樣,下面看ngx_epoll_process_events,這個函數主要用來完成事件的等待并處理。

            static ngx_int_t
            ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
            {
                int                events;
                uint32_t           revents;
                ngx_int_t          instance, i;
                ngx_uint_t         level;
                ngx_err_t          err;
                ngx_log_t         *log;
                ngx_event_t       *rev, *wev, **queue;
                ngx_connection_t  *c;
            	/*一開始就是等待事件,最長等待時間為timer;nginx為事件
            	專門用紅黑樹維護了一個計時器。后續對這個timer單獨分析。
            	*/
                events = epoll_wait(ep, event_list, (int) nevents, timer);
                if (events == -1) {
                    err = ngx_errno;
                } else {
                    err = 0;
                }
                if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
                    /*執行一次時間更新, nginx將時間緩存到了一組全局變量中,方便程序高效的獲取事件。*/
                    ngx_time_update();
                }
            	/*處理wait錯誤*/
                if (err) {
                    if (err == NGX_EINTR) {
                        if (ngx_event_timer_alarm) {
                            ngx_event_timer_alarm = 0;
                            return NGX_OK;
                        }
                        level = NGX_LOG_INFO;
                    } else {
                        level = NGX_LOG_ALERT;
                    }
                    ngx_log_error(level, cycle->log, err, "epoll_wait() failed");
                    return NGX_ERROR;
                }
            	/*wait返回事件數0,可能是timeout返回,也可能是非timeout返回;非timeout返回則是error*/
                if (events == 0) {
                    if (timer != NGX_TIMER_INFINITE) {
                        return NGX_OK;
                    }
                    ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                                  "epoll_wait() returned no events without timeout");
                    return NGX_ERROR;
                }
                log = cycle->log;
            	/*for循環開始處理收到的所有事件*/
                for (i = 0; i read;
            		。。。。。。。。。。。。。
            
            		/*取得發生一個事件*/
                    revents = event_list[i].events;
            
            		/*記錄wait的錯誤返回狀態*/
                    if (revents & (EPOLLERR|EPOLLHUP)) {
                        ngx_log_debug2(NGX_LOG_DEBUG_EVENT, log, 0,
                                       "epoll_wait() error on fd:%d ev:%04XD",
                                       c->fd, revents);
                    }
                    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;
                    }
            		/*該事件是一個讀事件,并該連接上注冊的讀事件是active的*/
                    if ((revents & EPOLLIN) && rev->active) {
                        if ((flags & NGX_POST_THREAD_EVENTS) && !rev->accept) {
                            rev->posted_ready = 1;
                        } else {
                            rev->ready = 1;
                        }
            
            			/*事件放入相應的隊列中;關于此處的先入隊再處理,在前面的文章中已經介紹過了。*/
                        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 (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);
                        }
                    }
                }
                return NGX_OK;
            }
            

            本文將關注的兩個epoll函數也就這么一點代碼了,但整個epoll還有添加事件和刪除事件等的相關函數,代碼都很簡單,本文就不做具體的分析了。

            posted on 2011-07-10 00:54 周強 閱讀(935) 評論(0)  編輯 收藏 引用 所屬分類: nginx

            久久久这里只有精品加勒比| 伊人色综合久久天天人守人婷| 久久人人爽人人人人爽AV| 亚洲第一极品精品无码久久| 青青青青久久精品国产h| 思思久久好好热精品国产| 精品伊人久久久| 99久久成人18免费网站| 久久亚洲中文字幕精品有坂深雪| 无码任你躁久久久久久| 国内精品久久久久影院网站| 国产V综合V亚洲欧美久久| 久久婷婷色香五月综合激情| 久久99精品久久久久久久不卡| 亚洲狠狠久久综合一区77777| 亚洲午夜福利精品久久| 丰满少妇高潮惨叫久久久| 久久久久无码国产精品不卡| 亚洲精品国产成人99久久| 久久久国产视频| 久久精品国产色蜜蜜麻豆 | 亚洲va久久久噜噜噜久久| 亚洲午夜久久影院| 久久精品国产亚洲AV大全| 国产亚洲综合久久系列| 久久受www免费人成_看片中文| 久久夜色tv网站| 国产成人久久精品区一区二区| 久久国产精品99精品国产| 欧美激情精品久久久久久久| 久久天天躁夜夜躁狠狠躁2022| 丁香久久婷婷国产午夜视频| 久久久久99精品成人片牛牛影视| 国产精品久久久久久一区二区三区| 97久久国产综合精品女不卡 | 色狠狠久久AV五月综合| 热久久最新网站获取| 亚洲国产精品综合久久一线| 深夜久久AAAAA级毛片免费看| 久久久久香蕉视频| 青青草原综合久久大伊人导航|