• nginx 事件模块


    操作系统和内核版本决定事件驱动机制,不同的操作系统对应不同的事件驱动机制,在Linux 2.6之后使用epoll机制,对应的事件驱动模块是ngx_epoll_module。Nginx的ngx_event_core_module模块根据操作系统确定使用哪一个事件驱动模块。

    根据宏定义是否有值,确实使用哪种事件驱动模块,例如在编译后的文件NGINX/NGINX-1.6.2/objs/ngx_auto_config.h查找对应的宏定义,NGX_HAVE_EPOLL值为1,则使用epoll驱动。对应代码:

    ngx_event_module_t  ngx_event_core_module_ctx = {
        &event_core_name,
        ngx_event_core_create_conf,            /* create configuration */
        ngx_event_core_init_conf,              /* init configuration */
    
        { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
    };
    
    
    ngx_module_t  ngx_event_core_module = {
        NGX_MODULE_V1,
        &ngx_event_core_module_ctx,            /* module context */
        ngx_event_core_commands,               /* module directives */
        NGX_EVENT_MODULE,                      /* module type */
        NULL,                                  /* init master */
        ngx_event_module_init,                 /* init module */
        ngx_event_process_init,                /* init process */
        NULL,                                  /* init thread */
        NULL,                                  /* exit thread */
        NULL,                                  /* exit process */
        NULL,                                  /* exit master */
        NGX_MODULE_V1_PADDING
    };
    
    static char *
    ngx_event_core_init_conf(ngx_cycle_t *cycle, void *conf)
    {
        ngx_event_conf_t  *ecf = conf;
    
    #if (NGX_HAVE_EPOLL) && !(NGX_TEST_BUILD_EPOLL)
        int                  fd;
    #endif
    #if (NGX_HAVE_RTSIG)
        ngx_uint_t           rtsig;
        ngx_core_conf_t     *ccf;
    #endif
        ngx_int_t            i;
        ngx_module_t        *module;
        ngx_event_module_t  *event_module;
    
        module = NULL;
    
    #if (NGX_HAVE_EPOLL) && !(NGX_TEST_BUILD_EPOLL)
    
        fd = epoll_create(100);
    
        if (fd != -1) {
            (void) close(fd);
            module = &ngx_epoll_module;
    
        } else if (ngx_errno != NGX_ENOSYS) {
            module = &ngx_epoll_module;
        }
    
    #endif
    
    #if (NGX_HAVE_RTSIG)
    
        if (module == NULL) {
            module = &ngx_rtsig_module;
            rtsig = 1;
    
        } else {
            rtsig = 0;
        }
    
    #endif
    
    #if (NGX_HAVE_DEVPOLL)
    
        module = &ngx_devpoll_module;
    
    #endif
    
    #if (NGX_HAVE_KQUEUE)
    
        module = &ngx_kqueue_module;
    
    #endif
    
    #if (NGX_HAVE_SELECT)
    
        if (module == NULL) {
            module = &ngx_select_module;
        }
    
    #endif
    
        if (module == NULL) {
            for (i = 0; ngx_modules[i]; i++) {
    
                if (ngx_modules[i]->type != NGX_EVENT_MODULE) {
                    continue;
                }
    
                event_module = ngx_modules[i]->ctx;
    
                if (ngx_strcmp(event_module->name->data, event_core_name.data) == 0)
                {
                    continue;
                }
    
                module = ngx_modules[i];
                break;
            }
        }
    
        if (module == NULL) {
            ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, "no events module found");
            return NGX_CONF_ERROR;
        }
    
        ngx_conf_init_uint_value(ecf->connections, DEFAULT_CONNECTIONS);
        cycle->connection_n = ecf->connections;
    
        ngx_conf_init_uint_value(ecf->use, module->ctx_index);
    
        event_module = module->ctx;
        ngx_conf_init_ptr_value(ecf->name, event_module->name->data);
    
        ngx_conf_init_value(ecf->multi_accept, 0);
        ngx_conf_init_value(ecf->accept_mutex, 0);
        ngx_conf_init_msec_value(ecf->accept_mutex_delay, 500);
    
    
    #if (NGX_HAVE_RTSIG)
    
        if (!rtsig) {
            return NGX_CONF_OK;
        }
    
        if (ecf->accept_mutex) {
            return NGX_CONF_OK;
        }
    
        ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
    
        if (ccf->worker_processes == 0) {
            return NGX_CONF_OK;
        }
    
        ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
                      "the "rtsig" method requires "accept_mutex" to be on");
    
        return NGX_CONF_ERROR;
    
    #else
    
        return NGX_CONF_OK;
    
    #endif
    }
    

    事件驱动模块在ngx_module_t的ctx通用接口是ngx_event_module_t,定义如下所示:

    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, ngx_int_t event, ngx_uint_t flags);
        ngx_int_t  (*del)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);
    
        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);
    
        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_changes)(ngx_cycle_t *cycle, ngx_uint_t nowait);
        ngx_int_t  (*process_events)(ngx_cycle_t *cycle, ngx_msec_t timer,
                       ngx_uint_t flags);
    
        ngx_int_t  (*init)(ngx_cycle_t *cycle, ngx_msec_t timer);
        void       (*done)(ngx_cycle_t *cycle);
    } ngx_event_actions_t;

    事件由ngx_event_t结构体定义:

    struct ngx_event_s{
        void            *data;
    
        unsigned         write:1;
    
        unsigned         accept:1;
    
        /* used to detect the stale events in kqueue, rtsig, and epoll */
        unsigned         instance:1;
    
        /*
         * the event was passed or would be passed to a kernel;
         * in aio mode - operation was posted.
         */
        unsigned         active:1;
    
        unsigned         disabled:1;
    
        /* the ready event; in aio mode 0 means that no operation can be posted */
        unsigned         ready:1;
    
        unsigned         oneshot:1;
    
        /* aio operation is complete */
        unsigned         complete:1;
    
        unsigned         eof:1;
        unsigned         error:1;
    
        unsigned         timedout:1;
        unsigned         timer_set:1;
    
        unsigned         delayed:1;
    
        unsigned         deferred_accept:1;
    
        /* the pending eof reported by kqueue, epoll or in aio chain operation */
        unsigned         pending_eof:1;
    
    #if !(NGX_THREADS)
        unsigned         posted_ready:1;
    #endif
    
    #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;
    #else
        unsigned         available:1;
    #endif
    
        ngx_event_handler_pt  handler;
    
    
    #if (NGX_HAVE_AIO)
    
    #if (NGX_HAVE_IOCP)
        ngx_event_ovlp_t ovlp;
    #else
        struct aiocb     aiocb;
    #endif
    
    #endif
    
        ngx_uint_t       index;
    
        ngx_log_t       *log;
    
        ngx_rbtree_node_t   timer;
    
        unsigned         closed:1;
    
        /* to test on worker exit */
        unsigned         channel:1;
        unsigned         resolver:1;
    
    #if (NGX_THREADS)
    
        unsigned         locked:1;
    
        unsigned         posted_ready:1;
        unsigned         posted_timedout:1;
        unsigned         posted_eof:1;
    
    #if (NGX_HAVE_KQUEUE)
        /* the pending errno reported by kqueue */
        int              posted_errno;
    #endif
    
    #if (NGX_HAVE_KQUEUE) || (NGX_HAVE_IOCP)
        int              posted_available;
    #else
        unsigned         posted_available:1;
    #endif
    
        ngx_atomic_t    *lock;
        ngx_atomic_t    *own_lock;
    
    #endif
    
        /* the links of the posted queue */
        ngx_event_t     *next;
        ngx_event_t    **prev;
    
    
    #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
    }

    在ngx_event_t中,我们最关心handler成员,它决定了它所属的事件发生时的处理方法

    转载于:https://my.oschina.net/u/2326611/blog/847236

  • 相关阅读:
    一些博弈
    中国剩余定理分析及扩展
    2018年全国多校算法寒假训练营练习比赛(第三场)
    数论——逆元
    扩展欧几里得
    算法思维题
    匈牙利算法
    Codeforces #449 div2 C题
    16级C程序设计竞赛C题
    动态规划--模板--hdu 1059 Dividing
  • 原文地址:https://www.cnblogs.com/twodog/p/12141171.html
Copyright © 2020-2023  润新知