FreeRDP
Loading...
Searching...
No Matches
TestSynchInit.c
1#include <stdio.h>
2#include <winpr/crt.h>
3#include <winpr/crypto.h>
4#include <winpr/synch.h>
5#include <winpr/thread.h>
6#include <winpr/interlocked.h>
7
8#define TEST_NUM_THREADS 100
9#define TEST_NUM_FAILURES 10
10
11static INIT_ONCE initOnceTest = INIT_ONCE_STATIC_INIT;
12
13static HANDLE hStartEvent = nullptr;
14static LONG* pErrors = nullptr;
15static LONG* pTestThreadFunctionCalls = nullptr;
16static LONG* pTestOnceFunctionCalls = nullptr;
17static LONG* pInitOnceExecuteOnceCalls = nullptr;
18
19static UINT32 prand(UINT32 max)
20{
21 UINT32 tmp = 0;
22 if (max <= 1)
23 return 1;
24 if (winpr_RAND(&tmp, sizeof(tmp)) < 0)
25 return 0;
26 return tmp % (max - 1) + 1;
27}
28
29static BOOL CALLBACK TestOnceFunction(PINIT_ONCE once, PVOID param, PVOID* context)
30{
31 LONG calls = InterlockedIncrement(pTestOnceFunctionCalls) - 1;
32
33 WINPR_UNUSED(once);
34 WINPR_UNUSED(param);
35 WINPR_UNUSED(context);
36
37 /* simulate execution time */
38 Sleep(30 + prand(40));
39
40 if (calls < TEST_NUM_FAILURES)
41 {
42 /* simulated error */
43 return FALSE;
44 }
45 if (calls == TEST_NUM_FAILURES)
46 {
47 return TRUE;
48 }
49 (void)fprintf(stderr, "%s: error: called again after success\n", __func__);
50 InterlockedIncrement(pErrors);
51 return FALSE;
52}
53
54static DWORD WINAPI TestThreadFunction(LPVOID lpParam)
55{
56 LONG calls = 0;
57 BOOL ok = 0;
58
59 WINPR_UNUSED(lpParam);
60
61 InterlockedIncrement(pTestThreadFunctionCalls);
62 if (WaitForSingleObject(hStartEvent, INFINITE) != WAIT_OBJECT_0)
63 {
64 (void)fprintf(stderr, "%s: error: failed to wait for start event\n", __func__);
65 InterlockedIncrement(pErrors);
66 return 0;
67 }
68
69 ok = InitOnceExecuteOnce(&initOnceTest, TestOnceFunction, nullptr, nullptr);
70 calls = InterlockedIncrement(pInitOnceExecuteOnceCalls);
71 if (!ok && calls > TEST_NUM_FAILURES)
72 {
73 (void)fprintf(stderr, "%s: InitOnceExecuteOnce failed unexpectedly\n", __func__);
74 InterlockedIncrement(pErrors);
75 }
76 return 0;
77}
78
79int TestSynchInit(int argc, char* argv[])
80{
81 HANDLE hThreads[TEST_NUM_THREADS];
82 DWORD dwCreatedThreads = 0;
83 BOOL result = FALSE;
84
85 WINPR_UNUSED(argc);
86 WINPR_UNUSED(argv);
87
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));
92
93 if (!pErrors || !pTestThreadFunctionCalls || !pTestOnceFunctionCalls ||
94 !pInitOnceExecuteOnceCalls)
95 {
96 (void)fprintf(stderr, "error: _aligned_malloc failed\n");
97 goto out;
98 }
99
100 *pErrors = 0;
101 *pTestThreadFunctionCalls = 0;
102 *pTestOnceFunctionCalls = 0;
103 *pInitOnceExecuteOnceCalls = 0;
104
105 if (!(hStartEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr)))
106 {
107 (void)fprintf(stderr, "error creating start event\n");
108 InterlockedIncrement(pErrors);
109 goto out;
110 }
111
112 for (DWORD i = 0; i < TEST_NUM_THREADS; i++)
113 {
114 if (!(hThreads[i] = CreateThread(nullptr, 0, TestThreadFunction, nullptr, 0, nullptr)))
115 {
116 (void)fprintf(stderr, "error creating thread #%" PRIu32 "\n", i);
117 InterlockedIncrement(pErrors);
118 goto out;
119 }
120 dwCreatedThreads++;
121 }
122
123 Sleep(100);
124 (void)SetEvent(hStartEvent);
125
126 for (DWORD i = 0; i < dwCreatedThreads; i++)
127 {
128 if (WaitForSingleObject(hThreads[i], INFINITE) != WAIT_OBJECT_0)
129 {
130 (void)fprintf(stderr, "error: error waiting for thread #%" PRIu32 "\n", i);
131 InterlockedIncrement(pErrors);
132 goto out;
133 }
134 }
135
136 if (*pErrors == 0 && *pTestThreadFunctionCalls == TEST_NUM_THREADS &&
137 *pInitOnceExecuteOnceCalls == TEST_NUM_THREADS &&
138 *pTestOnceFunctionCalls == TEST_NUM_FAILURES + 1)
139 {
140 result = TRUE;
141 }
142
143out:
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);
153
154 winpr_aligned_free(pErrors);
155 winpr_aligned_free(pTestThreadFunctionCalls);
156 winpr_aligned_free(pTestOnceFunctionCalls);
157 winpr_aligned_free(pInitOnceExecuteOnceCalls);
158
159 (void)CloseHandle(hStartEvent);
160
161 for (DWORD i = 0; i < dwCreatedThreads; i++)
162 {
163 (void)CloseHandle(hThreads[i]);
164 }
165
166 return (result ? 0 : 1);
167}