|  | 
 | /* | 
 |  * Copyright (C) Igor Sysoev | 
 |  * Copyright (C) Nginx, Inc. | 
 |  */ | 
 |  | 
 |  | 
 | #include <ngx_config.h> | 
 | #include <ngx_core.h> | 
 | #include <ngx_event.h> | 
 |  | 
 |  | 
 | #define NGX_MAX_PENDING_CONN  10 | 
 |  | 
 |  | 
 | static CRITICAL_SECTION  connect_lock; | 
 | static int               nconnects; | 
 | static ngx_connection_t  pending_connects[NGX_MAX_PENDING_CONN]; | 
 |  | 
 | static HANDLE            pending_connect_event; | 
 |  | 
 | __declspec(thread) int                nevents = 0; | 
 | __declspec(thread) WSAEVENT           events[WSA_MAXIMUM_WAIT_EVENTS + 1]; | 
 | __declspec(thread) ngx_connection_t  *conn[WSA_MAXIMUM_WAIT_EVENTS + 1]; | 
 |  | 
 |  | 
 |  | 
 | int ngx_iocp_wait_connect(ngx_connection_t *c) | 
 | { | 
 |     for ( ;; ) { | 
 |         EnterCriticalSection(&connect_lock); | 
 |  | 
 |         if (nconnects < NGX_MAX_PENDING_CONN) { | 
 |             pending_connects[--nconnects] = c; | 
 |             LeaveCriticalSection(&connect_lock); | 
 |  | 
 |             if (SetEvent(pending_connect_event) == 0) { | 
 |                 ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, | 
 |                               "SetEvent() failed"); | 
 |                 return NGX_ERROR; | 
 |  | 
 |             break; | 
 |         } | 
 |  | 
 |         LeaveCriticalSection(&connect_lock); | 
 |         ngx_log_error(NGX_LOG_NOTICE, c->log, 0, | 
 |                       "max number of pending connect()s is %d", | 
 |                       NGX_MAX_PENDING_CONN); | 
 |         msleep(100); | 
 |     } | 
 |  | 
 |     if (!started) { | 
 |         if (ngx_iocp_new_thread(1) == NGX_ERROR) { | 
 |             return NGX_ERROR; | 
 |         } | 
 |         started = 1; | 
 |     } | 
 |  | 
 |     return NGX_OK; | 
 | } | 
 |  | 
 |  | 
 | int ngx_iocp_new_thread(int main) | 
 | { | 
 |     u_int  id; | 
 |  | 
 |     if (main) { | 
 |         pending_connect_event = CreateEvent(NULL, 0, 1, NULL); | 
 |         if (pending_connect_event == INVALID_HANDLE_VALUE) { | 
 |             ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, | 
 |                           "CreateThread() failed"); | 
 |             return NGX_ERROR; | 
 |         } | 
 |     } | 
 |  | 
 |     if (CreateThread(NULL, 0, ngx_iocp_wait_events, main, 0, &id) | 
 |                                                        == INVALID_HANDLE_VALUE) | 
 |     { | 
 |         ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, | 
 |                       "CreateThread() failed"); | 
 |         return NGX_ERROR; | 
 |     } | 
 |  | 
 |     SetEvent(event) { | 
 |         ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, | 
 |                       "SetEvent() failed"); | 
 |         return NGX_ERROR; | 
 |     } | 
 |  | 
 |     return NGX_OK; | 
 | } | 
 |  | 
 |  | 
 | int ngx_iocp_new_connect() | 
 | { | 
 |     EnterCriticalSection(&connect_lock); | 
 |     c = pending_connects[--nconnects]; | 
 |     LeaveCriticalSection(&connect_lock); | 
 |  | 
 |     conn[nevents] = c; | 
 |  | 
 |     events[nevents] = WSACreateEvent(); | 
 |     if (events[nevents] == INVALID_HANDLE_VALUE) { | 
 |         ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno, | 
 |                       "WSACreateEvent() failed"); | 
 |         return NGX_ERROR; | 
 |     } | 
 |  | 
 |     if (WSAEventSelect(c->fd, events[nevents], FD_CONNECT) == -1) | 
 |         ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno, | 
 |                       "WSAEventSelect() failed"); | 
 |         return NGX_ERROR; | 
 |     } | 
 |  | 
 |     nevents++; | 
 |  | 
 |     return NGX_OK; | 
 | } | 
 |  | 
 |  | 
 | void ngx_iocp_wait_events(int main) | 
 | { | 
 |     WSANETWORKEVENTS  ne; | 
 |  | 
 |     nevents = 1; | 
 |     events[0] = pending_connect_event; | 
 |     conn[0] = NULL; | 
 |  | 
 |     for ( ;; ) { | 
 |         offset = (nevents == WSA_MAXIMUM_WAIT_EVENTS + 1) ? 1: 0; | 
 |         timeout = (nevents == 1 && !first) ? 60000: INFINITE; | 
 |  | 
 |         n = WSAWaitForMultipleEvents(nevents - offset, events[offset], | 
 |                                      0, timeout, 0); | 
 |         if (n == WAIT_FAILED) { | 
 |             ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno, | 
 |                           "WSAWaitForMultipleEvents() failed"); | 
 |             continue; | 
 |         } | 
 |  | 
 |         if (n == WAIT_TIMEOUT) { | 
 |             if (nevents == 2 && !main) { | 
 |                 ExitThread(0); | 
 |             } | 
 |  | 
 |             ngx_log_error(NGX_LOG_ALERT, log, 0, | 
 |                           "WSAWaitForMultipleEvents() " | 
 |                           "returned unexpected WAIT_TIMEOUT"); | 
 |             continue; | 
 |         } | 
 |  | 
 |         n -= WSA_WAIT_EVENT_0; | 
 |  | 
 |         if (events[n] == NULL) { | 
 |  | 
 |             /* the pending_connect_event */ | 
 |  | 
 |             if (nevents == WSA_MAXIMUM_WAIT_EVENTS) { | 
 |                 ngx_iocp_new_thread(0); | 
 |             } else { | 
 |                 ngx_iocp_new_connect(); | 
 |             } | 
 |  | 
 |             continue; | 
 |         } | 
 |  | 
 |         if (WSAEnumNetworkEvents(c[n].fd, events[n], &ne) == -1) { | 
 |             ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno, | 
 |                           "WSAEnumNetworkEvents() failed"); | 
 |             continue; | 
 |         } | 
 |  | 
 |         if (ne.lNetworkEvents & FD_CONNECT) { | 
 |             conn[n].write->ovlp.error = ne.iErrorCode[FD_CONNECT_BIT]; | 
 |  | 
 |             if (PostQueuedCompletionStatus(iocp, 0, NGX_IOCP_CONNECT, | 
 |                                            &conn[n].write->ovlp) == 0) | 
 |             { | 
 |                 ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno, | 
 |                               "PostQueuedCompletionStatus() failed"); | 
 |                 continue; | 
 |             } | 
 |  | 
 |             if (n < nevents) { | 
 |                 conn[n] = conn[nevents]; | 
 |                 events[n] = events[nevents]; | 
 |             } | 
 |  | 
 |             nevents--; | 
 |             continue; | 
 |         } | 
 |  | 
 |         if (ne.lNetworkEvents & FD_ACCEPT) { | 
 |  | 
 |             /* CHECK ERROR ??? */ | 
 |  | 
 |             ngx_event_post_acceptex(conn[n].listening, 1); | 
 |             continue; | 
 |         } | 
 |  | 
 |         ngx_log_error(NGX_LOG_ALERT, c[n].log, 0, | 
 |                       "WSAWaitForMultipleEvents() " | 
 |                       "returned unexpected network event %ul", | 
 |                       ne.lNetworkEvents); | 
 |     } | 
 | } |