Switch to condition variables
This commit is contained in:
parent
c265e8625b
commit
48de2a9598
@ -4,7 +4,6 @@ project(wepoll)
|
||||
include(CMakeParseArguments)
|
||||
|
||||
link_libraries(ws2_32)
|
||||
link_libraries(synchronization)
|
||||
|
||||
if(MSVC)
|
||||
add_compile_options(/Wall /WX /wd4127 /wd4191 /wd4201 /wd4242 /wd4710 /wd4711 /wd4820)
|
||||
|
||||
@ -21,7 +21,7 @@ static BOOL CALLBACK init__once_callback(INIT_ONCE* once,
|
||||
|
||||
/* N.b. that initialization order matters here. */
|
||||
if (ws_global_init() < 0 || nt_global_init() < 0 ||
|
||||
epoll_global_init() < 0)
|
||||
reflock_global_init() < 0 || epoll_global_init() < 0)
|
||||
return FALSE;
|
||||
|
||||
init__done = true;
|
||||
|
||||
@ -14,31 +14,58 @@
|
||||
#define REFLOCK__DESTROY_MASK ((long) 0x10000000UL)
|
||||
#define REFLOCK__SIGNAL ((long) 0x20000000UL)
|
||||
#define REFLOCK__SIGNAL_MASK ((long) 0x20000000UL)
|
||||
#define REFLOCK__POISON ((long) 0x300dead0UL)
|
||||
#define REFLOCK__AWAIT ((long) 0x40000000UL)
|
||||
#define REFLOCK__AWAIT_MASK ((long) 0x40000000UL)
|
||||
#define REFLOCK__POISON ((long) 0x800dead0UL)
|
||||
/* clang-format on */
|
||||
|
||||
static CRITICAL_SECTION signalMutex;
|
||||
|
||||
int reflock_global_init(void) {
|
||||
InitializeCriticalSection(&signalMutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void reflock_init(reflock_t* reflock) {
|
||||
reflock->state = 0;
|
||||
InitializeConditionVariable(&reflock->cv_signal);
|
||||
InitializeConditionVariable(&reflock->cv_await);
|
||||
}
|
||||
|
||||
static void reflock__signal_event(reflock_t* reflock) {
|
||||
long state = InterlockedAdd(&reflock->state, REFLOCK__SIGNAL);
|
||||
unused_var(state);
|
||||
BOOL status = TRUE;
|
||||
|
||||
WakeByAddressSingle(reflock);
|
||||
EnterCriticalSection(&signalMutex);
|
||||
long state = InterlockedOr(&reflock->state, REFLOCK__SIGNAL);
|
||||
while ((reflock->state & REFLOCK__AWAIT_MASK) == 0) {
|
||||
status = SleepConditionVariableCS(&reflock->cv_signal, &signalMutex, INFINITE);
|
||||
}
|
||||
LeaveCriticalSection(&signalMutex);
|
||||
|
||||
if (status != TRUE)
|
||||
abort();
|
||||
|
||||
/* At most one reflock__await_event call per reflock. */
|
||||
WakeConditionVariable(&reflock->cv_await);
|
||||
unused_var(state);
|
||||
}
|
||||
|
||||
static void reflock__await_event(reflock_t* reflock) {
|
||||
BOOL status = TRUE;
|
||||
do {
|
||||
status = WaitOnAddress(reflock, reflock, sizeof(reflock_t*), INFINITE);
|
||||
} while ((reflock->state & REFLOCK__SIGNAL_MASK) == 0);
|
||||
|
||||
long state = InterlockedAdd(&reflock->state, -REFLOCK__SIGNAL);
|
||||
unused_var(state);
|
||||
EnterCriticalSection(&signalMutex);
|
||||
long state = InterlockedOr(&reflock->state, REFLOCK__AWAIT);
|
||||
while ((reflock->state & REFLOCK__SIGNAL_MASK) == 0) {
|
||||
status = SleepConditionVariableCS(&reflock->cv_await, &signalMutex, INFINITE);
|
||||
}
|
||||
LeaveCriticalSection(&signalMutex);
|
||||
|
||||
if (status != TRUE)
|
||||
abort();
|
||||
|
||||
/* Multiple threads could be waiting. */
|
||||
WakeAllConditionVariable(&reflock->cv_signal);
|
||||
unused_var(state);
|
||||
}
|
||||
|
||||
void reflock_ref(reflock_t* reflock) {
|
||||
@ -55,7 +82,8 @@ void reflock_unref(reflock_t* reflock) {
|
||||
/* Verify that the lock was referenced and not already destroyed. */
|
||||
assert((state & REFLOCK__DESTROY_MASK & ~REFLOCK__DESTROY) == 0);
|
||||
|
||||
if (state == REFLOCK__DESTROY)
|
||||
if ((state & REFLOCK__DESTROY_MASK) == REFLOCK__DESTROY &&
|
||||
(state & REFLOCK__REF_MASK) == 0)
|
||||
reflock__signal_event(reflock);
|
||||
}
|
||||
|
||||
@ -71,5 +99,6 @@ void reflock_unref_and_destroy(reflock_t* reflock) {
|
||||
reflock__await_event(reflock);
|
||||
|
||||
state = InterlockedExchange(&reflock->state, REFLOCK__POISON);
|
||||
assert(state == REFLOCK__DESTROY);
|
||||
assert((state & REFLOCK__DESTROY_MASK) == REFLOCK__DESTROY);
|
||||
assert((state & REFLOCK__REF_MASK) == 0);
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
#define WEPOLL_REFLOCK_H_
|
||||
|
||||
#include "config.h"
|
||||
#include "win.h"
|
||||
|
||||
/* A reflock is a special kind of lock that normally prevents a chunk of
|
||||
* memory from being freed, but does allow the chunk of memory to eventually be
|
||||
@ -23,8 +24,12 @@
|
||||
|
||||
typedef struct reflock {
|
||||
volatile long state; /* 32-bit Interlocked APIs operate on `long` values. */
|
||||
CONDITION_VARIABLE cv_signal;
|
||||
CONDITION_VARIABLE cv_await;
|
||||
} reflock_t;
|
||||
|
||||
WEPOLL_INTERNAL int reflock_global_init(void);
|
||||
|
||||
WEPOLL_INTERNAL void reflock_init(reflock_t* reflock);
|
||||
WEPOLL_INTERNAL void reflock_ref(reflock_t* reflock);
|
||||
WEPOLL_INTERNAL void reflock_unref(reflock_t* reflock);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user