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