diff options
Diffstat (limited to 'winpr/libwinpr/synch/test/TestSynchBarrier.c')
-rw-r--r-- | winpr/libwinpr/synch/test/TestSynchBarrier.c | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/winpr/libwinpr/synch/test/TestSynchBarrier.c b/winpr/libwinpr/synch/test/TestSynchBarrier.c new file mode 100644 index 0000000..b1c91c9 --- /dev/null +++ b/winpr/libwinpr/synch/test/TestSynchBarrier.c @@ -0,0 +1,257 @@ + +#include <winpr/crt.h> +#include <winpr/synch.h> +#include <winpr/thread.h> +#include <winpr/interlocked.h> +#include <winpr/sysinfo.h> + +#include "../synch.h" + +static SYNCHRONIZATION_BARRIER gBarrier; +static HANDLE gStartEvent = NULL; +static LONG gErrorCount = 0; + +#define MAX_SLEEP_MS 22 + +struct test_params +{ + LONG threadCount; + LONG trueCount; + LONG falseCount; + DWORD loops; + DWORD flags; +}; + +static DWORD WINAPI test_synch_barrier_thread(LPVOID lpParam) +{ + BOOL status = FALSE; + struct test_params* p = (struct test_params*)lpParam; + + InterlockedIncrement(&p->threadCount); + + // printf("Thread #%03u entered.\n", tnum); + + /* wait for start event from main */ + if (WaitForSingleObject(gStartEvent, INFINITE) != WAIT_OBJECT_0) + { + InterlockedIncrement(&gErrorCount); + goto out; + } + + // printf("Thread #%03u unblocked.\n", tnum); + + for (DWORD i = 0; i < p->loops && gErrorCount == 0; i++) + { + /* simulate different execution times before the barrier */ + Sleep(1 + abs((rand() % MAX_SLEEP_MS))); + status = EnterSynchronizationBarrier(&gBarrier, p->flags); + + // printf("Thread #%03u status: %s\n", tnum, status ? "TRUE" : "FALSE"); + if (status) + InterlockedIncrement(&p->trueCount); + else + InterlockedIncrement(&p->falseCount); + } + +out: + // printf("Thread #%03u leaving.\n", tnum); + return 0; +} + +static BOOL TestSynchBarrierWithFlags(DWORD dwFlags, DWORD dwThreads, DWORD dwLoops) +{ + HANDLE* threads = NULL; + struct test_params p; + DWORD dwStatus = 0; + DWORD expectedTrueCount = 0; + DWORD expectedFalseCount = 0; + p.threadCount = 0; + p.trueCount = 0; + p.falseCount = 0; + p.loops = dwLoops; + p.flags = dwFlags; + expectedTrueCount = dwLoops; + expectedFalseCount = dwLoops * (dwThreads - 1); + printf("%s: >> Testing with flags 0x%08" PRIx32 ". Using %" PRIu32 + " threads performing %" PRIu32 " loops\n", + __func__, dwFlags, dwThreads, dwLoops); + + if (!(threads = calloc(dwThreads, sizeof(HANDLE)))) + { + printf("%s: error allocatin thread array memory\n", __func__); + return FALSE; + } + + if (!InitializeSynchronizationBarrier(&gBarrier, dwThreads, -1)) + { + printf("%s: InitializeSynchronizationBarrier failed. GetLastError() = 0x%08x", __func__, + GetLastError()); + free(threads); + DeleteSynchronizationBarrier(&gBarrier); + return FALSE; + } + + if (!(gStartEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) + { + printf("%s: CreateEvent failed with error 0x%08x", __func__, GetLastError()); + free(threads); + DeleteSynchronizationBarrier(&gBarrier); + return FALSE; + } + + DWORD i = 0; + for (; i < dwThreads; i++) + { + if (!(threads[i] = CreateThread(NULL, 0, test_synch_barrier_thread, &p, 0, NULL))) + { + printf("%s: CreateThread failed for thread #%" PRIu32 " with error 0x%08x\n", __func__, + i, GetLastError()); + InterlockedIncrement(&gErrorCount); + break; + } + } + + if (i > 0) + { + if (!SetEvent(gStartEvent)) + { + printf("%s: SetEvent(gStartEvent) failed with error = 0x%08x)\n", __func__, + GetLastError()); + InterlockedIncrement(&gErrorCount); + } + + while (i--) + { + if (WAIT_OBJECT_0 != (dwStatus = WaitForSingleObject(threads[i], INFINITE))) + { + printf("%s: WaitForSingleObject(thread[%" PRIu32 "] unexpectedly returned %" PRIu32 + " (error = 0x%08x)\n", + __func__, i, dwStatus, GetLastError()); + InterlockedIncrement(&gErrorCount); + } + + if (!CloseHandle(threads[i])) + { + printf("%s: CloseHandle(thread[%" PRIu32 "]) failed with error = 0x%08x)\n", + __func__, i, GetLastError()); + InterlockedIncrement(&gErrorCount); + } + } + } + + free(threads); + + if (!CloseHandle(gStartEvent)) + { + printf("%s: CloseHandle(gStartEvent) failed with error = 0x%08x)\n", __func__, + GetLastError()); + InterlockedIncrement(&gErrorCount); + } + + DeleteSynchronizationBarrier(&gBarrier); + + if (p.threadCount != (INT64)dwThreads) + InterlockedIncrement(&gErrorCount); + + if (p.trueCount != (INT64)expectedTrueCount) + InterlockedIncrement(&gErrorCount); + + if (p.falseCount != (INT64)expectedFalseCount) + InterlockedIncrement(&gErrorCount); + + printf("%s: error count: %" PRId32 "\n", __func__, gErrorCount); + printf("%s: thread count: %" PRId32 " (expected %" PRIu32 ")\n", __func__, p.threadCount, + dwThreads); + printf("%s: true count: %" PRId32 " (expected %" PRIu32 ")\n", __func__, p.trueCount, + expectedTrueCount); + printf("%s: false count: %" PRId32 " (expected %" PRIu32 ")\n", __func__, p.falseCount, + expectedFalseCount); + + if (gErrorCount > 0) + { + printf("%s: Error test failed with %" PRId32 " reported errors\n", __func__, gErrorCount); + return FALSE; + } + + return TRUE; +} + +int TestSynchBarrier(int argc, char* argv[]) +{ + SYSTEM_INFO sysinfo; + DWORD dwMaxThreads = 0; + DWORD dwMinThreads = 0; + DWORD dwNumLoops = 10; + + WINPR_UNUSED(argc); + WINPR_UNUSED(argv); + + GetNativeSystemInfo(&sysinfo); + printf("%s: Number of processors: %" PRIu32 "\n", __func__, sysinfo.dwNumberOfProcessors); + dwMinThreads = sysinfo.dwNumberOfProcessors; + dwMaxThreads = sysinfo.dwNumberOfProcessors * 4; + + if (dwMaxThreads > 32) + dwMaxThreads = 32; + + /* Test invalid parameters */ + if (InitializeSynchronizationBarrier(&gBarrier, 0, -1)) + { + fprintf( + stderr, + "%s: InitializeSynchronizationBarrier unecpectedly succeeded with lTotalThreads = 0\n", + __func__); + return -1; + } + + if (InitializeSynchronizationBarrier(&gBarrier, -1, -1)) + { + fprintf( + stderr, + "%s: InitializeSynchronizationBarrier unecpectedly succeeded with lTotalThreads = -1\n", + __func__); + return -1; + } + + if (InitializeSynchronizationBarrier(&gBarrier, 1, -2)) + { + fprintf( + stderr, + "%s: InitializeSynchronizationBarrier unecpectedly succeeded with lSpinCount = -2\n", + __func__); + return -1; + } + + /* Functional tests */ + + if (!TestSynchBarrierWithFlags(0, dwMaxThreads, dwNumLoops)) + { + fprintf(stderr, + "%s: TestSynchBarrierWithFlags(0) unecpectedly succeeded with lTotalThreads = -1\n", + __func__); + return -1; + } + + if (!TestSynchBarrierWithFlags(SYNCHRONIZATION_BARRIER_FLAGS_SPIN_ONLY, dwMinThreads, + dwNumLoops)) + { + fprintf(stderr, + "%s: TestSynchBarrierWithFlags(SYNCHRONIZATION_BARRIER_FLAGS_SPIN_ONLY) " + "unecpectedly succeeded with lTotalThreads = -1\n", + __func__); + return -1; + } + + if (!TestSynchBarrierWithFlags(SYNCHRONIZATION_BARRIER_FLAGS_BLOCK_ONLY, dwMaxThreads, + dwNumLoops)) + { + fprintf(stderr, + "%s: TestSynchBarrierWithFlags(SYNCHRONIZATION_BARRIER_FLAGS_BLOCK_ONLY) " + "unecpectedly succeeded with lTotalThreads = -1\n", + __func__); + return -1; + } + + printf("%s: Test successfully completed\n", __func__); + return 0; +} |