diff options
author | Benoit 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 |
---|---|---|
committer | Benoit 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 |
commit | a2dc01d60e8b0fc32b98fe885068720492de1406 (patch) | |
tree | efcec39656a9c9b3162e2881f38eb71d91df0302 /src | |
parent | d9cab463ac5d9539092fde03b22905f76f06844b (diff) | |
download | lanes-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.c | 155 | ||||
-rw-r--r-- | src/threading.h | 12 |
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); |