|  |  | 
|  | /* | 
|  | * 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); | 
|  | } | 
|  | } |