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