daedalus/Source/SysW32/Utility/CondW32.cpp
2023-12-07 22:56:38 +08:00

100 lines
2.1 KiB
C++

#include "windows.h"
#include "Base/Types.h"
#include "System/Condition.h"
#include "System/Mutex.h"
const double kTimeoutInfinity = 0.f;
// Cond wrapper derived from GLFW 2.7, see http://www.glfw.org/.
enum
{
COND_SIGNAL = 0,
COND_BROADCAST = 1
};
struct _cond
{
HANDLE events[ 2 ];
u32 waiters_count;
CRITICAL_SECTION waiters_count_lock;
};
Cond * CondCreate()
{
_cond *cond;
cond = (_cond *) malloc( sizeof(_cond) );
if( !cond )
{
return NULL;
}
cond->waiters_count = 0;
cond->events[ COND_SIGNAL ] = CreateEvent( NULL, false, false, NULL );
cond->events[ COND_BROADCAST ] = CreateEvent( NULL, true, false, NULL );
InitializeCriticalSection( &cond->waiters_count_lock );
return (Cond*)cond;
}
void CondDestroy(Cond * cond)
{
CloseHandle( ((_cond *)cond)->events[ COND_SIGNAL ] );
CloseHandle( ((_cond *)cond)->events[ COND_BROADCAST ] );
DeleteCriticalSection( &((_cond*)cond)->waiters_count_lock );
free( (void *)cond );
}
void CondWait(Cond * cond, Mutex * mutex, double timeout)
{
_cond *cv = (_cond *)cond;
s32 result, last_waiter;
u32 ms;
EnterCriticalSection( &cv->waiters_count_lock );
cv->waiters_count ++;
LeaveCriticalSection( &cv->waiters_count_lock );
mutex->Unlock();
if (timeout <= 0)
{
ms = INFINITE;
}
else
{
ms = (u32) (1000.0 * timeout + 0.5);
ms = ( ms <= 0 ) ? 1 : ms;
}
result = WaitForMultipleObjects( 2, cv->events, false, ms );
EnterCriticalSection( &cv->waiters_count_lock );
cv->waiters_count--;
last_waiter = (result == WAIT_OBJECT_0 + COND_BROADCAST) &&(cv->waiters_count == 0);
LeaveCriticalSection( &cv->waiters_count_lock );
if( last_waiter )
{
ResetEvent( cv->events[ COND_BROADCAST ] );
}
mutex->Lock();
}
void CondSignal(Cond * cond)
{
_cond *cv = (_cond*)cond;
s32 have_waiters;
// Avoid race conditions
EnterCriticalSection( &cv->waiters_count_lock );
have_waiters = cv->waiters_count > 0;
LeaveCriticalSection( &cv->waiters_count_lock );
if( have_waiters )
{
SetEvent( cv->events[ COND_SIGNAL ] );
}
}