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 #endif
0023 
0024 /* Solaris declarations */
0025 
0026 #define PORT_SOURCE_AIO         1
0027 #define PORT_SOURCE_TIMER       2
0028 #define PORT_SOURCE_USER        3
0029 #define PORT_SOURCE_FD          4
0030 #define PORT_SOURCE_ALERT       5
0031 #define PORT_SOURCE_MQ          6
0032 
0033 #ifndef ETIME
0034 #define ETIME                   64
0035 #endif
0036 
0037 #define SIGEV_PORT              4
0038 
0039 typedef struct {
0040     int         portev_events;  /* event data is source specific */
0041     ushort_t    portev_source;  /* event source */
0042     ushort_t    portev_pad;     /* port internal use */
0043     uintptr_t   portev_object;  /* source specific object */
0044     void       *portev_user;    /* user cookie */
0045 } port_event_t;
0046 
0047 typedef struct  port_notify {
0048     int         portnfy_port;   /* bind request(s) to port */
0049     void       *portnfy_user;   /* user defined */
0050 } port_notify_t;
0051 
0052 #if (__FreeBSD__ && __FreeBSD_version < 700005) || (NGX_DARWIN)
0053 
0054 typedef struct itimerspec {     /* definition per POSIX.4 */
0055     struct timespec it_interval;/* timer period */
0056     struct timespec it_value;   /* timer expiration */
0057 } itimerspec_t;
0058 
0059 #endif
0060 
0061 int port_create(void);
0062 
0063 int port_create(void)
0064 {
0065     return -1;
0066 }
0067 
0068 
0069 int port_associate(int port, int source, uintptr_t object, int events,
0070     void *user);
0071 
0072 int port_associate(int port, int source, uintptr_t object, int events,
0073     void *user)
0074 {
0075     return -1;
0076 }
0077 
0078 
0079 int port_dissociate(int port, int source, uintptr_t object);
0080 
0081 int port_dissociate(int port, int source, uintptr_t object)
0082 {
0083     return -1;
0084 }
0085 
0086 
0087 int port_getn(int port, port_event_t list[], uint_t max, uint_t *nget,
0088     struct timespec *timeout);
0089 
0090 int port_getn(int port, port_event_t list[], uint_t max, uint_t *nget,
0091     struct timespec *timeout)
0092 {
0093     return -1;
0094 }
0095 
0096 int port_send(int port, int events, void *user);
0097 
0098 int port_send(int port, int events, void *user)
0099 {
0100     return -1;
0101 }
0102 
0103 
0104 int timer_create(clockid_t clock_id, struct sigevent *evp, timer_t *timerid);
0105 
0106 int timer_create(clockid_t clock_id, struct sigevent *evp, timer_t *timerid)
0107 {
0108     return -1;
0109 }
0110 
0111 
0112 int timer_settime(timer_t timerid, int flags, const struct itimerspec *value,
0113     struct itimerspec *ovalue);
0114 
0115 int timer_settime(timer_t timerid, int flags, const struct itimerspec *value,
0116     struct itimerspec *ovalue)
0117 {
0118     return -1;
0119 }
0120 
0121 
0122 int timer_delete(timer_t timerid);
0123 
0124 int timer_delete(timer_t timerid)
0125 {
0126     return -1;
0127 }
0128 
0129 #endif
0130 
0131 
0132 typedef struct {
0133     ngx_uint_t  events;
0134 } ngx_eventport_conf_t;
0135 
0136 
0137 static ngx_int_t ngx_eventport_init(ngx_cycle_t *cycle, ngx_msec_t timer);
0138 static void ngx_eventport_done(ngx_cycle_t *cycle);
0139 static ngx_int_t ngx_eventport_add_event(ngx_event_t *ev, ngx_int_t event,
0140     ngx_uint_t flags);
0141 static ngx_int_t ngx_eventport_del_event(ngx_event_t *ev, ngx_int_t event,
0142     ngx_uint_t flags);
0143 static ngx_int_t ngx_eventport_notify(ngx_event_handler_pt handler);
0144 static ngx_int_t ngx_eventport_process_events(ngx_cycle_t *cycle,
0145     ngx_msec_t timer, ngx_uint_t flags);
0146 
0147 static void *ngx_eventport_create_conf(ngx_cycle_t *cycle);
0148 static char *ngx_eventport_init_conf(ngx_cycle_t *cycle, void *conf);
0149 
0150 static int            ep = -1;
0151 static port_event_t  *event_list;
0152 static ngx_uint_t     nevents;
0153 static timer_t        event_timer = (timer_t) -1;
0154 static ngx_event_t    notify_event;
0155 
0156 static ngx_str_t      eventport_name = ngx_string("eventport");
0157 
0158 
0159 static ngx_command_t  ngx_eventport_commands[] = {
0160 
0161     { ngx_string("eventport_events"),
0162       NGX_EVENT_CONF|NGX_CONF_TAKE1,
0163       ngx_conf_set_num_slot,
0164       0,
0165       offsetof(ngx_eventport_conf_t, events),
0166       NULL },
0167 
0168       ngx_null_command
0169 };
0170 
0171 
0172 static ngx_event_module_t  ngx_eventport_module_ctx = {
0173     &eventport_name,
0174     ngx_eventport_create_conf,             /* create configuration */
0175     ngx_eventport_init_conf,               /* init configuration */
0176 
0177     {
0178         ngx_eventport_add_event,           /* add an event */
0179         ngx_eventport_del_event,           /* delete an event */
0180         ngx_eventport_add_event,           /* enable an event */
0181         ngx_eventport_del_event,           /* disable an event */
0182         NULL,                              /* add an connection */
0183         NULL,                              /* delete an connection */
0184         ngx_eventport_notify,              /* trigger a notify */
0185         ngx_eventport_process_events,      /* process the events */
0186         ngx_eventport_init,                /* init the events */
0187         ngx_eventport_done,                /* done the events */
0188     }
0189 
0190 };
0191 
0192 ngx_module_t  ngx_eventport_module = {
0193     NGX_MODULE_V1,
0194     &ngx_eventport_module_ctx,             /* module context */
0195     ngx_eventport_commands,                /* module directives */
0196     NGX_EVENT_MODULE,                      /* module type */
0197     NULL,                                  /* init master */
0198     NULL,                                  /* init module */
0199     NULL,                                  /* init process */
0200     NULL,                                  /* init thread */
0201     NULL,                                  /* exit thread */
0202     NULL,                                  /* exit process */
0203     NULL,                                  /* exit master */
0204     NGX_MODULE_V1_PADDING
0205 };
0206 
0207 
0208 static ngx_int_t
0209 ngx_eventport_init(ngx_cycle_t *cycle, ngx_msec_t timer)
0210 {
0211     port_notify_t          pn;
0212     struct itimerspec      its;
0213     struct sigevent        sev;
0214     ngx_eventport_conf_t  *epcf;
0215 
0216     epcf = ngx_event_get_conf(cycle->conf_ctx, ngx_eventport_module);
0217 
0218     if (ep == -1) {
0219         ep = port_create();
0220 
0221         if (ep == -1) {
0222             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
0223                           "port_create() failed");
0224             return NGX_ERROR;
0225         }
0226 
0227         notify_event.active = 1;
0228         notify_event.log = cycle->log;
0229     }
0230 
0231     if (nevents < epcf->events) {
0232         if (event_list) {
0233             ngx_free(event_list);
0234         }
0235 
0236         event_list = ngx_alloc(sizeof(port_event_t) * epcf->events,
0237                                cycle->log);
0238         if (event_list == NULL) {
0239             return NGX_ERROR;
0240         }
0241     }
0242 
0243     ngx_event_flags = NGX_USE_EVENTPORT_EVENT;
0244 
0245     if (timer) {
0246         ngx_memzero(&pn, sizeof(port_notify_t));
0247         pn.portnfy_port = ep;
0248 
0249         ngx_memzero(&sev, sizeof(struct sigevent));
0250         sev.sigev_notify = SIGEV_PORT;
0251 #if !(NGX_TEST_BUILD_EVENTPORT)
0252         sev.sigev_value.sival_ptr = &pn;
0253 #endif
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 }