Annotation of embedaddon/nginx/src/event/modules/ngx_select_module.c, revision 1.1.1.1

1.1       misho       1: 
                      2: /*
                      3:  * Copyright (C) Igor Sysoev
                      4:  * Copyright (C) Nginx, Inc.
                      5:  */
                      6: 
                      7: 
                      8: #include <ngx_config.h>
                      9: #include <ngx_core.h>
                     10: #include <ngx_event.h>
                     11: 
                     12: 
                     13: static ngx_int_t ngx_select_init(ngx_cycle_t *cycle, ngx_msec_t timer);
                     14: static void ngx_select_done(ngx_cycle_t *cycle);
                     15: static ngx_int_t ngx_select_add_event(ngx_event_t *ev, ngx_int_t event,
                     16:     ngx_uint_t flags);
                     17: static ngx_int_t ngx_select_del_event(ngx_event_t *ev, ngx_int_t event,
                     18:     ngx_uint_t flags);
                     19: static ngx_int_t ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
                     20:     ngx_uint_t flags);
                     21: static void ngx_select_repair_fd_sets(ngx_cycle_t *cycle);
                     22: static char *ngx_select_init_conf(ngx_cycle_t *cycle, void *conf);
                     23: 
                     24: 
                     25: static fd_set         master_read_fd_set;
                     26: static fd_set         master_write_fd_set;
                     27: static fd_set         work_read_fd_set;
                     28: static fd_set         work_write_fd_set;
                     29: 
                     30: static ngx_int_t      max_fd;
                     31: static ngx_uint_t     nevents;
                     32: 
                     33: static ngx_event_t  **event_index;
                     34: 
                     35: 
                     36: static ngx_str_t    select_name = ngx_string("select");
                     37: 
                     38: ngx_event_module_t  ngx_select_module_ctx = {
                     39:     &select_name,
                     40:     NULL,                                  /* create configuration */
                     41:     ngx_select_init_conf,                  /* init configuration */
                     42: 
                     43:     {
                     44:         ngx_select_add_event,              /* add an event */
                     45:         ngx_select_del_event,              /* delete an event */
                     46:         ngx_select_add_event,              /* enable an event */
                     47:         ngx_select_del_event,              /* disable an event */
                     48:         NULL,                              /* add an connection */
                     49:         NULL,                              /* delete an connection */
                     50:         NULL,                              /* process the changes */
                     51:         ngx_select_process_events,         /* process the events */
                     52:         ngx_select_init,                   /* init the events */
                     53:         ngx_select_done                    /* done the events */
                     54:     }
                     55: 
                     56: };
                     57: 
                     58: ngx_module_t  ngx_select_module = {
                     59:     NGX_MODULE_V1,
                     60:     &ngx_select_module_ctx,                /* module context */
                     61:     NULL,                                  /* module directives */
                     62:     NGX_EVENT_MODULE,                      /* module type */
                     63:     NULL,                                  /* init master */
                     64:     NULL,                                  /* init module */
                     65:     NULL,                                  /* init process */
                     66:     NULL,                                  /* init thread */
                     67:     NULL,                                  /* exit thread */
                     68:     NULL,                                  /* exit process */
                     69:     NULL,                                  /* exit master */
                     70:     NGX_MODULE_V1_PADDING
                     71: };
                     72: 
                     73: 
                     74: static ngx_int_t
                     75: ngx_select_init(ngx_cycle_t *cycle, ngx_msec_t timer)
                     76: {
                     77:     ngx_event_t  **index;
                     78: 
                     79:     if (event_index == NULL) {
                     80:         FD_ZERO(&master_read_fd_set);
                     81:         FD_ZERO(&master_write_fd_set);
                     82:         nevents = 0;
                     83:     }
                     84: 
                     85:     if (ngx_process >= NGX_PROCESS_WORKER
                     86:         || cycle->old_cycle == NULL
                     87:         || cycle->old_cycle->connection_n < cycle->connection_n)
                     88:     {
                     89:         index = ngx_alloc(sizeof(ngx_event_t *) * 2 * cycle->connection_n,
                     90:                           cycle->log);
                     91:         if (index == NULL) {
                     92:             return NGX_ERROR;
                     93:         }
                     94: 
                     95:         if (event_index) {
                     96:             ngx_memcpy(index, event_index, sizeof(ngx_event_t *) * nevents);
                     97:             ngx_free(event_index);
                     98:         }
                     99: 
                    100:         event_index = index;
                    101:     }
                    102: 
                    103:     ngx_io = ngx_os_io;
                    104: 
                    105:     ngx_event_actions = ngx_select_module_ctx.actions;
                    106: 
                    107:     ngx_event_flags = NGX_USE_LEVEL_EVENT;
                    108: 
                    109:     max_fd = -1;
                    110: 
                    111:     return NGX_OK;
                    112: }
                    113: 
                    114: 
                    115: static void
                    116: ngx_select_done(ngx_cycle_t *cycle)
                    117: {
                    118:     ngx_free(event_index);
                    119: 
                    120:     event_index = NULL;
                    121: }
                    122: 
                    123: 
                    124: static ngx_int_t
                    125: ngx_select_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
                    126: {
                    127:     ngx_connection_t  *c;
                    128: 
                    129:     c = ev->data;
                    130: 
                    131:     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
                    132:                    "select add event fd:%d ev:%i", c->fd, event);
                    133: 
                    134:     if (ev->index != NGX_INVALID_INDEX) {
                    135:         ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
                    136:                       "select event fd:%d ev:%i is already set", c->fd, event);
                    137:         return NGX_OK;
                    138:     }
                    139: 
                    140:     if ((event == NGX_READ_EVENT && ev->write)
                    141:         || (event == NGX_WRITE_EVENT && !ev->write))
                    142:     {
                    143:         ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
                    144:                       "invalid select %s event fd:%d ev:%i",
                    145:                       ev->write ? "write" : "read", c->fd, event);
                    146:         return NGX_ERROR;
                    147:     }
                    148: 
                    149:     if (event == NGX_READ_EVENT) {
                    150:         FD_SET(c->fd, &master_read_fd_set);
                    151: 
                    152:     } else if (event == NGX_WRITE_EVENT) {
                    153:         FD_SET(c->fd, &master_write_fd_set);
                    154:     }
                    155: 
                    156:     if (max_fd != -1 && max_fd < c->fd) {
                    157:         max_fd = c->fd;
                    158:     }
                    159: 
                    160:     ev->active = 1;
                    161: 
                    162:     event_index[nevents] = ev;
                    163:     ev->index = nevents;
                    164:     nevents++;
                    165: 
                    166:     return NGX_OK;
                    167: }
                    168: 
                    169: 
                    170: static ngx_int_t
                    171: ngx_select_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
                    172: {
                    173:     ngx_event_t       *e;
                    174:     ngx_connection_t  *c;
                    175: 
                    176:     c = ev->data;
                    177: 
                    178:     ev->active = 0;
                    179: 
                    180:     if (ev->index == NGX_INVALID_INDEX) {
                    181:         return NGX_OK;
                    182:     }
                    183: 
                    184:     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
                    185:                    "select del event fd:%d ev:%i", c->fd, event);
                    186: 
                    187:     if (event == NGX_READ_EVENT) {
                    188:         FD_CLR(c->fd, &master_read_fd_set);
                    189: 
                    190:     } else if (event == NGX_WRITE_EVENT) {
                    191:         FD_CLR(c->fd, &master_write_fd_set);
                    192:     }
                    193: 
                    194:     if (max_fd == c->fd) {
                    195:         max_fd = -1;
                    196:     }
                    197: 
                    198:     if (ev->index < --nevents) {
                    199:         e = event_index[nevents];
                    200:         event_index[ev->index] = e;
                    201:         e->index = ev->index;
                    202:     }
                    203: 
                    204:     ev->index = NGX_INVALID_INDEX;
                    205: 
                    206:     return NGX_OK;
                    207: }
                    208: 
                    209: 
                    210: static ngx_int_t
                    211: ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
                    212:     ngx_uint_t flags)
                    213: {
                    214:     int                ready, nready;
                    215:     ngx_err_t          err;
                    216:     ngx_uint_t         i, found;
                    217:     ngx_event_t       *ev, **queue;
                    218:     struct timeval     tv, *tp;
                    219:     ngx_connection_t  *c;
                    220: 
                    221:     if (max_fd == -1) {
                    222:         for (i = 0; i < nevents; i++) {
                    223:             c = event_index[i]->data;
                    224:             if (max_fd < c->fd) {
                    225:                 max_fd = c->fd;
                    226:             }
                    227:         }
                    228: 
                    229:         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                    230:                        "change max_fd: %d", max_fd);
                    231:     }
                    232: 
                    233: #if (NGX_DEBUG)
                    234:     if (cycle->log->log_level & NGX_LOG_DEBUG_ALL) {
                    235:         for (i = 0; i < nevents; i++) {
                    236:             ev = event_index[i];
                    237:             c = ev->data;
                    238:             ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                    239:                            "select event: fd:%d wr:%d", c->fd, ev->write);
                    240:         }
                    241: 
                    242:         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                    243:                        "max_fd: %d", max_fd);
                    244:     }
                    245: #endif
                    246: 
                    247:     if (timer == NGX_TIMER_INFINITE) {
                    248:         tp = NULL;
                    249: 
                    250:     } else {
                    251:         tv.tv_sec = (long) (timer / 1000);
                    252:         tv.tv_usec = (long) ((timer % 1000) * 1000);
                    253:         tp = &tv;
                    254:     }
                    255: 
                    256:     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                    257:                    "select timer: %M", timer);
                    258: 
                    259:     work_read_fd_set = master_read_fd_set;
                    260:     work_write_fd_set = master_write_fd_set;
                    261: 
                    262:     ready = select(max_fd + 1, &work_read_fd_set, &work_write_fd_set, NULL, tp);
                    263: 
                    264:     err = (ready == -1) ? ngx_errno : 0;
                    265: 
                    266:     if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
                    267:         ngx_time_update();
                    268:     }
                    269: 
                    270:     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                    271:                    "select ready %d", ready);
                    272: 
                    273:     if (err) {
                    274:         ngx_uint_t  level;
                    275: 
                    276:         if (err == NGX_EINTR) {
                    277: 
                    278:             if (ngx_event_timer_alarm) {
                    279:                 ngx_event_timer_alarm = 0;
                    280:                 return NGX_OK;
                    281:             }
                    282: 
                    283:             level = NGX_LOG_INFO;
                    284: 
                    285:         } else {
                    286:             level = NGX_LOG_ALERT;
                    287:         }
                    288: 
                    289:         ngx_log_error(level, cycle->log, err, "select() failed");
                    290: 
                    291:         if (err == EBADF) {
                    292:             ngx_select_repair_fd_sets(cycle);
                    293:         }
                    294: 
                    295:         return NGX_ERROR;
                    296:     }
                    297: 
                    298:     if (ready == 0) {
                    299:         if (timer != NGX_TIMER_INFINITE) {
                    300:             return NGX_OK;
                    301:         }
                    302: 
                    303:         ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                    304:                       "select() returned no events without timeout");
                    305:         return NGX_ERROR;
                    306:     }
                    307: 
                    308:     ngx_mutex_lock(ngx_posted_events_mutex);
                    309: 
                    310:     nready = 0;
                    311: 
                    312:     for (i = 0; i < nevents; i++) {
                    313:         ev = event_index[i];
                    314:         c = ev->data;
                    315:         found = 0;
                    316: 
                    317:         if (ev->write) {
                    318:             if (FD_ISSET(c->fd, &work_write_fd_set)) {
                    319:                 found = 1;
                    320:                 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                    321:                                "select write %d", c->fd);
                    322:             }
                    323: 
                    324:         } else {
                    325:             if (FD_ISSET(c->fd, &work_read_fd_set)) {
                    326:                 found = 1;
                    327:                 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                    328:                                "select read %d", c->fd);
                    329:             }
                    330:         }
                    331: 
                    332:         if (found) {
                    333:             ev->ready = 1;
                    334: 
                    335:             queue = (ngx_event_t **) (ev->accept ? &ngx_posted_accept_events:
                    336:                                                    &ngx_posted_events);
                    337:             ngx_locked_post_event(ev, queue);
                    338: 
                    339:             nready++;
                    340:         }
                    341:     }
                    342: 
                    343:     ngx_mutex_unlock(ngx_posted_events_mutex);
                    344: 
                    345:     if (ready != nready) {
                    346:         ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                    347:                       "select ready != events: %d:%d", ready, nready);
                    348: 
                    349:         ngx_select_repair_fd_sets(cycle);
                    350:     }
                    351: 
                    352:     return NGX_OK;
                    353: }
                    354: 
                    355: 
                    356: static void
                    357: ngx_select_repair_fd_sets(ngx_cycle_t *cycle)
                    358: {
                    359:     int           n;
                    360:     socklen_t     len;
                    361:     ngx_err_t     err;
                    362:     ngx_socket_t  s;
                    363: 
                    364:     for (s = 0; s <= max_fd; s++) {
                    365: 
                    366:         if (FD_ISSET(s, &master_read_fd_set) == 0) {
                    367:             continue;
                    368:         }
                    369: 
                    370:         len = sizeof(int);
                    371: 
                    372:         if (getsockopt(s, SOL_SOCKET, SO_TYPE, &n, &len) == -1) {
                    373:             err = ngx_socket_errno;
                    374: 
                    375:             ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
                    376:                           "invalid descriptor #%d in read fd_set", s);
                    377: 
                    378:             FD_CLR(s, &master_read_fd_set);
                    379:         }
                    380:     }
                    381: 
                    382:     for (s = 0; s <= max_fd; s++) {
                    383: 
                    384:         if (FD_ISSET(s, &master_write_fd_set) == 0) {
                    385:             continue;
                    386:         }
                    387: 
                    388:         len = sizeof(int);
                    389: 
                    390:         if (getsockopt(s, SOL_SOCKET, SO_TYPE, &n, &len) == -1) {
                    391:             err = ngx_socket_errno;
                    392: 
                    393:             ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
                    394:                           "invalid descriptor #%d in write fd_set", s);
                    395: 
                    396:             FD_CLR(s, &master_write_fd_set);
                    397:         }
                    398:     }
                    399: 
                    400:     max_fd = -1;
                    401: }
                    402: 
                    403: 
                    404: static char *
                    405: ngx_select_init_conf(ngx_cycle_t *cycle, void *conf)
                    406: {
                    407:     ngx_event_conf_t  *ecf;
                    408: 
                    409:     ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module);
                    410: 
                    411:     if (ecf->use != ngx_select_module.ctx_index) {
                    412:         return NGX_CONF_OK;
                    413:     }
                    414: 
                    415:     /* disable warning: the default FD_SETSIZE is 1024U in FreeBSD 5.x */
                    416: 
                    417:     if (cycle->connection_n > FD_SETSIZE) {
                    418:         ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
                    419:                       "the maximum number of files "
                    420:                       "supported by select() is %ud", FD_SETSIZE);
                    421:         return NGX_CONF_ERROR;
                    422:     }
                    423: 
                    424: #if (NGX_THREADS)
                    425: 
                    426:     ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
                    427:                   "select() is not supported in the threaded mode");
                    428:     return NGX_CONF_ERROR;
                    429: 
                    430: #else
                    431: 
                    432:     return NGX_CONF_OK;
                    433: 
                    434: #endif
                    435: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>