2 * Copyright 2009-2012 Niels Provos and Nick Mathewson
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
26 #include "event2/event-config.h"
28 #ifndef _EVENT_DISABLE_THREAD_SUPPORT
32 /* Minimum required for InitializeCriticalSectionAndSpinCount */
33 #define _WIN32_WINNT 0x0403
36 #define WIN32_LEAN_AND_MEAN
38 #undef WIN32_LEAN_AND_MEAN
39 #include <sys/locking.h>
43 #include "event2/thread.h"
45 #include "mm-internal.h"
46 #include "evthread-internal.h"
48 #define SPIN_COUNT 2000
51 evthread_win32_lock_create(unsigned locktype
)
53 CRITICAL_SECTION
*lock
= mm_malloc(sizeof(CRITICAL_SECTION
));
56 if (InitializeCriticalSectionAndSpinCount(lock
, SPIN_COUNT
) == 0) {
64 evthread_win32_lock_free(void *_lock
, unsigned locktype
)
66 CRITICAL_SECTION
*lock
= _lock
;
67 DeleteCriticalSection(lock
);
72 evthread_win32_lock(unsigned mode
, void *_lock
)
74 CRITICAL_SECTION
*lock
= _lock
;
75 if ((mode
& EVTHREAD_TRY
)) {
76 return ! TryEnterCriticalSection(lock
);
78 EnterCriticalSection(lock
);
84 evthread_win32_unlock(unsigned mode
, void *_lock
)
86 CRITICAL_SECTION
*lock
= _lock
;
87 LeaveCriticalSection(lock
);
92 evthread_win32_get_id(void)
94 return (unsigned long) GetCurrentThreadId();
97 #ifdef WIN32_HAVE_CONDITION_VARIABLES
98 static void WINAPI (*InitializeConditionVariable_fn
)(PCONDITION_VARIABLE
)
100 static BOOL
WINAPI (*SleepConditionVariableCS_fn
)(
101 PCONDITION_VARIABLE
, PCRITICAL_SECTION
, DWORD
) = NULL
;
102 static void WINAPI (*WakeAllConditionVariable_fn
)(PCONDITION_VARIABLE
) = NULL
;
103 static void WINAPI (*WakeConditionVariable_fn
)(PCONDITION_VARIABLE
) = NULL
;
106 evthread_win32_condvar_init(void)
110 lib
= GetModuleHandle(TEXT("kernel32.dll"));
115 name##_fn = GetProcAddress(lib, #name)
116 LOAD(InitializeConditionVariable
);
117 LOAD(SleepConditionVariableCS
);
118 LOAD(WakeAllConditionVariable
);
119 LOAD(WakeConditionVariable
);
121 return InitializeConditionVariable_fn
&& SleepConditionVariableCS_fn
&&
122 WakeAllConditionVariable_fn
&& WakeConditionVariable_fn
;
125 /* XXXX Even if we can build this, we don't necessarily want to: the functions
126 * in question didn't exist before Vista, so we'd better LoadProc them. */
128 evthread_win32_condvar_alloc(unsigned condflags
)
130 CONDITION_VARIABLE
*cond
= mm_malloc(sizeof(CONDITION_VARIABLE
));
133 InitializeConditionVariable_fn(cond
);
138 evthread_win32_condvar_free(void *_cond
)
140 CONDITION_VARIABLE
*cond
= _cond
;
141 /* There doesn't _seem_ to be a cleaup fn here... */
146 evthread_win32_condvar_signal(void *_cond
, int broadcast
)
148 CONDITION_VARIABLE
*cond
= _cond
;
150 WakeAllConditionVariable_fn(cond
);
152 WakeConditionVariable_fn(cond
);
157 evthread_win32_condvar_wait(void *_cond
, void *_lock
, const struct timeval
*tv
)
159 CONDITION_VARIABLE
*cond
= _cond
;
160 CRITICAL_SECTION
*lock
= _lock
;
165 ms
= evutil_tv_to_msec(tv
);
168 result
= SleepConditionVariableCS_fn(cond
, lock
, ms
);
170 if (GetLastError() == WAIT_TIMEOUT
)
180 struct evthread_win32_cond
{
183 CRITICAL_SECTION lock
;
190 evthread_win32_cond_alloc(unsigned flags
)
192 struct evthread_win32_cond
*cond
;
193 if (!(cond
= mm_malloc(sizeof(struct evthread_win32_cond
))))
195 if (InitializeCriticalSectionAndSpinCount(&cond
->lock
, SPIN_COUNT
)==0) {
199 if ((cond
->event
= CreateEvent(NULL
,TRUE
,FALSE
,NULL
)) == NULL
) {
200 DeleteCriticalSection(&cond
->lock
);
204 cond
->n_waiting
= cond
->n_to_wake
= cond
->generation
= 0;
209 evthread_win32_cond_free(void *_cond
)
211 struct evthread_win32_cond
*cond
= _cond
;
212 DeleteCriticalSection(&cond
->lock
);
213 CloseHandle(cond
->event
);
218 evthread_win32_cond_signal(void *_cond
, int broadcast
)
220 struct evthread_win32_cond
*cond
= _cond
;
221 EnterCriticalSection(&cond
->lock
);
223 cond
->n_to_wake
= cond
->n_waiting
;
227 SetEvent(cond
->event
);
228 LeaveCriticalSection(&cond
->lock
);
233 evthread_win32_cond_wait(void *_cond
, void *_lock
, const struct timeval
*tv
)
235 struct evthread_win32_cond
*cond
= _cond
;
236 CRITICAL_SECTION
*lock
= _lock
;
237 int generation_at_start
;
240 DWORD ms
= INFINITE
, ms_orig
= INFINITE
, startTime
, endTime
;
242 ms_orig
= ms
= evutil_tv_to_msec(tv
);
244 EnterCriticalSection(&cond
->lock
);
246 generation_at_start
= cond
->generation
;
247 LeaveCriticalSection(&cond
->lock
);
249 LeaveCriticalSection(lock
);
251 startTime
= GetTickCount();
254 res
= WaitForSingleObject(cond
->event
, ms
);
255 EnterCriticalSection(&cond
->lock
);
256 if (cond
->n_to_wake
&&
257 cond
->generation
!= generation_at_start
) {
263 } else if (res
!= WAIT_OBJECT_0
) {
264 result
= (res
==WAIT_TIMEOUT
) ? 1 : -1;
268 } else if (ms
!= INFINITE
) {
269 endTime
= GetTickCount();
270 if (startTime
+ ms_orig
<= endTime
) {
271 result
= 1; /* Timeout */
276 ms
= startTime
+ ms_orig
- endTime
;
279 /* If we make it here, we are still waiting. */
280 if (cond
->n_to_wake
== 0) {
281 /* There is nobody else who should wake up; reset
283 ResetEvent(cond
->event
);
286 LeaveCriticalSection(&cond
->lock
);
289 EnterCriticalSection(lock
);
291 EnterCriticalSection(&cond
->lock
);
292 if (!cond
->n_waiting
)
293 ResetEvent(cond
->event
);
294 LeaveCriticalSection(&cond
->lock
);
300 evthread_use_windows_threads(void)
302 struct evthread_lock_callbacks cbs
= {
303 EVTHREAD_LOCK_API_VERSION
,
304 EVTHREAD_LOCKTYPE_RECURSIVE
,
305 evthread_win32_lock_create
,
306 evthread_win32_lock_free
,
308 evthread_win32_unlock
312 struct evthread_condition_callbacks cond_cbs
= {
313 EVTHREAD_CONDITION_API_VERSION
,
314 evthread_win32_cond_alloc
,
315 evthread_win32_cond_free
,
316 evthread_win32_cond_signal
,
317 evthread_win32_cond_wait
319 #ifdef WIN32_HAVE_CONDITION_VARIABLES
320 struct evthread_condition_callbacks condvar_cbs
= {
321 EVTHREAD_CONDITION_API_VERSION
,
322 evthread_win32_condvar_alloc
,
323 evthread_win32_condvar_free
,
324 evthread_win32_condvar_signal
,
325 evthread_win32_condvar_wait
329 evthread_set_lock_callbacks(&cbs
);
330 evthread_set_id_callback(evthread_win32_get_id
);
331 #ifdef WIN32_HAVE_CONDITION_VARIABLES
332 if (evthread_win32_condvar_init()) {
333 evthread_set_condition_callbacks(&condvar_cbs
);
337 evthread_set_condition_callbacks(&cond_cbs
);