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