2 * Copyright (c) 2009-2012 Niels Provos, Nick Mathewson
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 #include "evconfig-private.h"
29 /* Minimum required for InitializeCriticalSectionAndSpinCount */
30 #define _WIN32_WINNT 0x0403
38 #include "event2/util.h"
39 #include "util-internal.h"
40 #include "iocp-internal.h"
41 #include "log-internal.h"
42 #include "mm-internal.h"
43 #include "event-internal.h"
44 #include "evthread-internal.h"
46 #define NOTIFICATION_KEY ((ULONG_PTR)-1)
49 event_overlapped_init_(struct event_overlapped
*o
, iocp_callback cb
)
51 memset(o
, 0, sizeof(struct event_overlapped
));
56 handle_entry(OVERLAPPED
*o
, ULONG_PTR completion_key
, DWORD nBytes
, int ok
)
58 struct event_overlapped
*eo
=
59 EVUTIL_UPCAST(o
, struct event_overlapped
, overlapped
);
60 eo
->cb(eo
, completion_key
, nBytes
, ok
);
66 struct event_iocp_port
*port
= port_
;
68 HANDLE p
= port
->port
;
74 OVERLAPPED
*overlapped
=NULL
;
77 int ok
= GetQueuedCompletionStatus(p
, &bytes
, &key
,
79 EnterCriticalSection(&port
->lock
);
81 if (--port
->n_live_threads
== 0)
82 ReleaseSemaphore(port
->shutdownSemaphore
, 1,
84 LeaveCriticalSection(&port
->lock
);
87 LeaveCriticalSection(&port
->lock
);
89 if (key
!= NOTIFICATION_KEY
&& overlapped
)
90 handle_entry(overlapped
, key
, bytes
, ok
);
94 event_warnx("GetQueuedCompletionStatus exited with no event.");
95 EnterCriticalSection(&port
->lock
);
96 if (--port
->n_live_threads
== 0)
97 ReleaseSemaphore(port
->shutdownSemaphore
, 1, NULL
);
98 LeaveCriticalSection(&port
->lock
);
102 event_iocp_port_associate_(struct event_iocp_port
*port
, evutil_socket_t fd
,
106 h
= CreateIoCompletionPort((HANDLE
)fd
, port
->port
, key
, port
->n_threads
);
113 get_extension_function(SOCKET s
, const GUID
*which_fn
)
117 WSAIoctl(s
, SIO_GET_EXTENSION_FUNCTION_POINTER
,
118 (GUID
*)which_fn
, sizeof(*which_fn
),
122 /* No need to detect errors here: if ptr is set, then we have a good
123 function pointer. Otherwise, we should behave as if we had no
129 /* Mingw doesn't have these in its mswsock.h. The values are copied from
130 wine.h. Perhaps if we copy them exactly, the cargo will come again.
132 #ifndef WSAID_ACCEPTEX
133 #define WSAID_ACCEPTEX \
134 {0xb5367df1,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}}
136 #ifndef WSAID_CONNECTEX
137 #define WSAID_CONNECTEX \
138 {0x25a207b9,0xddf3,0x4660,{0x8e,0xe9,0x76,0xe5,0x8c,0x74,0x06,0x3e}}
140 #ifndef WSAID_GETACCEPTEXSOCKADDRS
141 #define WSAID_GETACCEPTEXSOCKADDRS \
142 {0xb5367df2,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}}
145 static int extension_fns_initialized
= 0;
148 init_extension_functions(struct win32_extension_fns
*ext
)
150 const GUID acceptex
= WSAID_ACCEPTEX
;
151 const GUID connectex
= WSAID_CONNECTEX
;
152 const GUID getacceptexsockaddrs
= WSAID_GETACCEPTEXSOCKADDRS
;
153 SOCKET s
= socket(AF_INET
, SOCK_STREAM
, 0);
154 if (s
== INVALID_SOCKET
)
156 ext
->AcceptEx
= get_extension_function(s
, &acceptex
);
157 ext
->ConnectEx
= get_extension_function(s
, &connectex
);
158 ext
->GetAcceptExSockaddrs
= get_extension_function(s
,
159 &getacceptexsockaddrs
);
162 extension_fns_initialized
= 1;
165 static struct win32_extension_fns the_extension_fns
;
167 const struct win32_extension_fns
*
168 event_get_win32_extension_fns_(void)
170 return &the_extension_fns
;
173 #define N_CPUS_DEFAULT 2
175 struct event_iocp_port
*
176 event_iocp_port_launch_(int n_cpus
)
178 struct event_iocp_port
*port
;
181 if (!extension_fns_initialized
)
182 init_extension_functions(&the_extension_fns
);
184 if (!(port
= mm_calloc(1, sizeof(struct event_iocp_port
))))
188 n_cpus
= N_CPUS_DEFAULT
;
189 port
->n_threads
= n_cpus
* 2;
190 port
->threads
= mm_calloc(port
->n_threads
, sizeof(HANDLE
));
194 port
->port
= CreateIoCompletionPort(INVALID_HANDLE_VALUE
, NULL
, 0,
200 port
->shutdownSemaphore
= CreateSemaphore(NULL
, 0, 1, NULL
);
201 if (!port
->shutdownSemaphore
)
204 for (i
=0; i
<port
->n_threads
; ++i
) {
205 ev_uintptr_t th
= _beginthread(loop
, 0, port
);
206 if (th
== (ev_uintptr_t
)-1)
208 port
->threads
[i
] = (HANDLE
)th
;
209 ++port
->n_live_threads
;
212 InitializeCriticalSectionAndSpinCount(&port
->lock
, 1000);
217 CloseHandle(port
->port
);
219 mm_free(port
->threads
);
220 if (port
->shutdownSemaphore
)
221 CloseHandle(port
->shutdownSemaphore
);
227 event_iocp_port_unlock_and_free_(struct event_iocp_port
*port
)
229 DeleteCriticalSection(&port
->lock
);
230 CloseHandle(port
->port
);
231 CloseHandle(port
->shutdownSemaphore
);
232 mm_free(port
->threads
);
237 event_iocp_notify_all(struct event_iocp_port
*port
)
240 for (i
=0; i
<port
->n_threads
; ++i
) {
241 r
= PostQueuedCompletionStatus(port
->port
, 0, NOTIFICATION_KEY
,
250 event_iocp_shutdown_(struct event_iocp_port
*port
, long waitMsec
)
255 EnterCriticalSection(&port
->lock
);
257 LeaveCriticalSection(&port
->lock
);
258 event_iocp_notify_all(port
);
263 WaitForSingleObject(port
->shutdownSemaphore
, ms
);
264 EnterCriticalSection(&port
->lock
);
265 n
= port
->n_live_threads
;
266 LeaveCriticalSection(&port
->lock
);
268 event_iocp_port_unlock_and_free_(port
);
276 event_iocp_activate_overlapped_(
277 struct event_iocp_port
*port
, struct event_overlapped
*o
,
278 ev_uintptr_t key
, ev_uint32_t n
)
282 r
= PostQueuedCompletionStatus(port
->port
, n
, key
, &o
->overlapped
);
283 return (r
==0) ? -1 : 0;
286 struct event_iocp_port
*
287 event_base_get_iocp_(struct event_base
*base
)