Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.13.12 ]​[ nginx-1.12.2 ]​

0001 
0002 /*
0003  * Copyright (C) Igor Sysoev
0004  * Copyright (C) Nginx, Inc.
0005  */
0006 
0007 
0008 #include <ngx_config.h>
0009 #include <ngx_core.h>
0010 #include <ngx_event.h>
0011 
0012 
0013 #if (NGX_TEST_BUILD_EVENTPORT)
0014 
0015 #define ushort_t  u_short
0016 #define uint_t    u_int
0017 
0018 #ifndef CLOCK_REALTIME
0019 #define CLOCK_REALTIME          0
0020 typedef int     clockid_t;
0021 typedef void *  timer_t;
0022 #elif (NGX_DARWIN)
0023 typedef void *  timer_t;
0024 #endif
0025 
0026 /* Solaris declarations */
0027 
0028 #define PORT_SOURCE_AIO         1
0029 #define PORT_SOURCE_TIMER       2
0030 #define PORT_SOURCE_USER        3
0031 #define PORT_SOURCE_FD          4
0032 #define PORT_SOURCE_ALERT       5
0033 #define PORT_SOURCE_MQ          6
0034 
0035 #ifndef ETIME
0036 #define ETIME                   64
0037 #endif
0038 
0039 #define SIGEV_PORT              4
0040 
0041 typedef struct {
0042     int         portev_events;  /* event data is source specific */
0043     ushort_t    portev_source;  /* event source */
0044     ushort_t    portev_pad;     /* port internal use */
0045     uintptr_t   portev_object;  /* source specific object */
0046     void       *portev_user;    /* user cookie */
0047 } port_event_t;
0048 
0049 typedef struct  port_notify {
0050     int         portnfy_port;   /* bind request(s) to port */
0051     void       *portnfy_user;   /* user defined */
0052 } port_notify_t;
0053 
0054 #if (__FreeBSD__ && __FreeBSD_version < 700005) || (NGX_DARWIN)
0055 
0056 typedef struct itimerspec {     /* definition per POSIX.4 */
0057     struct timespec it_interval;/* timer period */
0058     struct timespec it_value;   /* timer expiration */
0059 } itimerspec_t;
0060 
0061 #endif
0062 
0063 int port_create(void);
0064 
0065 int port_create(void)
0066 {
0067     return -1;
0068 }
0069 
0070 
0071 int port_associate(int port, int source, uintptr_t object, int events,
0072     void *user);
0073 
0074 int port_associate(int port, int source, uintptr_t object, int events,
0075     void *user)
0076 {
0077     return -1;
0078 }
0079 
0080 
0081 int port_dissociate(int port, int source, uintptr_t object);
0082 
0083 int port_dissociate(int port, int source, uintptr_t object)
0084 {
0085     return -1;
0086 }
0087 
0088 
0089 int port_getn(int port, port_event_t list[], uint_t max, uint_t *nget,
0090     struct timespec *timeout);
0091 
0092 int port_getn(int port, port_event_t list[], uint_t max, uint_t *nget,
0093     struct timespec *timeout)
0094 {
0095     return -1;
0096 }
0097 
0098 int port_send(int port, int events, void *user);
0099 
0100 int port_send(int port, int events, void *user)
0101 {
0102     return -1;
0103 }
0104 
0105 
0106 int timer_create(clockid_t clock_id, struct sigevent *evp, timer_t *timerid);
0107 
0108 int timer_create(clockid_t clock_id, struct sigevent *evp, timer_t *timerid)
0109 {
0110     return -1;
0111 }
0112 
0113 
0114 int timer_settime(timer_t timerid, int flags, const struct itimerspec *value,
0115     struct itimerspec *ovalue);
0116 
0117 int timer_settime(timer_t timerid, int flags, const struct itimerspec *value,
0118     struct itimerspec *ovalue)
0119 {
0120     return -1;
0121 }
0122 
0123 
0124 int timer_delete(timer_t timerid);
0125 
0126 int timer_delete(timer_t timerid)
0127 {
0128     return -1;
0129 }
0130 
0131 #endif
0132 
0133 
0134 typedef struct {
0135     ngx_uint_t  events;
0136 } ngx_eventport_conf_t;
0137 
0138 
0139 static ngx_int_t ngx_eventport_init(ngx_cycle_t *cycle, ngx_msec_t timer);
0140 static void ngx_eventport_done(ngx_cycle_t *cycle);
0141 static ngx_int_t ngx_eventport_add_event(ngx_event_t *ev, ngx_int_t event,
0142     ngx_uint_t flags);
0143 static ngx_int_t ngx_eventport_del_event(ngx_event_t *ev, ngx_int_t event,
0144     ngx_uint_t flags);
0145 static ngx_int_t ngx_eventport_notify(ngx_event_handler_pt handler);
0146 static ngx_int_t ngx_eventport_process_events(ngx_cycle_t *cycle,
0147     ngx_msec_t timer, ngx_uint_t flags);
0148 
0149 static void *ngx_eventport_create_conf(ngx_cycle_t *cycle);
0150 static char *ngx_eventport_init_conf(ngx_cycle_t *cycle, void *conf);
0151 
0152 static int            ep = -1;
0153 static port_event_t  *event_list;
0154 static ngx_uint_t     nevents;
0155 static timer_t        event_timer = (timer_t) -1;
0156 static ngx_event_t    notify_event;
0157 
0158 static ngx_str_t      eventport_name = ngx_string("eventport");
0159 
0160 
0161 static ngx_command_t  ngx_eventport_commands[] = {
0162 
0163     { ngx_string("eventport_events"),
0164       NGX_EVENT_CONF|NGX_CONF_TAKE1,
0165       ngx_conf_set_num_slot,
0166       0,
0167       offsetof(ngx_eventport_conf_t, events),
0168       NULL },
0169 
0170       ngx_null_command
0171 };
0172 
0173 
0174 static ngx_event_module_t  ngx_eventport_module_ctx = {
0175     &eventport_name,
0176     ngx_eventport_create_conf,             /* create configuration */
0177     ngx_eventport_init_conf,               /* init configuration */
0178 
0179     {
0180         ngx_eventport_add_event,           /* add an event */
0181         ngx_eventport_del_event,           /* delete an event */
0182         ngx_eventport_add_event,           /* enable an event */
0183         ngx_eventport_del_event,           /* disable an event */
0184         NULL,                              /* add an connection */
0185         NULL,                              /* delete an connection */
0186         ngx_eventport_notify,              /* trigger a notify */
0187         ngx_eventport_process_events,      /* process the events */
0188         ngx_eventport_init,                /* init the events */
0189         ngx_eventport_done,                /* done the events */
0190     }
0191 
0192 };
0193 
0194 ngx_module_t  ngx_eventport_module = {
0195     NGX_MODULE_V1,
0196     &ngx_eventport_module_ctx,             /* module context */
0197     ngx_eventport_commands,                /* module directives */
0198     NGX_EVENT_MODULE,                      /* module type */
0199     NULL,                                  /* init master */
0200     NULL,                                  /* init module */
0201     NULL,                                  /* init process */
0202     NULL,                                  /* init thread */
0203     NULL,                                  /* exit thread */
0204     NULL,                                  /* exit process */
0205     NULL,                                  /* exit master */
0206     NGX_MODULE_V1_PADDING
0207 };
0208 
0209 
0210 static ngx_int_t
0211 ngx_eventport_init(ngx_cycle_t *cycle, ngx_msec_t timer)
0212 {
0213     port_notify_t          pn;
0214     struct itimerspec      its;
0215     struct sigevent        sev;
0216     ngx_eventport_conf_t  *epcf;
0217 
0218     epcf = ngx_event_get_conf(cycle->conf_ctx, ngx_eventport_module);
0219 
0220     if (ep == -1) {
0221         ep = port_create();
0222 
0223         if (ep == -1) {
0224             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
0225                           "port_create() failed");
0226             return NGX_ERROR;
0227         }
0228 
0229         notify_event.active = 1;
0230         notify_event.log = cycle->log;
0231     }
0232 
0233     if (nevents < epcf->events) {
0234         if (event_list) {
0235             ngx_free(event_list);
0236         }
0237 
0238         event_list = ngx_alloc(sizeof(port_event_t) * epcf->events,
0239                                cycle->log);
0240         if (event_list == NULL) {
0241             return NGX_ERROR;
0242         }
0243     }
0244 
0245     ngx_event_flags = NGX_USE_EVENTPORT_EVENT;
0246 
0247     if (timer) {
0248         ngx_memzero(&pn, sizeof(port_notify_t));
0249         pn.portnfy_port = ep;
0250 
0251         ngx_memzero(&sev, sizeof(struct sigevent));
0252         sev.sigev_notify = SIGEV_PORT;
0253 #if !(NGX_TEST_BUILD_EVENTPORT)
0254         sev.sigev_value.sival_ptr = &pn;
0255 #endif
0256 
0257         if (timer_create(CLOCK_REALTIME, &sev, &event_timer) == -1) {
0258             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
0259                           "timer_create() failed");
0260             return NGX_ERROR;
0261         }
0262 
0263         its.it_interval.tv_sec = timer / 1000;
0264         its.it_interval.tv_nsec = (timer % 1000) * 1000000;
0265         its.it_value.tv_sec = timer / 1000;
0266         its.it_value.tv_nsec = (timer % 1000) * 1000000;
0267 
0268         if (timer_settime(event_timer, 0, &its, NULL) == -1) {
0269             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
0270                           "timer_settime() failed");
0271             return NGX_ERROR;
0272         }
0273 
0274         ngx_event_flags |= NGX_USE_TIMER_EVENT;
0275     }
0276 
0277     nevents = epcf->events;
0278 
0279     ngx_io = ngx_os_io;
0280 
0281     ngx_event_actions = ngx_eventport_module_ctx.actions;
0282 
0283     return NGX_OK;
0284 }
0285 
0286 
0287 static void
0288 ngx_eventport_done(ngx_cycle_t *cycle)
0289 {
0290     if (event_timer != (timer_t) -1) {
0291         if (timer_delete(event_timer) == -1) {
0292             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
0293                           "timer_delete() failed");
0294         }
0295 
0296         event_timer = (timer_t) -1;
0297     }
0298 
0299     if (close(ep) == -1) {
0300         ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
0301                       "close() event port failed");
0302     }
0303 
0304     ep = -1;
0305 
0306     ngx_free(event_list);
0307 
0308     event_list = NULL;
0309     nevents = 0;
0310 }
0311 
0312 
0313 static ngx_int_t
0314 ngx_eventport_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
0315 {
0316     ngx_int_t          events, prev;
0317     ngx_event_t       *e;
0318     ngx_connection_t  *c;
0319 
0320     c = ev->data;
0321 
0322     events = event;
0323 
0324     if (event == NGX_READ_EVENT) {
0325         e = c->write;
0326         prev = POLLOUT;
0327 #if (NGX_READ_EVENT != POLLIN)
0328         events = POLLIN;
0329 #endif
0330 
0331     } else {
0332         e = c->read;
0333         prev = POLLIN;
0334 #if (NGX_WRITE_EVENT != POLLOUT)
0335         events = POLLOUT;
0336 #endif
0337     }
0338 
0339     if (e->oneshot) {
0340         events |= prev;
0341     }
0342 
0343     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
0344                    "eventport add event: fd:%d ev:%04Xi", c->fd, events);
0345 
0346     if (port_associate(ep, PORT_SOURCE_FD, c->fd, events,
0347                        (void *) ((uintptr_t) ev | ev->instance))
0348         == -1)
0349     {
0350         ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
0351                       "port_associate() failed");
0352         return NGX_ERROR;
0353     }
0354 
0355     ev->active = 1;
0356     ev->oneshot = 1;
0357 
0358     return NGX_OK;
0359 }
0360 
0361 
0362 static ngx_int_t
0363 ngx_eventport_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
0364 {
0365     ngx_event_t       *e;
0366     ngx_connection_t  *c;
0367 
0368     /*
0369      * when the file descriptor is closed, the event port automatically
0370      * dissociates it from the port, so we do not need to dissociate explicitly
0371      * the event before the closing the file descriptor
0372      */
0373 
0374     if (flags & NGX_CLOSE_EVENT) {
0375         ev->active = 0;
0376         ev->oneshot = 0;
0377         return NGX_OK;
0378     }
0379 
0380     c = ev->data;
0381 
0382     if (event == NGX_READ_EVENT) {
0383         e = c->write;
0384         event = POLLOUT;
0385 
0386     } else {
0387         e = c->read;
0388         event = POLLIN;
0389     }
0390 
0391     if (e->oneshot) {
0392         ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
0393                        "eventport change event: fd:%d ev:%04Xi", c->fd, event);
0394 
0395         if (port_associate(ep, PORT_SOURCE_FD, c->fd, event,
0396                            (void *) ((uintptr_t) ev | ev->instance))
0397             == -1)
0398         {
0399             ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
0400                           "port_associate() failed");
0401             return NGX_ERROR;
0402         }
0403 
0404     } else {
0405         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0,
0406                        "eventport del event: fd:%d", c->fd);
0407 
0408         if (port_dissociate(ep, PORT_SOURCE_FD, c->fd) == -1) {
0409             ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
0410                           "port_dissociate() failed");
0411             return NGX_ERROR;
0412         }
0413     }
0414 
0415     ev->active = 0;
0416     ev->oneshot = 0;
0417 
0418     return NGX_OK;
0419 }
0420 
0421 
0422 static ngx_int_t
0423 ngx_eventport_notify(ngx_event_handler_pt handler)
0424 {
0425     notify_event.handler = handler;
0426 
0427     if (port_send(ep, 0, &notify_event) != 0) {
0428         ngx_log_error(NGX_LOG_ALERT, notify_event.log, ngx_errno,
0429                       "port_send() failed");
0430         return NGX_ERROR;
0431     }
0432 
0433     return NGX_OK;
0434 }
0435 
0436 
0437 static ngx_int_t
0438 ngx_eventport_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
0439     ngx_uint_t flags)
0440 {
0441     int                 n, revents;
0442     u_int               events;
0443     ngx_err_t           err;
0444     ngx_int_t           instance;
0445     ngx_uint_t          i, level;
0446     ngx_event_t        *ev, *rev, *wev;
0447     ngx_queue_t        *queue;
0448     ngx_connection_t   *c;
0449     struct timespec     ts, *tp;
0450 
0451     if (timer == NGX_TIMER_INFINITE) {
0452         tp = NULL;
0453 
0454     } else {
0455         ts.tv_sec = timer / 1000;
0456         ts.tv_nsec = (timer % 1000) * 1000000;
0457         tp = &ts;
0458     }
0459 
0460     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
0461                    "eventport timer: %M", timer);
0462 
0463     events = 1;
0464 
0465     n = port_getn(ep, event_list, (u_int) nevents, &events, tp);
0466 
0467     err = ngx_errno;
0468 
0469     if (flags & NGX_UPDATE_TIME) {
0470         ngx_time_update();
0471     }
0472 
0473     if (n == -1) {
0474         if (err == ETIME) {
0475             if (timer != NGX_TIMER_INFINITE) {
0476                 return NGX_OK;
0477             }
0478 
0479             ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
0480                           "port_getn() returned no events without timeout");
0481             return NGX_ERROR;
0482         }
0483 
0484         level = (err == NGX_EINTR) ? NGX_LOG_INFO : NGX_LOG_ALERT;
0485         ngx_log_error(level, cycle->log, err, "port_getn() failed");
0486         return NGX_ERROR;
0487     }
0488 
0489     if (events == 0) {
0490         if (timer != NGX_TIMER_INFINITE) {
0491             return NGX_OK;
0492         }
0493 
0494         ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
0495                       "port_getn() returned no events without timeout");
0496         return NGX_ERROR;
0497     }
0498 
0499     for (i = 0; i < events; i++) {
0500 
0501         if (event_list[i].portev_source == PORT_SOURCE_TIMER) {
0502             ngx_time_update();
0503             continue;
0504         }
0505 
0506         ev = event_list[i].portev_user;
0507 
0508         switch (event_list[i].portev_source) {
0509 
0510         case PORT_SOURCE_FD:
0511 
0512             instance = (uintptr_t) ev & 1;
0513             ev = (ngx_event_t *) ((uintptr_t) ev & (uintptr_t) ~1);
0514 
0515             if (ev->closed || ev->instance != instance) {
0516 
0517                 /*
0518                  * the stale event from a file descriptor
0519                  * that was just closed in this iteration
0520                  */
0521 
0522                 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
0523                                "eventport: stale event %p", ev);
0524                 continue;
0525             }
0526 
0527             revents = event_list[i].portev_events;
0528 
0529             ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
0530                            "eventport: fd:%d, ev:%04Xd",
0531                            (int) event_list[i].portev_object, revents);
0532 
0533             if (revents & (POLLERR|POLLHUP|POLLNVAL)) {
0534                 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
0535                                "port_getn() error fd:%d ev:%04Xd",
0536                                (int) event_list[i].portev_object, revents);
0537             }
0538 
0539             if (revents & ~(POLLIN|POLLOUT|POLLERR|POLLHUP|POLLNVAL)) {
0540                 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
0541                               "strange port_getn() events fd:%d ev:%04Xd",
0542                               (int) event_list[i].portev_object, revents);
0543             }
0544 
0545             if (revents & (POLLERR|POLLHUP|POLLNVAL)) {
0546 
0547                 /*
0548                  * if the error events were returned, add POLLIN and POLLOUT
0549                  * to handle the events at least in one active handler
0550                  */
0551 
0552                 revents |= POLLIN|POLLOUT;
0553             }
0554 
0555             c = ev->data;
0556             rev = c->read;
0557             wev = c->write;
0558 
0559             rev->active = 0;
0560             wev->active = 0;
0561 
0562             if (revents & POLLIN) {
0563                 rev->ready = 1;
0564 
0565                 if (flags & NGX_POST_EVENTS) {
0566                     queue = rev->accept ? &ngx_posted_accept_events
0567                                         : &ngx_posted_events;
0568 
0569                     ngx_post_event(rev, queue);
0570 
0571                 } else {
0572                     rev->handler(rev);
0573 
0574                     if (ev->closed || ev->instance != instance) {
0575                         continue;
0576                     }
0577                 }
0578 
0579                 if (rev->accept) {
0580                     if (ngx_use_accept_mutex) {
0581                         ngx_accept_events = 1;
0582                         continue;
0583                     }
0584 
0585                     if (port_associate(ep, PORT_SOURCE_FD, c->fd, POLLIN,
0586                                        (void *) ((uintptr_t) ev | ev->instance))
0587                         == -1)
0588                     {
0589                         ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
0590                                       "port_associate() failed");
0591                         return NGX_ERROR;
0592                     }
0593                 }
0594             }
0595 
0596             if (revents & POLLOUT) {
0597                 wev->ready = 1;
0598 
0599                 if (flags & NGX_POST_EVENTS) {
0600                     ngx_post_event(wev, &ngx_posted_events);
0601 
0602                 } else {
0603                     wev->handler(wev);
0604                 }
0605             }
0606 
0607             continue;
0608 
0609         case PORT_SOURCE_USER:
0610 
0611             ev->handler(ev);
0612 
0613             continue;
0614 
0615         default:
0616             ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
0617                           "unexpected eventport object %d",
0618                           (int) event_list[i].portev_object);
0619             continue;
0620         }
0621     }
0622 
0623     return NGX_OK;
0624 }
0625 
0626 
0627 static void *
0628 ngx_eventport_create_conf(ngx_cycle_t *cycle)
0629 {
0630     ngx_eventport_conf_t  *epcf;
0631 
0632     epcf = ngx_palloc(cycle->pool, sizeof(ngx_eventport_conf_t));
0633     if (epcf == NULL) {
0634         return NULL;
0635     }
0636 
0637     epcf->events = NGX_CONF_UNSET;
0638 
0639     return epcf;
0640 }
0641 
0642 
0643 static char *
0644 ngx_eventport_init_conf(ngx_cycle_t *cycle, void *conf)
0645 {
0646     ngx_eventport_conf_t *epcf = conf;
0647 
0648     ngx_conf_init_uint_value(epcf->events, 32);
0649 
0650     return NGX_CONF_OK;
0651 }