mirror of
https://github.com/decompals/wibo.git
synced 2025-12-11 22:43:58 +00:00
199 lines
5.4 KiB
C
199 lines
5.4 KiB
C
#include "test_assert.h"
|
|
#include <windows.h>
|
|
|
|
typedef struct {
|
|
SRWLOCK *lock;
|
|
HANDLE acquired;
|
|
HANDLE release;
|
|
HANDLE done;
|
|
} SharedHoldContext;
|
|
|
|
static DWORD WINAPI shared_hold_worker(LPVOID param) {
|
|
SharedHoldContext *ctx = (SharedHoldContext *)param;
|
|
AcquireSRWLockShared(ctx->lock);
|
|
TEST_CHECK(SetEvent(ctx->acquired));
|
|
|
|
DWORD wait = WaitForSingleObject(ctx->release, 2000);
|
|
TEST_CHECK_EQ(WAIT_OBJECT_0, wait);
|
|
|
|
ReleaseSRWLockShared(ctx->lock);
|
|
TEST_CHECK(SetEvent(ctx->done));
|
|
return 0;
|
|
}
|
|
|
|
typedef struct {
|
|
SRWLOCK *lock;
|
|
HANDLE acquired;
|
|
HANDLE done;
|
|
} SharedAcquireContext;
|
|
|
|
static DWORD WINAPI shared_acquire_worker(LPVOID param) {
|
|
SharedAcquireContext *ctx = (SharedAcquireContext *)param;
|
|
AcquireSRWLockShared(ctx->lock);
|
|
TEST_CHECK(SetEvent(ctx->acquired));
|
|
ReleaseSRWLockShared(ctx->lock);
|
|
TEST_CHECK(SetEvent(ctx->done));
|
|
return 0;
|
|
}
|
|
|
|
typedef struct {
|
|
SRWLOCK *lock;
|
|
HANDLE acquired;
|
|
HANDLE release;
|
|
HANDLE done;
|
|
} ExclusiveHoldContext;
|
|
|
|
static DWORD WINAPI exclusive_hold_worker(LPVOID param) {
|
|
ExclusiveHoldContext *ctx = (ExclusiveHoldContext *)param;
|
|
AcquireSRWLockExclusive(ctx->lock);
|
|
TEST_CHECK(SetEvent(ctx->acquired));
|
|
|
|
DWORD wait = WaitForSingleObject(ctx->release, 2000);
|
|
TEST_CHECK_EQ(WAIT_OBJECT_0, wait);
|
|
|
|
ReleaseSRWLockExclusive(ctx->lock);
|
|
TEST_CHECK(SetEvent(ctx->done));
|
|
return 0;
|
|
}
|
|
|
|
static void close_pair(HANDLE a, HANDLE b) {
|
|
if (a) {
|
|
TEST_CHECK(CloseHandle(a));
|
|
}
|
|
if (b) {
|
|
TEST_CHECK(CloseHandle(b));
|
|
}
|
|
}
|
|
|
|
static void test_shared_readers(void) {
|
|
SRWLOCK lock = SRWLOCK_INIT;
|
|
|
|
HANDLE ready1 = CreateEventA(NULL, FALSE, FALSE, NULL);
|
|
HANDLE release1 = CreateEventA(NULL, FALSE, FALSE, NULL);
|
|
HANDLE done1 = CreateEventA(NULL, FALSE, FALSE, NULL);
|
|
HANDLE ready2 = CreateEventA(NULL, FALSE, FALSE, NULL);
|
|
HANDLE release2 = CreateEventA(NULL, FALSE, FALSE, NULL);
|
|
HANDLE done2 = CreateEventA(NULL, FALSE, FALSE, NULL);
|
|
TEST_CHECK(ready1 && release1 && done1 && ready2 && release2 && done2);
|
|
|
|
SharedHoldContext ctx1 = {&lock, ready1, release1, done1};
|
|
SharedHoldContext ctx2 = {&lock, ready2, release2, done2};
|
|
|
|
HANDLE t1 = CreateThread(NULL, 0, shared_hold_worker, &ctx1, 0, NULL);
|
|
HANDLE t2 = CreateThread(NULL, 0, shared_hold_worker, &ctx2, 0, NULL);
|
|
TEST_CHECK(t1 && t2);
|
|
|
|
DWORD wait = WaitForSingleObject(ready1, 2000);
|
|
TEST_CHECK_EQ(WAIT_OBJECT_0, wait);
|
|
wait = WaitForSingleObject(ready2, 2000);
|
|
TEST_CHECK_EQ(WAIT_OBJECT_0, wait);
|
|
|
|
// Main thread should also be able to take a shared lock while others hold it.
|
|
AcquireSRWLockShared(&lock);
|
|
ReleaseSRWLockShared(&lock);
|
|
|
|
TEST_CHECK(SetEvent(release1));
|
|
TEST_CHECK(SetEvent(release2));
|
|
|
|
wait = WaitForSingleObject(done1, 2000);
|
|
TEST_CHECK_EQ(WAIT_OBJECT_0, wait);
|
|
wait = WaitForSingleObject(done2, 2000);
|
|
TEST_CHECK_EQ(WAIT_OBJECT_0, wait);
|
|
|
|
wait = WaitForSingleObject(t1, 2000);
|
|
TEST_CHECK_EQ(WAIT_OBJECT_0, wait);
|
|
wait = WaitForSingleObject(t2, 2000);
|
|
TEST_CHECK_EQ(WAIT_OBJECT_0, wait);
|
|
|
|
TEST_CHECK(CloseHandle(t1));
|
|
TEST_CHECK(CloseHandle(t2));
|
|
close_pair(ready1, release1);
|
|
close_pair(done1, ready2);
|
|
close_pair(release2, done2);
|
|
}
|
|
|
|
static void test_exclusive_blocks_shared(void) {
|
|
SRWLOCK lock = SRWLOCK_INIT;
|
|
AcquireSRWLockExclusive(&lock);
|
|
|
|
HANDLE acquired = CreateEventA(NULL, FALSE, FALSE, NULL);
|
|
HANDLE done = CreateEventA(NULL, FALSE, FALSE, NULL);
|
|
TEST_CHECK(acquired && done);
|
|
|
|
SharedAcquireContext ctx = {&lock, acquired, done};
|
|
HANDLE thread = CreateThread(NULL, 0, shared_acquire_worker, &ctx, 0, NULL);
|
|
TEST_CHECK(thread != NULL);
|
|
|
|
DWORD wait = WaitForSingleObject(acquired, 100);
|
|
TEST_CHECK_EQ(WAIT_TIMEOUT, wait);
|
|
|
|
ReleaseSRWLockExclusive(&lock);
|
|
|
|
wait = WaitForSingleObject(acquired, 2000);
|
|
TEST_CHECK_EQ(WAIT_OBJECT_0, wait);
|
|
wait = WaitForSingleObject(done, 2000);
|
|
TEST_CHECK_EQ(WAIT_OBJECT_0, wait);
|
|
wait = WaitForSingleObject(thread, 2000);
|
|
TEST_CHECK_EQ(WAIT_OBJECT_0, wait);
|
|
|
|
TEST_CHECK(CloseHandle(thread));
|
|
close_pair(acquired, done);
|
|
}
|
|
|
|
static void test_shared_then_exclusive(void) {
|
|
SRWLOCK lock = SRWLOCK_INIT;
|
|
AcquireSRWLockShared(&lock);
|
|
|
|
HANDLE acquired = CreateEventA(NULL, FALSE, FALSE, NULL);
|
|
HANDLE release = CreateEventA(NULL, FALSE, FALSE, NULL);
|
|
HANDLE done = CreateEventA(NULL, FALSE, FALSE, NULL);
|
|
TEST_CHECK(acquired && release && done);
|
|
|
|
ExclusiveHoldContext ctx = {&lock, acquired, release, done};
|
|
HANDLE thread = CreateThread(NULL, 0, exclusive_hold_worker, &ctx, 0, NULL);
|
|
TEST_CHECK(thread != NULL);
|
|
|
|
DWORD wait = WaitForSingleObject(acquired, 100);
|
|
TEST_CHECK_EQ(WAIT_TIMEOUT, wait);
|
|
|
|
ReleaseSRWLockShared(&lock);
|
|
|
|
wait = WaitForSingleObject(acquired, 2000);
|
|
TEST_CHECK_EQ(WAIT_OBJECT_0, wait);
|
|
|
|
TEST_CHECK(SetEvent(release));
|
|
|
|
wait = WaitForSingleObject(done, 2000);
|
|
TEST_CHECK_EQ(WAIT_OBJECT_0, wait);
|
|
wait = WaitForSingleObject(thread, 2000);
|
|
TEST_CHECK_EQ(WAIT_OBJECT_0, wait);
|
|
|
|
TEST_CHECK(CloseHandle(thread));
|
|
close_pair(acquired, release);
|
|
TEST_CHECK(CloseHandle(done));
|
|
}
|
|
|
|
static void test_try_acquire(void) {
|
|
SRWLOCK lock = SRWLOCK_INIT;
|
|
|
|
TEST_CHECK(TryAcquireSRWLockShared(&lock) != 0);
|
|
ReleaseSRWLockShared(&lock);
|
|
|
|
TEST_CHECK(TryAcquireSRWLockExclusive(&lock) != 0);
|
|
TEST_CHECK(TryAcquireSRWLockShared(&lock) == 0);
|
|
TEST_CHECK(TryAcquireSRWLockExclusive(&lock) == 0);
|
|
ReleaseSRWLockExclusive(&lock);
|
|
|
|
AcquireSRWLockShared(&lock);
|
|
TEST_CHECK(TryAcquireSRWLockExclusive(&lock) == 0);
|
|
ReleaseSRWLockShared(&lock);
|
|
}
|
|
|
|
int main(void) {
|
|
test_shared_readers();
|
|
test_exclusive_blocks_shared();
|
|
test_shared_then_exclusive();
|
|
test_try_acquire();
|
|
return 0;
|
|
}
|