23.ngx_event_core_module模块之ngx_event_process_init

来源:互联网 发布:alias 软件 编辑:程序博客网 时间:2024/06/16 21:37

学习了上一篇worker进程处理函数的代码,有很多细节我们还没掌握,首先,Nginx是怎么接收连接的?前面我们的确是看到了创建监听套接字这些操作,但是这些监听套接字的读事件是怎么添加进事件处理模型的呢?这就是本篇学习的内容,如上一篇中所学,worker进程在进入主循环之前,会调用Nginx各个模块的init_process函数,而ngx_event_core_module模块的init_process函数就是答案所在。


/* event/ngx_event_timer.c *//* 初始化定时器红黑树 */ ngx_int_t ngx_event_timer_init(ngx_log_t *log){    if (ngx_event_timer_rbtree) {        // 如果ngx_event_timer_rbtree不为空, 表示已被初始化过        #if (NGX_THREADS)        ngx_event_timer_mutex->log = log;#endif        // 返回NGX_OK        return NGX_OK;    }    // 置ngx_event_timer_rbtree为ngx_event_timer_sentinel叶子哨兵节点, 表示当前定时器红黑树为空树    ngx_event_timer_rbtree = &ngx_event_timer_sentinel;#if (NGX_THREADS)    // 如果线程化, 那么需要创建与定时器红黑树有关的互斥锁ngx_event_timer_mutex    if (!(ngx_event_timer_mutex = ngx_mutex_init(log, 0))) {        return NGX_ERROR;    }#endif    return NGX_OK;}/* event/event.h */typedef struct {                                                        // 事件处理模型相关模块的上下文    ngx_str_t              *name;                                       // 事件处理模型名称    void                 *(*create_conf)(ngx_cycle_t *cycle);           //    char                 *(*init_conf)(ngx_cycle_t *cycle, void *conf); //    ngx_event_actions_t     actions;                                    // 事件处理模型的相关操作} ngx_event_module_t;typedef struct {                                                        // 事件处理模型相关操作的结构体定义    ngx_int_t  (*add)(ngx_event_t *ev, int event, u_int flags);         // 添加事件    ngx_int_t  (*del)(ngx_event_t *ev, int event, u_int flags);         // 删除事件    ngx_int_t  (*enable)(ngx_event_t *ev, int event, u_int flags);      // 使能事件    ngx_int_t  (*disable)(ngx_event_t *ev, int event, u_int flags);     // 禁止事件    ngx_int_t  (*add_conn)(ngx_connection_t *c);                        // 添加连接    ngx_int_t  (*del_conn)(ngx_connection_t *c, u_int flags);           // 删除连接    ngx_int_t  (*process_changes)(ngx_cycle_t *cycle, ngx_uint_t try);  // 处理变化    ngx_int_t  (*process_events)(ngx_cycle_t *cycle);                   // 处理事件    ngx_int_t  (*init)(ngx_cycle_t *cycle);                             // 初始化工作    void       (*done)(ngx_cycle_t *cycle);                             // 结束工作} ngx_event_actions_t;/* event/ngx_event.c */ngx_module_t  ngx_event_core_module = {    NGX_MODULE,    &ngx_event_core_module_ctx,                ngx_event_core_commands,                   NGX_EVENT_MODULE,                          ngx_event_module_init,                     ngx_event_process_init                 };/* ngx_event_core_module模块的init_process函数 */static ngx_int_t ngx_event_process_init(ngx_cycle_t *cycle){    ngx_uint_t           m, i;    ngx_socket_t         fd;    ngx_event_t         *rev, *wev;    ngx_listening_t     *s;    ngx_connection_t    *c;    ngx_core_conf_t     *ccf;    ngx_event_conf_t    *ecf;    ngx_event_module_t  *module;#if (WIN32)    ngx_iocp_conf_t     *iocpcf;#endif        // 获取ngx_core_module模块的配置信息ccf    ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);    // 获取ngx_event_core_module模块的配置信息ecf    ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module);    if (ngx_accept_mutex_ptr && ccf->worker_processes > 1 && ecf->accept_mutex)    {        // 如果ngx_accept_mutex_ptr不为空即accept互斥锁存在,        // 且ccf->worker_processes大于1即worker进程至少为2个,        // 且ecf->accept_mutex为1即需要通过accept加锁来解决惊群问题                // 置ngx_accept_mutex锁为ngx_accept_mutex_ptr        ngx_accept_mutex = ngx_accept_mutex_ptr;        // 初始化ngx_accept_mutex_held为0, 因为当前还没有获取ngx_accept_mutex锁        ngx_accept_mutex_held = 0;        // 置ngx_accept_mutex_delay为配置的ecf->accept_mutex_delay        ngx_accept_mutex_delay = ecf->accept_mutex_delay;    }#if (NGX_THREADS)    // 如果线程化, 那么我们需要为ngx_posted_events队列创建互斥锁ngx_posted_events_mutex    if (!(ngx_posted_events_mutex = ngx_mutex_init(cycle->log, 0))) {        return NGX_ERROR;    }#endif    // 初始化用来维护定时器的红黑树    if (ngx_event_timer_init(cycle->log) == NGX_ERROR) {        return NGX_ERROR;    }    // 置cycle->connection_n为ecf->connections,    // ecf->connections也就是配置的worker进程最大连接数    cycle->connection_n = ecf->connections;    // 遍历ngx_modules数组    for (m = 0; ngx_modules[m]; m++) {        if (ngx_modules[m]->type != NGX_EVENT_MODULE) {            // 我们只对NGX_EVENT_MODULE类型的模块感兴趣            continue;        }        // 我们可以通过use指令来配置使用的事件处理模型, 目前支持epoll、/dev/poll、aio、kqueue、poll、rtsig和select等;        // 每个事件处理模型都对应一个模块, 我们需要找到对应的模块.        if (ngx_modules[m]->ctx_index == ecf->use) {            // 找到该模块的上下文            module = ngx_modules[m]->ctx;            // 事件处理模型对应的模块的上下文具有相同的结构            // 这里调用actions成员的init方法, 用于对事件处理模型进行初始化工作            // 对应epoll, 这里就是调用ngx_epoll_init创建epoll句柄            if (module->actions.init(cycle) == NGX_ERROR) {                exit(2);            }            break;        }    }    // 创建连接结构体数组(连接池), 元素个数为ecf->connections    // 注意这里不是从内存池而是直接从系统申请的内存空间    cycle->connections = ngx_alloc(sizeof(ngx_connection_t) * ecf->connections,                                   cycle->log);    if (cycle->connections == NULL) {        return NGX_ERROR;    }    c = cycle->connections;    // 对连接池进行初始化    for (i = 0; i < cycle->connection_n; i++) {        c[i].fd = (ngx_socket_t) -1;        c[i].data = NULL;#if (NGX_THREADS)        c[i].lock = 0;#endif    }    // 创建read_events事件数组, 里面会存放Nginx所有的读事件    cycle->read_events = ngx_alloc(sizeof(ngx_event_t) * ecf->connections,                                   cycle->log);    if (cycle->read_events == NULL) {        return NGX_ERROR;    }        rev = cycle->read_events;    // read_events数组初始化    for (i = 0; i < cycle->connection_n; i++) {        rev[i].closed = 1;#if (NGX_THREADS)        rev[i].lock = &c[i].lock;        rev[i].own_lock = &c[i].lock;#endif    }    // 创建write_events事件数组, 里面会存放Nginx所有的写事件    cycle->write_events = ngx_alloc(sizeof(ngx_event_t) * ecf->connections,                                   cycle->log);    if (cycle->write_events == NULL) {        return NGX_ERROR;    }    wev = cycle->write_events;    // write_events数组初始化    for (i = 0; i < cycle->connection_n; i++) {        wev[i].closed = 1;#if (NGX_THREADS)        wev[i].lock = &c[i].lock;        wev[i].own_lock = &c[i].lock;#endif    }    s = cycle->listening.elts;    // 遍历监听套接字数组    for (i = 0; i < cycle->listening.nelts; i++) {        fd = s[i].fd;#if (WIN32)        fd /= 4;#endif        /* 监听套接字和已连接套接字都会占用连接池的一个连接,          * 同样, 它们也会各占用read_events和write_events的一个事件,          * 索引均为它们的文件描述符;         */        c = &cycle->connections[fd];        rev = &cycle->read_events[fd];        wev = &cycle->write_events[fd];        // 对连接c和读事件rev进行初始化        // 为什么不对写事件wev进行初始化呢? 因为监听套接字一般是不可写的, 而且我们只关系它的读事件        ngx_memzero(c, sizeof(ngx_connection_t));        ngx_memzero(rev, sizeof(ngx_event_t));        // 设置连接的fd和listening        c->fd = s[i].fd;        c->listening = &s[i];        // 设置连接的上下文ctx、servers、日志log、rev和wev        c->ctx = s[i].ctx;        c->servers = s[i].servers;        c->log = s[i].log;        c->read = rev;        c->write = wev;        wev->index = NGX_INVALID_INDEX;        rev->log = c->log;        // 设置读事件rev的data为连接c        // 从上面这些我们可以得出, 连接、监听套接字、读事件和写事件这四者是紧密联系的,        // 我们可以从任意一个获取到其它三个        rev->data = c;        rev->index = NGX_INVALID_INDEX;        // 因为读事件还没产生, 设置available为0        rev->available = 0;        // 由于是监听套接字, 设置accept标志为1        rev->accept = 1;#if (HAVE_DEFERRED_ACCEPT)        rev->deferred_accept = s[i].deferred_accept;#endif        if (!(ngx_event_flags & NGX_USE_IOCP_EVENT)) {            // 如果事件处理模型的标志不包含NGX_USE_IOCP_EVENT, 即不使用Windows下的IOCP            if (s[i].remain) {                // 如果监听套接字的remain为1                                // 从事件处理模型中删除旧cycle中该监听套接字的读事件                if (ngx_del_event(&cycle->old_cycle->read_events[fd],                                 NGX_READ_EVENT, NGX_CLOSE_EVENT) == NGX_ERROR)                {                    return NGX_ERROR;                }                cycle->old_cycle->connections[fd].fd = (ngx_socket_t) -1;            }        }#if (WIN32)        // Windows下的IOCP, 这里不做讨论            if (ngx_event_flags & NGX_USE_IOCP_EVENT) {            rev->event_handler = &ngx_event_acceptex;            if (ngx_add_event(rev, 0, NGX_IOCP_ACCEPT) == NGX_ERROR) {                return NGX_ERROR;            }            iocpcf = ngx_event_get_conf(cycle->conf_ctx, ngx_iocp_module);            if (ngx_event_post_acceptex(&s[i], iocpcf->post_acceptex)                                                                  == NGX_ERROR)            {                return NGX_ERROR;            }        } else {            rev->event_handler = &ngx_event_accept;            if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) {                return NGX_ERROR;            }        }#else        // 设置读事件rev的event_handler即事件处理函数为ngx_event_accept,        // 监听套接字可读时一般意味着有新的连接到来, 那么就可以进行accept了        rev->event_handler = &ngx_event_accept;        if (ngx_accept_mutex) {            // 如果ngx_accept_mutex不为空, 意味着会使用互斥锁ngx_accept_mutex来防止worker进程的惊群现象,            // 也就是拿到锁的worker进程, 才能接收新的连接, 那么这里就结束本次循环            continue;        }        if (ngx_event_flags & NGX_USE_RTSIG_EVENT) {            // 如果事件处理模型的标志包含NGX_USE_RTSIG_EVENT                        // 添加连接c            if (ngx_add_conn(c) == NGX_ERROR) {                return NGX_ERROR;            }        } else {            // 不使用ngx_accept_mutex锁的情况下, 可以直接添加读事件rev            if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) {                return NGX_ERROR;            }        }#endif    }    return NGX_OK;}


原创粉丝点击