aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBenoit Germain <b n t DOT g e r m a i n AT g m a i l DOT c o m>2013-07-20 09:25:39 +0200
committerBenoit Germain <b n t DOT g e r m a i n AT g m a i l DOT c o m>2013-07-20 09:25:39 +0200
commita2dc01d60e8b0fc32b98fe885068720492de1406 (patch)
treeefcec39656a9c9b3162e2881f38eb71d91df0302 /src
parentd9cab463ac5d9539092fde03b22905f76f06844b (diff)
downloadlanes-a2dc01d60e8b0fc32b98fe885068720492de1406.tar.gz
lanes-a2dc01d60e8b0fc32b98fe885068720492de1406.tar.bz2
lanes-a2dc01d60e8b0fc32b98fe885068720492de1406.zip
Ditch PulseEvent usage on WIN32 builds
Diffstat (limited to 'src')
-rw-r--r--src/threading.c155
-rw-r--r--src/threading.h12
2 files changed, 97 insertions, 70 deletions
diff --git a/src/threading.c b/src/threading.c
index 43e5f46..1e4fc92 100644
--- a/src/threading.c
+++ b/src/threading.c
@@ -358,79 +358,98 @@ bool_t THREAD_WAIT_IMPL( THREAD_T *ref, double secs)
358#endif // !__GNUC__ 358#endif // !__GNUC__
359 } 359 }
360 360
361#if WINVER <= 0x0400 // Windows NT4: Use PulseEvent, although it is unreliable, but then... 361#if WINVER <= 0x0400 // Windows NT4
362 362
363 // 363 void SIGNAL_INIT( SIGNAL_T* ref)
364 void SIGNAL_INIT( SIGNAL_T *ref ) { 364 {
365 // 'manual reset' event type selected, to be able to wake up all the 365 InitializeCriticalSection( &ref->signalCS);
366 // waiting threads. 366 InitializeCriticalSection( &ref->countCS);
367 // 367 if( 0 == (ref->waitEvent = CreateEvent( 0, TRUE, FALSE, 0))) // manual-reset
368 HANDLE h= CreateEvent( NULL, // security attributes 368 FAIL( "CreateEvent", GetLastError());
369 TRUE, // TRUE: manual event 369 if( 0 == (ref->waitDoneEvent = CreateEvent( 0, FALSE, FALSE, 0))) // auto-reset
370 FALSE, // Initial state 370 FAIL( "CreateEvent", GetLastError());
371 NULL ); // name 371 ref->waitersCount = 0;
372 }
372 373
373 if (h == NULL) FAIL( "CreateEvent", GetLastError() ); 374 void SIGNAL_FREE( SIGNAL_T* ref)
374 *ref= h; 375 {
375 } 376 CloseHandle( ref->waitDoneEvent);
376 void SIGNAL_FREE( SIGNAL_T *ref ) { 377 CloseHandle( ref->waitEvent);
377 if (!CloseHandle(*ref)) FAIL( "CloseHandle (event)", GetLastError() ); 378 DeleteCriticalSection( &ref->countCS);
378 *ref= NULL; 379 DeleteCriticalSection( &ref->signalCS);
379 } 380 }
380 //
381 bool_t SIGNAL_WAIT( SIGNAL_T *ref, MUTEX_T *mu_ref, time_d abs_secs ) {
382 DWORD rc;
383 long ms;
384
385 if (abs_secs<0.0)
386 ms= INFINITE;
387 else if (abs_secs==0.0)
388 ms= 0;
389 else {
390 ms= (long) ((abs_secs - now_secs())*1000.0 + 0.5);
391
392 // If the time already passed, still try once (ms==0). A short timeout
393 // may have turned negative or 0 because of the two time samples done.
394 //
395 if (ms<0) ms= 0;
396 }
397 381
398 // Unlock and start a wait, atomically (like condition variables do) 382 bool_t SIGNAL_WAIT( SIGNAL_T* ref, MUTEX_T* mu_ref, time_d abs_secs)
399 // 383 {
400 rc= SignalObjectAndWait( *mu_ref, // "object to signal" (unlock) 384 DWORD errc;
401 *ref, // "object to wait on" 385 DWORD ms;
402 ms,
403 FALSE ); // not alertable
404 386
405 // All waiting locks are woken here; each competes for the lock in turn. 387 if( abs_secs < 0.0)
406 // 388 ms = INFINITE;
407 // Note: We must get the lock even if we've timed out; it makes upper 389 else if( abs_secs == 0.0)
408 // level code equivalent to how PThread does it. 390 ms = 0;
409 // 391 else
410 MUTEX_LOCK(mu_ref); 392 {
393 time_d msd = (abs_secs - now_secs()) * 1000.0 + 0.5;
394 // If the time already passed, still try once (ms==0). A short timeout
395 // may have turned negative or 0 because of the two time samples done.
396 ms = msd <= 0.0 ? 0 : (DWORD)msd;
397 }
411 398
412 if (rc==WAIT_TIMEOUT) return FALSE; 399 EnterCriticalSection( &ref->signalCS);
413 if (rc!=0) FAIL( "SignalObjectAndWait", rc ); 400 EnterCriticalSection( &ref->countCS);
414 return TRUE; 401 ++ ref->waitersCount;
415 } 402 LeaveCriticalSection( &ref->countCS);
416 void SIGNAL_ALL( SIGNAL_T *ref ) { 403 LeaveCriticalSection( &ref->signalCS);
417/* 404
418 * MSDN tries to scare that 'PulseEvent' is bad, unreliable and should not be 405 errc = SignalObjectAndWait( *mu_ref, ref->waitEvent, ms, FALSE);
419 * used. Use condition variables instead (wow, they have that!?!); which will 406
420 * ONLY WORK on Vista and 2008 Server, it seems... so MS, isn't it. 407 EnterCriticalSection( &ref->countCS);
421 * 408 if( 0 == -- ref->waitersCount)
422 * I refuse to believe that; using 'PulseEvent' is probably just as good as 409 {
423 * using Windows (XP) in the first place. Just don't use APC's (asynchronous 410 // we're the last one leaving...
424 * process calls) in your C side coding. 411 ResetEvent( ref->waitEvent);
425 */ 412 SetEvent( ref->waitDoneEvent);
426 // PulseEvent on manual event: 413 }
427 // 414 LeaveCriticalSection( &ref->countCS);
428 // Release ALL threads waiting for it (and go instantly back to unsignalled 415 MUTEX_LOCK( mu_ref);
429 // status = future threads to start a wait will wait) 416
430 // 417 switch( errc)
431 if (!PulseEvent( *ref )) 418 {
432 FAIL( "PulseEvent", GetLastError() ); 419 case WAIT_TIMEOUT:
433 } 420 return FALSE;
421 case WAIT_OBJECT_0:
422 return TRUE;
423 }
424
425 FAIL( "SignalObjectAndWait", GetLastError());
426 return FALSE;
427 }
428
429 void SIGNAL_ALL( SIGNAL_T* ref)
430 {
431 DWORD errc = WAIT_OBJECT_0;
432
433 EnterCriticalSection( &ref->signalCS);
434 EnterCriticalSection( &ref->countCS);
435
436 if( ref->waitersCount > 0)
437 {
438 ResetEvent( ref->waitDoneEvent);
439 SetEvent( ref->waitEvent);
440 LeaveCriticalSection( &ref->countCS);
441 errc = WaitForSingleObject( ref->waitDoneEvent, INFINITE);
442 }
443 else
444 {
445 LeaveCriticalSection( &ref->countCS);
446 }
447
448 LeaveCriticalSection( &ref->signalCS);
449
450 if( WAIT_OBJECT_0 != errc)
451 FAIL( "WaitForSingleObject", GetLastError());
452 }
434 453
435#else // Windows Vista and above: condition variables exist, use them 454#else // Windows Vista and above: condition variables exist, use them
436 455
diff --git a/src/threading.h b/src/threading.h
index e559910..7d94f26 100644
--- a/src/threading.h
+++ b/src/threading.h
@@ -64,7 +64,7 @@ enum e_status { PENDING, RUNNING, WAITING, DONE, ERROR_ST, CANCELLED };
64 #else // !PLATFORM_XBOX 64 #else // !PLATFORM_XBOX
65 #define WIN32_LEAN_AND_MEAN 65 #define WIN32_LEAN_AND_MEAN
66 // 'SignalObjectAndWait' needs this (targets Windows 2000 and above) 66 // 'SignalObjectAndWait' needs this (targets Windows 2000 and above)
67 //#define _WIN32_WINNT 0x0500 Let the compiler decide depending on the host OS 67 #define _WIN32_WINNT 0x0400
68 #include <windows.h> 68 #include <windows.h>
69 #endif // !PLATFORM_XBOX 69 #endif // !PLATFORM_XBOX
70 #include <process.h> 70 #include <process.h>
@@ -76,8 +76,16 @@ enum e_status { PENDING, RUNNING, WAITING, DONE, ERROR_ST, CANCELLED };
76 // 76 //
77 77
78 #if WINVER <= 0x0400 // Windows NT4: use a signal 78 #if WINVER <= 0x0400 // Windows NT4: use a signal
79 typedef struct
80 {
81 CRITICAL_SECTION signalCS;
82 CRITICAL_SECTION countCS;
83 HANDLE waitEvent;
84 HANDLE waitDoneEvent;
85 LONG waitersCount;
86 } SIGNAL_T;
87
79 88
80 #define SIGNAL_T HANDLE
81 #define MUTEX_T HANDLE 89 #define MUTEX_T HANDLE
82 void MUTEX_INIT( MUTEX_T* ref); 90 void MUTEX_INIT( MUTEX_T* ref);
83 void MUTEX_FREE( MUTEX_T* ref); 91 void MUTEX_FREE( MUTEX_T* ref);