xref: /libevent-2.1.12/event_iocp.c (revision e66078a0)
1eda27f95SNick Mathewson /*
2e49e2891SNick Mathewson  * Copyright (c) 2009-2012 Niels Provos, Nick Mathewson
3eda27f95SNick Mathewson  *
4eda27f95SNick Mathewson  * Redistribution and use in source and binary forms, with or without
5eda27f95SNick Mathewson  * modification, are permitted provided that the following conditions
6eda27f95SNick Mathewson  * are met:
7eda27f95SNick Mathewson  * 1. Redistributions of source code must retain the above copyright
8eda27f95SNick Mathewson  *    notice, this list of conditions and the following disclaimer.
9eda27f95SNick Mathewson  * 2. Redistributions in binary form must reproduce the above copyright
10eda27f95SNick Mathewson  *    notice, this list of conditions and the following disclaimer in the
11eda27f95SNick Mathewson  *    documentation and/or other materials provided with the distribution.
12eda27f95SNick Mathewson  * 3. The name of the author may not be used to endorse or promote products
13eda27f95SNick Mathewson  *    derived from this software without specific prior written permission.
14eda27f95SNick Mathewson  *
15eda27f95SNick Mathewson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16eda27f95SNick Mathewson  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17eda27f95SNick Mathewson  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18eda27f95SNick Mathewson  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19eda27f95SNick Mathewson  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20eda27f95SNick Mathewson  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21eda27f95SNick Mathewson  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22eda27f95SNick Mathewson  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23eda27f95SNick Mathewson  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24eda27f95SNick Mathewson  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25eda27f95SNick Mathewson  */
26ded0a090SKevin Bowling #include "evconfig-private.h"
27ca737ff3SNick Mathewson 
28816115a1SPeter Rosin #ifndef _WIN32_WINNT
29816115a1SPeter Rosin /* Minimum required for InitializeCriticalSectionAndSpinCount */
30816115a1SPeter Rosin #define _WIN32_WINNT 0x0403
31816115a1SPeter Rosin #endif
325b5b880bSNick Mathewson #include <winsock2.h>
3393d4f884SNick Mathewson #include <windows.h>
340b987813SNick Mathewson #include <process.h>
35f1090833SNick Mathewson #include <stdio.h>
36fa313f28SNick Mathewson #include <mswsock.h>
370b987813SNick Mathewson 
3893d4f884SNick Mathewson #include "event2/util.h"
3993d4f884SNick Mathewson #include "util-internal.h"
40ca737ff3SNick Mathewson #include "iocp-internal.h"
410b987813SNick Mathewson #include "log-internal.h"
420b987813SNick Mathewson #include "mm-internal.h"
43fe47003dSNick Mathewson #include "event-internal.h"
4476f7e7aeSChristopher Davis #include "evthread-internal.h"
45ca737ff3SNick Mathewson 
46f1090833SNick Mathewson #define NOTIFICATION_KEY ((ULONG_PTR)-1)
47f1090833SNick Mathewson 
48ca737ff3SNick Mathewson void
event_overlapped_init_(struct event_overlapped * o,iocp_callback cb)498ac3c4c2SNick Mathewson event_overlapped_init_(struct event_overlapped *o, iocp_callback cb)
50ca737ff3SNick Mathewson {
5193d4f884SNick Mathewson 	memset(o, 0, sizeof(struct event_overlapped));
52ca737ff3SNick Mathewson 	o->cb = cb;
53ca737ff3SNick Mathewson }
54ca737ff3SNick Mathewson 
55ca737ff3SNick Mathewson static void
handle_entry(OVERLAPPED * o,ULONG_PTR completion_key,DWORD nBytes,int ok)56a84c87d7SNick Mathewson handle_entry(OVERLAPPED *o, ULONG_PTR completion_key, DWORD nBytes, int ok)
57ca737ff3SNick Mathewson {
58ca737ff3SNick Mathewson 	struct event_overlapped *eo =
59ca737ff3SNick Mathewson 	    EVUTIL_UPCAST(o, struct event_overlapped, overlapped);
60a84c87d7SNick Mathewson 	eo->cb(eo, completion_key, nBytes, ok);
61ca737ff3SNick Mathewson }
62ca737ff3SNick Mathewson 
63ca737ff3SNick Mathewson static void
loop(void * port_)64946b5841SNick Mathewson loop(void *port_)
65ca737ff3SNick Mathewson {
66946b5841SNick Mathewson 	struct event_iocp_port *port = port_;
670b987813SNick Mathewson 	long ms = port->ms;
68f1090833SNick Mathewson 	HANDLE p = port->port;
69ca737ff3SNick Mathewson 
70ca737ff3SNick Mathewson 	if (ms <= 0)
71ca737ff3SNick Mathewson 		ms = INFINITE;
72ca737ff3SNick Mathewson 
73a84c87d7SNick Mathewson 	while (1) {
74a84c87d7SNick Mathewson 		OVERLAPPED *overlapped=NULL;
75a84c87d7SNick Mathewson 		ULONG_PTR key=0;
76a84c87d7SNick Mathewson 		DWORD bytes=0;
77a84c87d7SNick Mathewson 		int ok = GetQueuedCompletionStatus(p, &bytes, &key,
78a84c87d7SNick Mathewson 			&overlapped, ms);
79f1090833SNick Mathewson 		EnterCriticalSection(&port->lock);
80f1090833SNick Mathewson 		if (port->shutdown) {
81f1090833SNick Mathewson 			if (--port->n_live_threads == 0)
82d844242fSChristopher Davis 				ReleaseSemaphore(port->shutdownSemaphore, 1,
83d844242fSChristopher Davis 						NULL);
84f1090833SNick Mathewson 			LeaveCriticalSection(&port->lock);
850b987813SNick Mathewson 			return;
86f1090833SNick Mathewson 		}
87f1090833SNick Mathewson 		LeaveCriticalSection(&port->lock);
88f1090833SNick Mathewson 
89a84c87d7SNick Mathewson 		if (key != NOTIFICATION_KEY && overlapped)
90a84c87d7SNick Mathewson 			handle_entry(overlapped, key, bytes, ok);
91a84c87d7SNick Mathewson 		else if (!overlapped)
92a84c87d7SNick Mathewson 			break;
93ca737ff3SNick Mathewson 	}
940b987813SNick Mathewson 	event_warnx("GetQueuedCompletionStatus exited with no event.");
95f1090833SNick Mathewson 	EnterCriticalSection(&port->lock);
96f1090833SNick Mathewson 	if (--port->n_live_threads == 0)
97f1090833SNick Mathewson 		ReleaseSemaphore(port->shutdownSemaphore, 1, NULL);
98f1090833SNick Mathewson 	LeaveCriticalSection(&port->lock);
99ca737ff3SNick Mathewson }
100ca737ff3SNick Mathewson 
1010b987813SNick Mathewson int
event_iocp_port_associate_(struct event_iocp_port * port,evutil_socket_t fd,ev_uintptr_t key)1028ac3c4c2SNick Mathewson event_iocp_port_associate_(struct event_iocp_port *port, evutil_socket_t fd,
103cef61a2fSNick Mathewson     ev_uintptr_t key)
1040b987813SNick Mathewson {
1050b987813SNick Mathewson 	HANDLE h;
1060b987813SNick Mathewson 	h = CreateIoCompletionPort((HANDLE)fd, port->port, key, port->n_threads);
1070b987813SNick Mathewson 	if (!h)
1080b987813SNick Mathewson 		return -1;
1090b987813SNick Mathewson 	return 0;
1100b987813SNick Mathewson }
1110b987813SNick Mathewson 
112fa313f28SNick Mathewson static void *
get_extension_function(SOCKET s,const GUID * which_fn)113fa313f28SNick Mathewson get_extension_function(SOCKET s, const GUID *which_fn)
114fa313f28SNick Mathewson {
115fa313f28SNick Mathewson 	void *ptr = NULL;
116fa313f28SNick Mathewson 	DWORD bytes=0;
117fa313f28SNick Mathewson 	WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER,
118fa313f28SNick Mathewson 	    (GUID*)which_fn, sizeof(*which_fn),
119fa313f28SNick Mathewson 	    &ptr, sizeof(ptr),
120fa313f28SNick Mathewson 	    &bytes, NULL, NULL);
121fa313f28SNick Mathewson 
122fa313f28SNick Mathewson 	/* No need to detect errors here: if ptr is set, then we have a good
123fa313f28SNick Mathewson 	   function pointer.  Otherwise, we should behave as if we had no
124fa313f28SNick Mathewson 	   function pointer.
125fa313f28SNick Mathewson 	*/
126fa313f28SNick Mathewson 	return ptr;
127fa313f28SNick Mathewson }
128fa313f28SNick Mathewson 
129fa313f28SNick Mathewson /* Mingw doesn't have these in its mswsock.h.  The values are copied from
130fa313f28SNick Mathewson    wine.h.   Perhaps if we copy them exactly, the cargo will come again.
131fa313f28SNick Mathewson */
132fa313f28SNick Mathewson #ifndef WSAID_ACCEPTEX
133fa313f28SNick Mathewson #define WSAID_ACCEPTEX \
134fa313f28SNick Mathewson 	{0xb5367df1,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}}
135fa313f28SNick Mathewson #endif
136fa313f28SNick Mathewson #ifndef WSAID_CONNECTEX
137fa313f28SNick Mathewson #define WSAID_CONNECTEX \
138fa313f28SNick Mathewson 	{0x25a207b9,0xddf3,0x4660,{0x8e,0xe9,0x76,0xe5,0x8c,0x74,0x06,0x3e}}
139fa313f28SNick Mathewson #endif
140fa313f28SNick Mathewson #ifndef WSAID_GETACCEPTEXSOCKADDRS
141fa313f28SNick Mathewson #define WSAID_GETACCEPTEXSOCKADDRS \
142fa313f28SNick Mathewson 	{0xb5367df2,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}}
143fa313f28SNick Mathewson #endif
144fa313f28SNick Mathewson 
1453b77d628SNick Mathewson static int extension_fns_initialized = 0;
1463b77d628SNick Mathewson 
147fa313f28SNick Mathewson static void
init_extension_functions(struct win32_extension_fns * ext)148fa313f28SNick Mathewson init_extension_functions(struct win32_extension_fns *ext)
149fa313f28SNick Mathewson {
150fa313f28SNick Mathewson 	const GUID acceptex = WSAID_ACCEPTEX;
151fa313f28SNick Mathewson 	const GUID connectex = WSAID_CONNECTEX;
152fa313f28SNick Mathewson 	const GUID getacceptexsockaddrs = WSAID_GETACCEPTEXSOCKADDRS;
153fa313f28SNick Mathewson 	SOCKET s = socket(AF_INET, SOCK_STREAM, 0);
154*e66078a0SAzat Khuzhin 	if (s == EVUTIL_INVALID_SOCKET)
155fa313f28SNick Mathewson 		return;
156fa313f28SNick Mathewson 	ext->AcceptEx = get_extension_function(s, &acceptex);
157fa313f28SNick Mathewson 	ext->ConnectEx = get_extension_function(s, &connectex);
158fa313f28SNick Mathewson 	ext->GetAcceptExSockaddrs = get_extension_function(s,
159fa313f28SNick Mathewson 	    &getacceptexsockaddrs);
160fa313f28SNick Mathewson 	closesocket(s);
1613b77d628SNick Mathewson 
1623b77d628SNick Mathewson 	extension_fns_initialized = 1;
163fa313f28SNick Mathewson }
164fa313f28SNick Mathewson 
165fa313f28SNick Mathewson static struct win32_extension_fns the_extension_fns;
166fa313f28SNick Mathewson 
167fa313f28SNick Mathewson const struct win32_extension_fns *
event_get_win32_extension_fns_(void)1688ac3c4c2SNick Mathewson event_get_win32_extension_fns_(void)
169fa313f28SNick Mathewson {
170fa313f28SNick Mathewson 	return &the_extension_fns;
171fa313f28SNick Mathewson }
172fa313f28SNick Mathewson 
1732447fe88SChristopher Davis #define N_CPUS_DEFAULT 2
1742447fe88SChristopher Davis 
1750b987813SNick Mathewson struct event_iocp_port *
event_iocp_port_launch_(int n_cpus)1768ac3c4c2SNick Mathewson event_iocp_port_launch_(int n_cpus)
1770b987813SNick Mathewson {
1780b987813SNick Mathewson 	struct event_iocp_port *port;
179f1090833SNick Mathewson 	int i;
1800b987813SNick Mathewson 
181fa313f28SNick Mathewson 	if (!extension_fns_initialized)
182fa313f28SNick Mathewson 		init_extension_functions(&the_extension_fns);
183fa313f28SNick Mathewson 
1840b987813SNick Mathewson 	if (!(port = mm_calloc(1, sizeof(struct event_iocp_port))))
1850b987813SNick Mathewson 		return NULL;
1862447fe88SChristopher Davis 
1872447fe88SChristopher Davis 	if (n_cpus <= 0)
1882447fe88SChristopher Davis 		n_cpus = N_CPUS_DEFAULT;
1892447fe88SChristopher Davis 	port->n_threads = n_cpus * 2;
19019715a60SNick Mathewson 	port->threads = mm_calloc(port->n_threads, sizeof(HANDLE));
191f1090833SNick Mathewson 	if (!port->threads)
192f1090833SNick Mathewson 		goto err;
193f1090833SNick Mathewson 
1942447fe88SChristopher Davis 	port->port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0,
1952447fe88SChristopher Davis 			n_cpus);
1960b987813SNick Mathewson 	port->ms = -1;
1970b987813SNick Mathewson 	if (!port->port)
198f1090833SNick Mathewson 		goto err;
1990b987813SNick Mathewson 
200f1090833SNick Mathewson 	port->shutdownSemaphore = CreateSemaphore(NULL, 0, 1, NULL);
201f1090833SNick Mathewson 	if (!port->shutdownSemaphore)
202f1090833SNick Mathewson 		goto err;
2030b987813SNick Mathewson 
204f1090833SNick Mathewson 	for (i=0; i<port->n_threads; ++i) {
205cef61a2fSNick Mathewson 		ev_uintptr_t th = _beginthread(loop, 0, port);
206cef61a2fSNick Mathewson 		if (th == (ev_uintptr_t)-1)
207f1090833SNick Mathewson 			goto err;
208f1090833SNick Mathewson 		port->threads[i] = (HANDLE)th;
209f1090833SNick Mathewson 		++port->n_live_threads;
2100b987813SNick Mathewson 	}
2110b987813SNick Mathewson 
21232c6f1baSNick Mathewson 	InitializeCriticalSectionAndSpinCount(&port->lock, 1000);
2130b987813SNick Mathewson 
214f1090833SNick Mathewson 	return port;
215f1090833SNick Mathewson err:
216f1090833SNick Mathewson 	if (port->port)
217f1090833SNick Mathewson 		CloseHandle(port->port);
218f1090833SNick Mathewson 	if (port->threads)
219f1090833SNick Mathewson 		mm_free(port->threads);
220f1090833SNick Mathewson 	if (port->shutdownSemaphore)
221f1090833SNick Mathewson 		CloseHandle(port->shutdownSemaphore);
222f1090833SNick Mathewson 	mm_free(port);
223f1090833SNick Mathewson 	return NULL;
224f1090833SNick Mathewson }
225f1090833SNick Mathewson 
226f1090833SNick Mathewson static void
event_iocp_port_unlock_and_free_(struct event_iocp_port * port)227cb9da0bfSNick Mathewson event_iocp_port_unlock_and_free_(struct event_iocp_port *port)
2280b987813SNick Mathewson {
229f1090833SNick Mathewson 	DeleteCriticalSection(&port->lock);
230f1090833SNick Mathewson 	CloseHandle(port->port);
231f1090833SNick Mathewson 	CloseHandle(port->shutdownSemaphore);
232f1090833SNick Mathewson 	mm_free(port->threads);
233f1090833SNick Mathewson 	mm_free(port);
234f1090833SNick Mathewson }
235f1090833SNick Mathewson 
236f1090833SNick Mathewson static int
event_iocp_notify_all(struct event_iocp_port * port)237f1090833SNick Mathewson event_iocp_notify_all(struct event_iocp_port *port)
238f1090833SNick Mathewson {
239f1090833SNick Mathewson 	int i, r, ok=1;
240f1090833SNick Mathewson 	for (i=0; i<port->n_threads; ++i) {
241f1090833SNick Mathewson 		r = PostQueuedCompletionStatus(port->port, 0, NOTIFICATION_KEY,
242f1090833SNick Mathewson 		    NULL);
243f1090833SNick Mathewson 		if (!r)
244f1090833SNick Mathewson 			ok = 0;
245f1090833SNick Mathewson 	}
246f1090833SNick Mathewson 	return ok ? 0 : -1;
247f1090833SNick Mathewson }
248f1090833SNick Mathewson 
249f1090833SNick Mathewson int
event_iocp_shutdown_(struct event_iocp_port * port,long waitMsec)2508ac3c4c2SNick Mathewson event_iocp_shutdown_(struct event_iocp_port *port, long waitMsec)
251f1090833SNick Mathewson {
252d844242fSChristopher Davis 	DWORD ms = INFINITE;
253f1090833SNick Mathewson 	int n;
254d844242fSChristopher Davis 
255f1090833SNick Mathewson 	EnterCriticalSection(&port->lock);
2560b987813SNick Mathewson 	port->shutdown = 1;
257f1090833SNick Mathewson 	LeaveCriticalSection(&port->lock);
258f1090833SNick Mathewson 	event_iocp_notify_all(port);
259f1090833SNick Mathewson 
260d844242fSChristopher Davis 	if (waitMsec >= 0)
261d844242fSChristopher Davis 		ms = waitMsec;
262d844242fSChristopher Davis 
263d844242fSChristopher Davis 	WaitForSingleObject(port->shutdownSemaphore, ms);
264f1090833SNick Mathewson 	EnterCriticalSection(&port->lock);
265f1090833SNick Mathewson 	n = port->n_live_threads;
266f1090833SNick Mathewson 	LeaveCriticalSection(&port->lock);
267f1090833SNick Mathewson 	if (n == 0) {
268cb9da0bfSNick Mathewson 		event_iocp_port_unlock_and_free_(port);
269f1090833SNick Mathewson 		return 0;
270f1090833SNick Mathewson 	} else {
271f1090833SNick Mathewson 		return -1;
272f1090833SNick Mathewson 	}
273f1090833SNick Mathewson }
274f1090833SNick Mathewson 
275f1090833SNick Mathewson int
event_iocp_activate_overlapped_(struct event_iocp_port * port,struct event_overlapped * o,ev_uintptr_t key,ev_uint32_t n)2768ac3c4c2SNick Mathewson event_iocp_activate_overlapped_(
277f1090833SNick Mathewson     struct event_iocp_port *port, struct event_overlapped *o,
278cef61a2fSNick Mathewson     ev_uintptr_t key, ev_uint32_t n)
279f1090833SNick Mathewson {
280f1090833SNick Mathewson 	BOOL r;
281f1090833SNick Mathewson 
282f1090833SNick Mathewson 	r = PostQueuedCompletionStatus(port->port, n, key, &o->overlapped);
283f1090833SNick Mathewson 	return (r==0) ? -1 : 0;
2840b987813SNick Mathewson }
285b69d03b5SNick Mathewson 
286fe47003dSNick Mathewson struct event_iocp_port *
event_base_get_iocp_(struct event_base * base)2878ac3c4c2SNick Mathewson event_base_get_iocp_(struct event_base *base)
288b69d03b5SNick Mathewson {
2899f560bfaSNick Mathewson #ifdef _WIN32
290b69d03b5SNick Mathewson 	return base->iocp;
291b69d03b5SNick Mathewson #else
2927a844735SNick Mathewson 	return NULL;
293b69d03b5SNick Mathewson #endif
294b69d03b5SNick Mathewson }
295