etc/services - sync with NetBSD-8
[minix.git] / external / bsd / libevent / dist / evthread_win32.c
blobe2032c7a953eab6e3679964800eb3b5cefb326ec
1 /* $NetBSD: evthread_win32.c,v 1.1.1.2 2015/01/29 06:38:09 spz Exp $ */
2 /*
3 * Copyright 2009-2012 Niels Provos and Nick Mathewson
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "event2/event-config.h"
28 #include <sys/cdefs.h>
29 __RCSID("$NetBSD: evthread_win32.c,v 1.1.1.2 2015/01/29 06:38:09 spz Exp $");
31 #ifdef WIN32
32 #ifndef _WIN32_WINNT
33 /* Minimum required for InitializeCriticalSectionAndSpinCount */
34 #define _WIN32_WINNT 0x0403
35 #endif
36 #include <winsock2.h>
37 #define WIN32_LEAN_AND_MEAN
38 #include <windows.h>
39 #undef WIN32_LEAN_AND_MEAN
40 #include <sys/locking.h>
41 #endif
43 struct event_base;
44 #include "event2/thread.h"
46 #include "mm-internal.h"
47 #include "evthread-internal.h"
49 #define SPIN_COUNT 2000
51 static void *
52 evthread_win32_lock_create(unsigned locktype)
54 CRITICAL_SECTION *lock = mm_malloc(sizeof(CRITICAL_SECTION));
55 if (!lock)
56 return NULL;
57 if (InitializeCriticalSectionAndSpinCount(lock, SPIN_COUNT) == 0) {
58 mm_free(lock);
59 return NULL;
61 return lock;
64 static void
65 evthread_win32_lock_free(void *_lock, unsigned locktype)
67 CRITICAL_SECTION *lock = _lock;
68 DeleteCriticalSection(lock);
69 mm_free(lock);
72 static int
73 evthread_win32_lock(unsigned mode, void *_lock)
75 CRITICAL_SECTION *lock = _lock;
76 if ((mode & EVTHREAD_TRY)) {
77 return ! TryEnterCriticalSection(lock);
78 } else {
79 EnterCriticalSection(lock);
80 return 0;
84 static int
85 evthread_win32_unlock(unsigned mode, void *_lock)
87 CRITICAL_SECTION *lock = _lock;
88 LeaveCriticalSection(lock);
89 return 0;
92 static unsigned long
93 evthread_win32_get_id(void)
95 return (unsigned long) GetCurrentThreadId();
98 #ifdef WIN32_HAVE_CONDITION_VARIABLES
99 static void WINAPI (*InitializeConditionVariable_fn)(PCONDITION_VARIABLE)
100 = NULL;
101 static BOOL WINAPI (*SleepConditionVariableCS_fn)(
102 PCONDITION_VARIABLE, PCRITICAL_SECTION, DWORD) = NULL;
103 static void WINAPI (*WakeAllConditionVariable_fn)(PCONDITION_VARIABLE) = NULL;
104 static void WINAPI (*WakeConditionVariable_fn)(PCONDITION_VARIABLE) = NULL;
106 static int
107 evthread_win32_condvar_init(void)
109 HANDLE lib;
111 lib = GetModuleHandle(TEXT("kernel32.dll"));
112 if (lib == NULL)
113 return 0;
115 #define LOAD(name) \
116 name##_fn = GetProcAddress(lib, #name)
117 LOAD(InitializeConditionVariable);
118 LOAD(SleepConditionVariableCS);
119 LOAD(WakeAllConditionVariable);
120 LOAD(WakeConditionVariable);
122 return InitializeConditionVariable_fn && SleepConditionVariableCS_fn &&
123 WakeAllConditionVariable_fn && WakeConditionVariable_fn;
126 /* XXXX Even if we can build this, we don't necessarily want to: the functions
127 * in question didn't exist before Vista, so we'd better LoadProc them. */
128 static void *
129 evthread_win32_condvar_alloc(unsigned condflags)
131 CONDITION_VARIABLE *cond = mm_malloc(sizeof(CONDITION_VARIABLE));
132 if (!cond)
133 return NULL;
134 InitializeConditionVariable_fn(cond);
135 return cond;
138 static void
139 evthread_win32_condvar_free(void *_cond)
141 CONDITION_VARIABLE *cond = _cond;
142 /* There doesn't _seem_ to be a cleaup fn here... */
143 mm_free(cond);
146 static int
147 evthread_win32_condvar_signal(void *_cond, int broadcast)
149 CONDITION_VARIABLE *cond = _cond;
150 if (broadcast)
151 WakeAllConditionVariable_fn(cond);
152 else
153 WakeConditionVariable_fn(cond);
154 return 0;
157 static int
158 evthread_win32_condvar_wait(void *_cond, void *_lock, const struct timeval *tv)
160 CONDITION_VARIABLE *cond = _cond;
161 CRITICAL_SECTION *lock = _lock;
162 DWORD ms, err;
163 BOOL result;
165 if (tv)
166 ms = evutil_tv_to_msec(tv);
167 else
168 ms = INFINITE;
169 result = SleepConditionVariableCS_fn(cond, lock, ms);
170 if (result) {
171 if (GetLastError() == WAIT_TIMEOUT)
172 return 1;
173 else
174 return -1;
175 } else {
176 return 0;
179 #endif
181 struct evthread_win32_cond {
182 HANDLE event;
184 CRITICAL_SECTION lock;
185 int n_waiting;
186 int n_to_wake;
187 int generation;
190 static void *
191 evthread_win32_cond_alloc(unsigned flags)
193 struct evthread_win32_cond *cond;
194 if (!(cond = mm_malloc(sizeof(struct evthread_win32_cond))))
195 return NULL;
196 if (InitializeCriticalSectionAndSpinCount(&cond->lock, SPIN_COUNT)==0) {
197 mm_free(cond);
198 return NULL;
200 if ((cond->event = CreateEvent(NULL,TRUE,FALSE,NULL)) == NULL) {
201 DeleteCriticalSection(&cond->lock);
202 mm_free(cond);
203 return NULL;
205 cond->n_waiting = cond->n_to_wake = cond->generation = 0;
206 return cond;
209 static void
210 evthread_win32_cond_free(void *_cond)
212 struct evthread_win32_cond *cond = _cond;
213 DeleteCriticalSection(&cond->lock);
214 CloseHandle(cond->event);
215 mm_free(cond);
218 static int
219 evthread_win32_cond_signal(void *_cond, int broadcast)
221 struct evthread_win32_cond *cond = _cond;
222 EnterCriticalSection(&cond->lock);
223 if (broadcast)
224 cond->n_to_wake = cond->n_waiting;
225 else
226 ++cond->n_to_wake;
227 cond->generation++;
228 SetEvent(cond->event);
229 LeaveCriticalSection(&cond->lock);
230 return 0;
233 static int
234 evthread_win32_cond_wait(void *_cond, void *_lock, const struct timeval *tv)
236 struct evthread_win32_cond *cond = _cond;
237 CRITICAL_SECTION *lock = _lock;
238 int generation_at_start;
239 int waiting = 1;
240 int result = -1;
241 DWORD ms = INFINITE, ms_orig = INFINITE, startTime, endTime;
242 if (tv)
243 ms_orig = ms = evutil_tv_to_msec(tv);
245 EnterCriticalSection(&cond->lock);
246 ++cond->n_waiting;
247 generation_at_start = cond->generation;
248 LeaveCriticalSection(&cond->lock);
250 LeaveCriticalSection(lock);
252 startTime = GetTickCount();
253 do {
254 DWORD res;
255 res = WaitForSingleObject(cond->event, ms);
256 EnterCriticalSection(&cond->lock);
257 if (cond->n_to_wake &&
258 cond->generation != generation_at_start) {
259 --cond->n_to_wake;
260 --cond->n_waiting;
261 result = 0;
262 waiting = 0;
263 goto out;
264 } else if (res != WAIT_OBJECT_0) {
265 result = (res==WAIT_TIMEOUT) ? 1 : -1;
266 --cond->n_waiting;
267 waiting = 0;
268 goto out;
269 } else if (ms != INFINITE) {
270 endTime = GetTickCount();
271 if (startTime + ms_orig <= endTime) {
272 result = 1; /* Timeout */
273 --cond->n_waiting;
274 waiting = 0;
275 goto out;
276 } else {
277 ms = startTime + ms_orig - endTime;
280 /* If we make it here, we are still waiting. */
281 if (cond->n_to_wake == 0) {
282 /* There is nobody else who should wake up; reset
283 * the event. */
284 ResetEvent(cond->event);
286 out:
287 LeaveCriticalSection(&cond->lock);
288 } while (waiting);
290 EnterCriticalSection(lock);
292 EnterCriticalSection(&cond->lock);
293 if (!cond->n_waiting)
294 ResetEvent(cond->event);
295 LeaveCriticalSection(&cond->lock);
297 return result;
301 evthread_use_windows_threads(void)
303 struct evthread_lock_callbacks cbs = {
304 EVTHREAD_LOCK_API_VERSION,
305 EVTHREAD_LOCKTYPE_RECURSIVE,
306 evthread_win32_lock_create,
307 evthread_win32_lock_free,
308 evthread_win32_lock,
309 evthread_win32_unlock
313 struct evthread_condition_callbacks cond_cbs = {
314 EVTHREAD_CONDITION_API_VERSION,
315 evthread_win32_cond_alloc,
316 evthread_win32_cond_free,
317 evthread_win32_cond_signal,
318 evthread_win32_cond_wait
320 #ifdef WIN32_HAVE_CONDITION_VARIABLES
321 struct evthread_condition_callbacks condvar_cbs = {
322 EVTHREAD_CONDITION_API_VERSION,
323 evthread_win32_condvar_alloc,
324 evthread_win32_condvar_free,
325 evthread_win32_condvar_signal,
326 evthread_win32_condvar_wait
328 #endif
330 evthread_set_lock_callbacks(&cbs);
331 evthread_set_id_callback(evthread_win32_get_id);
332 #ifdef WIN32_HAVE_CONDITION_VARIABLES
333 if (evthread_win32_condvar_init()) {
334 evthread_set_condition_callbacks(&condvar_cbs);
335 return 0;
337 #endif
338 evthread_set_condition_callbacks(&cond_cbs);
340 return 0;