ipc/chromium/src/third_party/libevent/event_iocp.c

changeset 0
6474c204b198
     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 +}

mercurial