1 /* $NetBSD: evthread_win32.c,v 1.1.1.2 2015/01/29 06:38:09 spz Exp $ */
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
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 $");
33 /* Minimum required for InitializeCriticalSectionAndSpinCount */
34 #define _WIN32_WINNT 0x0403
37 #define WIN32_LEAN_AND_MEAN
39 #undef WIN32_LEAN_AND_MEAN
40 #include <sys/locking.h>
44 #include "event2/thread.h"
46 #include "mm-internal.h"
47 #include "evthread-internal.h"
49 #define SPIN_COUNT 2000
52 evthread_win32_lock_create(unsigned locktype
)
54 CRITICAL_SECTION
*lock
= mm_malloc(sizeof(CRITICAL_SECTION
));
57 if (InitializeCriticalSectionAndSpinCount(lock
, SPIN_COUNT
) == 0) {
65 evthread_win32_lock_free(void *_lock
, unsigned locktype
)
67 CRITICAL_SECTION
*lock
= _lock
;
68 DeleteCriticalSection(lock
);
73 evthread_win32_lock(unsigned mode
, void *_lock
)
75 CRITICAL_SECTION
*lock
= _lock
;
76 if ((mode
& EVTHREAD_TRY
)) {
77 return ! TryEnterCriticalSection(lock
);
79 EnterCriticalSection(lock
);
85 evthread_win32_unlock(unsigned mode
, void *_lock
)
87 CRITICAL_SECTION
*lock
= _lock
;
88 LeaveCriticalSection(lock
);
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
)
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
;
107 evthread_win32_condvar_init(void)
111 lib
= GetModuleHandle(TEXT("kernel32.dll"));
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. */
129 evthread_win32_condvar_alloc(unsigned condflags
)
131 CONDITION_VARIABLE
*cond
= mm_malloc(sizeof(CONDITION_VARIABLE
));
134 InitializeConditionVariable_fn(cond
);
139 evthread_win32_condvar_free(void *_cond
)
141 CONDITION_VARIABLE
*cond
= _cond
;
142 /* There doesn't _seem_ to be a cleaup fn here... */
147 evthread_win32_condvar_signal(void *_cond
, int broadcast
)
149 CONDITION_VARIABLE
*cond
= _cond
;
151 WakeAllConditionVariable_fn(cond
);
153 WakeConditionVariable_fn(cond
);
158 evthread_win32_condvar_wait(void *_cond
, void *_lock
, const struct timeval
*tv
)
160 CONDITION_VARIABLE
*cond
= _cond
;
161 CRITICAL_SECTION
*lock
= _lock
;
166 ms
= evutil_tv_to_msec(tv
);
169 result
= SleepConditionVariableCS_fn(cond
, lock
, ms
);
171 if (GetLastError() == WAIT_TIMEOUT
)
181 struct evthread_win32_cond
{
184 CRITICAL_SECTION lock
;
191 evthread_win32_cond_alloc(unsigned flags
)
193 struct evthread_win32_cond
*cond
;
194 if (!(cond
= mm_malloc(sizeof(struct evthread_win32_cond
))))
196 if (InitializeCriticalSectionAndSpinCount(&cond
->lock
, SPIN_COUNT
)==0) {
200 if ((cond
->event
= CreateEvent(NULL
,TRUE
,FALSE
,NULL
)) == NULL
) {
201 DeleteCriticalSection(&cond
->lock
);
205 cond
->n_waiting
= cond
->n_to_wake
= cond
->generation
= 0;
210 evthread_win32_cond_free(void *_cond
)
212 struct evthread_win32_cond
*cond
= _cond
;
213 DeleteCriticalSection(&cond
->lock
);
214 CloseHandle(cond
->event
);
219 evthread_win32_cond_signal(void *_cond
, int broadcast
)
221 struct evthread_win32_cond
*cond
= _cond
;
222 EnterCriticalSection(&cond
->lock
);
224 cond
->n_to_wake
= cond
->n_waiting
;
228 SetEvent(cond
->event
);
229 LeaveCriticalSection(&cond
->lock
);
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
;
241 DWORD ms
= INFINITE
, ms_orig
= INFINITE
, startTime
, endTime
;
243 ms_orig
= ms
= evutil_tv_to_msec(tv
);
245 EnterCriticalSection(&cond
->lock
);
247 generation_at_start
= cond
->generation
;
248 LeaveCriticalSection(&cond
->lock
);
250 LeaveCriticalSection(lock
);
252 startTime
= GetTickCount();
255 res
= WaitForSingleObject(cond
->event
, ms
);
256 EnterCriticalSection(&cond
->lock
);
257 if (cond
->n_to_wake
&&
258 cond
->generation
!= generation_at_start
) {
264 } else if (res
!= WAIT_OBJECT_0
) {
265 result
= (res
==WAIT_TIMEOUT
) ? 1 : -1;
269 } else if (ms
!= INFINITE
) {
270 endTime
= GetTickCount();
271 if (startTime
+ ms_orig
<= endTime
) {
272 result
= 1; /* Timeout */
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
284 ResetEvent(cond
->event
);
287 LeaveCriticalSection(&cond
->lock
);
290 EnterCriticalSection(lock
);
292 EnterCriticalSection(&cond
->lock
);
293 if (!cond
->n_waiting
)
294 ResetEvent(cond
->event
);
295 LeaveCriticalSection(&cond
->lock
);
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
,
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
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
);
338 evthread_set_condition_callbacks(&cond_cbs
);