1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/ipc/chromium/src/third_party/libevent/evthread_win32.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,339 @@ 1.4 +/* 1.5 + * Copyright 2009-2012 Niels Provos and 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 +#include "event2/event-config.h" 1.30 + 1.31 +#ifdef WIN32 1.32 +#ifndef _WIN32_WINNT 1.33 +/* Minimum required for InitializeCriticalSectionAndSpinCount */ 1.34 +#define _WIN32_WINNT 0x0403 1.35 +#endif 1.36 +#include <winsock2.h> 1.37 +#define WIN32_LEAN_AND_MEAN 1.38 +#include <windows.h> 1.39 +#undef WIN32_LEAN_AND_MEAN 1.40 +#include <sys/locking.h> 1.41 +#endif 1.42 + 1.43 +struct event_base; 1.44 +#include "event2/thread.h" 1.45 + 1.46 +#include "mm-internal.h" 1.47 +#include "evthread-internal.h" 1.48 + 1.49 +#define SPIN_COUNT 2000 1.50 + 1.51 +static void * 1.52 +evthread_win32_lock_create(unsigned locktype) 1.53 +{ 1.54 + CRITICAL_SECTION *lock = mm_malloc(sizeof(CRITICAL_SECTION)); 1.55 + if (!lock) 1.56 + return NULL; 1.57 + if (InitializeCriticalSectionAndSpinCount(lock, SPIN_COUNT) == 0) { 1.58 + mm_free(lock); 1.59 + return NULL; 1.60 + } 1.61 + return lock; 1.62 +} 1.63 + 1.64 +static void 1.65 +evthread_win32_lock_free(void *_lock, unsigned locktype) 1.66 +{ 1.67 + CRITICAL_SECTION *lock = _lock; 1.68 + DeleteCriticalSection(lock); 1.69 + mm_free(lock); 1.70 +} 1.71 + 1.72 +static int 1.73 +evthread_win32_lock(unsigned mode, void *_lock) 1.74 +{ 1.75 + CRITICAL_SECTION *lock = _lock; 1.76 + if ((mode & EVTHREAD_TRY)) { 1.77 + return ! TryEnterCriticalSection(lock); 1.78 + } else { 1.79 + EnterCriticalSection(lock); 1.80 + return 0; 1.81 + } 1.82 +} 1.83 + 1.84 +static int 1.85 +evthread_win32_unlock(unsigned mode, void *_lock) 1.86 +{ 1.87 + CRITICAL_SECTION *lock = _lock; 1.88 + LeaveCriticalSection(lock); 1.89 + return 0; 1.90 +} 1.91 + 1.92 +static unsigned long 1.93 +evthread_win32_get_id(void) 1.94 +{ 1.95 + return (unsigned long) GetCurrentThreadId(); 1.96 +} 1.97 + 1.98 +#ifdef WIN32_HAVE_CONDITION_VARIABLES 1.99 +static void WINAPI (*InitializeConditionVariable_fn)(PCONDITION_VARIABLE) 1.100 + = NULL; 1.101 +static BOOL WINAPI (*SleepConditionVariableCS_fn)( 1.102 + PCONDITION_VARIABLE, PCRITICAL_SECTION, DWORD) = NULL; 1.103 +static void WINAPI (*WakeAllConditionVariable_fn)(PCONDITION_VARIABLE) = NULL; 1.104 +static void WINAPI (*WakeConditionVariable_fn)(PCONDITION_VARIABLE) = NULL; 1.105 + 1.106 +static int 1.107 +evthread_win32_condvar_init(void) 1.108 +{ 1.109 + HANDLE lib; 1.110 + 1.111 + lib = GetModuleHandle(TEXT("kernel32.dll")); 1.112 + if (lib == NULL) 1.113 + return 0; 1.114 + 1.115 +#define LOAD(name) \ 1.116 + name##_fn = GetProcAddress(lib, #name) 1.117 + LOAD(InitializeConditionVariable); 1.118 + LOAD(SleepConditionVariable); 1.119 + LOAD(WakeAllConditionVariable); 1.120 + LOAD(WakeConditionVariable); 1.121 + 1.122 + return InitializeConditionVariable_fn && SleepConditionVariableCS_fn && 1.123 + WakeAllConditionVariable_fn && WakeConditionVariable_fn; 1.124 +} 1.125 + 1.126 +/* XXXX Even if we can build this, we don't necessarily want to: the functions 1.127 + * in question didn't exist before Vista, so we'd better LoadProc them. */ 1.128 +static void * 1.129 +evthread_win32_condvar_alloc(unsigned condflags) 1.130 +{ 1.131 + CONDITION_VARIABLE *cond = mm_malloc(sizeof(CONDITION_VARIABLE)); 1.132 + if (!cond) 1.133 + return NULL; 1.134 + InitializeConditionVariable_fn(cond); 1.135 + return cond; 1.136 +} 1.137 + 1.138 +static void 1.139 +evthread_win32_condvar_free(void *_cond) 1.140 +{ 1.141 + CONDITION_VARIABLE *cond = _cond; 1.142 + /* There doesn't _seem_ to be a cleaup fn here... */ 1.143 + mm_free(cond); 1.144 +} 1.145 + 1.146 +static int 1.147 +evthread_win32_condvar_signal(void *_cond, int broadcast) 1.148 +{ 1.149 + CONDITION_VARIABLE *cond = _cond; 1.150 + if (broadcast) 1.151 + WakeAllConditionVariable_fn(cond); 1.152 + else 1.153 + WakeConditionVariable_fn(cond); 1.154 + return 0; 1.155 +} 1.156 + 1.157 +static int 1.158 +evthread_win32_condvar_wait(void *_cond, void *_lock, const struct timeval *tv) 1.159 +{ 1.160 + CONDITION_VARIABLE *cond = _cond; 1.161 + CRITICAL_SECTION *lock = _lock; 1.162 + DWORD ms, err; 1.163 + BOOL result; 1.164 + 1.165 + if (tv) 1.166 + ms = evutil_tv_to_msec(tv); 1.167 + else 1.168 + ms = INFINITE; 1.169 + result = SleepConditionVariableCS_fn(cond, lock, ms); 1.170 + if (result) { 1.171 + if (GetLastError() == WAIT_TIMEOUT) 1.172 + return 1; 1.173 + else 1.174 + return -1; 1.175 + } else { 1.176 + return 0; 1.177 + } 1.178 +} 1.179 +#endif 1.180 + 1.181 +struct evthread_win32_cond { 1.182 + HANDLE event; 1.183 + 1.184 + CRITICAL_SECTION lock; 1.185 + int n_waiting; 1.186 + int n_to_wake; 1.187 + int generation; 1.188 +}; 1.189 + 1.190 +static void * 1.191 +evthread_win32_cond_alloc(unsigned flags) 1.192 +{ 1.193 + struct evthread_win32_cond *cond; 1.194 + if (!(cond = mm_malloc(sizeof(struct evthread_win32_cond)))) 1.195 + return NULL; 1.196 + if (InitializeCriticalSectionAndSpinCount(&cond->lock, SPIN_COUNT)==0) { 1.197 + mm_free(cond); 1.198 + return NULL; 1.199 + } 1.200 + if ((cond->event = CreateEvent(NULL,TRUE,FALSE,NULL)) == NULL) { 1.201 + DeleteCriticalSection(&cond->lock); 1.202 + mm_free(cond); 1.203 + return NULL; 1.204 + } 1.205 + cond->n_waiting = cond->n_to_wake = cond->generation = 0; 1.206 + return cond; 1.207 +} 1.208 + 1.209 +static void 1.210 +evthread_win32_cond_free(void *_cond) 1.211 +{ 1.212 + struct evthread_win32_cond *cond = _cond; 1.213 + DeleteCriticalSection(&cond->lock); 1.214 + CloseHandle(cond->event); 1.215 + mm_free(cond); 1.216 +} 1.217 + 1.218 +static int 1.219 +evthread_win32_cond_signal(void *_cond, int broadcast) 1.220 +{ 1.221 + struct evthread_win32_cond *cond = _cond; 1.222 + EnterCriticalSection(&cond->lock); 1.223 + if (broadcast) 1.224 + cond->n_to_wake = cond->n_waiting; 1.225 + else 1.226 + ++cond->n_to_wake; 1.227 + cond->generation++; 1.228 + SetEvent(cond->event); 1.229 + LeaveCriticalSection(&cond->lock); 1.230 + return 0; 1.231 +} 1.232 + 1.233 +static int 1.234 +evthread_win32_cond_wait(void *_cond, void *_lock, const struct timeval *tv) 1.235 +{ 1.236 + struct evthread_win32_cond *cond = _cond; 1.237 + CRITICAL_SECTION *lock = _lock; 1.238 + int generation_at_start; 1.239 + int waiting = 1; 1.240 + int result = -1; 1.241 + DWORD ms = INFINITE, ms_orig = INFINITE, startTime, endTime; 1.242 + if (tv) 1.243 + ms_orig = ms = evutil_tv_to_msec(tv); 1.244 + 1.245 + EnterCriticalSection(&cond->lock); 1.246 + ++cond->n_waiting; 1.247 + generation_at_start = cond->generation; 1.248 + LeaveCriticalSection(&cond->lock); 1.249 + 1.250 + LeaveCriticalSection(lock); 1.251 + 1.252 + startTime = GetTickCount(); 1.253 + do { 1.254 + DWORD res; 1.255 + res = WaitForSingleObject(cond->event, ms); 1.256 + EnterCriticalSection(&cond->lock); 1.257 + if (cond->n_to_wake && 1.258 + cond->generation != generation_at_start) { 1.259 + --cond->n_to_wake; 1.260 + --cond->n_waiting; 1.261 + result = 0; 1.262 + waiting = 0; 1.263 + goto out; 1.264 + } else if (res != WAIT_OBJECT_0) { 1.265 + result = (res==WAIT_TIMEOUT) ? 1 : -1; 1.266 + --cond->n_waiting; 1.267 + waiting = 0; 1.268 + goto out; 1.269 + } else if (ms != INFINITE) { 1.270 + endTime = GetTickCount(); 1.271 + if (startTime + ms_orig <= endTime) { 1.272 + result = 1; /* Timeout */ 1.273 + --cond->n_waiting; 1.274 + waiting = 0; 1.275 + goto out; 1.276 + } else { 1.277 + ms = startTime + ms_orig - endTime; 1.278 + } 1.279 + } 1.280 + /* If we make it here, we are still waiting. */ 1.281 + if (cond->n_to_wake == 0) { 1.282 + /* There is nobody else who should wake up; reset 1.283 + * the event. */ 1.284 + ResetEvent(cond->event); 1.285 + } 1.286 + out: 1.287 + LeaveCriticalSection(&cond->lock); 1.288 + } while (waiting); 1.289 + 1.290 + EnterCriticalSection(lock); 1.291 + 1.292 + EnterCriticalSection(&cond->lock); 1.293 + if (!cond->n_waiting) 1.294 + ResetEvent(cond->event); 1.295 + LeaveCriticalSection(&cond->lock); 1.296 + 1.297 + return result; 1.298 +} 1.299 + 1.300 +int 1.301 +evthread_use_windows_threads(void) 1.302 +{ 1.303 + struct evthread_lock_callbacks cbs = { 1.304 + EVTHREAD_LOCK_API_VERSION, 1.305 + EVTHREAD_LOCKTYPE_RECURSIVE, 1.306 + evthread_win32_lock_create, 1.307 + evthread_win32_lock_free, 1.308 + evthread_win32_lock, 1.309 + evthread_win32_unlock 1.310 + }; 1.311 + 1.312 + 1.313 + struct evthread_condition_callbacks cond_cbs = { 1.314 + EVTHREAD_CONDITION_API_VERSION, 1.315 + evthread_win32_cond_alloc, 1.316 + evthread_win32_cond_free, 1.317 + evthread_win32_cond_signal, 1.318 + evthread_win32_cond_wait 1.319 + }; 1.320 +#ifdef WIN32_HAVE_CONDITION_VARIABLES 1.321 + struct evthread_condition_callbacks condvar_cbs = { 1.322 + EVTHREAD_CONDITION_API_VERSION, 1.323 + evthread_win32_condvar_alloc, 1.324 + evthread_win32_condvar_free, 1.325 + evthread_win32_condvar_signal, 1.326 + evthread_win32_condvar_wait 1.327 + }; 1.328 +#endif 1.329 + 1.330 + evthread_set_lock_callbacks(&cbs); 1.331 + evthread_set_id_callback(evthread_win32_get_id); 1.332 +#ifdef WIN32_HAVE_CONDITION_VARIABLES 1.333 + if (evthread_win32_condvar_init()) { 1.334 + evthread_set_condition_callbacks(&condvar_cbs); 1.335 + return 0; 1.336 + } 1.337 +#endif 1.338 + evthread_set_condition_callbacks(&cond_cbs); 1.339 + 1.340 + return 0; 1.341 +} 1.342 +