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"
30 /* Minimum required for InitializeCriticalSectionAndSpinCount */
31 #define _WIN32_WINNT 0x0403
34 #define WIN32_LEAN_AND_MEAN
36 #undef WIN32_LEAN_AND_MEAN
37 #include <sys/locking.h>
41 #include "event2/thread.h"
43 #include "mm-internal.h"
44 #include "evthread-internal.h"
46 #define SPIN_COUNT 2000
49 evthread_win32_lock_create(unsigned locktype
)
51 CRITICAL_SECTION
*lock
= mm_malloc(sizeof(CRITICAL_SECTION
));
54 if (InitializeCriticalSectionAndSpinCount(lock
, SPIN_COUNT
) == 0) {
62 evthread_win32_lock_free(void *_lock
, unsigned locktype
)
64 CRITICAL_SECTION
*lock
= _lock
;
65 DeleteCriticalSection(lock
);
70 evthread_win32_lock(unsigned mode
, void *_lock
)
72 CRITICAL_SECTION
*lock
= _lock
;
73 if ((mode
& EVTHREAD_TRY
)) {
74 return ! TryEnterCriticalSection(lock
);
76 EnterCriticalSection(lock
);
82 evthread_win32_unlock(unsigned mode
, void *_lock
)
84 CRITICAL_SECTION
*lock
= _lock
;
85 LeaveCriticalSection(lock
);
90 evthread_win32_get_id(void)
92 return (unsigned long) GetCurrentThreadId();
95 #ifdef WIN32_HAVE_CONDITION_VARIABLES
96 static void WINAPI (*InitializeConditionVariable_fn
)(PCONDITION_VARIABLE
)
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
;
104 evthread_win32_condvar_init(void)
108 lib
= GetModuleHandle(TEXT("kernel32.dll"));
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
;
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. */
126 evthread_win32_condvar_alloc(unsigned condflags
)
128 CONDITION_VARIABLE
*cond
= mm_malloc(sizeof(CONDITION_VARIABLE
));
131 InitializeConditionVariable_fn(cond
);
136 evthread_win32_condvar_free(void *_cond
)
138 CONDITION_VARIABLE
*cond
= _cond
;
139 /* There doesn't _seem_ to be a cleaup fn here... */
144 evthread_win32_condvar_signal(void *_cond
, int broadcast
)
146 CONDITION_VARIABLE
*cond
= _cond
;
148 WakeAllConditionVariable_fn(cond
);
150 WakeConditionVariable_fn(cond
);
155 evthread_win32_condvar_wait(void *_cond
, void *_lock
, const struct timeval
*tv
)
157 CONDITION_VARIABLE
*cond
= _cond
;
158 CRITICAL_SECTION
*lock
= _lock
;
163 ms
= evutil_tv_to_msec(tv
);
166 result
= SleepConditionVariableCS_fn(cond
, lock
, ms
);
168 if (GetLastError() == WAIT_TIMEOUT
)
178 struct evthread_win32_cond
{
181 CRITICAL_SECTION lock
;
188 evthread_win32_cond_alloc(unsigned flags
)
190 struct evthread_win32_cond
*cond
;
191 if (!(cond
= mm_malloc(sizeof(struct evthread_win32_cond
))))
193 if (InitializeCriticalSectionAndSpinCount(&cond
->lock
, SPIN_COUNT
)==0) {
197 if ((cond
->event
= CreateEvent(NULL
,TRUE
,FALSE
,NULL
)) == NULL
) {
198 DeleteCriticalSection(&cond
->lock
);
202 cond
->n_waiting
= cond
->n_to_wake
= cond
->generation
= 0;
207 evthread_win32_cond_free(void *_cond
)
209 struct evthread_win32_cond
*cond
= _cond
;
210 DeleteCriticalSection(&cond
->lock
);
211 CloseHandle(cond
->event
);
216 evthread_win32_cond_signal(void *_cond
, int broadcast
)
218 struct evthread_win32_cond
*cond
= _cond
;
219 EnterCriticalSection(&cond
->lock
);
221 cond
->n_to_wake
= cond
->n_waiting
;
225 SetEvent(cond
->event
);
226 LeaveCriticalSection(&cond
->lock
);
231 evthread_win32_cond_wait(void *_cond
, void *_lock
, const struct timeval
*tv
)
233 struct evthread_win32_cond
*cond
= _cond
;
234 CRITICAL_SECTION
*lock
= _lock
;
235 int generation_at_start
;
238 DWORD ms
= INFINITE
, ms_orig
= INFINITE
, startTime
, endTime
;
240 ms_orig
= ms
= evutil_tv_to_msec(tv
);
242 EnterCriticalSection(&cond
->lock
);
244 generation_at_start
= cond
->generation
;
245 LeaveCriticalSection(&cond
->lock
);
247 LeaveCriticalSection(lock
);
249 startTime
= GetTickCount();
252 res
= WaitForSingleObject(cond
->event
, ms
);
253 EnterCriticalSection(&cond
->lock
);
254 if (cond
->n_to_wake
&&
255 cond
->generation
!= generation_at_start
) {
261 } else if (res
!= WAIT_OBJECT_0
) {
262 result
= (res
==WAIT_TIMEOUT
) ? 1 : -1;
266 } else if (ms
!= INFINITE
) {
267 endTime
= GetTickCount();
268 if (startTime
+ ms_orig
<= endTime
) {
269 result
= 1; /* Timeout */
274 ms
= startTime
+ ms_orig
- endTime
;
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
281 ResetEvent(cond
->event
);
284 LeaveCriticalSection(&cond
->lock
);
287 EnterCriticalSection(lock
);
289 EnterCriticalSection(&cond
->lock
);
290 if (!cond
->n_waiting
)
291 ResetEvent(cond
->event
);
292 LeaveCriticalSection(&cond
->lock
);
298 evthread_use_windows_threads(void)
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
,
306 evthread_win32_unlock
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
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
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
);
335 evthread_set_condition_callbacks(&cond_cbs
);