FreeRDP
Loading...
Searching...
No Matches
TestSynchBarrier.c
1
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#include <winpr/sysinfo.h>
8
9#include "../synch.h"
10
11static SYNCHRONIZATION_BARRIER gBarrier;
12static HANDLE gStartEvent = nullptr;
13static LONG gErrorCount = 0;
14
15#define MAX_SLEEP_MS 22
16
17struct test_params
18{
19 LONG threadCount;
20 LONG trueCount;
21 LONG falseCount;
22 DWORD loops;
23 DWORD flags;
24};
25
26static UINT32 prand(UINT32 max)
27{
28 UINT32 tmp = 0;
29 if (max <= 1)
30 return 1;
31 if (winpr_RAND(&tmp, sizeof(tmp)) < 0)
32 {
33 // NOLINTNEXTLINE(concurrency-mt-unsafe)
34 exit(-1);
35 }
36 return tmp % (max - 1) + 1;
37}
38
39static DWORD WINAPI test_synch_barrier_thread(LPVOID lpParam)
40{
41 BOOL status = FALSE;
42 struct test_params* p = (struct test_params*)lpParam;
43
44 InterlockedIncrement(&p->threadCount);
45
46 // printf("Thread #%03u entered.\n", tnum);
47
48 /* wait for start event from main */
49 if (WaitForSingleObject(gStartEvent, INFINITE) != WAIT_OBJECT_0)
50 {
51 InterlockedIncrement(&gErrorCount);
52 goto out;
53 }
54
55 // printf("Thread #%03u unblocked.\n", tnum);
56
57 for (DWORD i = 0; i < p->loops && gErrorCount == 0; i++)
58 {
59 /* simulate different execution times before the barrier */
60 Sleep(1 + prand(MAX_SLEEP_MS));
61 status = EnterSynchronizationBarrier(&gBarrier, p->flags);
62
63 // printf("Thread #%03u status: %s\n", tnum, status ? "TRUE" : "FALSE");
64 if (status)
65 InterlockedIncrement(&p->trueCount);
66 else
67 InterlockedIncrement(&p->falseCount);
68 }
69
70out:
71 // printf("Thread #%03u leaving.\n", tnum);
72 return 0;
73}
74
75static BOOL TestSynchBarrierWithFlags(DWORD dwFlags, DWORD dwThreads, DWORD dwLoops)
76{
77 BOOL rc = FALSE;
78 DWORD dwStatus = 0;
79
80 struct test_params p = {
81 .threadCount = 0, .trueCount = 0, .falseCount = 0, .loops = dwLoops, .flags = dwFlags
82 };
83 DWORD expectedTrueCount = dwLoops;
84 DWORD expectedFalseCount = dwLoops * (dwThreads - 1);
85
86 printf("%s: >> Testing with flags 0x%08" PRIx32 ". Using %" PRIu32
87 " threads performing %" PRIu32 " loops\n",
88 __func__, dwFlags, dwThreads, dwLoops);
89
90 HANDLE* threads = (HANDLE*)calloc(dwThreads, sizeof(HANDLE));
91 if (!threads)
92 {
93 printf("%s: error allocatin thread array memory\n", __func__);
94 return FALSE;
95 }
96
97 if (dwThreads > INT32_MAX)
98 goto fail;
99
100 if (!InitializeSynchronizationBarrier(&gBarrier, (LONG)dwThreads, -1))
101 {
102 printf("%s: InitializeSynchronizationBarrier failed. GetLastError() = 0x%08x", __func__,
103 GetLastError());
104 goto fail;
105 }
106
107 if (!(gStartEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr)))
108 {
109 printf("%s: CreateEvent failed with error 0x%08x", __func__, GetLastError());
110 goto fail;
111 }
112
113 DWORD i = 0;
114 for (; i < dwThreads; i++)
115 {
116 threads[i] = CreateThread(nullptr, 0, test_synch_barrier_thread, &p, 0, nullptr);
117 if (!threads[i])
118 {
119 printf("%s: CreateThread failed for thread #%" PRIu32 " with error 0x%08x\n", __func__,
120 i, GetLastError());
121 InterlockedIncrement(&gErrorCount);
122 break;
123 }
124 }
125
126 if (i > 0)
127 {
128 if (!SetEvent(gStartEvent))
129 {
130 printf("%s: SetEvent(gStartEvent) failed with error = 0x%08x)\n", __func__,
131 GetLastError());
132 InterlockedIncrement(&gErrorCount);
133 }
134
135 while (i--)
136 {
137 if (WAIT_OBJECT_0 != (dwStatus = WaitForSingleObject(threads[i], INFINITE)))
138 {
139 printf("%s: WaitForSingleObject(thread[%" PRIu32 "] unexpectedly returned %" PRIu32
140 " (error = 0x%08x)\n",
141 __func__, i, dwStatus, GetLastError());
142 InterlockedIncrement(&gErrorCount);
143 }
144
145 if (!CloseHandle(threads[i]))
146 {
147 printf("%s: CloseHandle(thread[%" PRIu32 "]) failed with error = 0x%08x)\n",
148 __func__, i, GetLastError());
149 InterlockedIncrement(&gErrorCount);
150 }
151 }
152 }
153
154 if (!CloseHandle(gStartEvent))
155 {
156 printf("%s: CloseHandle(gStartEvent) failed with error = 0x%08x)\n", __func__,
157 GetLastError());
158 InterlockedIncrement(&gErrorCount);
159 }
160
161 if (p.threadCount != (INT64)dwThreads)
162 InterlockedIncrement(&gErrorCount);
163
164 if (p.trueCount != (INT64)expectedTrueCount)
165 InterlockedIncrement(&gErrorCount);
166
167 if (p.falseCount != (INT64)expectedFalseCount)
168 InterlockedIncrement(&gErrorCount);
169
170 printf("%s: error count: %" PRId32 "\n", __func__, gErrorCount);
171 printf("%s: thread count: %" PRId32 " (expected %" PRIu32 ")\n", __func__, p.threadCount,
172 dwThreads);
173 printf("%s: true count: %" PRId32 " (expected %" PRIu32 ")\n", __func__, p.trueCount,
174 expectedTrueCount);
175 printf("%s: false count: %" PRId32 " (expected %" PRIu32 ")\n", __func__, p.falseCount,
176 expectedFalseCount);
177
178 rc = TRUE;
179fail:
180 free((void*)threads);
181 DeleteSynchronizationBarrier(&gBarrier);
182 if (gErrorCount > 0)
183 {
184 printf("%s: Error test failed with %" PRId32 " reported errors\n", __func__, gErrorCount);
185 return FALSE;
186 }
187
188 return rc;
189}
190
191int TestSynchBarrier(int argc, char* argv[])
192{
193 SYSTEM_INFO sysinfo;
194 DWORD dwMaxThreads = 0;
195 DWORD dwMinThreads = 0;
196 DWORD dwNumLoops = 10;
197
198 WINPR_UNUSED(argc);
199 WINPR_UNUSED(argv);
200
201 GetNativeSystemInfo(&sysinfo);
202 printf("%s: Number of processors: %" PRIu32 "\n", __func__, sysinfo.dwNumberOfProcessors);
203 dwMinThreads = sysinfo.dwNumberOfProcessors;
204 dwMaxThreads = sysinfo.dwNumberOfProcessors * 4;
205
206 if (dwMaxThreads > 32)
207 dwMaxThreads = 32;
208
209 /* Test invalid parameters */
210 if (InitializeSynchronizationBarrier(&gBarrier, 0, -1))
211 {
212 (void)fprintf(
213 stderr,
214 "%s: InitializeSynchronizationBarrier unecpectedly succeeded with lTotalThreads = 0\n",
215 __func__);
216 return -1;
217 }
218
219 if (InitializeSynchronizationBarrier(&gBarrier, -1, -1))
220 {
221 (void)fprintf(
222 stderr,
223 "%s: InitializeSynchronizationBarrier unecpectedly succeeded with lTotalThreads = -1\n",
224 __func__);
225 return -1;
226 }
227
228 if (InitializeSynchronizationBarrier(&gBarrier, 1, -2))
229 {
230 (void)fprintf(
231 stderr,
232 "%s: InitializeSynchronizationBarrier unecpectedly succeeded with lSpinCount = -2\n",
233 __func__);
234 return -1;
235 }
236
237 /* Functional tests */
238
239 if (!TestSynchBarrierWithFlags(0, dwMaxThreads, dwNumLoops))
240 {
241 (void)fprintf(
242 stderr,
243 "%s: TestSynchBarrierWithFlags(0) unecpectedly succeeded with lTotalThreads = -1\n",
244 __func__);
245 return -1;
246 }
247
248 if (!TestSynchBarrierWithFlags(SYNCHRONIZATION_BARRIER_FLAGS_SPIN_ONLY, dwMinThreads,
249 dwNumLoops))
250 {
251 (void)fprintf(stderr,
252 "%s: TestSynchBarrierWithFlags(SYNCHRONIZATION_BARRIER_FLAGS_SPIN_ONLY) "
253 "unecpectedly succeeded with lTotalThreads = -1\n",
254 __func__);
255 return -1;
256 }
257
258 if (!TestSynchBarrierWithFlags(SYNCHRONIZATION_BARRIER_FLAGS_BLOCK_ONLY, dwMaxThreads,
259 dwNumLoops))
260 {
261 (void)fprintf(stderr,
262 "%s: TestSynchBarrierWithFlags(SYNCHRONIZATION_BARRIER_FLAGS_BLOCK_ONLY) "
263 "unecpectedly succeeded with lTotalThreads = -1\n",
264 __func__);
265 return -1;
266 }
267
268 printf("%s: Test successfully completed\n", __func__);
269 return 0;
270}