ntdll: Ensure force_exec_prot is also used for views with write watch permissions.
[wine.git] / dlls / kernel32 / tests / thread.c
blobd3ecd2a60de5c6f050f323719d1443ac65f2266c
1 /*
2 * Unit test suite for thread functions.
4 * Copyright 2002 Geoffrey Hausheer
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 /* Define _WIN32_WINNT to get SetThreadIdealProcessor on Windows */
22 #define _WIN32_WINNT 0x0600
24 #include <assert.h>
25 #include <stdarg.h>
26 #include <stdio.h>
28 /* the tests intentionally pass invalid pointers and need an exception handler */
29 #define WINE_NO_INLINE_STRING
31 #include <windef.h>
32 #include <winbase.h>
33 #include <winnt.h>
34 #include <winerror.h>
35 #include <winnls.h>
36 #include "wine/test.h"
38 /* THREAD_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */
39 #define THREAD_ALL_ACCESS_NT4 (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3ff)
41 /* Specify the number of simultaneous threads to test */
42 #define NUM_THREADS 4
43 /* Specify whether to test the extended priorities for Win2k/XP */
44 #define USE_EXTENDED_PRIORITIES 0
45 /* Specify whether to test the stack allocation in CreateThread */
46 #define CHECK_STACK 0
48 /* Set CHECK_STACK to 1 if you want to try to test the stack-limit from
49 CreateThread. So far I have been unable to make this work, and
50 I am in doubt as to how portable it is. Also, according to MSDN,
51 you shouldn't mix C-run-time-libraries (i.e. alloca) with CreateThread.
52 Anyhow, the check is currently commented out
54 #if CHECK_STACK
55 # ifdef __try
56 # define __TRY __try
57 # define __EXCEPT __except
58 # define __ENDTRY
59 # else
60 # include "wine/exception.h"
61 # endif
62 #endif
64 #ifdef __i386__
65 #define ARCH "x86"
66 #elif defined __x86_64__
67 #define ARCH "amd64"
68 #else
69 #define ARCH "none"
70 #endif
72 static BOOL (WINAPI *pGetThreadPriorityBoost)(HANDLE,PBOOL);
73 static HANDLE (WINAPI *pOpenThread)(DWORD,BOOL,DWORD);
74 static BOOL (WINAPI *pQueueUserWorkItem)(LPTHREAD_START_ROUTINE,PVOID,ULONG);
75 static DWORD (WINAPI *pSetThreadIdealProcessor)(HANDLE,DWORD);
76 static BOOL (WINAPI *pSetThreadPriorityBoost)(HANDLE,BOOL);
77 static BOOL (WINAPI *pRegisterWaitForSingleObject)(PHANDLE,HANDLE,WAITORTIMERCALLBACK,PVOID,ULONG,ULONG);
78 static BOOL (WINAPI *pUnregisterWait)(HANDLE);
79 static BOOL (WINAPI *pIsWow64Process)(HANDLE,PBOOL);
80 static BOOL (WINAPI *pSetThreadErrorMode)(DWORD,PDWORD);
81 static DWORD (WINAPI *pGetThreadErrorMode)(void);
82 static DWORD (WINAPI *pRtlGetThreadErrorMode)(void);
83 static BOOL (WINAPI *pActivateActCtx)(HANDLE,ULONG_PTR*);
84 static HANDLE (WINAPI *pCreateActCtxW)(PCACTCTXW);
85 static BOOL (WINAPI *pDeactivateActCtx)(DWORD,ULONG_PTR);
86 static BOOL (WINAPI *pGetCurrentActCtx)(HANDLE *);
87 static void (WINAPI *pReleaseActCtx)(HANDLE);
88 static PTP_POOL (WINAPI *pCreateThreadpool)(PVOID);
89 static PTP_WORK (WINAPI *pCreateThreadpoolWork)(PTP_WORK_CALLBACK,PVOID,PTP_CALLBACK_ENVIRON);
90 static void (WINAPI *pSubmitThreadpoolWork)(PTP_WORK);
91 static void (WINAPI *pWaitForThreadpoolWorkCallbacks)(PTP_WORK,BOOL);
92 static void (WINAPI *pCloseThreadpoolWork)(PTP_WORK);
94 static HANDLE create_target_process(const char *arg)
96 char **argv;
97 char cmdline[MAX_PATH];
98 PROCESS_INFORMATION pi;
99 BOOL ret;
100 STARTUPINFOA si = { 0 };
101 si.cb = sizeof(si);
103 winetest_get_mainargs( &argv );
104 sprintf(cmdline, "%s %s %s", argv[0], argv[1], arg);
105 ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
106 ok(ret, "error: %u\n", GetLastError());
107 ret = CloseHandle(pi.hThread);
108 ok(ret, "error %u\n", GetLastError());
109 return pi.hProcess;
112 /* Functions not tested yet:
113 AttachThreadInput
114 SetThreadContext
115 SwitchToThread
117 In addition there are no checks that the inheritance works properly in
118 CreateThread
121 /* Functions to ensure that from a group of threads, only one executes
122 certain chunks of code at a time, and we know which one is executing
123 it. It basically makes multithreaded execution linear, which defeats
124 the purpose of multiple threads, but makes testing easy. */
125 static HANDLE start_event, stop_event;
126 static LONG num_synced;
128 static void init_thread_sync_helpers(void)
130 start_event = CreateEventW(NULL, TRUE, FALSE, NULL);
131 ok(start_event != NULL, "CreateEvent failed\n");
132 stop_event = CreateEventW(NULL, TRUE, FALSE, NULL);
133 ok(stop_event != NULL, "CreateEvent failed\n");
134 num_synced = -1;
137 static BOOL sync_threads_and_run_one(DWORD sync_id, DWORD my_id)
139 LONG num = InterlockedIncrement(&num_synced);
140 assert(-1 <= num && num <= 1);
141 if (num == 1)
143 ResetEvent( stop_event );
144 SetEvent( start_event );
146 else
148 DWORD ret = WaitForSingleObject(start_event, 10000);
149 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed %x\n",ret);
151 return sync_id == my_id;
154 static void resync_after_run(void)
156 LONG num = InterlockedDecrement(&num_synced);
157 assert(-1 <= num && num <= 1);
158 if (num == -1)
160 ResetEvent( start_event );
161 SetEvent( stop_event );
163 else
165 DWORD ret = WaitForSingleObject(stop_event, 10000);
166 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
170 static void cleanup_thread_sync_helpers(void)
172 CloseHandle(start_event);
173 CloseHandle(stop_event);
176 static DWORD tlsIndex;
178 typedef struct {
179 int threadnum;
180 HANDLE *event;
181 DWORD *threadmem;
182 } t1Struct;
184 /* WinME supports OpenThread but doesn't know about access restrictions so
185 we require them to be either completely ignored or always obeyed.
187 static INT obeying_ars = 0; /* -1 == no, 0 == dunno yet, 1 == yes */
188 #define obey_ar(x) \
189 (obeying_ars == 0 \
190 ? ((x) \
191 ? (obeying_ars = +1) \
192 : ((obeying_ars = -1), \
193 trace("not restricted, assuming consistent behaviour\n"))) \
194 : (obeying_ars < 0) \
195 ? ok(!(x), "access restrictions obeyed\n") \
196 : ok( (x), "access restrictions not obeyed\n"))
198 /* Basic test that simultaneous threads can access shared memory,
199 that the thread local storage routines work correctly, and that
200 threads actually run concurrently
202 static DWORD WINAPI threadFunc1(LPVOID p)
204 t1Struct *tstruct = p;
205 int i;
206 /* write our thread # into shared memory */
207 tstruct->threadmem[tstruct->threadnum]=GetCurrentThreadId();
208 ok(TlsSetValue(tlsIndex,(LPVOID)(INT_PTR)(tstruct->threadnum+1))!=0,
209 "TlsSetValue failed\n");
210 /* The threads synchronize before terminating. This is done by
211 Signaling an event, and waiting for all events to occur
213 SetEvent(tstruct->event[tstruct->threadnum]);
214 WaitForMultipleObjects(NUM_THREADS,tstruct->event,TRUE,INFINITE);
215 /* Double check that all threads really did run by validating that
216 they have all written to the shared memory. There should be no race
217 here, since all threads were synchronized after the write.*/
218 for(i=0;i<NUM_THREADS;i++) {
219 while(tstruct->threadmem[i]==0) ;
222 /* lstrlenA contains an exception handler so this makes sure exceptions work in threads */
223 ok( lstrlenA( (char *)0xdeadbeef ) == 0, "lstrlenA: unexpected success\n" );
225 /* Check that no one changed our tls memory */
226 ok((INT_PTR)TlsGetValue(tlsIndex)-1==tstruct->threadnum,
227 "TlsGetValue failed\n");
228 return NUM_THREADS+tstruct->threadnum;
231 static DWORD WINAPI threadFunc2(LPVOID p)
233 return 99;
236 static DWORD WINAPI threadFunc3(LPVOID p)
238 HANDLE thread;
239 thread=GetCurrentThread();
240 SuspendThread(thread);
241 return 99;
244 static DWORD WINAPI threadFunc4(LPVOID p)
246 HANDLE event = p;
247 if(event != NULL) {
248 SetEvent(event);
250 Sleep(99000);
251 return 0;
254 #if CHECK_STACK
255 static DWORD WINAPI threadFunc5(LPVOID p)
257 DWORD *exitCode = p;
258 SYSTEM_INFO sysInfo;
259 sysInfo.dwPageSize=0;
260 GetSystemInfo(&sysInfo);
261 *exitCode=0;
262 __TRY
264 alloca(2*sysInfo.dwPageSize);
266 __EXCEPT(1) {
267 *exitCode=1;
269 __ENDTRY
270 return 0;
272 #endif
274 static DWORD WINAPI threadFunc_SetEvent(LPVOID p)
276 SetEvent(p);
277 return 0;
280 static DWORD WINAPI threadFunc_CloseHandle(LPVOID p)
282 CloseHandle(p);
283 return 0;
286 struct thread_actctx_param
288 HANDLE thread_context;
289 HANDLE handle;
292 static DWORD WINAPI thread_actctx_func(void *p)
294 struct thread_actctx_param *param = (struct thread_actctx_param*)p;
295 HANDLE cur;
296 BOOL ret;
298 cur = (void*)0xdeadbeef;
299 ret = pGetCurrentActCtx(&cur);
300 ok(ret, "thread GetCurrentActCtx failed, %u\n", GetLastError());
301 ok(cur == param->handle, "got %p, expected %p\n", cur, param->handle);
302 param->thread_context = cur;
304 return 0;
307 static void create_function_addr_events(HANDLE events[2])
309 char buffer[256];
311 sprintf(buffer, "threadFunc_SetEvent %p", threadFunc_SetEvent);
312 events[0] = CreateEventA(NULL, FALSE, FALSE, buffer);
314 sprintf(buffer, "threadFunc_CloseHandle %p", threadFunc_CloseHandle);
315 events[1] = CreateEventA(NULL, FALSE, FALSE, buffer);
318 /* check CreateRemoteThread */
319 static VOID test_CreateRemoteThread(void)
321 HANDLE hProcess, hThread, hEvent, hRemoteEvent;
322 DWORD tid, ret, exitcode;
323 HANDLE hAddrEvents[2];
325 hProcess = create_target_process("sleep");
326 ok(hProcess != NULL, "Can't start process\n");
328 /* ensure threadFunc_SetEvent & threadFunc_CloseHandle are the same
329 * address as in the child process */
330 create_function_addr_events(hAddrEvents);
331 ret = WaitForMultipleObjects(2, hAddrEvents, TRUE, 5000);
332 if (ret == WAIT_TIMEOUT)
334 skip("child process wasn't mapped at same address, so can't do CreateRemoteThread tests.\n");
335 return;
337 ok(ret == WAIT_OBJECT_0 || broken(ret == WAIT_OBJECT_0+1 /* nt4,w2k */), "WaitForAllObjects 2 events %d\n", ret);
339 hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
340 ok(hEvent != NULL, "Can't create event, err=%u\n", GetLastError());
341 ret = DuplicateHandle(GetCurrentProcess(), hEvent, hProcess, &hRemoteEvent,
342 0, FALSE, DUPLICATE_SAME_ACCESS);
343 ok(ret != 0, "DuplicateHandle failed, err=%u\n", GetLastError());
345 /* create suspended remote thread with entry point SetEvent() */
346 SetLastError(0xdeadbeef);
347 hThread = CreateRemoteThread(hProcess, NULL, 0, threadFunc_SetEvent,
348 hRemoteEvent, CREATE_SUSPENDED, &tid);
349 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
351 win_skip("CreateRemoteThread is not implemented\n");
352 goto cleanup;
354 ok(hThread != NULL, "CreateRemoteThread failed, err=%u\n", GetLastError());
355 ok(tid != 0, "null tid\n");
356 ret = SuspendThread(hThread);
357 ok(ret == 1, "ret=%u, err=%u\n", ret, GetLastError());
358 ret = ResumeThread(hThread);
359 ok(ret == 2, "ret=%u, err=%u\n", ret, GetLastError());
361 /* thread still suspended, so wait times out */
362 ret = WaitForSingleObject(hEvent, 1000);
363 ok(ret == WAIT_TIMEOUT, "wait did not time out, ret=%u\n", ret);
365 ret = ResumeThread(hThread);
366 ok(ret == 1, "ret=%u, err=%u\n", ret, GetLastError());
368 /* wait that doesn't time out */
369 ret = WaitForSingleObject(hEvent, 1000);
370 ok(ret == WAIT_OBJECT_0, "object not signaled, ret=%u\n", ret);
372 /* wait for thread end */
373 ret = WaitForSingleObject(hThread, 1000);
374 ok(ret == WAIT_OBJECT_0, "waiting for thread failed, ret=%u\n", ret);
375 CloseHandle(hThread);
377 /* create and wait for remote thread with entry point CloseHandle() */
378 hThread = CreateRemoteThread(hProcess, NULL, 0,
379 threadFunc_CloseHandle,
380 hRemoteEvent, 0, &tid);
381 ok(hThread != NULL, "CreateRemoteThread failed, err=%u\n", GetLastError());
382 ret = WaitForSingleObject(hThread, 1000);
383 ok(ret == WAIT_OBJECT_0, "waiting for thread failed, ret=%u\n", ret);
384 CloseHandle(hThread);
386 /* create remote thread with entry point SetEvent() */
387 hThread = CreateRemoteThread(hProcess, NULL, 0,
388 threadFunc_SetEvent,
389 hRemoteEvent, 0, &tid);
390 ok(hThread != NULL, "CreateRemoteThread failed, err=%u\n", GetLastError());
392 /* closed handle, so wait times out */
393 ret = WaitForSingleObject(hEvent, 1000);
394 ok(ret == WAIT_TIMEOUT, "wait did not time out, ret=%u\n", ret);
396 /* check that remote SetEvent() failed */
397 ret = GetExitCodeThread(hThread, &exitcode);
398 ok(ret != 0, "GetExitCodeThread failed, err=%u\n", GetLastError());
399 if (ret) ok(exitcode == 0, "SetEvent succeeded, expected to fail\n");
400 CloseHandle(hThread);
402 cleanup:
403 TerminateProcess(hProcess, 0);
404 CloseHandle(hEvent);
405 CloseHandle(hProcess);
408 /* Check basic functionality of CreateThread and Tls* functions */
409 static VOID test_CreateThread_basic(void)
411 HANDLE thread[NUM_THREADS],event[NUM_THREADS];
412 DWORD threadid[NUM_THREADS],curthreadId;
413 DWORD threadmem[NUM_THREADS];
414 DWORD exitCode;
415 t1Struct tstruct[NUM_THREADS];
416 int error;
417 DWORD i,j;
418 DWORD GLE, ret;
419 DWORD tid;
420 BOOL bRet;
422 /* lstrlenA contains an exception handler so this makes sure exceptions work in the main thread */
423 ok( lstrlenA( (char *)0xdeadbeef ) == 0, "lstrlenA: unexpected success\n" );
425 /* Retrieve current Thread ID for later comparisons */
426 curthreadId=GetCurrentThreadId();
427 /* Allocate some local storage */
428 ok((tlsIndex=TlsAlloc())!=TLS_OUT_OF_INDEXES,"TlsAlloc failed\n");
429 /* Create events for thread synchronization */
430 for(i=0;i<NUM_THREADS;i++) {
431 threadmem[i]=0;
432 /* Note that it doesn't matter what type of event we choose here. This
433 test isn't trying to thoroughly test events
435 event[i]=CreateEventA(NULL,TRUE,FALSE,NULL);
436 tstruct[i].threadnum=i;
437 tstruct[i].threadmem=threadmem;
438 tstruct[i].event=event;
441 /* Test that passing arguments to threads works okay */
442 for(i=0;i<NUM_THREADS;i++) {
443 thread[i] = CreateThread(NULL,0,threadFunc1,
444 &tstruct[i],0,&threadid[i]);
445 ok(thread[i]!=NULL,"Create Thread failed\n");
447 /* Test that the threads actually complete */
448 for(i=0;i<NUM_THREADS;i++) {
449 error=WaitForSingleObject(thread[i],5000);
450 ok(error==WAIT_OBJECT_0, "Thread did not complete within timelimit\n");
451 if(error!=WAIT_OBJECT_0) {
452 TerminateThread(thread[i],i+NUM_THREADS);
454 ok(GetExitCodeThread(thread[i],&exitCode),"Could not retrieve ext code\n");
455 ok(exitCode==i+NUM_THREADS,"Thread returned an incorrect exit code\n");
457 /* Test that each thread executed in its parent's address space
458 (it was able to change threadmem and pass that change back to its parent)
459 and that each thread id was independent). Note that we prove that the
460 threads actually execute concurrently by having them block on each other
461 in threadFunc1
463 for(i=0;i<NUM_THREADS;i++) {
464 error=0;
465 for(j=i+1;j<NUM_THREADS;j++) {
466 if (threadmem[i]==threadmem[j]) {
467 error=1;
470 ok(!error && threadmem[i]==threadid[i] && threadmem[i]!=curthreadId,
471 "Thread did not execute successfully\n");
472 ok(CloseHandle(thread[i])!=0,"CloseHandle failed\n");
475 SetLastError(0xCAFEF00D);
476 bRet = TlsFree(tlsIndex);
477 ok(bRet, "TlsFree failed: %08x\n", GetLastError());
478 ok(GetLastError()==0xCAFEF00D,
479 "GetLastError: expected 0xCAFEF00D, got %08x\n", GetLastError());
481 /* Test freeing an already freed TLS index */
482 SetLastError(0xCAFEF00D);
483 ok(TlsFree(tlsIndex)==0,"TlsFree succeeded\n");
484 ok(GetLastError()==ERROR_INVALID_PARAMETER,
485 "GetLastError: expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
487 /* Test how passing NULL as a pointer to threadid works */
488 SetLastError(0xFACEaBAD);
489 thread[0] = CreateThread(NULL,0,threadFunc2,NULL,0,&tid);
490 GLE = GetLastError();
491 if (thread[0]) { /* NT */
492 ok(GLE==0xFACEaBAD, "CreateThread set last error to %d, expected 4207848365\n", GLE);
493 ret = WaitForSingleObject(thread[0],100);
494 ok(ret==WAIT_OBJECT_0, "threadFunc2 did not exit during 100 ms\n");
495 ret = GetExitCodeThread(thread[0],&exitCode);
496 ok(ret!=0, "GetExitCodeThread returned %d (expected nonzero)\n", ret);
497 ok(exitCode==99, "threadFunc2 exited with code: %d (expected 99)\n", exitCode);
498 ok(CloseHandle(thread[0])!=0,"Error closing thread handle\n");
500 else { /* 9x */
501 ok(GLE==ERROR_INVALID_PARAMETER, "CreateThread set last error to %d, expected 87\n", GLE);
505 /* Check that using the CREATE_SUSPENDED flag works */
506 static VOID test_CreateThread_suspended(void)
508 HANDLE thread;
509 DWORD threadId;
510 DWORD suspend_count;
511 int error;
513 thread = CreateThread(NULL,0,threadFunc2,NULL,
514 CREATE_SUSPENDED,&threadId);
515 ok(thread!=NULL,"Create Thread failed\n");
516 /* Check that the thread is suspended */
517 ok(SuspendThread(thread)==1,"Thread did not start suspended\n");
518 ok(ResumeThread(thread)==2,"Resume thread returned an invalid value\n");
519 /* Check that resume thread didn't actually start the thread. I can't think
520 of a better way of checking this than just waiting. I am not sure if this
521 will work on slow computers.
523 ok(WaitForSingleObject(thread,1000)==WAIT_TIMEOUT,
524 "ResumeThread should not have actually started the thread\n");
525 /* Now actually resume the thread and make sure that it actually completes*/
526 ok(ResumeThread(thread)==1,"Resume thread returned an invalid value\n");
527 ok((error=WaitForSingleObject(thread,1000))==WAIT_OBJECT_0,
528 "Thread did not resume\n");
529 if(error!=WAIT_OBJECT_0) {
530 TerminateThread(thread,1);
533 suspend_count = SuspendThread(thread);
534 ok(suspend_count == -1, "SuspendThread returned %d, expected -1\n", suspend_count);
536 suspend_count = ResumeThread(thread);
537 ok(suspend_count == 0 ||
538 broken(suspend_count == -1), /* win9x */
539 "ResumeThread returned %d, expected 0\n", suspend_count);
541 ok(CloseHandle(thread)!=0,"CloseHandle failed\n");
544 /* Check that SuspendThread and ResumeThread work */
545 static VOID test_SuspendThread(void)
547 HANDLE thread,access_thread;
548 DWORD threadId,exitCode,error;
549 int i;
551 thread = CreateThread(NULL,0,threadFunc3,NULL,
552 0,&threadId);
553 ok(thread!=NULL,"Create Thread failed\n");
554 /* Check that the thread is suspended */
555 /* Note that this is a polling method, and there is a race between
556 SuspendThread being called (in the child, and the loop below timing out,
557 so the test could fail on a heavily loaded or slow computer.
559 error=0;
560 for(i=0;error==0 && i<100;i++) {
561 error=SuspendThread(thread);
562 ResumeThread(thread);
563 if(error==0) {
564 Sleep(50);
565 i++;
568 ok(error==1,"SuspendThread did not work\n");
569 /* check that access restrictions are obeyed */
570 if (pOpenThread) {
571 access_thread=pOpenThread(THREAD_ALL_ACCESS_NT4 & (~THREAD_SUSPEND_RESUME),
572 0,threadId);
573 ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
574 if (access_thread!=NULL) {
575 obey_ar(SuspendThread(access_thread)==~0U);
576 obey_ar(ResumeThread(access_thread)==~0U);
577 ok(CloseHandle(access_thread)!=0,"CloseHandle Failed\n");
580 /* Double check that the thread really is suspended */
581 ok((error=GetExitCodeThread(thread,&exitCode))!=0 && exitCode==STILL_ACTIVE,
582 "Thread did not really suspend\n");
583 /* Resume the thread, and make sure it actually completes */
584 ok(ResumeThread(thread)==1,"Resume thread returned an invalid value\n");
585 ok((error=WaitForSingleObject(thread,1000))==WAIT_OBJECT_0,
586 "Thread did not resume\n");
587 if(error!=WAIT_OBJECT_0) {
588 TerminateThread(thread,1);
590 /* Trying to suspend a terminated thread should fail */
591 error=SuspendThread(thread);
592 ok(error==~0U, "wrong return code: %d\n", error);
593 ok(GetLastError()==ERROR_ACCESS_DENIED || GetLastError()==ERROR_NO_MORE_ITEMS, "unexpected error code: %d\n", GetLastError());
595 ok(CloseHandle(thread)!=0,"CloseHandle Failed\n");
598 /* Check that TerminateThread works properly
600 static VOID test_TerminateThread(void)
602 HANDLE thread,access_thread,event;
603 DWORD threadId,exitCode;
604 event=CreateEventA(NULL,TRUE,FALSE,NULL);
605 thread = CreateThread(NULL,0,threadFunc4,event,0,&threadId);
606 ok(thread!=NULL,"Create Thread failed\n");
607 /* TerminateThread has a race condition in Wine. If the thread is terminated
608 before it starts, it leaves a process behind. Therefore, we wait for the
609 thread to signal that it has started. There is no easy way to force the
610 race to occur, so we don't try to find it.
612 ok(WaitForSingleObject(event,5000)==WAIT_OBJECT_0,
613 "TerminateThread didn't work\n");
614 /* check that access restrictions are obeyed */
615 if (pOpenThread) {
616 access_thread=pOpenThread(THREAD_ALL_ACCESS_NT4 & (~THREAD_TERMINATE),
617 0,threadId);
618 ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
619 if (access_thread!=NULL) {
620 obey_ar(TerminateThread(access_thread,99)==0);
621 ok(CloseHandle(access_thread)!=0,"CloseHandle Failed\n");
624 /* terminate a job and make sure it terminates */
625 ok(TerminateThread(thread,99)!=0,"TerminateThread failed\n");
626 ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
627 "TerminateThread didn't work\n");
628 ok(GetExitCodeThread(thread,&exitCode)!=STILL_ACTIVE,
629 "TerminateThread should not leave the thread 'STILL_ACTIVE'\n");
630 ok(exitCode==99, "TerminateThread returned invalid exit code\n");
631 ok(CloseHandle(thread)!=0,"Error Closing thread handle\n");
634 /* Check if CreateThread obeys the specified stack size. This code does
635 not work properly, and is currently disabled
637 static VOID test_CreateThread_stack(void)
639 #if CHECK_STACK
640 /* The only way I know of to test the stack size is to use alloca
641 and __try/__except. However, this is probably not portable,
642 and I couldn't get it to work under Wine anyhow. However, here
643 is the code which should allow for testing that CreateThread
644 respects the stack-size limit
646 HANDLE thread;
647 DWORD threadId,exitCode;
649 SYSTEM_INFO sysInfo;
650 sysInfo.dwPageSize=0;
651 GetSystemInfo(&sysInfo);
652 ok(sysInfo.dwPageSize>0,"GetSystemInfo should return a valid page size\n");
653 thread = CreateThread(NULL,sysInfo.dwPageSize,
654 threadFunc5,&exitCode,
655 0,&threadId);
656 ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
657 "TerminateThread didn't work\n");
658 ok(exitCode==1,"CreateThread did not obey stack-size-limit\n");
659 ok(CloseHandle(thread)!=0,"CloseHandle failed\n");
660 #endif
663 /* Check whether setting/retrieving thread priorities works */
664 static VOID test_thread_priority(void)
666 HANDLE curthread,access_thread;
667 DWORD curthreadId,exitCode;
668 int min_priority=-2,max_priority=2;
669 BOOL disabled,rc;
670 int i;
672 curthread=GetCurrentThread();
673 curthreadId=GetCurrentThreadId();
674 /* Check thread priority */
675 /* NOTE: on Win2k/XP priority can be from -7 to 6. All other platforms it
676 is -2 to 2. However, even on a real Win2k system, using thread
677 priorities beyond the -2 to 2 range does not work. If you want to try
678 anyway, enable USE_EXTENDED_PRIORITIES
680 ok(GetThreadPriority(curthread)==THREAD_PRIORITY_NORMAL,
681 "GetThreadPriority Failed\n");
683 if (pOpenThread) {
684 /* check that access control is obeyed */
685 access_thread=pOpenThread(THREAD_ALL_ACCESS_NT4 &
686 (~THREAD_QUERY_INFORMATION) & (~THREAD_SET_INFORMATION),
687 0,curthreadId);
688 ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
689 if (access_thread!=NULL) {
690 obey_ar(SetThreadPriority(access_thread,1)==0);
691 obey_ar(GetThreadPriority(access_thread)==THREAD_PRIORITY_ERROR_RETURN);
692 obey_ar(GetExitCodeThread(access_thread,&exitCode)==0);
693 ok(CloseHandle(access_thread),"Error Closing thread handle\n");
696 #if USE_EXTENDED_PRIORITIES
697 min_priority=-7; max_priority=6;
698 #endif
699 for(i=min_priority;i<=max_priority;i++) {
700 ok(SetThreadPriority(curthread,i)!=0,
701 "SetThreadPriority Failed for priority: %d\n",i);
702 ok(GetThreadPriority(curthread)==i,
703 "GetThreadPriority Failed for priority: %d\n",i);
705 ok(SetThreadPriority(curthread,THREAD_PRIORITY_TIME_CRITICAL)!=0,
706 "SetThreadPriority Failed\n");
707 ok(GetThreadPriority(curthread)==THREAD_PRIORITY_TIME_CRITICAL,
708 "GetThreadPriority Failed\n");
709 ok(SetThreadPriority(curthread,THREAD_PRIORITY_IDLE)!=0,
710 "SetThreadPriority Failed\n");
711 ok(GetThreadPriority(curthread)==THREAD_PRIORITY_IDLE,
712 "GetThreadPriority Failed\n");
713 ok(SetThreadPriority(curthread,0)!=0,"SetThreadPriority Failed\n");
715 /* Check that the thread priority is not changed if SetThreadPriority
716 is called with a value outside of the max/min range */
717 SetThreadPriority(curthread,min_priority);
718 SetLastError(0xdeadbeef);
719 rc = SetThreadPriority(curthread,min_priority-1);
721 ok(rc == FALSE, "SetThreadPriority passed with a bad argument\n");
722 ok(GetLastError() == ERROR_INVALID_PARAMETER ||
723 GetLastError() == ERROR_INVALID_PRIORITY /* Win9x */,
724 "SetThreadPriority error %d, expected ERROR_INVALID_PARAMETER or ERROR_INVALID_PRIORITY\n",
725 GetLastError());
726 ok(GetThreadPriority(curthread)==min_priority,
727 "GetThreadPriority didn't return min_priority\n");
729 SetThreadPriority(curthread,max_priority);
730 SetLastError(0xdeadbeef);
731 rc = SetThreadPriority(curthread,max_priority+1);
733 ok(rc == FALSE, "SetThreadPriority passed with a bad argument\n");
734 ok(GetLastError() == ERROR_INVALID_PARAMETER ||
735 GetLastError() == ERROR_INVALID_PRIORITY /* Win9x */,
736 "SetThreadPriority error %d, expected ERROR_INVALID_PARAMETER or ERROR_INVALID_PRIORITY\n",
737 GetLastError());
738 ok(GetThreadPriority(curthread)==max_priority,
739 "GetThreadPriority didn't return max_priority\n");
741 /* Check thread priority boost */
742 if (!pGetThreadPriorityBoost || !pSetThreadPriorityBoost)
743 return; /* Win9x */
745 SetLastError(0xdeadbeef);
746 rc=pGetThreadPriorityBoost(curthread,&disabled);
747 if (rc==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
749 win_skip("GetThreadPriorityBoost is not implemented on WinME\n");
750 return;
753 ok(rc!=0,"error=%d\n",GetLastError());
755 if (pOpenThread) {
756 /* check that access control is obeyed */
757 access_thread=pOpenThread(THREAD_ALL_ACCESS_NT4 &
758 (~THREAD_QUERY_INFORMATION) & (~THREAD_SET_INFORMATION),
759 0,curthreadId);
760 ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
761 if (access_thread!=NULL) {
762 todo_wine obey_ar(pSetThreadPriorityBoost(access_thread,1)==0);
763 todo_wine obey_ar(pGetThreadPriorityBoost(access_thread,&disabled)==0);
764 ok(CloseHandle(access_thread),"Error Closing thread handle\n");
768 rc = pSetThreadPriorityBoost(curthread,1);
769 ok( rc != 0, "error=%d\n",GetLastError());
770 todo_wine {
771 rc=pGetThreadPriorityBoost(curthread,&disabled);
772 ok(rc!=0 && disabled==1,
773 "rc=%d error=%d disabled=%d\n",rc,GetLastError(),disabled);
776 rc = pSetThreadPriorityBoost(curthread,0);
777 ok( rc != 0, "error=%d\n",GetLastError());
778 rc=pGetThreadPriorityBoost(curthread,&disabled);
779 ok(rc!=0 && disabled==0,
780 "rc=%d error=%d disabled=%d\n",rc,GetLastError(),disabled);
783 /* check the GetThreadTimes function */
784 static VOID test_GetThreadTimes(void)
786 HANDLE thread,access_thread=NULL;
787 FILETIME creationTime,exitTime,kernelTime,userTime;
788 DWORD threadId;
789 int error;
791 thread = CreateThread(NULL,0,threadFunc2,NULL,
792 CREATE_SUSPENDED,&threadId);
794 ok(thread!=NULL,"Create Thread failed\n");
795 /* check that access control is obeyed */
796 if (pOpenThread) {
797 access_thread=pOpenThread(THREAD_ALL_ACCESS_NT4 &
798 (~THREAD_QUERY_INFORMATION), 0,threadId);
799 ok(access_thread!=NULL,
800 "OpenThread returned an invalid handle\n");
802 ok(ResumeThread(thread)==1,"Resume thread returned an invalid value\n");
803 ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
804 "ResumeThread didn't work\n");
805 creationTime.dwLowDateTime=99; creationTime.dwHighDateTime=99;
806 exitTime.dwLowDateTime=99; exitTime.dwHighDateTime=99;
807 kernelTime.dwLowDateTime=99; kernelTime.dwHighDateTime=99;
808 userTime.dwLowDateTime=99; userTime.dwHighDateTime=99;
809 /* GetThreadTimes should set all of the parameters passed to it */
810 error=GetThreadTimes(thread,&creationTime,&exitTime,
811 &kernelTime,&userTime);
813 if (error == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
814 win_skip("GetThreadTimes is not implemented\n");
815 else {
816 ok(error!=0,"GetThreadTimes failed\n");
817 ok(creationTime.dwLowDateTime!=99 || creationTime.dwHighDateTime!=99,
818 "creationTime was invalid\n");
819 ok(exitTime.dwLowDateTime!=99 || exitTime.dwHighDateTime!=99,
820 "exitTime was invalid\n");
821 ok(kernelTime.dwLowDateTime!=99 || kernelTime.dwHighDateTime!=99,
822 "kernelTimewas invalid\n");
823 ok(userTime.dwLowDateTime!=99 || userTime.dwHighDateTime!=99,
824 "userTime was invalid\n");
825 ok(CloseHandle(thread)!=0,"CloseHandle failed\n");
826 if(access_thread!=NULL)
828 error=GetThreadTimes(access_thread,&creationTime,&exitTime,
829 &kernelTime,&userTime);
830 obey_ar(error==0);
833 if(access_thread!=NULL) {
834 ok(CloseHandle(access_thread)!=0,"CloseHandle Failed\n");
838 /* Check the processor affinity functions */
839 /* NOTE: These functions should also be checked that they obey access control
841 static VOID test_thread_processor(void)
843 HANDLE curthread,curproc;
844 DWORD_PTR processMask,systemMask,retMask;
845 SYSTEM_INFO sysInfo;
846 int error=0;
847 BOOL is_wow64;
849 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
851 sysInfo.dwNumberOfProcessors=0;
852 GetSystemInfo(&sysInfo);
853 ok(sysInfo.dwNumberOfProcessors>0,
854 "GetSystemInfo failed to return a valid # of processors\n");
855 /* Use the current Thread/process for all tests */
856 curthread=GetCurrentThread();
857 ok(curthread!=NULL,"GetCurrentThread failed\n");
858 curproc=GetCurrentProcess();
859 ok(curproc!=NULL,"GetCurrentProcess failed\n");
860 /* Check the Affinity Mask functions */
861 ok(GetProcessAffinityMask(curproc,&processMask,&systemMask)!=0,
862 "GetProcessAffinityMask failed\n");
863 ok(SetThreadAffinityMask(curthread,processMask)==processMask,
864 "SetThreadAffinityMask failed\n");
865 ok(SetThreadAffinityMask(curthread,processMask+1)==0,
866 "SetThreadAffinityMask passed for an illegal processor\n");
867 /* NOTE: Pre-Vista does not recognize the "all processors" flag (all bits set) */
868 retMask = SetThreadAffinityMask(curthread,~0);
869 ok(broken(retMask==0) || retMask==processMask,
870 "SetThreadAffinityMask(thread,-1) failed to request all processors.\n");
871 if (retMask == processMask && sizeof(ULONG_PTR) > sizeof(ULONG))
873 /* only the low 32-bits matter */
874 retMask = SetThreadAffinityMask(curthread,~(ULONG_PTR)0);
875 ok(retMask == processMask, "SetThreadAffinityMask failed\n");
876 retMask = SetThreadAffinityMask(curthread,~(ULONG_PTR)0 >> 3);
877 ok(retMask == processMask, "SetThreadAffinityMask failed\n");
879 /* NOTE: This only works on WinNT/2000/XP) */
880 if (pSetThreadIdealProcessor) {
881 SetLastError(0xdeadbeef);
882 error=pSetThreadIdealProcessor(curthread,0);
883 if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
885 win_skip("SetThreadIdealProcessor is not implemented\n");
886 return;
888 ok(error!=-1, "SetThreadIdealProcessor failed\n");
890 if (is_wow64)
892 SetLastError(0xdeadbeef);
893 error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS+1);
894 todo_wine
895 ok(error!=-1, "SetThreadIdealProcessor failed for %u on Wow64\n", MAXIMUM_PROCESSORS+1);
897 SetLastError(0xdeadbeef);
898 error=pSetThreadIdealProcessor(curthread,65);
899 ok(error==-1, "SetThreadIdealProcessor succeeded with an illegal processor #\n");
900 ok(GetLastError()==ERROR_INVALID_PARAMETER,
901 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
903 else
905 SetLastError(0xdeadbeef);
906 error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS+1);
907 ok(error==-1, "SetThreadIdealProcessor succeeded with an illegal processor #\n");
908 ok(GetLastError()==ERROR_INVALID_PARAMETER,
909 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
912 error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS);
913 ok(error!=-1, "SetThreadIdealProcessor failed\n");
917 static VOID test_GetThreadExitCode(void)
919 DWORD exitCode, threadid;
920 DWORD GLE, ret;
921 HANDLE thread;
923 ret = GetExitCodeThread((HANDLE)0x2bad2bad,&exitCode);
924 ok(ret==0, "GetExitCodeThread returned non zero value: %d\n", ret);
925 GLE = GetLastError();
926 ok(GLE==ERROR_INVALID_HANDLE, "GetLastError returned %d (expected 6)\n", GLE);
928 thread = CreateThread(NULL,0,threadFunc2,NULL,0,&threadid);
929 ret = WaitForSingleObject(thread,100);
930 ok(ret==WAIT_OBJECT_0, "threadFunc2 did not exit during 100 ms\n");
931 ret = GetExitCodeThread(thread,&exitCode);
932 ok(ret==exitCode || ret==1,
933 "GetExitCodeThread returned %d (expected 1 or %d)\n", ret, exitCode);
934 ok(exitCode==99, "threadFunc2 exited with code %d (expected 99)\n", exitCode);
935 ok(CloseHandle(thread)!=0,"Error closing thread handle\n");
938 #ifdef __i386__
940 static int test_value = 0;
941 static HANDLE event;
943 static void WINAPI set_test_val( int val )
945 test_value += val;
946 ExitThread(0);
949 static DWORD WINAPI threadFunc6(LPVOID p)
951 SetEvent( event );
952 Sleep( 1000 );
953 test_value *= (int)p;
954 return 0;
957 static void test_SetThreadContext(void)
959 CONTEXT ctx;
960 int *stack;
961 HANDLE thread;
962 DWORD threadid;
963 DWORD prevcount;
964 BOOL ret;
966 SetLastError(0xdeadbeef);
967 event = CreateEventW( NULL, TRUE, FALSE, NULL );
968 thread = CreateThread( NULL, 0, threadFunc6, (void *)2, 0, &threadid );
969 ok( thread != NULL, "CreateThread failed : (%d)\n", GetLastError() );
970 if (!thread)
972 trace("Thread creation failed, skipping rest of test\n");
973 return;
975 WaitForSingleObject( event, INFINITE );
976 SuspendThread( thread );
977 CloseHandle( event );
979 ctx.ContextFlags = CONTEXT_FULL;
980 SetLastError(0xdeadbeef);
981 ret = GetThreadContext( thread, &ctx );
982 ok( ret, "GetThreadContext failed : (%u)\n", GetLastError() );
984 if (ret)
986 /* simulate a call to set_test_val(10) */
987 stack = (int *)ctx.Esp;
988 stack[-1] = 10;
989 stack[-2] = ctx.Eip;
990 ctx.Esp -= 2 * sizeof(int *);
991 ctx.Eip = (DWORD)set_test_val;
992 SetLastError(0xdeadbeef);
993 ret = SetThreadContext( thread, &ctx );
994 ok( ret, "SetThreadContext failed : (%d)\n", GetLastError() );
997 SetLastError(0xdeadbeef);
998 prevcount = ResumeThread( thread );
999 ok ( prevcount == 1, "Previous suspend count (%d) instead of 1, last error : (%d)\n",
1000 prevcount, GetLastError() );
1002 WaitForSingleObject( thread, INFINITE );
1003 ok( test_value == 10, "test_value %d\n", test_value );
1005 ctx.ContextFlags = CONTEXT_FULL;
1006 SetLastError(0xdeadbeef);
1007 ret = GetThreadContext( thread, &ctx );
1008 ok( (!ret && (GetLastError() == ERROR_GEN_FAILURE)) ||
1009 (!ret && broken(GetLastError() == ERROR_INVALID_HANDLE)) || /* win2k */
1010 broken(ret), /* 32bit application on NT 5.x 64bit */
1011 "got %d with %u (expected FALSE with ERROR_GEN_FAILURE)\n",
1012 ret, GetLastError() );
1014 SetLastError(0xdeadbeef);
1015 ret = SetThreadContext( thread, &ctx );
1016 ok( (!ret && ((GetLastError() == ERROR_GEN_FAILURE) || (GetLastError() == ERROR_ACCESS_DENIED))) ||
1017 (!ret && broken(GetLastError() == ERROR_INVALID_HANDLE)) || /* win2k */
1018 broken(ret), /* 32bit application on NT 5.x 64bit */
1019 "got %d with %u (expected FALSE with ERROR_GEN_FAILURE or ERROR_ACCESS_DENIED)\n",
1020 ret, GetLastError() );
1022 CloseHandle( thread );
1025 #endif /* __i386__ */
1027 static HANDLE finish_event;
1028 static LONG times_executed;
1030 static DWORD CALLBACK work_function(void *p)
1032 LONG executed = InterlockedIncrement(&times_executed);
1034 if (executed == 100)
1035 SetEvent(finish_event);
1036 return 0;
1039 static void test_QueueUserWorkItem(void)
1041 INT_PTR i;
1042 DWORD wait_result;
1043 DWORD before, after;
1045 /* QueueUserWorkItem not present on win9x */
1046 if (!pQueueUserWorkItem) return;
1048 finish_event = CreateEventW(NULL, TRUE, FALSE, NULL);
1050 before = GetTickCount();
1052 for (i = 0; i < 100; i++)
1054 BOOL ret = pQueueUserWorkItem(work_function, (void *)i, WT_EXECUTEDEFAULT);
1055 ok(ret, "QueueUserWorkItem failed with error %d\n", GetLastError());
1058 wait_result = WaitForSingleObject(finish_event, 10000);
1060 after = GetTickCount();
1061 trace("100 QueueUserWorkItem calls took %dms\n", after - before);
1062 ok(wait_result == WAIT_OBJECT_0, "wait failed with error 0x%x\n", wait_result);
1064 ok(times_executed == 100, "didn't execute all of the work items\n");
1067 static void CALLBACK signaled_function(PVOID p, BOOLEAN TimerOrWaitFired)
1069 HANDLE event = p;
1070 SetEvent(event);
1071 ok(!TimerOrWaitFired, "wait shouldn't have timed out\n");
1074 static void CALLBACK timeout_function(PVOID p, BOOLEAN TimerOrWaitFired)
1076 HANDLE event = p;
1077 SetEvent(event);
1078 ok(TimerOrWaitFired, "wait should have timed out\n");
1081 static void test_RegisterWaitForSingleObject(void)
1083 BOOL ret;
1084 HANDLE wait_handle;
1085 HANDLE handle;
1086 HANDLE complete_event;
1088 if (!pRegisterWaitForSingleObject || !pUnregisterWait)
1090 win_skip("RegisterWaitForSingleObject or UnregisterWait not implemented\n");
1091 return;
1094 /* test signaled case */
1096 handle = CreateEventW(NULL, TRUE, TRUE, NULL);
1097 complete_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1099 ret = pRegisterWaitForSingleObject(&wait_handle, handle, signaled_function, complete_event, INFINITE, WT_EXECUTEONLYONCE);
1100 ok(ret, "RegisterWaitForSingleObject failed with error %d\n", GetLastError());
1102 WaitForSingleObject(complete_event, INFINITE);
1103 /* give worker thread chance to complete */
1104 Sleep(100);
1106 ret = pUnregisterWait(wait_handle);
1107 ok(ret, "UnregisterWait failed with error %d\n", GetLastError());
1109 /* test cancel case */
1111 ResetEvent(handle);
1113 ret = pRegisterWaitForSingleObject(&wait_handle, handle, signaled_function, complete_event, INFINITE, WT_EXECUTEONLYONCE);
1114 ok(ret, "RegisterWaitForSingleObject failed with error %d\n", GetLastError());
1116 ret = pUnregisterWait(wait_handle);
1117 ok(ret, "UnregisterWait failed with error %d\n", GetLastError());
1119 /* test timeout case */
1121 ret = pRegisterWaitForSingleObject(&wait_handle, handle, timeout_function, complete_event, 0, WT_EXECUTEONLYONCE);
1122 ok(ret, "RegisterWaitForSingleObject failed with error %d\n", GetLastError());
1124 WaitForSingleObject(complete_event, INFINITE);
1125 /* give worker thread chance to complete */
1126 Sleep(100);
1128 ret = pUnregisterWait(wait_handle);
1129 ok(ret, "UnregisterWait failed with error %d\n", GetLastError());
1132 static DWORD TLS_main;
1133 static DWORD TLS_index0, TLS_index1;
1135 static DWORD WINAPI TLS_InheritanceProc(LPVOID p)
1137 /* We should NOT inherit the TLS values from our parent or from the
1138 main thread. */
1139 LPVOID val;
1141 val = TlsGetValue(TLS_main);
1142 ok(val == NULL, "TLS inheritance failed\n");
1144 val = TlsGetValue(TLS_index0);
1145 ok(val == NULL, "TLS inheritance failed\n");
1147 val = TlsGetValue(TLS_index1);
1148 ok(val == NULL, "TLS inheritance failed\n");
1150 return 0;
1153 /* Basic TLS usage test. Make sure we can create slots and the values we
1154 store in them are separate among threads. Also test TLS value
1155 inheritance with TLS_InheritanceProc. */
1156 static DWORD WINAPI TLS_ThreadProc(LPVOID p)
1158 LONG_PTR id = (LONG_PTR) p;
1159 LPVOID val;
1160 BOOL ret;
1162 if (sync_threads_and_run_one(0, id))
1164 TLS_index0 = TlsAlloc();
1165 ok(TLS_index0 != TLS_OUT_OF_INDEXES, "TlsAlloc failed\n");
1167 resync_after_run();
1169 if (sync_threads_and_run_one(1, id))
1171 TLS_index1 = TlsAlloc();
1172 ok(TLS_index1 != TLS_OUT_OF_INDEXES, "TlsAlloc failed\n");
1174 /* Slot indices should be different even if created in different
1175 threads. */
1176 ok(TLS_index0 != TLS_index1, "TlsAlloc failed\n");
1178 /* Both slots should be initialized to NULL */
1179 val = TlsGetValue(TLS_index0);
1180 ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
1181 ok(val == NULL, "TLS slot not initialized correctly\n");
1183 val = TlsGetValue(TLS_index1);
1184 ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
1185 ok(val == NULL, "TLS slot not initialized correctly\n");
1187 resync_after_run();
1189 if (sync_threads_and_run_one(0, id))
1191 val = TlsGetValue(TLS_index0);
1192 ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
1193 ok(val == NULL, "TLS slot not initialized correctly\n");
1195 val = TlsGetValue(TLS_index1);
1196 ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
1197 ok(val == NULL, "TLS slot not initialized correctly\n");
1199 ret = TlsSetValue(TLS_index0, (LPVOID) 1);
1200 ok(ret, "TlsSetValue failed\n");
1202 ret = TlsSetValue(TLS_index1, (LPVOID) 2);
1203 ok(ret, "TlsSetValue failed\n");
1205 val = TlsGetValue(TLS_index0);
1206 ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
1207 ok(val == (LPVOID) 1, "TLS slot not initialized correctly\n");
1209 val = TlsGetValue(TLS_index1);
1210 ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
1211 ok(val == (LPVOID) 2, "TLS slot not initialized correctly\n");
1213 resync_after_run();
1215 if (sync_threads_and_run_one(1, id))
1217 val = TlsGetValue(TLS_index0);
1218 ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
1219 ok(val == NULL, "TLS slot not initialized correctly\n");
1221 val = TlsGetValue(TLS_index1);
1222 ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
1223 ok(val == NULL, "TLS slot not initialized correctly\n");
1225 ret = TlsSetValue(TLS_index0, (LPVOID) 3);
1226 ok(ret, "TlsSetValue failed\n");
1228 ret = TlsSetValue(TLS_index1, (LPVOID) 4);
1229 ok(ret, "TlsSetValue failed\n");
1231 val = TlsGetValue(TLS_index0);
1232 ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
1233 ok(val == (LPVOID) 3, "TLS slot not initialized correctly\n");
1235 val = TlsGetValue(TLS_index1);
1236 ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
1237 ok(val == (LPVOID) 4, "TLS slot not initialized correctly\n");
1239 resync_after_run();
1241 if (sync_threads_and_run_one(0, id))
1243 HANDLE thread;
1244 DWORD waitret, tid;
1246 val = TlsGetValue(TLS_index0);
1247 ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
1248 ok(val == (LPVOID) 1, "TLS slot not initialized correctly\n");
1250 val = TlsGetValue(TLS_index1);
1251 ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
1252 ok(val == (LPVOID) 2, "TLS slot not initialized correctly\n");
1254 thread = CreateThread(NULL, 0, TLS_InheritanceProc, 0, 0, &tid);
1255 ok(thread != NULL, "CreateThread failed\n");
1256 waitret = WaitForSingleObject(thread, 60000);
1257 ok(waitret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
1258 CloseHandle(thread);
1260 ret = TlsFree(TLS_index0);
1261 ok(ret, "TlsFree failed\n");
1263 resync_after_run();
1265 if (sync_threads_and_run_one(1, id))
1267 ret = TlsFree(TLS_index1);
1268 ok(ret, "TlsFree failed\n");
1270 resync_after_run();
1272 return 0;
1275 static void test_TLS(void)
1277 HANDLE threads[2];
1278 LONG_PTR i;
1279 DWORD ret;
1280 BOOL suc;
1282 init_thread_sync_helpers();
1284 /* Allocate a TLS slot in the main thread to test for inheritance. */
1285 TLS_main = TlsAlloc();
1286 ok(TLS_main != TLS_OUT_OF_INDEXES, "TlsAlloc failed\n");
1287 suc = TlsSetValue(TLS_main, (LPVOID) 4114);
1288 ok(suc, "TlsSetValue failed\n");
1290 for (i = 0; i < 2; ++i)
1292 DWORD tid;
1294 threads[i] = CreateThread(NULL, 0, TLS_ThreadProc, (LPVOID) i, 0, &tid);
1295 ok(threads[i] != NULL, "CreateThread failed\n");
1298 ret = WaitForMultipleObjects(2, threads, TRUE, 60000);
1299 ok(ret == WAIT_OBJECT_0 || broken(ret == WAIT_OBJECT_0+1 /* nt4,w2k */), "WaitForAllObjects 2 threads %d\n",ret);
1301 for (i = 0; i < 2; ++i)
1302 CloseHandle(threads[i]);
1304 suc = TlsFree(TLS_main);
1305 ok(suc, "TlsFree failed\n");
1306 cleanup_thread_sync_helpers();
1309 static void test_ThreadErrorMode(void)
1311 DWORD oldmode;
1312 DWORD mode;
1313 DWORD rtlmode;
1314 BOOL ret;
1316 if (!pSetThreadErrorMode || !pGetThreadErrorMode)
1318 win_skip("SetThreadErrorMode and/or GetThreadErrorMode unavailable (added in Windows 7)\n");
1319 return;
1322 if (!pRtlGetThreadErrorMode) {
1323 win_skip("RtlGetThreadErrorMode not available\n");
1324 return;
1327 oldmode = pGetThreadErrorMode();
1329 ret = pSetThreadErrorMode(0, &mode);
1330 ok(ret, "SetThreadErrorMode failed\n");
1331 ok(mode == oldmode,
1332 "SetThreadErrorMode returned old mode 0x%x, expected 0x%x\n",
1333 mode, oldmode);
1334 mode = pGetThreadErrorMode();
1335 ok(mode == 0, "GetThreadErrorMode returned mode 0x%x, expected 0\n", mode);
1336 rtlmode = pRtlGetThreadErrorMode();
1337 ok(rtlmode == 0,
1338 "RtlGetThreadErrorMode returned mode 0x%x, expected 0\n", mode);
1340 ret = pSetThreadErrorMode(SEM_FAILCRITICALERRORS, &mode);
1341 ok(ret, "SetThreadErrorMode failed\n");
1342 ok(mode == 0,
1343 "SetThreadErrorMode returned old mode 0x%x, expected 0\n", mode);
1344 mode = pGetThreadErrorMode();
1345 ok(mode == SEM_FAILCRITICALERRORS,
1346 "GetThreadErrorMode returned mode 0x%x, expected SEM_FAILCRITICALERRORS\n",
1347 mode);
1348 rtlmode = pRtlGetThreadErrorMode();
1349 ok(rtlmode == 0x10,
1350 "RtlGetThreadErrorMode returned mode 0x%x, expected 0x10\n", mode);
1352 ret = pSetThreadErrorMode(SEM_NOGPFAULTERRORBOX, &mode);
1353 ok(ret, "SetThreadErrorMode failed\n");
1354 ok(mode == SEM_FAILCRITICALERRORS,
1355 "SetThreadErrorMode returned old mode 0x%x, expected SEM_FAILCRITICALERRORS\n",
1356 mode);
1357 mode = pGetThreadErrorMode();
1358 ok(mode == SEM_NOGPFAULTERRORBOX,
1359 "GetThreadErrorMode returned mode 0x%x, expected SEM_NOGPFAULTERRORBOX\n",
1360 mode);
1361 rtlmode = pRtlGetThreadErrorMode();
1362 ok(rtlmode == 0x20,
1363 "RtlGetThreadErrorMode returned mode 0x%x, expected 0x20\n", mode);
1365 ret = pSetThreadErrorMode(SEM_NOOPENFILEERRORBOX, NULL);
1366 ok(ret, "SetThreadErrorMode failed\n");
1367 mode = pGetThreadErrorMode();
1368 ok(mode == SEM_NOOPENFILEERRORBOX,
1369 "GetThreadErrorMode returned mode 0x%x, expected SEM_NOOPENFILEERRORBOX\n",
1370 mode);
1371 rtlmode = pRtlGetThreadErrorMode();
1372 ok(rtlmode == 0x40,
1373 "RtlGetThreadErrorMode returned mode 0x%x, expected 0x40\n", rtlmode);
1375 for (mode = 1; mode; mode <<= 1)
1377 ret = pSetThreadErrorMode(mode, NULL);
1378 if (mode & (SEM_FAILCRITICALERRORS |
1379 SEM_NOGPFAULTERRORBOX |
1380 SEM_NOOPENFILEERRORBOX))
1382 ok(ret,
1383 "SetThreadErrorMode(0x%x,NULL) failed with error %d\n",
1384 mode, GetLastError());
1386 else
1388 DWORD GLE = GetLastError();
1389 ok(!ret,
1390 "SetThreadErrorMode(0x%x,NULL) succeeded, expected failure\n",
1391 mode);
1392 ok(GLE == ERROR_INVALID_PARAMETER,
1393 "SetThreadErrorMode(0x%x,NULL) failed with %d, "
1394 "expected ERROR_INVALID_PARAMETER\n",
1395 mode, GLE);
1399 pSetThreadErrorMode(oldmode, NULL);
1402 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
1403 static inline void set_fpu_cw(WORD cw)
1405 __asm__ volatile ("fnclex; fldcw %0" : : "m" (cw));
1408 static inline WORD get_fpu_cw(void)
1410 WORD cw = 0;
1411 __asm__ volatile ("fnstcw %0" : "=m" (cw));
1412 return cw;
1415 struct fpu_thread_ctx
1417 WORD cw;
1418 HANDLE finished;
1421 static DWORD WINAPI fpu_thread(void *param)
1423 struct fpu_thread_ctx *ctx = param;
1424 BOOL ret;
1426 ctx->cw = get_fpu_cw();
1428 ret = SetEvent(ctx->finished);
1429 ok(ret, "SetEvent failed, last error %#x.\n", GetLastError());
1431 return 0;
1434 static WORD get_thread_fpu_cw(void)
1436 struct fpu_thread_ctx ctx;
1437 DWORD tid, res;
1438 HANDLE thread;
1440 ctx.finished = CreateEventW(NULL, FALSE, FALSE, NULL);
1441 ok(!!ctx.finished, "Failed to create event, last error %#x.\n", GetLastError());
1443 thread = CreateThread(NULL, 0, fpu_thread, &ctx, 0, &tid);
1444 ok(!!thread, "Failed to create thread, last error %#x.\n", GetLastError());
1446 res = WaitForSingleObject(ctx.finished, INFINITE);
1447 ok(res == WAIT_OBJECT_0, "Wait failed (%#x), last error %#x.\n", res, GetLastError());
1449 res = CloseHandle(ctx.finished);
1450 ok(!!res, "Failed to close event handle, last error %#x.\n", GetLastError());
1452 return ctx.cw;
1455 static void test_thread_fpu_cw(void)
1457 WORD initial_cw, cw;
1459 initial_cw = get_fpu_cw();
1460 ok(initial_cw == 0x27f, "Expected FPU control word 0x27f, got %#x.\n", initial_cw);
1462 cw = get_thread_fpu_cw();
1463 ok(cw == 0x27f, "Expected FPU control word 0x27f, got %#x.\n", cw);
1465 set_fpu_cw(0xf60);
1466 cw = get_fpu_cw();
1467 ok(cw == 0xf60, "Expected FPU control word 0xf60, got %#x.\n", cw);
1469 cw = get_thread_fpu_cw();
1470 ok(cw == 0x27f, "Expected FPU control word 0x27f, got %#x.\n", cw);
1472 cw = get_fpu_cw();
1473 ok(cw == 0xf60, "Expected FPU control word 0xf60, got %#x.\n", cw);
1475 set_fpu_cw(initial_cw);
1476 cw = get_fpu_cw();
1477 ok(cw == initial_cw, "Expected FPU control word %#x, got %#x.\n", initial_cw, cw);
1479 #endif
1481 static const char manifest_dep[] =
1482 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
1483 "<assemblyIdentity version=\"1.2.3.4\" name=\"testdep1\" type=\"win32\" processorArchitecture=\"" ARCH "\"/>"
1484 " <file name=\"testdep.dll\" />"
1485 "</assembly>";
1487 static const char manifest_main[] =
1488 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
1489 "<assemblyIdentity version=\"1.2.3.4\" name=\"Wine.Test\" type=\"win32\" />"
1490 "<dependency>"
1491 " <dependentAssembly>"
1492 " <assemblyIdentity type=\"win32\" name=\"testdep1\" version=\"1.2.3.4\" processorArchitecture=\"" ARCH "\" />"
1493 " </dependentAssembly>"
1494 "</dependency>"
1495 "</assembly>";
1497 static void create_manifest_file(const char *filename, const char *manifest)
1499 WCHAR path[MAX_PATH];
1500 HANDLE file;
1501 DWORD size;
1503 MultiByteToWideChar( CP_ACP, 0, filename, -1, path, MAX_PATH );
1504 file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1505 ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError());
1506 WriteFile(file, manifest, strlen(manifest), &size, NULL);
1507 CloseHandle(file);
1510 static HANDLE test_create(const char *file)
1512 WCHAR path[MAX_PATH];
1513 ACTCTXW actctx;
1514 HANDLE handle;
1516 MultiByteToWideChar(CP_ACP, 0, file, -1, path, MAX_PATH);
1517 memset(&actctx, 0, sizeof(ACTCTXW));
1518 actctx.cbSize = sizeof(ACTCTXW);
1519 actctx.lpSource = path;
1521 handle = pCreateActCtxW(&actctx);
1522 ok(handle != INVALID_HANDLE_VALUE, "failed to create context, error %u\n", GetLastError());
1524 ok(actctx.cbSize == sizeof(actctx), "cbSize=%d\n", actctx.cbSize);
1525 ok(actctx.dwFlags == 0, "dwFlags=%d\n", actctx.dwFlags);
1526 ok(actctx.lpSource == path, "lpSource=%p\n", actctx.lpSource);
1527 ok(actctx.wProcessorArchitecture == 0, "wProcessorArchitecture=%d\n", actctx.wProcessorArchitecture);
1528 ok(actctx.wLangId == 0, "wLangId=%d\n", actctx.wLangId);
1529 ok(actctx.lpAssemblyDirectory == NULL, "lpAssemblyDirectory=%p\n", actctx.lpAssemblyDirectory);
1530 ok(actctx.lpResourceName == NULL, "lpResourceName=%p\n", actctx.lpResourceName);
1531 ok(actctx.lpApplicationName == NULL, "lpApplicationName=%p\n", actctx.lpApplicationName);
1532 ok(actctx.hModule == NULL, "hModule=%p\n", actctx.hModule);
1534 return handle;
1537 static void test_thread_actctx(void)
1539 struct thread_actctx_param param;
1540 HANDLE thread, handle, context;
1541 ULONG_PTR cookie;
1542 DWORD tid, ret;
1543 BOOL b;
1545 if (!pActivateActCtx)
1547 win_skip("skipping activation context tests\n");
1548 return;
1551 create_manifest_file("testdep1.manifest", manifest_dep);
1552 create_manifest_file("main.manifest", manifest_main);
1554 context = test_create("main.manifest");
1555 DeleteFileA("testdep1.manifest");
1556 DeleteFileA("main.manifest");
1558 handle = (void*)0xdeadbeef;
1559 b = pGetCurrentActCtx(&handle);
1560 ok(b, "GetCurentActCtx failed: %u\n", GetLastError());
1561 ok(handle == 0, "active context %p\n", handle);
1563 /* without active context */
1564 param.thread_context = (void*)0xdeadbeef;
1565 param.handle = NULL;
1566 thread = CreateThread(NULL, 0, thread_actctx_func, &param, 0, &tid);
1567 ok(thread != NULL, "failed, got %u\n", GetLastError());
1569 ret = WaitForSingleObject(thread, 1000);
1570 ok(ret == WAIT_OBJECT_0, "wait timeout\n");
1571 ok(param.thread_context == NULL, "got wrong thread context %p\n", param.thread_context);
1572 CloseHandle(thread);
1574 b = pActivateActCtx(context, &cookie);
1575 ok(b, "activation failed: %u\n", GetLastError());
1577 handle = 0;
1578 b = pGetCurrentActCtx(&handle);
1579 ok(b, "GetCurentActCtx failed: %u\n", GetLastError());
1580 ok(handle != 0, "no active context\n");
1581 pReleaseActCtx(handle);
1583 param.handle = NULL;
1584 b = pGetCurrentActCtx(&param.handle);
1585 ok(b && param.handle != NULL, "failed to get context, %u\n", GetLastError());
1587 param.thread_context = (void*)0xdeadbeef;
1588 thread = CreateThread(NULL, 0, thread_actctx_func, &param, 0, &tid);
1589 ok(thread != NULL, "failed, got %u\n", GetLastError());
1591 ret = WaitForSingleObject(thread, 1000);
1592 ok(ret == WAIT_OBJECT_0, "wait timeout\n");
1593 ok(param.thread_context == context, "got wrong thread context %p, %p\n", param.thread_context, context);
1594 pReleaseActCtx(param.thread_context);
1595 CloseHandle(thread);
1597 /* similar test for CreateRemoteThread() */
1598 param.thread_context = (void*)0xdeadbeef;
1599 thread = CreateRemoteThread(GetCurrentProcess(), NULL, 0, thread_actctx_func, &param, 0, &tid);
1600 ok(thread != NULL, "failed, got %u\n", GetLastError());
1602 ret = WaitForSingleObject(thread, 1000);
1603 ok(ret == WAIT_OBJECT_0, "wait timeout\n");
1604 ok(param.thread_context == context, "got wrong thread context %p, %p\n", param.thread_context, context);
1605 pReleaseActCtx(param.thread_context);
1606 CloseHandle(thread);
1608 pReleaseActCtx(param.handle);
1610 b = pDeactivateActCtx(0, cookie);
1611 ok(b, "DeactivateActCtx failed: %u\n", GetLastError());
1612 pReleaseActCtx(context);
1616 static void WINAPI threadpool_workcallback(PTP_CALLBACK_INSTANCE instance, void *context, PTP_WORK work) {
1617 int *foo = (int*)context;
1619 (*foo)++;
1623 static void test_threadpool(void)
1625 PTP_POOL pool;
1626 PTP_WORK work;
1627 int workcalled = 0;
1629 if (!pCreateThreadpool) {
1630 todo_wine win_skip("thread pool apis not supported.\n");
1631 return;
1634 work = pCreateThreadpoolWork(threadpool_workcallback, &workcalled, NULL);
1635 ok (work != NULL, "Error %d in CreateThreadpoolWork\n", GetLastError());
1636 pSubmitThreadpoolWork(work);
1637 pWaitForThreadpoolWorkCallbacks(work, FALSE);
1638 pCloseThreadpoolWork(work);
1640 ok (workcalled == 1, "expected work to be called once, got %d\n", workcalled);
1642 pool = pCreateThreadpool(NULL);
1643 todo_wine ok (pool != NULL, "CreateThreadpool failed\n");
1646 static void test_reserved_tls(void)
1648 void *val;
1649 DWORD tls;
1650 BOOL ret;
1652 /* This seems to be a WinXP SP2+ feature. */
1653 if(!pIsWow64Process) {
1654 win_skip("Skipping reserved TLS slot on too old Windows.\n");
1655 return;
1658 val = TlsGetValue(0);
1659 ok(!val, "TlsGetValue(0) = %p\n", val);
1661 /* Also make sure that there is a TLS allocated. */
1662 tls = TlsAlloc();
1663 ok(tls && tls != TLS_OUT_OF_INDEXES, "tls = %x\n", tls);
1664 TlsSetValue(tls, (void*)1);
1666 val = TlsGetValue(0);
1667 ok(!val, "TlsGetValue(0) = %p\n", val);
1669 TlsFree(tls);
1671 /* The following is too ugly to be run by default */
1672 if(0) {
1673 /* Set TLS index 0 value and see that this works and doesn't cause problems
1674 * for remaining tests. */
1675 ret = TlsSetValue(0, (void*)1);
1676 ok(ret, "TlsSetValue(0, 1) failed: %u\n", GetLastError());
1678 val = TlsGetValue(0);
1679 ok(val == (void*)1, "TlsGetValue(0) = %p\n", val);
1683 static void init_funcs(void)
1685 HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
1687 /* Neither Cygwin nor mingW export OpenThread, so do a dynamic check
1688 so that the compile passes */
1690 #define X(f) p##f = (void*)GetProcAddress(hKernel32, #f)
1691 X(GetThreadPriorityBoost);
1692 X(OpenThread);
1693 X(QueueUserWorkItem);
1694 X(SetThreadIdealProcessor);
1695 X(SetThreadPriorityBoost);
1696 X(RegisterWaitForSingleObject);
1697 X(UnregisterWait);
1698 X(IsWow64Process);
1699 X(SetThreadErrorMode);
1700 X(GetThreadErrorMode);
1701 X(ActivateActCtx);
1702 X(CreateActCtxW);
1703 X(DeactivateActCtx);
1704 X(GetCurrentActCtx);
1705 X(ReleaseActCtx);
1707 X(CreateThreadpool);
1708 X(CreateThreadpoolWork);
1709 X(SubmitThreadpoolWork);
1710 X(WaitForThreadpoolWorkCallbacks);
1711 X(CloseThreadpoolWork);
1712 #undef X
1715 START_TEST(thread)
1717 HINSTANCE ntdll;
1718 int argc;
1719 char **argv;
1720 argc = winetest_get_mainargs( &argv );
1722 init_funcs();
1724 ntdll=GetModuleHandleA("ntdll.dll");
1725 if (ntdll)
1727 pRtlGetThreadErrorMode=(void *)GetProcAddress(ntdll,"RtlGetThreadErrorMode");
1730 if (argc >= 3)
1732 if (!strcmp(argv[2], "sleep"))
1734 HANDLE hAddrEvents[2];
1735 create_function_addr_events(hAddrEvents);
1736 SetEvent(hAddrEvents[0]);
1737 SetEvent(hAddrEvents[1]);
1738 Sleep(5000); /* spawned process runs for at most 5 seconds */
1739 return;
1741 while (1)
1743 HANDLE hThread;
1744 DWORD tid;
1745 hThread = CreateThread(NULL, 0, threadFunc2, NULL, 0, &tid);
1746 ok(hThread != NULL, "CreateThread failed, error %u\n",
1747 GetLastError());
1748 ok(WaitForSingleObject(hThread, 200) == WAIT_OBJECT_0,
1749 "Thread did not exit in time\n");
1750 if (hThread == NULL) break;
1751 CloseHandle(hThread);
1753 return;
1756 test_reserved_tls();
1757 test_CreateRemoteThread();
1758 test_CreateThread_basic();
1759 test_CreateThread_suspended();
1760 test_SuspendThread();
1761 test_TerminateThread();
1762 test_CreateThread_stack();
1763 test_thread_priority();
1764 test_GetThreadTimes();
1765 test_thread_processor();
1766 test_GetThreadExitCode();
1767 #ifdef __i386__
1768 test_SetThreadContext();
1769 #endif
1770 test_QueueUserWorkItem();
1771 test_RegisterWaitForSingleObject();
1772 test_TLS();
1773 test_ThreadErrorMode();
1774 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
1775 test_thread_fpu_cw();
1776 #endif
1777 test_thread_actctx();
1779 test_threadpool();