Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.15.12 ]​[ nginx-1.16.0 ]​

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         sev.sigev_value.sival_ptr = &pn;
0254 
0255         if (timer_create(CLOCK_REALTIME, &sev, &event_timer) == -1) {
0256             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
0257                           "timer_create() failed");
0258             return NGX_ERROR;
0259         }
0260 
0261         its.it_interval.tv_sec = timer / 1000;
0262         its.it_interval.tv_nsec = (timer % 1000) * 1000000;
0263         its.it_value.tv_sec = timer / 1000;
0264         its.it_value.tv_nsec = (timer % 1000) * 1000000;
0265 
0266         if (timer_settime(event_timer, 0, &its, NULL) == -1) {
0267             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
0268                           "timer_settime() failed");
0269             return NGX_ERROR;
0270         }
0271 
0272         ngx_event_flags |= NGX_USE_TIMER_EVENT;
0273     }
0274 
0275     nevents = epcf->events;
0276 
0277     ngx_io = ngx_os_io;
0278 
0279     ngx_event_actions = ngx_eventport_module_ctx.actions;
0280 
0281     return NGX_OK;
0282 }
0283 
0284 
0285 static void
0286 ngx_eventport_done(ngx_cycle_t *cycle)
0287 {
0288     if (event_timer != (timer_t) -1) {
0289         if (timer_delete(event_timer) == -1) {
0290             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
0291                           "timer_delete() failed");
0292         }
0293 
0294         event_timer = (timer_t) -1;
0295     }
0296 
0297     if (close(ep) == -1) {
0298         ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
0299                       "close() event port failed");
0300     }
0301 
0302     ep = -1;
0303 
0304     ngx_free(event_list);
0305 
0306     event_list = NULL;
0307     nevents = 0;
0308 }
0309 
0310 
0311 static ngx_int_t
0312 ngx_eventport_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
0313 {
0314     ngx_int_t          events, prev;
0315     ngx_event_t       *e;
0316     ngx_connection_t  *c;
0317 
0318     c = ev->data;
0319 
0320     events = event;
0321 
0322     if (event == NGX_READ_EVENT) {
0323         e = c->write;
0324         prev = POLLOUT;
0325 #if (NGX_READ_EVENT != POLLIN)
0326         events = POLLIN;
0327 #endif
0328 
0329     } else {
0330         e = c->read;
0331         prev = POLLIN;
0332 #if (NGX_WRITE_EVENT != POLLOUT)
0333         events = POLLOUT;
0334 #endif
0335     }
0336 
0337     if (e->oneshot) {
0338         events |= prev;
0339     }
0340 
0341     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
0342                    "eventport add event: fd:%d ev:%04Xi", c->fd, events);
0343 
0344     if (port_associate(ep, PORT_SOURCE_FD, c->fd, events,
0345                        (void *) ((uintptr_t) ev | ev->instance))
0346         == -1)
0347     {
0348         ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
0349                       "port_associate() failed");
0350         return NGX_ERROR;
0351     }
0352 
0353     ev->active = 1;
0354     ev->oneshot = 1;
0355 
0356     return NGX_OK;
0357 }
0358 
0359 
0360 static ngx_int_t
0361 ngx_eventport_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
0362 {
0363     ngx_event_t       *e;
0364     ngx_connection_t  *c;
0365 
0366     /*
0367      * when the file descriptor is closed, the event port automatically
0368      * dissociates it from the port, so we do not need to dissociate explicitly
0369      * the event before the closing the file descriptor
0370      */
0371 
0372     if (flags & NGX_CLOSE_EVENT) {
0373         ev->active = 0;
0374         ev->oneshot = 0;
0375         return NGX_OK;
0376     }
0377 
0378     c = ev->data;
0379 
0380     if (event == NGX_READ_EVENT) {
0381         e = c->write;
0382         event = POLLOUT;
0383 
0384     } else {
0385         e = c->read;
0386         event = POLLIN;
0387     }
0388 
0389     if (e->oneshot) {
0390         ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
0391                        "eventport change event: fd:%d ev:%04Xi", c->fd, event);
0392 
0393         if (port_associate(ep, PORT_SOURCE_FD, c->fd, event,
0394                            (void *) ((uintptr_t) ev | ev->instance))
0395             == -1)
0396         {
0397             ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
0398                           "port_associate() failed");
0399             return NGX_ERROR;
0400         }
0401 
0402     } else {
0403         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0,
0404                        "eventport del event: fd:%d", c->fd);
0405 
0406         if (port_dissociate(ep, PORT_SOURCE_FD, c->fd) == -1) {
0407             ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
0408                           "port_dissociate() failed");
0409             return NGX_ERROR;
0410         }
0411     }
0412 
0413     ev->active = 0;
0414     ev->oneshot = 0;
0415 
0416     return NGX_OK;
0417 }
0418 
0419 
0420 static ngx_int_t
0421 ngx_eventport_notify(ngx_event_handler_pt handler)
0422 {
0423     notify_event.handler = handler;
0424 
0425     if (port_send(ep, 0, &notify_event) != 0) {
0426         ngx_log_error(NGX_LOG_ALERT, notify_event.log, ngx_errno,
0427                       "port_send() failed");
0428         return NGX_ERROR;
0429     }
0430 
0431     return NGX_OK;
0432 }
0433 
0434 
0435 static ngx_int_t
0436 ngx_eventport_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
0437     ngx_uint_t flags)
0438 {
0439     int                 n, revents;
0440     u_int               events;
0441     ngx_err_t           err;
0442     ngx_int_t           instance;
0443     ngx_uint_t          i, level;
0444     ngx_event_t        *ev, *rev, *wev;
0445     ngx_queue_t        *queue;
0446     ngx_connection_t   *c;
0447     struct timespec     ts, *tp;
0448 
0449     if (timer == NGX_TIMER_INFINITE) {
0450         tp = NULL;
0451 
0452     } else {
0453         ts.tv_sec = timer / 1000;
0454         ts.tv_nsec = (timer % 1000) * 1000000;
0455         tp = &ts;
0456     }
0457 
0458     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
0459                    "eventport timer: %M", timer);
0460 
0461     events = 1;
0462 
0463     n = port_getn(ep, event_list, (u_int) nevents, &events, tp);
0464 
0465     err = ngx_errno;
0466 
0467     if (flags & NGX_UPDATE_TIME) {
0468         ngx_time_update();
0469     }
0470 
0471     if (n == -1) {
0472         if (err == ETIME) {
0473             if (timer != NGX_TIMER_INFINITE) {
0474                 return NGX_OK;
0475             }
0476 
0477             ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
0478                           "port_getn() returned no events without timeout");
0479             return NGX_ERROR;
0480         }
0481 
0482         level = (err == NGX_EINTR) ? NGX_LOG_INFO : NGX_LOG_ALERT;
0483         ngx_log_error(level, cycle->log, err, "port_getn() failed");
0484         return NGX_ERROR;
0485     }
0486 
0487     if (events == 0) {
0488         if (timer != NGX_TIMER_INFINITE) {
0489             return NGX_OK;
0490         }
0491 
0492         ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
0493                       "port_getn() returned no events without timeout");
0494         return NGX_ERROR;
0495     }
0496 
0497     for (i = 0; i < events; i++) {
0498 
0499         if (event_list[i].portev_source == PORT_SOURCE_TIMER) {
0500             ngx_time_update();
0501             continue;
0502         }
0503 
0504         ev = event_list[i].portev_user;
0505 
0506         switch (event_list[i].portev_source) {
0507 
0508         case PORT_SOURCE_FD:
0509 
0510             instance = (uintptr_t) ev & 1;
0511             ev = (ngx_event_t *) ((uintptr_t) ev & (uintptr_t) ~1);
0512 
0513             if (ev->closed || ev->instance != instance) {
0514 
0515                 /*
0516                  * the stale event from a file descriptor
0517                  * that was just closed in this iteration
0518                  */
0519 
0520                 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
0521                                "eventport: stale event %p", ev);
0522                 continue;
0523             }
0524 
0525             revents = event_list[i].portev_events;
0526 
0527             ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
0528                            "eventport: fd:%d, ev:%04Xd",
0529                            (int) event_list[i].portev_object, revents);
0530 
0531             if (revents & (POLLERR|POLLHUP|POLLNVAL)) {
0532                 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
0533                                "port_getn() error fd:%d ev:%04Xd",
0534                                (int) event_list[i].portev_object, revents);
0535             }
0536 
0537             if (revents & ~(POLLIN|POLLOUT|POLLERR|POLLHUP|POLLNVAL)) {
0538                 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
0539                               "strange port_getn() events fd:%d ev:%04Xd",
0540                               (int) event_list[i].portev_object, revents);
0541             }
0542 
0543             if (revents & (POLLERR|POLLHUP|POLLNVAL)) {
0544 
0545                 /*
0546                  * if the error events were returned, add POLLIN and POLLOUT
0547                  * to handle the events at least in one active handler
0548                  */
0549 
0550                 revents |= POLLIN|POLLOUT;
0551             }
0552 
0553             c = ev->data;
0554             rev = c->read;
0555             wev = c->write;
0556 
0557             rev->active = 0;
0558             wev->active = 0;
0559 
0560             if (revents & POLLIN) {
0561                 rev->ready = 1;
0562 
0563                 if (flags & NGX_POST_EVENTS) {
0564                     queue = rev->accept ? &ngx_posted_accept_events
0565                                         : &ngx_posted_events;
0566 
0567                     ngx_post_event(rev, queue);
0568 
0569                 } else {
0570                     rev->handler(rev);
0571 
0572                     if (ev->closed || ev->instance != instance) {
0573                         continue;
0574                     }
0575                 }
0576 
0577                 if (rev->accept) {
0578                     if (ngx_use_accept_mutex) {
0579                         ngx_accept_events = 1;
0580                         continue;
0581                     }
0582 
0583                     if (port_associate(ep, PORT_SOURCE_FD, c->fd, POLLIN,
0584                                        (void *) ((uintptr_t) ev | ev->instance))
0585                         == -1)
0586                     {
0587                         ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
0588                                       "port_associate() failed");
0589                         return NGX_ERROR;
0590                     }
0591                 }
0592             }
0593 
0594             if (revents & POLLOUT) {
0595                 wev->ready = 1;
0596 
0597                 if (flags & NGX_POST_EVENTS) {
0598                     ngx_post_event(wev, &ngx_posted_events);
0599 
0600                 } else {
0601                     wev->handler(wev);
0602                 }
0603             }
0604 
0605             continue;
0606 
0607         case PORT_SOURCE_USER:
0608 
0609             ev->handler(ev);
0610 
0611             continue;
0612 
0613         default:
0614             ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
0615                           "unexpected eventport object %d",
0616                           (int) event_list[i].portev_object);
0617             continue;
0618         }
0619     }
0620 
0621     return NGX_OK;
0622 }
0623 
0624 
0625 static void *
0626 ngx_eventport_create_conf(ngx_cycle_t *cycle)
0627 {
0628     ngx_eventport_conf_t  *epcf;
0629 
0630     epcf = ngx_palloc(cycle->pool, sizeof(ngx_eventport_conf_t));
0631     if (epcf == NULL) {
0632         return NULL;
0633     }
0634 
0635     epcf->events = NGX_CONF_UNSET;
0636 
0637     return epcf;
0638 }
0639 
0640 
0641 static char *
0642 ngx_eventport_init_conf(ngx_cycle_t *cycle, void *conf)
0643 {
0644     ngx_eventport_conf_t *epcf = conf;
0645 
0646     ngx_conf_init_uint_value(epcf->events, 32);
0647 
0648     return NGX_CONF_OK;
0649 }