ReactOS 0.4.15-dev-8219-ge8b88cf
InitOnce.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS API tests
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Tests for One-Time initialization APIs
5 * COPYRIGHT: Copyright 2023 Ratin Gao <ratin@knsoft.org>
6 */
7
8#include "precomp.h"
9
10typedef
11VOID
14
15typedef
16BOOL
19 _Inout_ PINIT_ONCE InitOnce,
23
24typedef
25BOOL
28 _Inout_ LPINIT_ONCE lpInitOnce,
30 _Out_ PBOOL fPending,
32
33typedef
34BOOL
37 _Inout_ LPINIT_ONCE lpInitOnce,
39 _In_opt_ LPVOID lpContext);
40
42
43static
44VOID
46{
47 /* Increase the initialization count */
48 (*InitCount)++;
49
50 /* Output context data */
52}
53
54static
55_Success_(return != FALSE)
56BOOL
58InitOnceProc(
59 _Inout_ PINIT_ONCE InitOnce,
62{
63 if (!Parameter || !Context)
64 {
65 return FALSE;
66 }
67
69 return TRUE;
70}
71
72START_TEST(InitOnce)
73{
74 BOOL bRet, fPending;
75 ULONG i, ulInitCount, ulSeed;
76 ULONG_PTR ulContextData, ulTempContext;
77 DWORD dwError;
78
80 FN_InitOnceInitialize* pfnInitOnceInitialize;
81 FN_InitOnceExecuteOnce* pfnInitOnceExecuteOnce;
82 FN_InitOnceBeginInitialize* pfnInitOnceBeginInitialize;
83 FN_InitOnceComplete* pfnInitOnceComplete;
84
85 /* Load functions */
86 hKernel32 = GetModuleHandleW(L"kernel32.dll");
87 if (!hKernel32)
88 {
89 skip("Module kernel32 not found\n");
90 return;
91 }
92 pfnInitOnceInitialize = (FN_InitOnceInitialize*)GetProcAddress(hKernel32, "InitOnceInitialize");
93 pfnInitOnceExecuteOnce = (FN_InitOnceExecuteOnce*)GetProcAddress(hKernel32, "InitOnceExecuteOnce");
94 pfnInitOnceBeginInitialize = (FN_InitOnceBeginInitialize*)GetProcAddress(hKernel32, "InitOnceBeginInitialize");
95 pfnInitOnceComplete = (FN_InitOnceComplete*)GetProcAddress(hKernel32, "InitOnceComplete");
96
97 /*
98 * Use a random as output context data,
99 * which the low-order INIT_ONCE_CTX_RESERVED_BITS bits should be zero.
100 */
101 ulSeed = (ULONG)(ULONG_PTR)&ulSeed ^ GetTickCount();
102 g_ulRandom = RtlRandom(&ulSeed);
103 for (i = 0; i < INIT_ONCE_CTX_RESERVED_BITS; i++)
104 {
105 g_ulRandom &= (~(1 << i));
106 }
107
108 /* Initialize One-Time initialization structure */
109 INIT_ONCE InitOnce = { (PVOID)(ULONG_PTR)0xDEADBEEF };
110 if (pfnInitOnceInitialize)
111 {
112 pfnInitOnceInitialize(&InitOnce);
113 }
114 else
115 {
116 skip("InitOnceInitialize not found\n");
118 }
119
120 if (!pfnInitOnceExecuteOnce)
121 {
122 skip("InitOnceExecuteOnce not found\n");
123 goto _test_sync;
124 }
125
126 /*
127 * Perform synchronous initialization by using InitOnceExecuteOnce,
128 * which executes user-defined callback to initialize.
129 * Call InitOnceExecuteOnce twice will success,
130 * initialization count should be 1 and retrieve correct context data.
131 */
132 ulInitCount = 0;
133 ulContextData = MAXULONG;
134 bRet = pfnInitOnceExecuteOnce(&InitOnce, InitOnceProc, &ulInitCount, (LPVOID*)&ulContextData);
135 ok(bRet, "InitOnceExecuteOnce failed with %lu\n", GetLastError());
136 if (bRet)
137 {
138 /* Call InitOnceExecuteOnce again and check output values if the first call succeeded */
139 bRet = pfnInitOnceExecuteOnce(&InitOnce,
140 InitOnceProc,
141 &ulInitCount,
142 (LPVOID*)&ulContextData);
143 ok(bRet, "InitOnceExecuteOnce failed with %lu\n", GetLastError());
144 ok(ulInitCount == 1, "ulInitCount is not 1\n");
145 ok(ulContextData == g_ulRandom, "Output ulContextData is incorrect\n");
146 }
147
148_test_sync:
149 if (!pfnInitOnceBeginInitialize || !pfnInitOnceComplete)
150 {
151 skip("InitOnceBeginInitialize or InitOnceComplete not found\n");
152 return;
153 }
154
155 /* Re-initialize One-Time initialization structure by using INIT_ONCE_STATIC_INIT */
157 ulContextData = 0xdeadbeef;
158
159 /* Perform synchronous initialization by using InitOnceBeginInitialize */
160 fPending = FALSE;
161 bRet = pfnInitOnceBeginInitialize(&InitOnce, 0, &fPending, (LPVOID*)&ulContextData);
162 ok(bRet, "InitOnceBeginInitialize failed with %lu\n", GetLastError());
163 if (!bRet)
164 {
165 goto _test_async;
166 }
167 ok(fPending, "fPending is not TRUE after the first success InitOnceBeginInitialize\n");
168 if (!fPending)
169 {
170 goto _test_async;
171 }
172
173 /* Call again to check whether initialization has completed */
174 fPending = 0xdeadbeef;
175 bRet = pfnInitOnceBeginInitialize(&InitOnce,
177 &fPending,
178 (LPVOID*)&ulContextData);
179 ok(bRet == FALSE, "InitOnceBeginInitialize should fail\n");
180 ok(fPending == 0xdeadbeef, "fPending should be unmodified\n");
181 ok(ulContextData == 0xdeadbeef, "ulContextData should be unmodified\n");
182
183 /* Complete the initialization */
184 InitWorker(&ulInitCount, &ulTempContext);
185 bRet = pfnInitOnceComplete(&InitOnce, 0, (LPVOID)ulTempContext);
186 ok(bRet, "InitOnceComplete failed with %lu\n", GetLastError());
187 if (!bRet)
188 {
189 goto _test_async;
190 }
191
192 /*
193 * Initialization is completed, call InitOnceBeginInitialize with
194 * INIT_ONCE_CHECK_ONLY should retrieve status and context data successfully
195 */
196 bRet = pfnInitOnceBeginInitialize(&InitOnce,
198 &fPending,
199 (LPVOID*)&ulContextData);
200 ok(bRet && !fPending && ulContextData == g_ulRandom,
201 "InitOnceBeginInitialize returns incorrect result for a completed initialization\n");
202
203_test_async:
205
206 /* Perform asynchronous initialization */
207 fPending = FALSE;
208 bRet = pfnInitOnceBeginInitialize(&InitOnce,
210 &fPending,
211 (LPVOID*)&ulContextData);
212 ok(bRet, "InitOnceBeginInitialize failed with %lu\n", GetLastError());
213 if (!bRet)
214 {
215 return;
216 }
217 ok(fPending, "fPending is not TRUE after a success InitOnceBeginInitialize\n");
218 if (!fPending)
219 {
220 return;
221 }
222
223 /*
224 * Now the initialization is in progress but not completed yet,
225 * call InitOnceBeginInitialize again without INIT_ONCE_ASYNC is invalid,
226 * should fail with ERROR_INVALID_PARAMETER
227 */
228 bRet = pfnInitOnceBeginInitialize(&InitOnce, 0, &fPending, (LPVOID*)&ulContextData);
229 ok(!bRet, "InitOnceBeginInitialize should not success\n");
230 if (!bRet)
231 {
232 dwError = GetLastError();
233 ok(dwError == ERROR_INVALID_PARAMETER,
234 "Last error is %lu, but %u is expected\n",
235 dwError,
237 }
238
239 /*
240 * Call InitOnceBeginInitialize again with INIT_ONCE_ASYNC
241 * should success because initialization could be executed in parallel
242 */
243 bRet = pfnInitOnceBeginInitialize(&InitOnce,
245 &fPending,
246 (LPVOID*)&ulContextData);
247 ok(bRet, "InitOnceBeginInitialize failed with %lu\n", GetLastError());
248 if (!bRet)
249 {
250 return;
251 }
252 ok(fPending, "fPending is not TRUE after a success InitOnceBeginInitialize\n");
253 if (!fPending)
254 {
255 return;
256 }
257
258 /* Complete the initialization once */
259 InitWorker(&ulInitCount, &ulTempContext);
260 bRet = pfnInitOnceComplete(&InitOnce, INIT_ONCE_ASYNC, (LPVOID)ulTempContext);
261 ok(bRet, "InitOnceComplete failed with %lu\n", GetLastError());
262 if (!bRet)
263 {
264 return;
265 }
266
267 /* Subsequent InitOnceComplete should fail with ERROR_GEN_FAILURE */
268 bRet = pfnInitOnceComplete(&InitOnce, INIT_ONCE_ASYNC, (LPVOID)ulTempContext);
269 ok(!bRet, "InitOnceComplete should not success\n");
270 if (!bRet)
271 {
272 dwError = GetLastError();
273 ok(dwError == ERROR_GEN_FAILURE,
274 "Last error is %lu, but %u is expected\n",
275 dwError,
277 }
278
279 /*
280 * Initialization is completed, call InitOnceBeginInitialize with
281 * INIT_ONCE_CHECK_ONLY should retrieve status and context data successfully
282 */
283 bRet = pfnInitOnceBeginInitialize(&InitOnce,
285 &fPending,
286 (LPVOID*)&ulContextData);
287 ok(bRet && !fPending && ulContextData == g_ulRandom,
288 "InitOnceBeginInitialize returns incorrect result for a completed initialization\n");
289
290 return;
291}
#define ok(value,...)
Definition: atltest.h:57
#define skip(...)
Definition: atltest.h:64
#define START_TEST(x)
Definition: atltest.h:75
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define ERROR_INVALID_PARAMETER
Definition: compat.h:101
#define GetProcAddress(x, y)
Definition: compat.h:753
HMODULE WINAPI GetModuleHandleW(LPCWSTR lpModuleName)
Definition: loader.c:838
DWORD WINAPI GetTickCount(VOID)
Definition: time.c:455
#define ULONG_PTR
Definition: config.h:101
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
BOOL WINAPI FN_InitOnceBeginInitialize(_Inout_ LPINIT_ONCE lpInitOnce, _In_ DWORD dwFlags, _Out_ PBOOL fPending, _Outptr_opt_result_maybenull_ LPVOID *lpContext)
Definition: InitOnce.c:27
static VOID InitWorker(_Inout_ PULONG InitCount, _Out_ PULONG_PTR Context)
Definition: InitOnce.c:45
BOOL WINAPI FN_InitOnceComplete(_Inout_ LPINIT_ONCE lpInitOnce, _In_ DWORD dwFlags, _In_opt_ LPVOID lpContext)
Definition: InitOnce.c:36
static ULONG g_ulRandom
Definition: InitOnce.c:41
VOID WINAPI FN_InitOnceInitialize(_Out_ PINIT_ONCE InitOnce)
Definition: InitOnce.c:13
BOOL WINAPI FN_InitOnceExecuteOnce(_Inout_ PINIT_ONCE InitOnce, _In_ __callback PINIT_ONCE_FN InitFn, _Inout_opt_ PVOID Parameter, _Outptr_opt_result_maybenull_ LPVOID *Context)
Definition: InitOnce.c:18
HANDLE hKernel32
Definition: locale.c:13
#define _Success_(expr)
Definition: ms_sal.h:259
#define _Inout_
Definition: ms_sal.h:378
#define _Outptr_opt_result_maybenull_
Definition: ms_sal.h:430
#define _Inout_opt_
Definition: ms_sal.h:379
#define __callback
Definition: ms_sal.h:2876
#define _Out_
Definition: ms_sal.h:345
#define _In_
Definition: ms_sal.h:308
#define _In_opt_
Definition: ms_sal.h:309
NTSYSAPI ULONG NTAPI RtlRandom(_Inout_ PULONG Seed)
#define L(x)
Definition: ntvdm.h:50
#define MAXULONG
Definition: typedefs.h:251
uint32_t * PULONG_PTR
Definition: typedefs.h:65
uint32_t * PULONG
Definition: typedefs.h:59
void * PVOID
Definition: typedefs.h:50
uint32_t ULONG_PTR
Definition: typedefs.h:65
uint32_t ULONG
Definition: typedefs.h:59
BOOL(WINAPI * PINIT_ONCE_FN)(_Inout_ PINIT_ONCE InitOnce, _Inout_opt_ PVOID Parameter, _Outptr_opt_result_maybenull_ PVOID *Context)
Definition: winbase.h:3942
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
PRTL_RUN_ONCE PINIT_ONCE
Definition: winbase.h:3932
PRTL_RUN_ONCE LPINIT_ONCE
Definition: winbase.h:3933
#define INIT_ONCE_CHECK_ONLY
Definition: winbase.h:3935
#define INIT_ONCE_ASYNC
Definition: winbase.h:3936
RTL_RUN_ONCE INIT_ONCE
Definition: winbase.h:3931
#define INIT_ONCE_CTX_RESERVED_BITS
Definition: winbase.h:3939
#define INIT_ONCE_STATIC_INIT
Definition: winbase.h:612
_In_ PCCERT_CONTEXT _In_ DWORD dwFlags
Definition: wincrypt.h:1176
BOOL * PBOOL
Definition: windef.h:161
#define WINAPI
Definition: msvc.h:6
#define ERROR_GEN_FAILURE
Definition: winerror.h:134
_In_ __inner_callback PRTL_RUN_ONCE_INIT_FN InitFn
Definition: rtlfuncs.h:2533
_Inout_opt_ PVOID Parameter
Definition: rtltypes.h:336