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