3#include <winpr/crypto.h>
4#include <winpr/synch.h>
5#include <winpr/thread.h>
6#include <winpr/interlocked.h>
8#define TEST_NUM_THREADS 100
9#define TEST_NUM_FAILURES 10
11static INIT_ONCE initOnceTest = INIT_ONCE_STATIC_INIT;
13static HANDLE hStartEvent =
nullptr;
14static LONG* pErrors =
nullptr;
15static LONG* pTestThreadFunctionCalls =
nullptr;
16static LONG* pTestOnceFunctionCalls =
nullptr;
17static LONG* pInitOnceExecuteOnceCalls =
nullptr;
19static UINT32 prand(UINT32 max)
24 if (winpr_RAND(&tmp,
sizeof(tmp)) < 0)
26 return tmp % (max - 1) + 1;
29static BOOL CALLBACK TestOnceFunction(
PINIT_ONCE once, PVOID param, PVOID* context)
31 LONG calls = InterlockedIncrement(pTestOnceFunctionCalls) - 1;
35 WINPR_UNUSED(context);
38 Sleep(30 + prand(40));
40 if (calls < TEST_NUM_FAILURES)
45 if (calls == TEST_NUM_FAILURES)
49 (void)fprintf(stderr,
"%s: error: called again after success\n", __func__);
50 InterlockedIncrement(pErrors);
54static DWORD WINAPI TestThreadFunction(LPVOID lpParam)
59 WINPR_UNUSED(lpParam);
61 InterlockedIncrement(pTestThreadFunctionCalls);
62 if (WaitForSingleObject(hStartEvent, INFINITE) != WAIT_OBJECT_0)
64 (void)fprintf(stderr,
"%s: error: failed to wait for start event\n", __func__);
65 InterlockedIncrement(pErrors);
69 ok = InitOnceExecuteOnce(&initOnceTest, TestOnceFunction,
nullptr,
nullptr);
70 calls = InterlockedIncrement(pInitOnceExecuteOnceCalls);
71 if (!ok && calls > TEST_NUM_FAILURES)
73 (void)fprintf(stderr,
"%s: InitOnceExecuteOnce failed unexpectedly\n", __func__);
74 InterlockedIncrement(pErrors);
79int TestSynchInit(
int argc,
char* argv[])
81 HANDLE hThreads[TEST_NUM_THREADS];
82 DWORD dwCreatedThreads = 0;
88 pErrors = winpr_aligned_malloc(
sizeof(LONG),
sizeof(LONG));
89 pTestThreadFunctionCalls = winpr_aligned_malloc(
sizeof(LONG),
sizeof(LONG));
90 pTestOnceFunctionCalls = winpr_aligned_malloc(
sizeof(LONG),
sizeof(LONG));
91 pInitOnceExecuteOnceCalls = winpr_aligned_malloc(
sizeof(LONG),
sizeof(LONG));
93 if (!pErrors || !pTestThreadFunctionCalls || !pTestOnceFunctionCalls ||
94 !pInitOnceExecuteOnceCalls)
96 (void)fprintf(stderr,
"error: _aligned_malloc failed\n");
101 *pTestThreadFunctionCalls = 0;
102 *pTestOnceFunctionCalls = 0;
103 *pInitOnceExecuteOnceCalls = 0;
105 if (!(hStartEvent = CreateEvent(
nullptr, TRUE, FALSE,
nullptr)))
107 (void)fprintf(stderr,
"error creating start event\n");
108 InterlockedIncrement(pErrors);
112 for (DWORD i = 0; i < TEST_NUM_THREADS; i++)
114 if (!(hThreads[i] = CreateThread(
nullptr, 0, TestThreadFunction,
nullptr, 0,
nullptr)))
116 (void)fprintf(stderr,
"error creating thread #%" PRIu32
"\n", i);
117 InterlockedIncrement(pErrors);
124 (void)SetEvent(hStartEvent);
126 for (DWORD i = 0; i < dwCreatedThreads; i++)
128 if (WaitForSingleObject(hThreads[i], INFINITE) != WAIT_OBJECT_0)
130 (void)fprintf(stderr,
"error: error waiting for thread #%" PRIu32
"\n", i);
131 InterlockedIncrement(pErrors);
136 if (*pErrors == 0 && *pTestThreadFunctionCalls == TEST_NUM_THREADS &&
137 *pInitOnceExecuteOnceCalls == TEST_NUM_THREADS &&
138 *pTestOnceFunctionCalls == TEST_NUM_FAILURES + 1)
144 (void)fprintf(stderr,
"Test result: %s\n", result ?
"OK" :
"ERROR");
145 (void)fprintf(stderr,
"Error count: %" PRId32
"\n", pErrors ? *pErrors : -1);
146 (void)fprintf(stderr,
"Threads created: %" PRIu32
"\n", dwCreatedThreads);
147 (void)fprintf(stderr,
"TestThreadFunctionCalls: %" PRId32
"\n",
148 pTestThreadFunctionCalls ? *pTestThreadFunctionCalls : -1);
149 (void)fprintf(stderr,
"InitOnceExecuteOnceCalls: %" PRId32
"\n",
150 pInitOnceExecuteOnceCalls ? *pInitOnceExecuteOnceCalls : -1);
151 (void)fprintf(stderr,
"TestOnceFunctionCalls: %" PRId32
"\n",
152 pTestOnceFunctionCalls ? *pTestOnceFunctionCalls : -1);
154 winpr_aligned_free(pErrors);
155 winpr_aligned_free(pTestThreadFunctionCalls);
156 winpr_aligned_free(pTestOnceFunctionCalls);
157 winpr_aligned_free(pInitOnceExecuteOnceCalls);
159 (void)CloseHandle(hStartEvent);
161 for (DWORD i = 0; i < dwCreatedThreads; i++)
163 (void)CloseHandle(hThreads[i]);
166 return (result ? 0 : 1);