Merge 48de2a9598fce0a1eda826a2099dac7bfcf6b7a2 into 7958b3048fa1e85ab5a71f18a07c24e1b1e64f1e

This commit is contained in:
Raymond Zhao 2024-07-22 15:43:54 -07:00 committed by GitHub
commit 5771b7bd5b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 48 additions and 47 deletions

View File

@ -6,7 +6,7 @@ include(CMakeParseArguments)
link_libraries(ws2_32)
if(MSVC)
add_compile_options(/Wall /WX /wd4127 /wd4201 /wd4242 /wd4710 /wd4711 /wd4820)
add_compile_options(/Wall /WX /wd4127 /wd4191 /wd4201 /wd4242 /wd4710 /wd4711 /wd4820)
if(MSVC_VERSION GREATER_EQUAL 1900)
add_compile_options(/wd5045)
endif()

View File

@ -63,11 +63,6 @@ typedef struct _OBJECT_ATTRIBUTES {
#define FILE_OPEN 0x00000001UL
#endif
#define KEYEDEVENT_WAIT 0x00000001UL
#define KEYEDEVENT_WAKE 0x00000002UL
#define KEYEDEVENT_ALL_ACCESS \
(STANDARD_RIGHTS_REQUIRED | KEYEDEVENT_WAIT | KEYEDEVENT_WAKE)
#define NT_NTDLL_IMPORT_LIST(X) \
X(NTSTATUS, \
NTAPI, \
@ -91,14 +86,6 @@ typedef struct _OBJECT_ATTRIBUTES {
PVOID EaBuffer, \
ULONG EaLength)) \
\
X(NTSTATUS, \
NTAPI, \
NtCreateKeyedEvent, \
(PHANDLE KeyedEventHandle, \
ACCESS_MASK DesiredAccess, \
POBJECT_ATTRIBUTES ObjectAttributes, \
ULONG Flags)) \
\
X(NTSTATUS, \
NTAPI, \
NtDeviceIoControlFile, \
@ -113,22 +100,6 @@ typedef struct _OBJECT_ATTRIBUTES {
PVOID OutputBuffer, \
ULONG OutputBufferLength)) \
\
X(NTSTATUS, \
NTAPI, \
NtReleaseKeyedEvent, \
(HANDLE KeyedEventHandle, \
PVOID KeyValue, \
BOOLEAN Alertable, \
PLARGE_INTEGER Timeout)) \
\
X(NTSTATUS, \
NTAPI, \
NtWaitForKeyedEvent, \
(HANDLE KeyedEventHandle, \
PVOID KeyValue, \
BOOLEAN Alertable, \
PLARGE_INTEGER Timeout)) \
\
X(ULONG, WINAPI, RtlNtStatusToDosError, (NTSTATUS Status))
#define X(return_type, attributes, name, parameters) \

View File

@ -11,36 +11,61 @@
#define REFLOCK__REF ((long) 0x00000001UL)
#define REFLOCK__REF_MASK ((long) 0x0fffffffUL)
#define REFLOCK__DESTROY ((long) 0x10000000UL)
#define REFLOCK__DESTROY_MASK ((long) 0xf0000000UL)
#define REFLOCK__POISON ((long) 0x300dead0UL)
#define REFLOCK__DESTROY_MASK ((long) 0x10000000UL)
#define REFLOCK__SIGNAL ((long) 0x20000000UL)
#define REFLOCK__SIGNAL_MASK ((long) 0x20000000UL)
#define REFLOCK__AWAIT ((long) 0x40000000UL)
#define REFLOCK__AWAIT_MASK ((long) 0x40000000UL)
#define REFLOCK__POISON ((long) 0x800dead0UL)
/* clang-format on */
static HANDLE reflock__keyed_event = NULL;
static CRITICAL_SECTION signalMutex;
int reflock_global_init(void) {
NTSTATUS status = NtCreateKeyedEvent(
&reflock__keyed_event, KEYEDEVENT_ALL_ACCESS, NULL, 0);
if (status != STATUS_SUCCESS)
return_set_error(-1, RtlNtStatusToDosError(status));
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(void* address) {
NTSTATUS status =
NtReleaseKeyedEvent(reflock__keyed_event, address, FALSE, NULL);
if (status != STATUS_SUCCESS)
static void reflock__signal_event(reflock_t* reflock) {
BOOL status = TRUE;
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(void* address) {
NTSTATUS status =
NtWaitForKeyedEvent(reflock__keyed_event, address, FALSE, NULL);
if (status != STATUS_SUCCESS)
static void reflock__await_event(reflock_t* reflock) {
BOOL status = TRUE;
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) {
@ -57,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);
}
@ -73,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);
}

View File

@ -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,6 +24,8 @@
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);