src/event/modules/ngx_iocp_module.c - nginx source code

Global variables defined

Functions defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>
  7. #include <ngx_event.h>
  8. #include <ngx_iocp_module.h>


  9. static ngx_int_t ngx_iocp_init(ngx_cycle_t *cycle, ngx_msec_t timer);
  10. static ngx_thread_value_t __stdcall ngx_iocp_timer(void *data);
  11. static void ngx_iocp_done(ngx_cycle_t *cycle);
  12. static ngx_int_t ngx_iocp_add_event(ngx_event_t *ev, ngx_int_t event,
  13.     ngx_uint_t key);
  14. static ngx_int_t ngx_iocp_del_connection(ngx_connection_t *c, ngx_uint_t flags);
  15. static ngx_int_t ngx_iocp_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
  16.     ngx_uint_t flags);
  17. static void *ngx_iocp_create_conf(ngx_cycle_t *cycle);
  18. static char *ngx_iocp_init_conf(ngx_cycle_t *cycle, void *conf);


  19. static ngx_str_t      iocp_name = ngx_string("iocp");

  20. static ngx_command_t  ngx_iocp_commands[] = {

  21.     { ngx_string("iocp_threads"),
  22.       NGX_EVENT_CONF|NGX_CONF_TAKE1,
  23.       ngx_conf_set_num_slot,
  24.       0,
  25.       offsetof(ngx_iocp_conf_t, threads),
  26.       NULL },

  27.     { ngx_string("post_acceptex"),
  28.       NGX_EVENT_CONF|NGX_CONF_TAKE1,
  29.       ngx_conf_set_num_slot,
  30.       0,
  31.       offsetof(ngx_iocp_conf_t, post_acceptex),
  32.       NULL },

  33.     { ngx_string("acceptex_read"),
  34.       NGX_EVENT_CONF|NGX_CONF_FLAG,
  35.       ngx_conf_set_flag_slot,
  36.       0,
  37.       offsetof(ngx_iocp_conf_t, acceptex_read),
  38.       NULL },

  39.       ngx_null_command
  40. };


  41. static ngx_event_module_t  ngx_iocp_module_ctx = {
  42.     &iocp_name,
  43.     ngx_iocp_create_conf,                  /* create configuration */
  44.     ngx_iocp_init_conf,                    /* init configuration */

  45.     {
  46.         ngx_iocp_add_event,                /* add an event */
  47.         NULL,                              /* delete an event */
  48.         NULL,                              /* enable an event */
  49.         NULL,                              /* disable an event */
  50.         NULL,                              /* add an connection */
  51.         ngx_iocp_del_connection,           /* delete an connection */
  52.         NULL,                              /* trigger a notify */
  53.         ngx_iocp_process_events,           /* process the events */
  54.         ngx_iocp_init,                     /* init the events */
  55.         ngx_iocp_done                      /* done the events */
  56.     }

  57. };

  58. ngx_module_t  ngx_iocp_module = {
  59.     NGX_MODULE_V1,
  60.     &ngx_iocp_module_ctx,                  /* module context */
  61.     ngx_iocp_commands,                     /* 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. ngx_os_io_t ngx_iocp_io = {
  73.     ngx_overlapped_wsarecv,
  74.     NULL,
  75.     ngx_udp_overlapped_wsarecv,
  76.     NULL,
  77.     NULL,
  78.     NULL,
  79.     ngx_overlapped_wsasend_chain,
  80.     0
  81. };


  82. static HANDLE      iocp;
  83. static ngx_tid_t   timer_thread;
  84. static ngx_msec_t  msec;


  85. static ngx_int_t
  86. ngx_iocp_init(ngx_cycle_t *cycle, ngx_msec_t timer)
  87. {
  88.     ngx_iocp_conf_t  *cf;

  89.     cf = ngx_event_get_conf(cycle->conf_ctx, ngx_iocp_module);

  90.     if (iocp == NULL) {
  91.         iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0,
  92.                                       cf->threads);
  93.     }

  94.     if (iocp == NULL) {
  95.         ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
  96.                       "CreateIoCompletionPort() failed");
  97.         return NGX_ERROR;
  98.     }

  99.     ngx_io = ngx_iocp_io;

  100.     ngx_event_actions = ngx_iocp_module_ctx.actions;

  101.     ngx_event_flags = NGX_USE_IOCP_EVENT;

  102.     if (timer == 0) {
  103.         return NGX_OK;
  104.     }

  105.     /*
  106.      * The waitable timer could not be used, because
  107.      * GetQueuedCompletionStatus() does not set a thread to alertable state
  108.      */

  109.     if (timer_thread == NULL) {

  110.         msec = timer;

  111.         if (ngx_create_thread(&timer_thread, ngx_iocp_timer, &msec, cycle->log)
  112.             != 0)
  113.         {
  114.             return NGX_ERROR;
  115.         }
  116.     }

  117.     ngx_event_flags |= NGX_USE_TIMER_EVENT;

  118.     return NGX_OK;
  119. }


  120. static ngx_thread_value_t __stdcall
  121. ngx_iocp_timer(void *data)
  122. {
  123.     ngx_msec_t  timer = *(ngx_msec_t *) data;

  124.     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0,
  125.                    "THREAD %p %p", &msec, data);

  126.     for ( ;; ) {
  127.         Sleep(timer);

  128.         ngx_time_update();
  129. #if 1
  130.         ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, "timer");
  131. #endif
  132.     }

  133. #if defined(__WATCOMC__) || defined(__GNUC__)
  134.     return 0;
  135. #endif
  136. }


  137. static void
  138. ngx_iocp_done(ngx_cycle_t *cycle)
  139. {
  140.     if (CloseHandle(iocp) == -1) {
  141.         ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
  142.                       "iocp CloseHandle() failed");
  143.     }

  144.     iocp = NULL;
  145. }


  146. static ngx_int_t
  147. ngx_iocp_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t key)
  148. {
  149.     ngx_connection_t  *c;

  150.     c = (ngx_connection_t *) ev->data;

  151.     c->read->active = 1;
  152.     c->write->active = 1;

  153.     ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0,
  154.                    "iocp add: fd:%d k:%ui ov:%p", c->fd, key, &ev->ovlp);

  155.     if (CreateIoCompletionPort((HANDLE) c->fd, iocp, key, 0) == NULL) {
  156.         ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
  157.                       "CreateIoCompletionPort() failed");
  158.         return NGX_ERROR;
  159.     }

  160.     return NGX_OK;
  161. }


  162. static ngx_int_t
  163. ngx_iocp_del_connection(ngx_connection_t *c, ngx_uint_t flags)
  164. {
  165. #if 0
  166.     if (flags & NGX_CLOSE_EVENT) {
  167.         return NGX_OK;
  168.     }

  169.     if (CancelIo((HANDLE) c->fd) == 0) {
  170.         ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, "CancelIo() failed");
  171.         return NGX_ERROR;
  172.     }
  173. #endif

  174.     return NGX_OK;
  175. }


  176. static ngx_int_t
  177. ngx_iocp_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
  178. {
  179.     int                rc;
  180.     u_int              key;
  181.     u_long             bytes;
  182.     ngx_err_t          err;
  183.     ngx_msec_t         delta;
  184.     ngx_event_t       *ev;
  185.     ngx_event_ovlp_t  *ovlp;

  186.     if (timer == NGX_TIMER_INFINITE) {
  187.         timer = INFINITE;
  188.     }

  189.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "iocp timer: %M", timer);

  190.     rc = GetQueuedCompletionStatus(iocp, &bytes, (PULONG_PTR) &key,
  191.                                    (LPOVERLAPPED *) &ovlp, (u_long) timer);

  192.     if (rc == 0) {
  193.         err = ngx_errno;
  194.     } else {
  195.         err = 0;
  196.     }

  197.     delta = ngx_current_msec;

  198.     if (flags & NGX_UPDATE_TIME) {
  199.         ngx_time_update();
  200.     }

  201.     ngx_log_debug4(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
  202.                    "iocp: %d b:%d k:%d ov:%p", rc, bytes, key, ovlp);

  203.     if (timer != INFINITE) {
  204.         delta = ngx_current_msec - delta;

  205.         ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
  206.                        "iocp timer: %M, delta: %M", timer, delta);
  207.     }

  208.     if (err) {
  209.         if (ovlp == NULL) {
  210.             if (err != WAIT_TIMEOUT) {
  211.                 ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
  212.                               "GetQueuedCompletionStatus() failed");

  213.                 return NGX_ERROR;
  214.             }

  215.             return NGX_OK;
  216.         }

  217.         ovlp->error = err;
  218.     }

  219.     if (ovlp == NULL) {
  220.         ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
  221.                       "GetQueuedCompletionStatus() returned no operation");
  222.         return NGX_ERROR;
  223.     }


  224.     ev = ovlp->event;

  225.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, err, "iocp event:%p", ev);


  226.     if (err == ERROR_NETNAME_DELETED /* the socket was closed */
  227.         || err == ERROR_OPERATION_ABORTED /* the operation was canceled */)
  228.     {

  229.         /*
  230.          * the WSA_OPERATION_ABORTED completion notification
  231.          * for a file descriptor that was closed
  232.          */

  233.         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, err,
  234.                        "iocp: aborted event %p", ev);

  235.         return NGX_OK;
  236.     }

  237.     if (err) {
  238.         ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
  239.                       "GetQueuedCompletionStatus() returned operation error");
  240.     }

  241.     switch (key) {

  242.     case NGX_IOCP_ACCEPT:
  243.         if (bytes) {
  244.             ev->ready = 1;
  245.         }
  246.         break;

  247.     case NGX_IOCP_IO:
  248.         ev->complete = 1;
  249.         ev->ready = 1;
  250.         break;

  251.     case NGX_IOCP_CONNECT:
  252.         ev->ready = 1;
  253.     }

  254.     ev->available = bytes;

  255.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
  256.                    "iocp event handler: %p", ev->handler);

  257.     ev->handler(ev);

  258.     return NGX_OK;
  259. }


  260. static void *
  261. ngx_iocp_create_conf(ngx_cycle_t *cycle)
  262. {
  263.     ngx_iocp_conf_t  *cf;

  264.     cf = ngx_palloc(cycle->pool, sizeof(ngx_iocp_conf_t));
  265.     if (cf == NULL) {
  266.         return NULL;
  267.     }

  268.     cf->threads = NGX_CONF_UNSET;
  269.     cf->post_acceptex = NGX_CONF_UNSET;
  270.     cf->acceptex_read = NGX_CONF_UNSET;

  271.     return cf;
  272. }


  273. static char *
  274. ngx_iocp_init_conf(ngx_cycle_t *cycle, void *conf)
  275. {
  276.     ngx_iocp_conf_t *cf = conf;

  277.     ngx_conf_init_value(cf->threads, 0);
  278.     ngx_conf_init_value(cf->post_acceptex, 10);
  279.     ngx_conf_init_value(cf->acceptex_read, 1);

  280.     return NGX_CONF_OK;
  281. }