| /* | |
| * Copyright (C) Igor Sysoev | |
| */ | |
| #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); | |
| } | |
| } |