Annotation of embedaddon/nginx/src/event/modules/ngx_devpoll_module.c, revision 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: #if (NGX_TEST_BUILD_DEVPOLL)
! 14:
! 15: /* Solaris declarations */
! 16:
! 17: #define POLLREMOVE 0x0800
! 18: #define DP_POLL 0xD001
! 19: #define DP_ISPOLLED 0xD002
! 20:
! 21: struct dvpoll {
! 22: struct pollfd *dp_fds;
! 23: int dp_nfds;
! 24: int dp_timeout;
! 25: };
! 26:
! 27: #endif
! 28:
! 29:
! 30: typedef struct {
! 31: ngx_uint_t changes;
! 32: ngx_uint_t events;
! 33: } ngx_devpoll_conf_t;
! 34:
! 35:
! 36: static ngx_int_t ngx_devpoll_init(ngx_cycle_t *cycle, ngx_msec_t timer);
! 37: static void ngx_devpoll_done(ngx_cycle_t *cycle);
! 38: static ngx_int_t ngx_devpoll_add_event(ngx_event_t *ev, ngx_int_t event,
! 39: ngx_uint_t flags);
! 40: static ngx_int_t ngx_devpoll_del_event(ngx_event_t *ev, ngx_int_t event,
! 41: ngx_uint_t flags);
! 42: static ngx_int_t ngx_devpoll_set_event(ngx_event_t *ev, ngx_int_t event,
! 43: ngx_uint_t flags);
! 44: static ngx_int_t ngx_devpoll_process_events(ngx_cycle_t *cycle,
! 45: ngx_msec_t timer, ngx_uint_t flags);
! 46:
! 47: static void *ngx_devpoll_create_conf(ngx_cycle_t *cycle);
! 48: static char *ngx_devpoll_init_conf(ngx_cycle_t *cycle, void *conf);
! 49:
! 50: static int dp = -1;
! 51: static struct pollfd *change_list, *event_list;
! 52: static ngx_uint_t nchanges, max_changes, nevents;
! 53:
! 54: static ngx_event_t **change_index;
! 55:
! 56:
! 57: static ngx_str_t devpoll_name = ngx_string("/dev/poll");
! 58:
! 59: static ngx_command_t ngx_devpoll_commands[] = {
! 60:
! 61: { ngx_string("devpoll_changes"),
! 62: NGX_EVENT_CONF|NGX_CONF_TAKE1,
! 63: ngx_conf_set_num_slot,
! 64: 0,
! 65: offsetof(ngx_devpoll_conf_t, changes),
! 66: NULL },
! 67:
! 68: { ngx_string("devpoll_events"),
! 69: NGX_EVENT_CONF|NGX_CONF_TAKE1,
! 70: ngx_conf_set_num_slot,
! 71: 0,
! 72: offsetof(ngx_devpoll_conf_t, events),
! 73: NULL },
! 74:
! 75: ngx_null_command
! 76: };
! 77:
! 78:
! 79: ngx_event_module_t ngx_devpoll_module_ctx = {
! 80: &devpoll_name,
! 81: ngx_devpoll_create_conf, /* create configuration */
! 82: ngx_devpoll_init_conf, /* init configuration */
! 83:
! 84: {
! 85: ngx_devpoll_add_event, /* add an event */
! 86: ngx_devpoll_del_event, /* delete an event */
! 87: ngx_devpoll_add_event, /* enable an event */
! 88: ngx_devpoll_del_event, /* disable an event */
! 89: NULL, /* add an connection */
! 90: NULL, /* delete an connection */
! 91: NULL, /* process the changes */
! 92: ngx_devpoll_process_events, /* process the events */
! 93: ngx_devpoll_init, /* init the events */
! 94: ngx_devpoll_done, /* done the events */
! 95: }
! 96:
! 97: };
! 98:
! 99: ngx_module_t ngx_devpoll_module = {
! 100: NGX_MODULE_V1,
! 101: &ngx_devpoll_module_ctx, /* module context */
! 102: ngx_devpoll_commands, /* module directives */
! 103: NGX_EVENT_MODULE, /* module type */
! 104: NULL, /* init master */
! 105: NULL, /* init module */
! 106: NULL, /* init process */
! 107: NULL, /* init thread */
! 108: NULL, /* exit thread */
! 109: NULL, /* exit process */
! 110: NULL, /* exit master */
! 111: NGX_MODULE_V1_PADDING
! 112: };
! 113:
! 114:
! 115: static ngx_int_t
! 116: ngx_devpoll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
! 117: {
! 118: size_t n;
! 119: ngx_devpoll_conf_t *dpcf;
! 120:
! 121: dpcf = ngx_event_get_conf(cycle->conf_ctx, ngx_devpoll_module);
! 122:
! 123: if (dp == -1) {
! 124: dp = open("/dev/poll", O_RDWR);
! 125:
! 126: if (dp == -1) {
! 127: ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
! 128: "open(/dev/poll) failed");
! 129: return NGX_ERROR;
! 130: }
! 131: }
! 132:
! 133: if (max_changes < dpcf->changes) {
! 134: if (nchanges) {
! 135: n = nchanges * sizeof(struct pollfd);
! 136: if (write(dp, change_list, n) != (ssize_t) n) {
! 137: ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
! 138: "write(/dev/poll) failed");
! 139: return NGX_ERROR;
! 140: }
! 141:
! 142: nchanges = 0;
! 143: }
! 144:
! 145: if (change_list) {
! 146: ngx_free(change_list);
! 147: }
! 148:
! 149: change_list = ngx_alloc(sizeof(struct pollfd) * dpcf->changes,
! 150: cycle->log);
! 151: if (change_list == NULL) {
! 152: return NGX_ERROR;
! 153: }
! 154:
! 155: if (change_index) {
! 156: ngx_free(change_index);
! 157: }
! 158:
! 159: change_index = ngx_alloc(sizeof(ngx_event_t *) * dpcf->changes,
! 160: cycle->log);
! 161: if (change_index == NULL) {
! 162: return NGX_ERROR;
! 163: }
! 164: }
! 165:
! 166: max_changes = dpcf->changes;
! 167:
! 168: if (nevents < dpcf->events) {
! 169: if (event_list) {
! 170: ngx_free(event_list);
! 171: }
! 172:
! 173: event_list = ngx_alloc(sizeof(struct pollfd) * dpcf->events,
! 174: cycle->log);
! 175: if (event_list == NULL) {
! 176: return NGX_ERROR;
! 177: }
! 178: }
! 179:
! 180: nevents = dpcf->events;
! 181:
! 182: ngx_io = ngx_os_io;
! 183:
! 184: ngx_event_actions = ngx_devpoll_module_ctx.actions;
! 185:
! 186: ngx_event_flags = NGX_USE_LEVEL_EVENT|NGX_USE_FD_EVENT;
! 187:
! 188: return NGX_OK;
! 189: }
! 190:
! 191:
! 192: static void
! 193: ngx_devpoll_done(ngx_cycle_t *cycle)
! 194: {
! 195: if (close(dp) == -1) {
! 196: ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
! 197: "close(/dev/poll) failed");
! 198: }
! 199:
! 200: dp = -1;
! 201:
! 202: ngx_free(change_list);
! 203: ngx_free(event_list);
! 204: ngx_free(change_index);
! 205:
! 206: change_list = NULL;
! 207: event_list = NULL;
! 208: change_index = NULL;
! 209: max_changes = 0;
! 210: nchanges = 0;
! 211: nevents = 0;
! 212: }
! 213:
! 214:
! 215: static ngx_int_t
! 216: ngx_devpoll_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
! 217: {
! 218: #if (NGX_DEBUG)
! 219: ngx_connection_t *c;
! 220: #endif
! 221:
! 222: #if (NGX_READ_EVENT != POLLIN)
! 223: event = (event == NGX_READ_EVENT) ? POLLIN : POLLOUT;
! 224: #endif
! 225:
! 226: #if (NGX_DEBUG)
! 227: c = ev->data;
! 228: ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
! 229: "devpoll add event: fd:%d ev:%04Xi", c->fd, event);
! 230: #endif
! 231:
! 232: ev->active = 1;
! 233:
! 234: return ngx_devpoll_set_event(ev, event, 0);
! 235: }
! 236:
! 237:
! 238: static ngx_int_t
! 239: ngx_devpoll_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
! 240: {
! 241: ngx_event_t *e;
! 242: ngx_connection_t *c;
! 243:
! 244: c = ev->data;
! 245:
! 246: #if (NGX_READ_EVENT != POLLIN)
! 247: event = (event == NGX_READ_EVENT) ? POLLIN : POLLOUT;
! 248: #endif
! 249:
! 250: ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
! 251: "devpoll del event: fd:%d ev:%04Xi", c->fd, event);
! 252:
! 253: if (ngx_devpoll_set_event(ev, POLLREMOVE, flags) == NGX_ERROR) {
! 254: return NGX_ERROR;
! 255: }
! 256:
! 257: ev->active = 0;
! 258:
! 259: if (flags & NGX_CLOSE_EVENT) {
! 260: e = (event == POLLIN) ? c->write : c->read;
! 261:
! 262: if (e) {
! 263: e->active = 0;
! 264: }
! 265:
! 266: return NGX_OK;
! 267: }
! 268:
! 269: /* restore the pair event if it exists */
! 270:
! 271: if (event == POLLIN) {
! 272: e = c->write;
! 273: event = POLLOUT;
! 274:
! 275: } else {
! 276: e = c->read;
! 277: event = POLLIN;
! 278: }
! 279:
! 280: if (e && e->active) {
! 281: return ngx_devpoll_set_event(e, event, 0);
! 282: }
! 283:
! 284: return NGX_OK;
! 285: }
! 286:
! 287:
! 288: static ngx_int_t
! 289: ngx_devpoll_set_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
! 290: {
! 291: size_t n;
! 292: ngx_connection_t *c;
! 293:
! 294: c = ev->data;
! 295:
! 296: ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0,
! 297: "devpoll fd:%d ev:%04Xi fl:%04Xi", c->fd, event, flags);
! 298:
! 299: if (nchanges >= max_changes) {
! 300: ngx_log_error(NGX_LOG_WARN, ev->log, 0,
! 301: "/dev/pool change list is filled up");
! 302:
! 303: n = nchanges * sizeof(struct pollfd);
! 304: if (write(dp, change_list, n) != (ssize_t) n) {
! 305: ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
! 306: "write(/dev/poll) failed");
! 307: return NGX_ERROR;
! 308: }
! 309:
! 310: nchanges = 0;
! 311: }
! 312:
! 313: change_list[nchanges].fd = c->fd;
! 314: change_list[nchanges].events = (short) event;
! 315: change_list[nchanges].revents = 0;
! 316:
! 317: change_index[nchanges] = ev;
! 318: ev->index = nchanges;
! 319:
! 320: nchanges++;
! 321:
! 322: if (flags & NGX_CLOSE_EVENT) {
! 323: n = nchanges * sizeof(struct pollfd);
! 324: if (write(dp, change_list, n) != (ssize_t) n) {
! 325: ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
! 326: "write(/dev/poll) failed");
! 327: return NGX_ERROR;
! 328: }
! 329:
! 330: nchanges = 0;
! 331: }
! 332:
! 333: return NGX_OK;
! 334: }
! 335:
! 336:
! 337: ngx_int_t
! 338: ngx_devpoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
! 339: ngx_uint_t flags)
! 340: {
! 341: int events, revents, rc;
! 342: size_t n;
! 343: ngx_fd_t fd;
! 344: ngx_err_t err;
! 345: ngx_int_t i;
! 346: ngx_uint_t level, instance;
! 347: ngx_event_t *rev, *wev, **queue;
! 348: ngx_connection_t *c;
! 349: struct pollfd pfd;
! 350: struct dvpoll dvp;
! 351:
! 352: /* NGX_TIMER_INFINITE == INFTIM */
! 353:
! 354: ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
! 355: "devpoll timer: %M", timer);
! 356:
! 357: if (nchanges) {
! 358: n = nchanges * sizeof(struct pollfd);
! 359: if (write(dp, change_list, n) != (ssize_t) n) {
! 360: ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
! 361: "write(/dev/poll) failed");
! 362: return NGX_ERROR;
! 363: }
! 364:
! 365: nchanges = 0;
! 366: }
! 367:
! 368: dvp.dp_fds = event_list;
! 369: dvp.dp_nfds = (int) nevents;
! 370: dvp.dp_timeout = timer;
! 371: events = ioctl(dp, DP_POLL, &dvp);
! 372:
! 373: err = (events == -1) ? ngx_errno : 0;
! 374:
! 375: if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
! 376: ngx_time_update();
! 377: }
! 378:
! 379: if (err) {
! 380: if (err == NGX_EINTR) {
! 381:
! 382: if (ngx_event_timer_alarm) {
! 383: ngx_event_timer_alarm = 0;
! 384: return NGX_OK;
! 385: }
! 386:
! 387: level = NGX_LOG_INFO;
! 388:
! 389: } else {
! 390: level = NGX_LOG_ALERT;
! 391: }
! 392:
! 393: ngx_log_error(level, cycle->log, err, "ioctl(DP_POLL) failed");
! 394: return NGX_ERROR;
! 395: }
! 396:
! 397: if (events == 0) {
! 398: if (timer != NGX_TIMER_INFINITE) {
! 399: return NGX_OK;
! 400: }
! 401:
! 402: ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
! 403: "ioctl(DP_POLL) returned no events without timeout");
! 404: return NGX_ERROR;
! 405: }
! 406:
! 407: ngx_mutex_lock(ngx_posted_events_mutex);
! 408:
! 409: for (i = 0; i < events; i++) {
! 410:
! 411: fd = event_list[i].fd;
! 412: revents = event_list[i].revents;
! 413:
! 414: c = ngx_cycle->files[fd];
! 415:
! 416: if (c == NULL || c->fd == -1) {
! 417:
! 418: pfd.fd = fd;
! 419: pfd.events = 0;
! 420: pfd.revents = 0;
! 421:
! 422: rc = ioctl(dp, DP_ISPOLLED, &pfd);
! 423:
! 424: switch (rc) {
! 425:
! 426: case -1:
! 427: ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
! 428: "ioctl(DP_ISPOLLED) failed for socket %d, event",
! 429: fd, revents);
! 430: break;
! 431:
! 432: case 0:
! 433: ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
! 434: "phantom event %04Xd for closed and removed socket %d",
! 435: revents, fd);
! 436: break;
! 437:
! 438: default:
! 439: ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
! 440: "unexpected event %04Xd for closed and removed socket %d, ",
! 441: "ioctl(DP_ISPOLLED) returned rc:%d, fd:%d, event %04Xd",
! 442: revents, fd, rc, pfd.fd, pfd.revents);
! 443:
! 444: pfd.fd = fd;
! 445: pfd.events = POLLREMOVE;
! 446: pfd.revents = 0;
! 447:
! 448: if (write(dp, &pfd, sizeof(struct pollfd))
! 449: != (ssize_t) sizeof(struct pollfd))
! 450: {
! 451: ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
! 452: "write(/dev/poll) for %d failed, fd");
! 453: }
! 454:
! 455: if (close(fd) == -1) {
! 456: ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
! 457: "close(%d) failed", fd);
! 458: }
! 459:
! 460: break;
! 461: }
! 462:
! 463: continue;
! 464: }
! 465:
! 466: ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
! 467: "devpoll: fd:%d, ev:%04Xd, rev:%04Xd",
! 468: fd, event_list[i].events, revents);
! 469:
! 470: if (revents & (POLLERR|POLLHUP|POLLNVAL)) {
! 471: ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
! 472: "ioctl(DP_POLL) error fd:%d ev:%04Xd rev:%04Xd",
! 473: fd, event_list[i].events, revents);
! 474: }
! 475:
! 476: if (revents & ~(POLLIN|POLLOUT|POLLERR|POLLHUP|POLLNVAL)) {
! 477: ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
! 478: "strange ioctl(DP_POLL) events "
! 479: "fd:%d ev:%04Xd rev:%04Xd",
! 480: fd, event_list[i].events, revents);
! 481: }
! 482:
! 483: if ((revents & (POLLERR|POLLHUP|POLLNVAL))
! 484: && (revents & (POLLIN|POLLOUT)) == 0)
! 485: {
! 486: /*
! 487: * if the error events were returned without POLLIN or POLLOUT,
! 488: * then add these flags to handle the events at least in one
! 489: * active handler
! 490: */
! 491:
! 492: revents |= POLLIN|POLLOUT;
! 493: }
! 494:
! 495: rev = c->read;
! 496:
! 497: if ((revents & POLLIN) && rev->active) {
! 498:
! 499: if ((flags & NGX_POST_THREAD_EVENTS) && !rev->accept) {
! 500: rev->posted_ready = 1;
! 501:
! 502: } else {
! 503: rev->ready = 1;
! 504: }
! 505:
! 506: if (flags & NGX_POST_EVENTS) {
! 507: queue = (ngx_event_t **) (rev->accept ?
! 508: &ngx_posted_accept_events : &ngx_posted_events);
! 509:
! 510: ngx_locked_post_event(rev, queue);
! 511:
! 512: } else {
! 513: instance = rev->instance;
! 514:
! 515: rev->handler(rev);
! 516:
! 517: if (c->fd == -1 || rev->instance != instance) {
! 518: continue;
! 519: }
! 520: }
! 521: }
! 522:
! 523: wev = c->write;
! 524:
! 525: if ((revents & POLLOUT) && wev->active) {
! 526:
! 527: if (flags & NGX_POST_THREAD_EVENTS) {
! 528: wev->posted_ready = 1;
! 529:
! 530: } else {
! 531: wev->ready = 1;
! 532: }
! 533:
! 534: if (flags & NGX_POST_EVENTS) {
! 535: ngx_locked_post_event(wev, &ngx_posted_events);
! 536:
! 537: } else {
! 538: wev->handler(wev);
! 539: }
! 540: }
! 541: }
! 542:
! 543: ngx_mutex_unlock(ngx_posted_events_mutex);
! 544:
! 545: return NGX_OK;
! 546: }
! 547:
! 548:
! 549: static void *
! 550: ngx_devpoll_create_conf(ngx_cycle_t *cycle)
! 551: {
! 552: ngx_devpoll_conf_t *dpcf;
! 553:
! 554: dpcf = ngx_palloc(cycle->pool, sizeof(ngx_devpoll_conf_t));
! 555: if (dpcf == NULL) {
! 556: return NULL;
! 557: }
! 558:
! 559: dpcf->changes = NGX_CONF_UNSET;
! 560: dpcf->events = NGX_CONF_UNSET;
! 561:
! 562: return dpcf;
! 563: }
! 564:
! 565:
! 566: static char *
! 567: ngx_devpoll_init_conf(ngx_cycle_t *cycle, void *conf)
! 568: {
! 569: ngx_devpoll_conf_t *dpcf = conf;
! 570:
! 571: ngx_conf_init_uint_value(dpcf->changes, 32);
! 572: ngx_conf_init_uint_value(dpcf->events, 32);
! 573:
! 574: return NGX_CONF_OK;
! 575: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>