2 * Unit tests for fiber functions
4 * Copyright (c) 2010 André Hentschel
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.
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.
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
21 #include "wine/test.h"
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
);
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
;
41 static int fiberCount
= 0;
42 static int cbCount
= 0;
44 static VOID
init_funcs(void)
46 HMODULE hKernel32
= GetModuleHandleA("kernel32.dll");
48 #define X(f) p##f = (void*)GetProcAddress(hKernel32, #f);
50 X(ConvertThreadToFiber
);
51 X(ConvertFiberToThread
);
54 X(ConvertThreadToFiberEx
);
64 static VOID WINAPI
FiberLocalStorageProc(PVOID lpFlsData
)
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
);
72 static VOID WINAPI
FiberMainProc(LPVOID lpFiberParameter
)
74 BYTE
*tparam
= (BYTE
*)lpFiberParameter
;
76 ok(*tparam
== 185, "Parameterdata expected not to be changed\n");
77 if (fls_index_to_set
!= FLS_OUT_OF_INDEXES
)
82 ret
= pFlsGetValue(fls_index_to_set
);
83 ok(ret
== NULL
, "FlsGetValue returned %p, expected NULL\n", ret
);
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());
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());
95 pSwitchToFiber(fibers
[0]);
98 static void test_ConvertThreadToFiber(void)
100 if (pConvertThreadToFiber
)
102 fibers
[0] = pConvertThreadToFiber(&testparam
);
103 ok(fibers
[0] != NULL
, "ConvertThreadToFiber failed with error %u\n", GetLastError());
107 win_skip( "ConvertThreadToFiber not present\n" );
111 static void test_ConvertThreadToFiberEx(void)
113 if (pConvertThreadToFiberEx
)
115 fibers
[0] = pConvertThreadToFiberEx(&testparam
, 0);
116 ok(fibers
[0] != NULL
, "ConvertThreadToFiberEx failed with error %u\n", GetLastError());
120 win_skip( "ConvertThreadToFiberEx not present\n" );
124 static void test_ConvertFiberToThread(void)
126 if (pConvertFiberToThread
)
128 BOOL ret
= pConvertFiberToThread();
129 ok(ret
, "ConvertFiberToThread failed with error %u\n", GetLastError());
133 win_skip( "ConvertFiberToThread not present\n" );
137 static void test_FiberHandling(void)
140 fibers
[0] = pCreateFiber(0,FiberMainProc
,&testparam
);
141 ok(fibers
[0] != NULL
, "CreateFiber failed with error %u\n", GetLastError());
142 pDeleteFiber(fibers
[0]);
144 test_ConvertThreadToFiber();
145 test_ConvertFiberToThread();
146 if (pConvertThreadToFiberEx
)
147 test_ConvertThreadToFiberEx();
149 test_ConvertThreadToFiber();
151 fibers
[1] = pCreateFiber(0,FiberMainProc
,&testparam
);
152 ok(fibers
[1] != NULL
, "CreateFiber failed with error %u\n", GetLastError());
154 pSwitchToFiber(fibers
[1]);
155 ok(fiberCount
== 1, "Wrong fiber count: %d\n", fiberCount
);
156 pDeleteFiber(fibers
[1]);
160 fibers
[1] = pCreateFiberEx(0,0,0,FiberMainProc
,&testparam
);
161 ok(fibers
[1] != NULL
, "CreateFiberEx failed with error %u\n", GetLastError());
163 pSwitchToFiber(fibers
[1]);
164 ok(fiberCount
== 2, "Wrong fiber count: %d\n", fiberCount
);
165 pDeleteFiber(fibers
[1]);
167 else win_skip( "CreateFiberEx not present\n" );
169 if (pIsThreadAFiber
) ok(pIsThreadAFiber(), "IsThreadAFiber reported FALSE\n");
170 test_ConvertFiberToThread();
171 if (pIsThreadAFiber
) ok(!pIsThreadAFiber(), "IsThreadAFiber reported TRUE\n");
174 static void test_FiberLocalStorage(void)
180 if (!pFlsAlloc
|| !pFlsSetValue
|| !pFlsGetValue
|| !pFlsFree
)
182 win_skip( "Fiber Local Storage not supported\n" );
186 /* Test an unallocated index
187 * FlsFree should fail
188 * FlsGetValue and FlsSetValue should succeed
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() );
196 val
= pFlsGetValue( 127 );
198 "getting fls index 127 (unallocated) failed with error %u\n", GetLastError() );
200 ret
= pFlsSetValue( 127, (void*) 0x217 );
201 ok( ret
, "setting fls index 127 (unallocated) failed with error %u\n", GetLastError() );
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() );
209 /* FlsFree, FlsGetValue, and FlsSetValue out of bounds should return
210 * ERROR_INVALID_PARAMETER
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() );
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() );
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() );
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() );
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() );
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() );
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
);
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
);
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() );
285 static void test_FiberLocalStorageCallback(PFLS_CALLBACK_FUNCTION cbfunc
)
291 if (!pFlsAlloc
|| !pFlsSetValue
|| !pFlsGetValue
|| !pFlsFree
)
293 win_skip( "Fiber Local Storage not supported\n" );
297 /* Test that the callback is executed */
299 fls
= pFlsAlloc( cbfunc
);
300 ok( fls
!= FLS_OUT_OF_INDEXES
, "FlsAlloc failed with error %u\n", GetLastError() );
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() );
307 val2
= pFlsGetValue( fls
);
308 ok(val
== val2
, "FlsGetValue returned %p, expected %p\n", val2
, val
);
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
);
314 /* Test that callback is not executed if value is NULL */
316 fls
= pFlsAlloc( cbfunc
);
317 ok( fls
!= FLS_OUT_OF_INDEXES
, "FlsAlloc failed with error %u\n", GetLastError() );
319 ret
= pFlsSetValue( fls
, NULL
);
320 ok( ret
, "FlsSetValue failed with error %u\n", GetLastError() );
323 ok( ret
, "FlsFree failed with error %u\n", GetLastError() );
324 ok( cbCount
== 0, "Wrong callback count: %d\n", cbCount
);
327 static void test_FiberLocalStorageWithFibers(PFLS_CALLBACK_FUNCTION cbfunc
)
329 void* val1
= (void*) 0x314;
330 void* val2
= (void*) 0x152;
333 if (!pFlsAlloc
|| !pFlsFree
|| !pFlsSetValue
|| !pFlsGetValue
)
335 win_skip( "Fiber Local Storage not supported\n" );
339 fls_index_to_set
= pFlsAlloc(cbfunc
);
340 ok(fls_index_to_set
!= FLS_OUT_OF_INDEXES
, "FlsAlloc failed with error %u\n", GetLastError());
342 test_ConvertThreadToFiber();
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
);
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
);
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
);
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");
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
);
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
);
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
);
393 test_ConvertFiberToThread();
402 win_skip( "Fibers not supported by win95\n" );
406 test_FiberHandling();
407 test_FiberLocalStorage();
408 test_FiberLocalStorageCallback(FiberLocalStorageProc
);
409 test_FiberLocalStorageWithFibers(FiberLocalStorageProc
);