Merge 48de2a9598fce0a1eda826a2099dac7bfcf6b7a2 into 7958b3048fa1e85ab5a71f18a07c24e1b1e64f1e
This commit is contained in:
commit
5771b7bd5b
@ -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()
|
||||
|
||||
29
src/nt.h
29
src/nt.h
@ -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) \
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user