diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 01:24:41 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 01:24:41 +0000 |
commit | a9bcc81f821d7c66f623779fa5147e728eb3c388 (patch) | |
tree | 98676963bcdd537ae5908a067a8eb110b93486a6 /winpr/libwinpr/synch/test/TestSynchInit.c | |
parent | Initial commit. (diff) | |
download | freerdp3-a9bcc81f821d7c66f623779fa5147e728eb3c388.tar.xz freerdp3-a9bcc81f821d7c66f623779fa5147e728eb3c388.zip |
Adding upstream version 3.3.0+dfsg1.upstream/3.3.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'winpr/libwinpr/synch/test/TestSynchInit.c')
-rw-r--r-- | winpr/libwinpr/synch/test/TestSynchInit.c | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/winpr/libwinpr/synch/test/TestSynchInit.c b/winpr/libwinpr/synch/test/TestSynchInit.c new file mode 100644 index 0000000..20da415 --- /dev/null +++ b/winpr/libwinpr/synch/test/TestSynchInit.c @@ -0,0 +1,156 @@ +#include <stdio.h> +#include <winpr/crt.h> +#include <winpr/synch.h> +#include <winpr/thread.h> +#include <winpr/interlocked.h> + +#define TEST_NUM_THREADS 100 +#define TEST_NUM_FAILURES 10 + +static INIT_ONCE initOnceTest = INIT_ONCE_STATIC_INIT; + +static HANDLE hStartEvent = NULL; +static LONG* pErrors = NULL; +static LONG* pTestThreadFunctionCalls = NULL; +static LONG* pTestOnceFunctionCalls = NULL; +static LONG* pInitOnceExecuteOnceCalls = NULL; + +static BOOL CALLBACK TestOnceFunction(PINIT_ONCE once, PVOID param, PVOID* context) +{ + LONG calls = InterlockedIncrement(pTestOnceFunctionCalls) - 1; + + WINPR_UNUSED(once); + WINPR_UNUSED(param); + WINPR_UNUSED(context); + + /* simulate execution time */ + Sleep(30 + rand() % 40); + + if (calls < TEST_NUM_FAILURES) + { + /* simulated error */ + return FALSE; + } + if (calls == TEST_NUM_FAILURES) + { + return TRUE; + } + fprintf(stderr, "%s: error: called again after success\n", __func__); + InterlockedIncrement(pErrors); + return FALSE; +} + +static DWORD WINAPI TestThreadFunction(LPVOID lpParam) +{ + LONG calls = 0; + BOOL ok = 0; + + WINPR_UNUSED(lpParam); + + InterlockedIncrement(pTestThreadFunctionCalls); + if (WaitForSingleObject(hStartEvent, INFINITE) != WAIT_OBJECT_0) + { + fprintf(stderr, "%s: error: failed to wait for start event\n", __func__); + InterlockedIncrement(pErrors); + return 0; + } + + ok = InitOnceExecuteOnce(&initOnceTest, TestOnceFunction, NULL, NULL); + calls = InterlockedIncrement(pInitOnceExecuteOnceCalls); + if (!ok && calls > TEST_NUM_FAILURES) + { + fprintf(stderr, "%s: InitOnceExecuteOnce failed unexpectedly\n", __func__); + InterlockedIncrement(pErrors); + } + return 0; +} + +int TestSynchInit(int argc, char* argv[]) +{ + HANDLE hThreads[TEST_NUM_THREADS]; + DWORD dwCreatedThreads = 0; + BOOL result = FALSE; + + WINPR_UNUSED(argc); + WINPR_UNUSED(argv); + + pErrors = winpr_aligned_malloc(sizeof(LONG), sizeof(LONG)); + pTestThreadFunctionCalls = winpr_aligned_malloc(sizeof(LONG), sizeof(LONG)); + pTestOnceFunctionCalls = winpr_aligned_malloc(sizeof(LONG), sizeof(LONG)); + pInitOnceExecuteOnceCalls = winpr_aligned_malloc(sizeof(LONG), sizeof(LONG)); + + if (!pErrors || !pTestThreadFunctionCalls || !pTestOnceFunctionCalls || + !pInitOnceExecuteOnceCalls) + { + fprintf(stderr, "error: _aligned_malloc failed\n"); + goto out; + } + + *pErrors = 0; + *pTestThreadFunctionCalls = 0; + *pTestOnceFunctionCalls = 0; + *pInitOnceExecuteOnceCalls = 0; + + if (!(hStartEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) + { + fprintf(stderr, "error creating start event\n"); + InterlockedIncrement(pErrors); + goto out; + } + + for (DWORD i = 0; i < TEST_NUM_THREADS; i++) + { + if (!(hThreads[i] = CreateThread(NULL, 0, TestThreadFunction, NULL, 0, NULL))) + { + fprintf(stderr, "error creating thread #%" PRIu32 "\n", i); + InterlockedIncrement(pErrors); + goto out; + } + dwCreatedThreads++; + } + + Sleep(100); + SetEvent(hStartEvent); + + for (DWORD i = 0; i < dwCreatedThreads; i++) + { + if (WaitForSingleObject(hThreads[i], INFINITE) != WAIT_OBJECT_0) + { + fprintf(stderr, "error: error waiting for thread #%" PRIu32 "\n", i); + InterlockedIncrement(pErrors); + goto out; + } + } + + if (*pErrors == 0 && *pTestThreadFunctionCalls == TEST_NUM_THREADS && + *pInitOnceExecuteOnceCalls == TEST_NUM_THREADS && + *pTestOnceFunctionCalls == TEST_NUM_FAILURES + 1) + { + result = TRUE; + } + +out: + fprintf(stderr, "Test result: %s\n", result ? "OK" : "ERROR"); + fprintf(stderr, "Error count: %" PRId32 "\n", pErrors ? *pErrors : -1); + fprintf(stderr, "Threads created: %" PRIu32 "\n", dwCreatedThreads); + fprintf(stderr, "TestThreadFunctionCalls: %" PRId32 "\n", + pTestThreadFunctionCalls ? *pTestThreadFunctionCalls : -1); + fprintf(stderr, "InitOnceExecuteOnceCalls: %" PRId32 "\n", + pInitOnceExecuteOnceCalls ? *pInitOnceExecuteOnceCalls : -1); + fprintf(stderr, "TestOnceFunctionCalls: %" PRId32 "\n", + pTestOnceFunctionCalls ? *pTestOnceFunctionCalls : -1); + + winpr_aligned_free(pErrors); + winpr_aligned_free(pTestThreadFunctionCalls); + winpr_aligned_free(pTestOnceFunctionCalls); + winpr_aligned_free(pInitOnceExecuteOnceCalls); + + CloseHandle(hStartEvent); + + for (DWORD i = 0; i < dwCreatedThreads; i++) + { + CloseHandle(hThreads[i]); + } + + return (result ? 0 : 1); +} |