FreeRDP
TestSynchMultipleThreads.c
1 
2 #include <stdlib.h>
3 
4 #include <winpr/crt.h>
5 #include <winpr/crypto.h>
6 #include <winpr/synch.h>
7 #include <winpr/thread.h>
8 
9 #define THREADS 8
10 
11 static UINT32 prand(UINT32 max)
12 {
13  UINT32 tmp = 0;
14  if (max <= 1)
15  return 1;
16  winpr_RAND(&tmp, sizeof(tmp));
17  return tmp % (max - 1) + 1;
18 }
19 
20 static DWORD WINAPI test_thread(LPVOID arg)
21 {
22  UINT32 timeout = 50 + prand(100);
23  WINPR_UNUSED(arg);
24  Sleep(timeout);
25  ExitThread(0);
26  return 0;
27 }
28 
29 static int start_threads(size_t count, HANDLE* threads)
30 {
31  for (size_t i = 0; i < count; i++)
32  {
33  threads[i] = CreateThread(NULL, 0, test_thread, NULL, CREATE_SUSPENDED, NULL);
34 
35  if (!threads[i])
36  {
37  (void)fprintf(stderr, "%s: CreateThread [%" PRIuz "] failure\n", __func__, i);
38  return -1;
39  }
40  }
41 
42  for (size_t i = 0; i < count; i++)
43  ResumeThread(threads[i]);
44  return 0;
45 }
46 
47 static int close_threads(DWORD count, HANDLE* threads)
48 {
49  int rc = 0;
50 
51  for (DWORD i = 0; i < count; i++)
52  {
53  if (!threads[i])
54  continue;
55 
56  if (!CloseHandle(threads[i]))
57  {
58  (void)fprintf(stderr, "%s: CloseHandle [%" PRIu32 "] failure\n", __func__, i);
59  rc = -1;
60  }
61  threads[i] = NULL;
62  }
63 
64  return rc;
65 }
66 
67 static BOOL TestWaitForAll(void)
68 {
69  BOOL rc = FALSE;
70  HANDLE threads[THREADS] = { 0 };
71  /* WaitForAll, timeout */
72  if (start_threads(ARRAYSIZE(threads), threads))
73  {
74  (void)fprintf(stderr, "%s: start_threads failed\n", __func__);
75  goto fail;
76  }
77 
78  const DWORD ret = WaitForMultipleObjects(ARRAYSIZE(threads), threads, TRUE, 10);
79  if (ret != WAIT_TIMEOUT)
80  {
81  (void)fprintf(stderr, "%s: WaitForMultipleObjects bWaitAll, timeout 10 failed, ret=%d\n",
82  __func__, ret);
83  goto fail;
84  }
85 
86  if (WaitForMultipleObjects(ARRAYSIZE(threads), threads, TRUE, INFINITE) != WAIT_OBJECT_0)
87  {
88  (void)fprintf(stderr, "%s: WaitForMultipleObjects bWaitAll, INFINITE failed\n", __func__);
89  goto fail;
90  }
91 
92  rc = TRUE;
93 fail:
94  if (close_threads(ARRAYSIZE(threads), threads))
95  {
96  (void)fprintf(stderr, "%s: close_threads failed\n", __func__);
97  return FALSE;
98  }
99 
100  return rc;
101 }
102 
103 static BOOL TestWaitOne(void)
104 {
105  BOOL rc = FALSE;
106  HANDLE threads[THREADS] = { 0 };
107  /* WaitForAll, timeout */
108  if (start_threads(ARRAYSIZE(threads), threads))
109  {
110  (void)fprintf(stderr, "%s: start_threads failed\n", __func__);
111  goto fail;
112  }
113 
114  const DWORD ret = WaitForMultipleObjects(ARRAYSIZE(threads), threads, FALSE, INFINITE);
115  if (ret > (WAIT_OBJECT_0 + ARRAYSIZE(threads)))
116  {
117  (void)fprintf(stderr, "%s: WaitForMultipleObjects INFINITE failed\n", __func__);
118  goto fail;
119  }
120 
121  if (WaitForMultipleObjects(ARRAYSIZE(threads), threads, TRUE, INFINITE) != WAIT_OBJECT_0)
122  {
123  (void)fprintf(stderr, "%s: WaitForMultipleObjects bWaitAll, INFINITE failed\n", __func__);
124  goto fail;
125  }
126 
127  rc = TRUE;
128 fail:
129  if (close_threads(ARRAYSIZE(threads), threads))
130  {
131  (void)fprintf(stderr, "%s: close_threads failed\n", __func__);
132  return FALSE;
133  }
134 
135  return rc;
136 }
137 
138 static BOOL TestWaitOneTimeout(void)
139 {
140  BOOL rc = FALSE;
141  HANDLE threads[THREADS] = { 0 };
142  /* WaitForAll, timeout */
143  if (start_threads(ARRAYSIZE(threads), threads))
144  {
145  (void)fprintf(stderr, "%s: start_threads failed\n", __func__);
146  goto fail;
147  }
148 
149  const DWORD ret = WaitForMultipleObjects(ARRAYSIZE(threads), threads, FALSE, 1);
150  if (ret != WAIT_TIMEOUT)
151  {
152  (void)fprintf(stderr, "%s: WaitForMultipleObjects timeout 50 failed, ret=%d\n", __func__,
153  ret);
154  goto fail;
155  }
156 
157  if (WaitForMultipleObjects(ARRAYSIZE(threads), threads, TRUE, INFINITE) != WAIT_OBJECT_0)
158  {
159  (void)fprintf(stderr, "%s: WaitForMultipleObjects bWaitAll, INFINITE failed\n", __func__);
160  goto fail;
161  }
162  rc = TRUE;
163 fail:
164  if (close_threads(ARRAYSIZE(threads), threads))
165  {
166  (void)fprintf(stderr, "%s: close_threads failed\n", __func__);
167  return FALSE;
168  }
169 
170  return rc;
171 }
172 
173 static BOOL TestWaitOneTimeoutMultijoin(void)
174 {
175  BOOL rc = FALSE;
176  HANDLE threads[THREADS] = { 0 };
177  /* WaitForAll, timeout */
178  if (start_threads(ARRAYSIZE(threads), threads))
179  {
180  (void)fprintf(stderr, "%s: start_threads failed\n", __func__);
181  goto fail;
182  }
183 
184  for (size_t i = 0; i < ARRAYSIZE(threads); i++)
185  {
186  const DWORD ret = WaitForMultipleObjects(ARRAYSIZE(threads), threads, FALSE, 0);
187  if (ret != WAIT_TIMEOUT)
188  {
189  (void)fprintf(stderr, "%s: WaitForMultipleObjects timeout 0 failed, ret=%d\n", __func__,
190  ret);
191  goto fail;
192  }
193  }
194 
195  if (WaitForMultipleObjects(ARRAYSIZE(threads), threads, TRUE, INFINITE) != WAIT_OBJECT_0)
196  {
197  (void)fprintf(stderr, "%s: WaitForMultipleObjects bWaitAll, INFINITE failed\n", __func__);
198  goto fail;
199  }
200 
201  rc = TRUE;
202 fail:
203  if (close_threads(ARRAYSIZE(threads), threads))
204  {
205  (void)fprintf(stderr, "%s: close_threads failed\n", __func__);
206  return FALSE;
207  }
208 
209  return rc;
210 }
211 
212 static BOOL TestDetach(void)
213 {
214  BOOL rc = FALSE;
215  HANDLE threads[THREADS] = { 0 };
216  /* WaitForAll, timeout */
217  if (start_threads(ARRAYSIZE(threads), threads))
218  {
219  (void)fprintf(stderr, "%s: start_threads failed\n", __func__);
220  goto fail;
221  }
222 
223  rc = TRUE;
224 fail:
225  if (close_threads(ARRAYSIZE(threads), threads))
226  {
227  (void)fprintf(stderr, "%s: close_threads failed\n", __func__);
228  return FALSE;
229  }
230 
231  return rc;
232 }
233 
234 int TestSynchMultipleThreads(int argc, char* argv[])
235 {
236  WINPR_UNUSED(argc);
237  WINPR_UNUSED(argv);
238 
239  if (!TestWaitForAll())
240  return -1;
241 
242  if (!TestWaitOne())
243  return -2;
244 
245  if (!TestWaitOneTimeout())
246  return -3;
247 
248  if (!TestWaitOneTimeoutMultijoin())
249  return -4;
250 
251  if (!TestDetach())
252  return -5;
253 
254  return 0;
255 }