1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/ipc/chromium/src/third_party/libevent/event_iocp.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,290 @@ 1.4 +/* 1.5 + * Copyright (c) 2009-2012 Niels Provos, Nick Mathewson 1.6 + * 1.7 + * Redistribution and use in source and binary forms, with or without 1.8 + * modification, are permitted provided that the following conditions 1.9 + * are met: 1.10 + * 1. Redistributions of source code must retain the above copyright 1.11 + * notice, this list of conditions and the following disclaimer. 1.12 + * 2. Redistributions in binary form must reproduce the above copyright 1.13 + * notice, this list of conditions and the following disclaimer in the 1.14 + * documentation and/or other materials provided with the distribution. 1.15 + * 3. The name of the author may not be used to endorse or promote products 1.16 + * derived from this software without specific prior written permission. 1.17 + * 1.18 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1.19 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1.20 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1.21 + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1.22 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1.23 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.24 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.25 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.26 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 1.27 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.28 + */ 1.29 + 1.30 +#ifndef _WIN32_WINNT 1.31 +/* Minimum required for InitializeCriticalSectionAndSpinCount */ 1.32 +#define _WIN32_WINNT 0x0403 1.33 +#endif 1.34 +#include <winsock2.h> 1.35 +#include <windows.h> 1.36 +#include <process.h> 1.37 +#include <stdio.h> 1.38 +#include <mswsock.h> 1.39 + 1.40 +#include "event2/util.h" 1.41 +#include "util-internal.h" 1.42 +#include "iocp-internal.h" 1.43 +#include "log-internal.h" 1.44 +#include "mm-internal.h" 1.45 +#include "event-internal.h" 1.46 +#include "evthread-internal.h" 1.47 + 1.48 +#define NOTIFICATION_KEY ((ULONG_PTR)-1) 1.49 + 1.50 +void 1.51 +event_overlapped_init(struct event_overlapped *o, iocp_callback cb) 1.52 +{ 1.53 + memset(o, 0, sizeof(struct event_overlapped)); 1.54 + o->cb = cb; 1.55 +} 1.56 + 1.57 +static void 1.58 +handle_entry(OVERLAPPED *o, ULONG_PTR completion_key, DWORD nBytes, int ok) 1.59 +{ 1.60 + struct event_overlapped *eo = 1.61 + EVUTIL_UPCAST(o, struct event_overlapped, overlapped); 1.62 + eo->cb(eo, completion_key, nBytes, ok); 1.63 +} 1.64 + 1.65 +static void 1.66 +loop(void *_port) 1.67 +{ 1.68 + struct event_iocp_port *port = _port; 1.69 + long ms = port->ms; 1.70 + HANDLE p = port->port; 1.71 + 1.72 + if (ms <= 0) 1.73 + ms = INFINITE; 1.74 + 1.75 + while (1) { 1.76 + OVERLAPPED *overlapped=NULL; 1.77 + ULONG_PTR key=0; 1.78 + DWORD bytes=0; 1.79 + int ok = GetQueuedCompletionStatus(p, &bytes, &key, 1.80 + &overlapped, ms); 1.81 + EnterCriticalSection(&port->lock); 1.82 + if (port->shutdown) { 1.83 + if (--port->n_live_threads == 0) 1.84 + ReleaseSemaphore(port->shutdownSemaphore, 1, 1.85 + NULL); 1.86 + LeaveCriticalSection(&port->lock); 1.87 + return; 1.88 + } 1.89 + LeaveCriticalSection(&port->lock); 1.90 + 1.91 + if (key != NOTIFICATION_KEY && overlapped) 1.92 + handle_entry(overlapped, key, bytes, ok); 1.93 + else if (!overlapped) 1.94 + break; 1.95 + } 1.96 + event_warnx("GetQueuedCompletionStatus exited with no event."); 1.97 + EnterCriticalSection(&port->lock); 1.98 + if (--port->n_live_threads == 0) 1.99 + ReleaseSemaphore(port->shutdownSemaphore, 1, NULL); 1.100 + LeaveCriticalSection(&port->lock); 1.101 +} 1.102 + 1.103 +int 1.104 +event_iocp_port_associate(struct event_iocp_port *port, evutil_socket_t fd, 1.105 + ev_uintptr_t key) 1.106 +{ 1.107 + HANDLE h; 1.108 + h = CreateIoCompletionPort((HANDLE)fd, port->port, key, port->n_threads); 1.109 + if (!h) 1.110 + return -1; 1.111 + return 0; 1.112 +} 1.113 + 1.114 +static void * 1.115 +get_extension_function(SOCKET s, const GUID *which_fn) 1.116 +{ 1.117 + void *ptr = NULL; 1.118 + DWORD bytes=0; 1.119 + WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, 1.120 + (GUID*)which_fn, sizeof(*which_fn), 1.121 + &ptr, sizeof(ptr), 1.122 + &bytes, NULL, NULL); 1.123 + 1.124 + /* No need to detect errors here: if ptr is set, then we have a good 1.125 + function pointer. Otherwise, we should behave as if we had no 1.126 + function pointer. 1.127 + */ 1.128 + return ptr; 1.129 +} 1.130 + 1.131 +/* Mingw doesn't have these in its mswsock.h. The values are copied from 1.132 + wine.h. Perhaps if we copy them exactly, the cargo will come again. 1.133 +*/ 1.134 +#ifndef WSAID_ACCEPTEX 1.135 +#define WSAID_ACCEPTEX \ 1.136 + {0xb5367df1,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}} 1.137 +#endif 1.138 +#ifndef WSAID_CONNECTEX 1.139 +#define WSAID_CONNECTEX \ 1.140 + {0x25a207b9,0xddf3,0x4660,{0x8e,0xe9,0x76,0xe5,0x8c,0x74,0x06,0x3e}} 1.141 +#endif 1.142 +#ifndef WSAID_GETACCEPTEXSOCKADDRS 1.143 +#define WSAID_GETACCEPTEXSOCKADDRS \ 1.144 + {0xb5367df2,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}} 1.145 +#endif 1.146 + 1.147 +static void 1.148 +init_extension_functions(struct win32_extension_fns *ext) 1.149 +{ 1.150 + const GUID acceptex = WSAID_ACCEPTEX; 1.151 + const GUID connectex = WSAID_CONNECTEX; 1.152 + const GUID getacceptexsockaddrs = WSAID_GETACCEPTEXSOCKADDRS; 1.153 + SOCKET s = socket(AF_INET, SOCK_STREAM, 0); 1.154 + if (s == INVALID_SOCKET) 1.155 + return; 1.156 + ext->AcceptEx = get_extension_function(s, &acceptex); 1.157 + ext->ConnectEx = get_extension_function(s, &connectex); 1.158 + ext->GetAcceptExSockaddrs = get_extension_function(s, 1.159 + &getacceptexsockaddrs); 1.160 + closesocket(s); 1.161 +} 1.162 + 1.163 +static struct win32_extension_fns the_extension_fns; 1.164 +static int extension_fns_initialized = 0; 1.165 + 1.166 +const struct win32_extension_fns * 1.167 +event_get_win32_extension_fns(void) 1.168 +{ 1.169 + return &the_extension_fns; 1.170 +} 1.171 + 1.172 +#define N_CPUS_DEFAULT 2 1.173 + 1.174 +struct event_iocp_port * 1.175 +event_iocp_port_launch(int n_cpus) 1.176 +{ 1.177 + struct event_iocp_port *port; 1.178 + int i; 1.179 + 1.180 + if (!extension_fns_initialized) 1.181 + init_extension_functions(&the_extension_fns); 1.182 + 1.183 + if (!(port = mm_calloc(1, sizeof(struct event_iocp_port)))) 1.184 + return NULL; 1.185 + 1.186 + if (n_cpus <= 0) 1.187 + n_cpus = N_CPUS_DEFAULT; 1.188 + port->n_threads = n_cpus * 2; 1.189 + port->threads = mm_calloc(port->n_threads, sizeof(HANDLE)); 1.190 + if (!port->threads) 1.191 + goto err; 1.192 + 1.193 + port->port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1.194 + n_cpus); 1.195 + port->ms = -1; 1.196 + if (!port->port) 1.197 + goto err; 1.198 + 1.199 + port->shutdownSemaphore = CreateSemaphore(NULL, 0, 1, NULL); 1.200 + if (!port->shutdownSemaphore) 1.201 + goto err; 1.202 + 1.203 + for (i=0; i<port->n_threads; ++i) { 1.204 + ev_uintptr_t th = _beginthread(loop, 0, port); 1.205 + if (th == (ev_uintptr_t)-1) 1.206 + goto err; 1.207 + port->threads[i] = (HANDLE)th; 1.208 + ++port->n_live_threads; 1.209 + } 1.210 + 1.211 + InitializeCriticalSectionAndSpinCount(&port->lock, 1000); 1.212 + 1.213 + return port; 1.214 +err: 1.215 + if (port->port) 1.216 + CloseHandle(port->port); 1.217 + if (port->threads) 1.218 + mm_free(port->threads); 1.219 + if (port->shutdownSemaphore) 1.220 + CloseHandle(port->shutdownSemaphore); 1.221 + mm_free(port); 1.222 + return NULL; 1.223 +} 1.224 + 1.225 +static void 1.226 +_event_iocp_port_unlock_and_free(struct event_iocp_port *port) 1.227 +{ 1.228 + DeleteCriticalSection(&port->lock); 1.229 + CloseHandle(port->port); 1.230 + CloseHandle(port->shutdownSemaphore); 1.231 + mm_free(port->threads); 1.232 + mm_free(port); 1.233 +} 1.234 + 1.235 +static int 1.236 +event_iocp_notify_all(struct event_iocp_port *port) 1.237 +{ 1.238 + int i, r, ok=1; 1.239 + for (i=0; i<port->n_threads; ++i) { 1.240 + r = PostQueuedCompletionStatus(port->port, 0, NOTIFICATION_KEY, 1.241 + NULL); 1.242 + if (!r) 1.243 + ok = 0; 1.244 + } 1.245 + return ok ? 0 : -1; 1.246 +} 1.247 + 1.248 +int 1.249 +event_iocp_shutdown(struct event_iocp_port *port, long waitMsec) 1.250 +{ 1.251 + DWORD ms = INFINITE; 1.252 + int n; 1.253 + 1.254 + EnterCriticalSection(&port->lock); 1.255 + port->shutdown = 1; 1.256 + LeaveCriticalSection(&port->lock); 1.257 + event_iocp_notify_all(port); 1.258 + 1.259 + if (waitMsec >= 0) 1.260 + ms = waitMsec; 1.261 + 1.262 + WaitForSingleObject(port->shutdownSemaphore, ms); 1.263 + EnterCriticalSection(&port->lock); 1.264 + n = port->n_live_threads; 1.265 + LeaveCriticalSection(&port->lock); 1.266 + if (n == 0) { 1.267 + _event_iocp_port_unlock_and_free(port); 1.268 + return 0; 1.269 + } else { 1.270 + return -1; 1.271 + } 1.272 +} 1.273 + 1.274 +int 1.275 +event_iocp_activate_overlapped( 1.276 + struct event_iocp_port *port, struct event_overlapped *o, 1.277 + ev_uintptr_t key, ev_uint32_t n) 1.278 +{ 1.279 + BOOL r; 1.280 + 1.281 + r = PostQueuedCompletionStatus(port->port, n, key, &o->overlapped); 1.282 + return (r==0) ? -1 : 0; 1.283 +} 1.284 + 1.285 +struct event_iocp_port * 1.286 +event_base_get_iocp(struct event_base *base) 1.287 +{ 1.288 +#ifdef WIN32 1.289 + return base->iocp; 1.290 +#else 1.291 + return NULL; 1.292 +#endif 1.293 +}