[KERNEL32_WINETEST] Add a PCH.
[reactos.git] / modules / rostests / winetests / kernel32 / fiber.c
1 /*
2 * Unit tests for fiber functions
3 *
4 * Copyright (c) 2010 André Hentschel
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include "precomp.h"
22
23 static LPVOID (WINAPI *pCreateFiber)(SIZE_T,LPFIBER_START_ROUTINE,LPVOID);
24 static LPVOID (WINAPI *pConvertThreadToFiber)(LPVOID);
25 static BOOL (WINAPI *pConvertFiberToThread)(void);
26 static void (WINAPI *pSwitchToFiber)(LPVOID);
27 static void (WINAPI *pDeleteFiber)(LPVOID);
28 static LPVOID (WINAPI *pConvertThreadToFiberEx)(LPVOID,DWORD);
29 static LPVOID (WINAPI *pCreateFiberEx)(SIZE_T,SIZE_T,DWORD,LPFIBER_START_ROUTINE,LPVOID);
30 static BOOL (WINAPI *pIsThreadAFiber)(void);
31 static DWORD (WINAPI *pFlsAlloc)(PFLS_CALLBACK_FUNCTION);
32 static BOOL (WINAPI *pFlsFree)(DWORD);
33 static PVOID (WINAPI *pFlsGetValue)(DWORD);
34 static BOOL (WINAPI *pFlsSetValue)(DWORD,PVOID);
35
36 static void *fibers[3];
37 static BYTE testparam = 185;
38 static DWORD fls_index_to_set = FLS_OUT_OF_INDEXES;
39 static void* fls_value_to_set;
40
41 static int fiberCount = 0;
42 static int cbCount = 0;
43
44 static VOID init_funcs(void)
45 {
46 HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
47
48 #define X(f) p##f = (void*)GetProcAddress(hKernel32, #f);
49 X(CreateFiber);
50 X(ConvertThreadToFiber);
51 X(ConvertFiberToThread);
52 X(SwitchToFiber);
53 X(DeleteFiber);
54 X(ConvertThreadToFiberEx);
55 X(CreateFiberEx);
56 X(IsThreadAFiber);
57 X(FlsAlloc);
58 X(FlsFree);
59 X(FlsGetValue);
60 X(FlsSetValue);
61 #undef X
62 }
63
64 static VOID WINAPI FiberLocalStorageProc(PVOID lpFlsData)
65 {
66 ok(lpFlsData == fls_value_to_set,
67 "FlsData expected not to be changed, value is %p, expected %p\n",
68 lpFlsData, fls_value_to_set);
69 cbCount++;
70 }
71
72 static VOID WINAPI FiberMainProc(LPVOID lpFiberParameter)
73 {
74 BYTE *tparam = (BYTE *)lpFiberParameter;
75 fiberCount++;
76 ok(*tparam == 185, "Parameterdata expected not to be changed\n");
77 if (fls_index_to_set != FLS_OUT_OF_INDEXES)
78 {
79 void* ret;
80 BOOL bret;
81
82 ret = pFlsGetValue(fls_index_to_set);
83 ok(ret == NULL, "FlsGetValue returned %p, expected NULL\n", ret);
84
85 /* Set the FLS value */
86 bret = pFlsSetValue(fls_index_to_set, fls_value_to_set);
87 ok(bret, "FlsSetValue failed with error %u\n", GetLastError());
88
89 /* Verify that FlsGetValue retrieves the value set by FlsSetValue */
90 SetLastError( 0xdeadbeef );
91 ret = pFlsGetValue(fls_index_to_set);
92 ok(ret == fls_value_to_set, "FlsGetValue returned %p, expected %p\n", ret, fls_value_to_set);
93 ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue error %u\n", GetLastError());
94 }
95 pSwitchToFiber(fibers[0]);
96 }
97
98 static void test_ConvertThreadToFiber(void)
99 {
100 if (pConvertThreadToFiber)
101 {
102 fibers[0] = pConvertThreadToFiber(&testparam);
103 ok(fibers[0] != NULL, "ConvertThreadToFiber failed with error %u\n", GetLastError());
104 }
105 else
106 {
107 win_skip( "ConvertThreadToFiber not present\n" );
108 }
109 }
110
111 static void test_ConvertThreadToFiberEx(void)
112 {
113 if (pConvertThreadToFiberEx)
114 {
115 fibers[0] = pConvertThreadToFiberEx(&testparam, 0);
116 ok(fibers[0] != NULL, "ConvertThreadToFiberEx failed with error %u\n", GetLastError());
117 }
118 else
119 {
120 win_skip( "ConvertThreadToFiberEx not present\n" );
121 }
122 }
123
124 static void test_ConvertFiberToThread(void)
125 {
126 if (pConvertFiberToThread)
127 {
128 BOOL ret = pConvertFiberToThread();
129 ok(ret, "ConvertFiberToThread failed with error %u\n", GetLastError());
130 }
131 else
132 {
133 win_skip( "ConvertFiberToThread not present\n" );
134 }
135 }
136
137 static void test_FiberHandling(void)
138 {
139 fiberCount = 0;
140 fibers[0] = pCreateFiber(0,FiberMainProc,&testparam);
141 ok(fibers[0] != NULL, "CreateFiber failed with error %u\n", GetLastError());
142 pDeleteFiber(fibers[0]);
143
144 test_ConvertThreadToFiber();
145 test_ConvertFiberToThread();
146 if (pConvertThreadToFiberEx)
147 test_ConvertThreadToFiberEx();
148 else
149 test_ConvertThreadToFiber();
150
151 fibers[1] = pCreateFiber(0,FiberMainProc,&testparam);
152 ok(fibers[1] != NULL, "CreateFiber failed with error %u\n", GetLastError());
153
154 pSwitchToFiber(fibers[1]);
155 ok(fiberCount == 1, "Wrong fiber count: %d\n", fiberCount);
156 pDeleteFiber(fibers[1]);
157
158 if (pCreateFiberEx)
159 {
160 fibers[1] = pCreateFiberEx(0,0,0,FiberMainProc,&testparam);
161 ok(fibers[1] != NULL, "CreateFiberEx failed with error %u\n", GetLastError());
162
163 pSwitchToFiber(fibers[1]);
164 ok(fiberCount == 2, "Wrong fiber count: %d\n", fiberCount);
165 pDeleteFiber(fibers[1]);
166 }
167 else win_skip( "CreateFiberEx not present\n" );
168
169 if (pIsThreadAFiber) ok(pIsThreadAFiber(), "IsThreadAFiber reported FALSE\n");
170 test_ConvertFiberToThread();
171 if (pIsThreadAFiber) ok(!pIsThreadAFiber(), "IsThreadAFiber reported TRUE\n");
172 }
173
174 static void test_FiberLocalStorage(void)
175 {
176 DWORD fls, fls_2;
177 BOOL ret;
178 void* val;
179
180 if (!pFlsAlloc || !pFlsSetValue || !pFlsGetValue || !pFlsFree)
181 {
182 win_skip( "Fiber Local Storage not supported\n" );
183 return;
184 }
185
186 /* Test an unallocated index
187 * FlsFree should fail
188 * FlsGetValue and FlsSetValue should succeed
189 */
190 SetLastError( 0xdeadbeef );
191 ret = pFlsFree( 127 );
192 ok( !ret, "freeing fls index 127 (unallocated) succeeded\n" );
193 ok( GetLastError() == ERROR_INVALID_PARAMETER,
194 "freeing fls index 127 (unallocated) wrong error %u\n", GetLastError() );
195
196 val = pFlsGetValue( 127 );
197 ok( val == NULL,
198 "getting fls index 127 (unallocated) failed with error %u\n", GetLastError() );
199
200 ret = pFlsSetValue( 127, (void*) 0x217 );
201 ok( ret, "setting fls index 127 (unallocated) failed with error %u\n", GetLastError() );
202
203 SetLastError( 0xdeadbeef );
204 val = pFlsGetValue( 127 );
205 ok( val == (void*) 0x217, "fls index 127 (unallocated) wrong value %p\n", val );
206 ok( GetLastError() == ERROR_SUCCESS,
207 "getting fls index 127 (unallocated) failed with error %u\n", GetLastError() );
208
209 /* FlsFree, FlsGetValue, and FlsSetValue out of bounds should return
210 * ERROR_INVALID_PARAMETER
211 */
212 SetLastError( 0xdeadbeef );
213 ret = pFlsFree( 128 );
214 ok( !ret, "freeing fls index 128 (out of bounds) succeeded\n" );
215 ok( GetLastError() == ERROR_INVALID_PARAMETER,
216 "freeing fls index 128 (out of bounds) wrong error %u\n", GetLastError() );
217
218 SetLastError( 0xdeadbeef );
219 ret = pFlsSetValue( 128, (void*) 0x217 );
220 ok( !ret, "setting fls index 128 (out of bounds) succeeded\n" );
221 ok( GetLastError() == ERROR_INVALID_PARAMETER,
222 "setting fls index 128 (out of bounds) wrong error %u\n", GetLastError() );
223
224 SetLastError( 0xdeadbeef );
225 val = pFlsGetValue( 128 );
226 ok( GetLastError() == ERROR_INVALID_PARAMETER,
227 "getting fls index 128 (out of bounds) wrong error %u\n", GetLastError() );
228
229 /* Test index 0 */
230 SetLastError( 0xdeadbeef );
231 val = pFlsGetValue( 0 );
232 ok( !val, "fls index 0 set to %p\n", val );
233 ok( GetLastError() == ERROR_INVALID_PARAMETER, "setting fls index wrong error %u\n", GetLastError() );
234 SetLastError( 0xdeadbeef );
235 ret = pFlsSetValue( 0, (void *)0xdeadbeef );
236 ok( !ret, "setting fls index 0 succeeded\n" );
237 ok( GetLastError() == ERROR_INVALID_PARAMETER, "setting fls index wrong error %u\n", GetLastError() );
238 SetLastError( 0xdeadbeef );
239 val = pFlsGetValue( 0 );
240 ok( !val, "fls index 0 wrong value %p\n", val );
241 ok( GetLastError() == ERROR_INVALID_PARAMETER, "setting fls index wrong error %u\n", GetLastError() );
242
243 /* Test creating an FLS index */
244 fls = pFlsAlloc( NULL );
245 ok( fls != FLS_OUT_OF_INDEXES, "FlsAlloc failed\n" );
246 ok( fls != 0, "fls index 0 allocated\n" );
247 val = pFlsGetValue( fls );
248 ok( !val, "fls index %u wrong value %p\n", fls, val );
249 ret = pFlsSetValue( fls, (void *)0xdeadbeef );
250 ok( ret, "setting fls index %u failed\n", fls );
251 SetLastError( 0xdeadbeef );
252 val = pFlsGetValue( fls );
253 ok( val == (void *)0xdeadbeef, "fls index %u wrong value %p\n", fls, val );
254 ok( GetLastError() == ERROR_SUCCESS,
255 "getting fls index %u failed with error %u\n", fls, GetLastError() );
256 pFlsFree( fls );
257
258 /* Undefined behavior: verify the value is NULL after it the slot is freed */
259 SetLastError( 0xdeadbeef );
260 val = pFlsGetValue( fls );
261 ok( val == NULL, "fls index %u wrong value %p\n", fls, val );
262 ok( GetLastError() == ERROR_SUCCESS,
263 "getting fls index %u failed with error %u\n", fls, GetLastError() );
264
265 /* Undefined behavior: verify the value is settable after the slot is freed */
266 ret = pFlsSetValue( fls, (void *)0xdeadbabe );
267 ok( ret, "setting fls index %u failed\n", fls );
268 val = pFlsGetValue( fls );
269 ok( val == (void *)0xdeadbabe, "fls index %u wrong value %p\n", fls, val );
270
271 /* Try to create the same FLS index again, and verify that is initialized to NULL */
272 fls_2 = pFlsAlloc( NULL );
273 ok( fls != FLS_OUT_OF_INDEXES, "FlsAlloc failed with error %u\n", GetLastError() );
274 /* If this fails it is not an API error, but the test will be inconclusive */
275 ok( fls_2 == fls, "different FLS index allocated, was %u, now %u\n", fls, fls_2 );
276
277 SetLastError( 0xdeadbeef );
278 val = pFlsGetValue( fls_2 );
279 ok( val == NULL, "fls index %u wrong value %p\n", fls, val );
280 ok( GetLastError() == ERROR_SUCCESS,
281 "getting fls index %u failed with error %u\n", fls_2, GetLastError() );
282 pFlsFree( fls_2 );
283 }
284
285 static void test_FiberLocalStorageCallback(PFLS_CALLBACK_FUNCTION cbfunc)
286 {
287 DWORD fls;
288 BOOL ret;
289 void* val, *val2;
290
291 if (!pFlsAlloc || !pFlsSetValue || !pFlsGetValue || !pFlsFree)
292 {
293 win_skip( "Fiber Local Storage not supported\n" );
294 return;
295 }
296
297 /* Test that the callback is executed */
298 cbCount = 0;
299 fls = pFlsAlloc( cbfunc );
300 ok( fls != FLS_OUT_OF_INDEXES, "FlsAlloc failed with error %u\n", GetLastError() );
301
302 val = (void*) 0x1587;
303 fls_value_to_set = val;
304 ret = pFlsSetValue( fls, val );
305 ok(ret, "FlsSetValue failed with error %u\n", GetLastError() );
306
307 val2 = pFlsGetValue( fls );
308 ok(val == val2, "FlsGetValue returned %p, expected %p\n", val2, val);
309
310 ret = pFlsFree( fls );
311 ok(ret, "FlsFree failed with error %u\n", GetLastError() );
312 todo_wine ok( cbCount == 1, "Wrong callback count: %d\n", cbCount );
313
314 /* Test that callback is not executed if value is NULL */
315 cbCount = 0;
316 fls = pFlsAlloc( cbfunc );
317 ok( fls != FLS_OUT_OF_INDEXES, "FlsAlloc failed with error %u\n", GetLastError() );
318
319 ret = pFlsSetValue( fls, NULL );
320 ok( ret, "FlsSetValue failed with error %u\n", GetLastError() );
321
322 pFlsFree( fls );
323 ok( ret, "FlsFree failed with error %u\n", GetLastError() );
324 ok( cbCount == 0, "Wrong callback count: %d\n", cbCount );
325 }
326
327 static void test_FiberLocalStorageWithFibers(PFLS_CALLBACK_FUNCTION cbfunc)
328 {
329 void* val1 = (void*) 0x314;
330 void* val2 = (void*) 0x152;
331 BOOL ret;
332
333 if (!pFlsAlloc || !pFlsFree || !pFlsSetValue || !pFlsGetValue)
334 {
335 win_skip( "Fiber Local Storage not supported\n" );
336 return;
337 }
338
339 fls_index_to_set = pFlsAlloc(cbfunc);
340 ok(fls_index_to_set != FLS_OUT_OF_INDEXES, "FlsAlloc failed with error %u\n", GetLastError());
341
342 test_ConvertThreadToFiber();
343
344 fiberCount = 0;
345 cbCount = 0;
346 fibers[1] = pCreateFiber(0,FiberMainProc,&testparam);
347 fibers[2] = pCreateFiber(0,FiberMainProc,&testparam);
348 ok(fibers[1] != NULL, "CreateFiber failed with error %u\n", GetLastError());
349 ok(fibers[2] != NULL, "CreateFiber failed with error %u\n", GetLastError());
350 ok(fiberCount == 0, "Wrong fiber count: %d\n", fiberCount);
351 ok(cbCount == 0, "Wrong callback count: %d\n", cbCount);
352
353 fiberCount = 0;
354 cbCount = 0;
355 fls_value_to_set = val1;
356 pSwitchToFiber(fibers[1]);
357 ok(fiberCount == 1, "Wrong fiber count: %d\n", fiberCount);
358 ok(cbCount == 0, "Wrong callback count: %d\n", cbCount);
359
360 fiberCount = 0;
361 cbCount = 0;
362 fls_value_to_set = val2;
363 pSwitchToFiber(fibers[2]);
364 ok(fiberCount == 1, "Wrong fiber count: %d\n", fiberCount);
365 ok(cbCount == 0, "Wrong callback count: %d\n", cbCount);
366
367 fls_value_to_set = val2;
368 ret = pFlsSetValue(fls_index_to_set, fls_value_to_set);
369 ok(ret, "FlsSetValue failed\n");
370 ok(val2 == pFlsGetValue(fls_index_to_set), "FlsGetValue failed\n");
371
372 fiberCount = 0;
373 cbCount = 0;
374 fls_value_to_set = val1;
375 pDeleteFiber(fibers[1]);
376 ok(fiberCount == 0, "Wrong fiber count: %d\n", fiberCount);
377 todo_wine ok(cbCount == 1, "Wrong callback count: %d\n", cbCount);
378
379 fiberCount = 0;
380 cbCount = 0;
381 fls_value_to_set = val2;
382 pFlsFree(fls_index_to_set);
383 ok(fiberCount == 0, "Wrong fiber count: %d\n", fiberCount);
384 todo_wine ok(cbCount == 2, "Wrong callback count: %d\n", cbCount);
385
386 fiberCount = 0;
387 cbCount = 0;
388 fls_value_to_set = val1;
389 pDeleteFiber(fibers[2]);
390 ok(fiberCount == 0, "Wrong fiber count: %d\n", fiberCount);
391 ok(cbCount == 0, "Wrong callback count: %d\n", cbCount);
392
393 test_ConvertFiberToThread();
394 }
395
396 START_TEST(fiber)
397 {
398 init_funcs();
399
400 if (!pCreateFiber)
401 {
402 win_skip( "Fibers not supported by win95\n" );
403 return;
404 }
405
406 test_FiberHandling();
407 test_FiberLocalStorage();
408 test_FiberLocalStorageCallback(FiberLocalStorageProc);
409 test_FiberLocalStorageWithFibers(FiberLocalStorageProc);
410 }