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