FreeRDP
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 
11 static SYNCHRONIZATION_BARRIER gBarrier;
12 static HANDLE gStartEvent = NULL;
13 static LONG gErrorCount = 0;
14 
15 #define MAX_SLEEP_MS 22
16 
17 struct test_params
18 {
19  LONG threadCount;
20  LONG trueCount;
21  LONG falseCount;
22  DWORD loops;
23  DWORD flags;
24 };
25 
26 static 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 
35 static 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 
66 out:
67  // printf("Thread #%03u leaving.\n", tnum);
68  return 0;
69 }
70 
71 static 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;
175 fail:
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 
187 int 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 }