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

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /*
     2  * Copyright 2009-2012 Niels Provos and Nick Mathewson
     3  *
     4  * Redistribution and use in source and binary forms, with or without
     5  * modification, are permitted provided that the following conditions
     6  * are met:
     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.
    14  *
    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.
    25  */
    26 #include "event2/event-config.h"
    28 #ifdef WIN32
    29 #ifndef _WIN32_WINNT
    30 /* Minimum required for InitializeCriticalSectionAndSpinCount */
    31 #define _WIN32_WINNT 0x0403
    32 #endif
    33 #include <winsock2.h>
    34 #define WIN32_LEAN_AND_MEAN
    35 #include <windows.h>
    36 #undef WIN32_LEAN_AND_MEAN
    37 #include <sys/locking.h>
    38 #endif
    40 struct event_base;
    41 #include "event2/thread.h"
    43 #include "mm-internal.h"
    44 #include "evthread-internal.h"
    46 #define SPIN_COUNT 2000
    48 static void *
    49 evthread_win32_lock_create(unsigned locktype)
    50 {
    51 	CRITICAL_SECTION *lock = mm_malloc(sizeof(CRITICAL_SECTION));
    52 	if (!lock)
    53 		return NULL;
    54 	if (InitializeCriticalSectionAndSpinCount(lock, SPIN_COUNT) == 0) {
    55 		mm_free(lock);
    56 		return NULL;
    57 	}
    58 	return lock;
    59 }
    61 static void
    62 evthread_win32_lock_free(void *_lock, unsigned locktype)
    63 {
    64 	CRITICAL_SECTION *lock = _lock;
    65 	DeleteCriticalSection(lock);
    66 	mm_free(lock);
    67 }
    69 static int
    70 evthread_win32_lock(unsigned mode, void *_lock)
    71 {
    72 	CRITICAL_SECTION *lock = _lock;
    73 	if ((mode & EVTHREAD_TRY)) {
    74 		return ! TryEnterCriticalSection(lock);
    75 	} else {
    76 		EnterCriticalSection(lock);
    77 		return 0;
    78 	}
    79 }
    81 static int
    82 evthread_win32_unlock(unsigned mode, void *_lock)
    83 {
    84 	CRITICAL_SECTION *lock = _lock;
    85 	LeaveCriticalSection(lock);
    86 	return 0;
    87 }
    89 static unsigned long
    90 evthread_win32_get_id(void)
    91 {
    92 	return (unsigned long) GetCurrentThreadId();
    93 }
    95 #ifdef WIN32_HAVE_CONDITION_VARIABLES
    96 static void WINAPI (*InitializeConditionVariable_fn)(PCONDITION_VARIABLE)
    97 	= NULL;
    98 static BOOL WINAPI (*SleepConditionVariableCS_fn)(
    99 	PCONDITION_VARIABLE, PCRITICAL_SECTION, DWORD) = NULL;
   100 static void WINAPI (*WakeAllConditionVariable_fn)(PCONDITION_VARIABLE) = NULL;
   101 static void WINAPI (*WakeConditionVariable_fn)(PCONDITION_VARIABLE) = NULL;
   103 static int
   104 evthread_win32_condvar_init(void)
   105 {
   106 	HANDLE lib;
   108 	lib = GetModuleHandle(TEXT("kernel32.dll"));
   109 	if (lib == NULL)
   110 		return 0;
   112 #define LOAD(name)				\
   113 	name##_fn = GetProcAddress(lib, #name)
   114 	LOAD(InitializeConditionVariable);
   115 	LOAD(SleepConditionVariable);
   116 	LOAD(WakeAllConditionVariable);
   117 	LOAD(WakeConditionVariable);
   119 	return InitializeConditionVariable_fn && SleepConditionVariableCS_fn &&
   120 	    WakeAllConditionVariable_fn && WakeConditionVariable_fn;
   121 }
   123 /* XXXX Even if we can build this, we don't necessarily want to: the functions
   124  * in question didn't exist before Vista, so we'd better LoadProc them. */
   125 static void *
   126 evthread_win32_condvar_alloc(unsigned condflags)
   127 {
   128 	CONDITION_VARIABLE *cond = mm_malloc(sizeof(CONDITION_VARIABLE));
   129 	if (!cond)
   130 		return NULL;
   131 	InitializeConditionVariable_fn(cond);
   132 	return cond;
   133 }
   135 static void
   136 evthread_win32_condvar_free(void *_cond)
   137 {
   138 	CONDITION_VARIABLE *cond = _cond;
   139 	/* There doesn't _seem_ to be a cleaup fn here... */
   140 	mm_free(cond);
   141 }
   143 static int
   144 evthread_win32_condvar_signal(void *_cond, int broadcast)
   145 {
   146 	CONDITION_VARIABLE *cond = _cond;
   147 	if (broadcast)
   148 		WakeAllConditionVariable_fn(cond);
   149 	else
   150 		WakeConditionVariable_fn(cond);
   151 	return 0;
   152 }
   154 static int
   155 evthread_win32_condvar_wait(void *_cond, void *_lock, const struct timeval *tv)
   156 {
   157 	CONDITION_VARIABLE *cond = _cond;
   158 	CRITICAL_SECTION *lock = _lock;
   159 	DWORD ms, err;
   160 	BOOL result;
   162 	if (tv)
   163 		ms = evutil_tv_to_msec(tv);
   164 	else
   165 		ms = INFINITE;
   166 	result = SleepConditionVariableCS_fn(cond, lock, ms);
   167 	if (result) {
   168 		if (GetLastError() == WAIT_TIMEOUT)
   169 			return 1;
   170 		else
   171 			return -1;
   172 	} else {
   173 		return 0;
   174 	}
   175 }
   176 #endif
   178 struct evthread_win32_cond {
   179 	HANDLE event;
   181 	CRITICAL_SECTION lock;
   182 	int n_waiting;
   183 	int n_to_wake;
   184 	int generation;
   185 };
   187 static void *
   188 evthread_win32_cond_alloc(unsigned flags)
   189 {
   190 	struct evthread_win32_cond *cond;
   191 	if (!(cond = mm_malloc(sizeof(struct evthread_win32_cond))))
   192 		return NULL;
   193 	if (InitializeCriticalSectionAndSpinCount(&cond->lock, SPIN_COUNT)==0) {
   194 		mm_free(cond);
   195 		return NULL;
   196 	}
   197 	if ((cond->event = CreateEvent(NULL,TRUE,FALSE,NULL)) == NULL) {
   198 		DeleteCriticalSection(&cond->lock);
   199 		mm_free(cond);
   200 		return NULL;
   201 	}
   202 	cond->n_waiting = cond->n_to_wake = cond->generation = 0;
   203 	return cond;
   204 }
   206 static void
   207 evthread_win32_cond_free(void *_cond)
   208 {
   209 	struct evthread_win32_cond *cond = _cond;
   210 	DeleteCriticalSection(&cond->lock);
   211 	CloseHandle(cond->event);
   212 	mm_free(cond);
   213 }
   215 static int
   216 evthread_win32_cond_signal(void *_cond, int broadcast)
   217 {
   218 	struct evthread_win32_cond *cond = _cond;
   219 	EnterCriticalSection(&cond->lock);
   220 	if (broadcast)
   221 		cond->n_to_wake = cond->n_waiting;
   222 	else
   223 		++cond->n_to_wake;
   224 	cond->generation++;
   225 	SetEvent(cond->event);
   226 	LeaveCriticalSection(&cond->lock);
   227 	return 0;
   228 }
   230 static int
   231 evthread_win32_cond_wait(void *_cond, void *_lock, const struct timeval *tv)
   232 {
   233 	struct evthread_win32_cond *cond = _cond;
   234 	CRITICAL_SECTION *lock = _lock;
   235 	int generation_at_start;
   236 	int waiting = 1;
   237 	int result = -1;
   238 	DWORD ms = INFINITE, ms_orig = INFINITE, startTime, endTime;
   239 	if (tv)
   240 		ms_orig = ms = evutil_tv_to_msec(tv);
   242 	EnterCriticalSection(&cond->lock);
   243 	++cond->n_waiting;
   244 	generation_at_start = cond->generation;
   245 	LeaveCriticalSection(&cond->lock);
   247 	LeaveCriticalSection(lock);
   249 	startTime = GetTickCount();
   250 	do {
   251 		DWORD res;
   252 		res = WaitForSingleObject(cond->event, ms);
   253 		EnterCriticalSection(&cond->lock);
   254 		if (cond->n_to_wake &&
   255 		    cond->generation != generation_at_start) {
   256 			--cond->n_to_wake;
   257 			--cond->n_waiting;
   258 			result = 0;
   259 			waiting = 0;
   260 			goto out;
   261 		} else if (res != WAIT_OBJECT_0) {
   262 			result = (res==WAIT_TIMEOUT) ? 1 : -1;
   263 			--cond->n_waiting;
   264 			waiting = 0;
   265 			goto out;
   266 		} else if (ms != INFINITE) {
   267 			endTime = GetTickCount();
   268 			if (startTime + ms_orig <= endTime) {
   269 				result = 1; /* Timeout */
   270 				--cond->n_waiting;
   271 				waiting = 0;
   272 				goto out;
   273 			} else {
   274 				ms = startTime + ms_orig - endTime;
   275 			}
   276 		}
   277 		/* If we make it here, we are still waiting. */
   278 		if (cond->n_to_wake == 0) {
   279 			/* There is nobody else who should wake up; reset
   280 			 * the event. */
   281 			ResetEvent(cond->event);
   282 		}
   283 	out:
   284 		LeaveCriticalSection(&cond->lock);
   285 	} while (waiting);
   287 	EnterCriticalSection(lock);
   289 	EnterCriticalSection(&cond->lock);
   290 	if (!cond->n_waiting)
   291 		ResetEvent(cond->event);
   292 	LeaveCriticalSection(&cond->lock);
   294 	return result;
   295 }
   297 int
   298 evthread_use_windows_threads(void)
   299 {
   300 	struct evthread_lock_callbacks cbs = {
   301 		EVTHREAD_LOCK_API_VERSION,
   302 		EVTHREAD_LOCKTYPE_RECURSIVE,
   303 		evthread_win32_lock_create,
   304 		evthread_win32_lock_free,
   305 		evthread_win32_lock,
   306 		evthread_win32_unlock
   307 	};
   310 	struct evthread_condition_callbacks cond_cbs = {
   311 		EVTHREAD_CONDITION_API_VERSION,
   312 		evthread_win32_cond_alloc,
   313 		evthread_win32_cond_free,
   314 		evthread_win32_cond_signal,
   315 		evthread_win32_cond_wait
   316 	};
   317 #ifdef WIN32_HAVE_CONDITION_VARIABLES
   318 	struct evthread_condition_callbacks condvar_cbs = {
   319 		EVTHREAD_CONDITION_API_VERSION,
   320 		evthread_win32_condvar_alloc,
   321 		evthread_win32_condvar_free,
   322 		evthread_win32_condvar_signal,
   323 		evthread_win32_condvar_wait
   324 	};
   325 #endif
   327 	evthread_set_lock_callbacks(&cbs);
   328 	evthread_set_id_callback(evthread_win32_get_id);
   329 #ifdef WIN32_HAVE_CONDITION_VARIABLES
   330 	if (evthread_win32_condvar_init()) {
   331 		evthread_set_condition_callbacks(&condvar_cbs);
   332 		return 0;
   333 	}
   334 #endif
   335 	evthread_set_condition_callbacks(&cond_cbs);
   337 	return 0;
   338 }

mercurial