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