1 /*
2  * Unit test suite for thread functions.
3  *
4  * Copyright 2002 Geoffrey Hausheer
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 /* THREAD_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */
24 #define THREAD_ALL_ACCESS_NT4 (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3ff)
25 
26 /* Specify the number of simultaneous threads to test */
27 #define NUM_THREADS 4
28 /* Specify whether to test the extended priorities for Win2k/XP */
29 #define USE_EXTENDED_PRIORITIES 0
30 /* Specify whether to test the stack allocation in CreateThread */
31 #define CHECK_STACK 0
32 
33 /* Set CHECK_STACK to 1 if you want to try to test the stack-limit from
34    CreateThread.  So far I have been unable to make this work, and
35    I am in doubt as to how portable it is.  Also, according to MSDN,
36    you shouldn't mix C-run-time-libraries (i.e. alloca) with CreateThread.
37    Anyhow, the check is currently commented out
38 */
39 #if CHECK_STACK
40 # ifdef __try
41 #  define __TRY __try
42 #  define __EXCEPT __except
43 #  define __ENDTRY
44 # else
45 #  include "wine/exception.h"
46 # endif
47 #endif
48 
49 #ifdef __i386__
50 #define ARCH "x86"
51 #elif defined __x86_64__
52 #define ARCH "amd64"
53 #elif defined __arm__
54 #define ARCH "arm"
55 #elif defined __aarch64__
56 #define ARCH "arm64"
57 #else
58 #define ARCH "none"
59 #endif
60 
61 static BOOL (WINAPI *pGetThreadPriorityBoost)(HANDLE,PBOOL);
62 static HANDLE (WINAPI *pOpenThread)(DWORD,BOOL,DWORD);
63 static BOOL (WINAPI *pQueueUserWorkItem)(LPTHREAD_START_ROUTINE,PVOID,ULONG);
64 static DWORD (WINAPI *pSetThreadIdealProcessor)(HANDLE,DWORD);
65 static BOOL (WINAPI *pSetThreadPriorityBoost)(HANDLE,BOOL);
66 static BOOL (WINAPI *pRegisterWaitForSingleObject)(PHANDLE,HANDLE,WAITORTIMERCALLBACK,PVOID,ULONG,ULONG);
67 static BOOL (WINAPI *pUnregisterWait)(HANDLE);
68 static BOOL (WINAPI *pIsWow64Process)(HANDLE,PBOOL);
69 static BOOL (WINAPI *pSetThreadErrorMode)(DWORD,PDWORD);
70 static DWORD (WINAPI *pGetThreadErrorMode)(void);
71 static DWORD (WINAPI *pRtlGetThreadErrorMode)(void);
72 static BOOL   (WINAPI *pActivateActCtx)(HANDLE,ULONG_PTR*);
73 static HANDLE (WINAPI *pCreateActCtxW)(PCACTCTXW);
74 static BOOL   (WINAPI *pDeactivateActCtx)(DWORD,ULONG_PTR);
75 static BOOL   (WINAPI *pGetCurrentActCtx)(HANDLE *);
76 static void   (WINAPI *pReleaseActCtx)(HANDLE);
77 static PTP_POOL (WINAPI *pCreateThreadpool)(PVOID);
78 static void (WINAPI *pCloseThreadpool)(PTP_POOL);
79 static PTP_WORK (WINAPI *pCreateThreadpoolWork)(PTP_WORK_CALLBACK,PVOID,PTP_CALLBACK_ENVIRON);
80 static void (WINAPI *pSubmitThreadpoolWork)(PTP_WORK);
81 static void (WINAPI *pWaitForThreadpoolWorkCallbacks)(PTP_WORK,BOOL);
82 static void (WINAPI *pCloseThreadpoolWork)(PTP_WORK);
83 static NTSTATUS (WINAPI *pNtQueryInformationThread)(HANDLE,THREADINFOCLASS,PVOID,ULONG,PULONG);
84 static BOOL (WINAPI *pGetThreadGroupAffinity)(HANDLE,GROUP_AFFINITY*);
85 static BOOL (WINAPI *pSetThreadGroupAffinity)(HANDLE,const GROUP_AFFINITY*,GROUP_AFFINITY*);
86 static NTSTATUS (WINAPI *pNtSetInformationThread)(HANDLE,THREADINFOCLASS,LPCVOID,ULONG);
87 static NTSTATUS (WINAPI *pNtSetLdtEntries)(ULONG,ULONG,ULONG,ULONG,ULONG,ULONG);
88 
89 static HANDLE create_target_process(const char *arg)
90 {
91     char **argv;
92     char cmdline[MAX_PATH];
93     PROCESS_INFORMATION pi;
94     BOOL ret;
95     STARTUPINFOA si = { 0 };
96     si.cb = sizeof(si);
97 
98     winetest_get_mainargs( &argv );
99     sprintf(cmdline, "%s %s %s", argv[0], argv[1], arg);
100     ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
101     ok(ret, "error: %u\n", GetLastError());
102     ret = CloseHandle(pi.hThread);
103     ok(ret, "error %u\n", GetLastError());
104     return pi.hProcess;
105 }
106 
107 /* Functions not tested yet:
108   AttachThreadInput
109   SetThreadContext
110   SwitchToThread
111 
112 In addition there are no checks that the inheritance works properly in
113 CreateThread
114 */
115 
116 /* Functions to ensure that from a group of threads, only one executes
117    certain chunks of code at a time, and we know which one is executing
118    it.  It basically makes multithreaded execution linear, which defeats
119    the purpose of multiple threads, but makes testing easy.  */
120 static HANDLE start_event, stop_event;
121 static LONG num_synced;
122 
123 static void init_thread_sync_helpers(void)
124 {
125   start_event = CreateEventW(NULL, TRUE, FALSE, NULL);
126   ok(start_event != NULL, "CreateEvent failed\n");
127   stop_event = CreateEventW(NULL, TRUE, FALSE, NULL);
128   ok(stop_event != NULL, "CreateEvent failed\n");
129   num_synced = -1;
130 }
131 
132 static BOOL sync_threads_and_run_one(DWORD sync_id, DWORD my_id)
133 {
134   LONG num = InterlockedIncrement(&num_synced);
135   assert(-1 <= num && num <= 1);
136   if (num == 1)
137   {
138       ResetEvent( stop_event );
139       SetEvent( start_event );
140   }
141   else
142   {
143     DWORD ret = WaitForSingleObject(start_event, 10000);
144     ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed %x\n",ret);
145   }
146   return sync_id == my_id;
147 }
148 
149 static void resync_after_run(void)
150 {
151   LONG num = InterlockedDecrement(&num_synced);
152   assert(-1 <= num && num <= 1);
153   if (num == -1)
154   {
155       ResetEvent( start_event );
156       SetEvent( stop_event );
157   }
158   else
159   {
160     DWORD ret = WaitForSingleObject(stop_event, 10000);
161     ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
162   }
163 }
164 
165 static void cleanup_thread_sync_helpers(void)
166 {
167   CloseHandle(start_event);
168   CloseHandle(stop_event);
169 }
170 
171 static DWORD tlsIndex;
172 
173 typedef struct {
174   int threadnum;
175   HANDLE *event;
176   DWORD *threadmem;
177 } t1Struct;
178 
179 /* WinME supports OpenThread but doesn't know about access restrictions so
180    we require them to be either completely ignored or always obeyed.
181 */
182 static INT obeying_ars = 0; /* -1 == no, 0 == dunno yet, 1 == yes */
183 #define obey_ar(x) \
184   (obeying_ars == 0 \
185     ? ((x) \
186       ? (obeying_ars = +1) \
187       : ((obeying_ars = -1), \
188          trace("not restricted, assuming consistent behaviour\n"))) \
189     : (obeying_ars < 0) \
190       ? ok(!(x), "access restrictions obeyed\n") \
191       : ok( (x), "access restrictions not obeyed\n"))
192 
193 /* Basic test that simultaneous threads can access shared memory,
194    that the thread local storage routines work correctly, and that
195    threads actually run concurrently
196 */
197 static DWORD WINAPI threadFunc1(LPVOID p)
198 {
199    t1Struct *tstruct = p;
200    int i;
201 /* write our thread # into shared memory */
202    tstruct->threadmem[tstruct->threadnum]=GetCurrentThreadId();
203    ok(TlsSetValue(tlsIndex,(LPVOID)(INT_PTR)(tstruct->threadnum+1))!=0,
204       "TlsSetValue failed\n");
205 /* The threads synchronize before terminating.  This is done by
206    Signaling an event, and waiting for all events to occur
207 */
208    SetEvent(tstruct->event[tstruct->threadnum]);
209    WaitForMultipleObjects(NUM_THREADS,tstruct->event,TRUE,INFINITE);
210 /* Double check that all threads really did run by validating that
211    they have all written to the shared memory. There should be no race
212    here, since all threads were synchronized after the write.*/
213    for (i = 0; i < NUM_THREADS; i++)
214       ok(tstruct->threadmem[i] != 0, "expected threadmem[%d] != 0\n", i);
215 
216    /* lstrlenA contains an exception handler so this makes sure exceptions work in threads */
217    ok( lstrlenA( (char *)0xdeadbeef ) == 0, "lstrlenA: unexpected success\n" );
218 
219 /* Check that no one changed our tls memory */
220    ok((INT_PTR)TlsGetValue(tlsIndex)-1==tstruct->threadnum,
221       "TlsGetValue failed\n");
222    return NUM_THREADS+tstruct->threadnum;
223 }
224 
225 static DWORD WINAPI threadFunc2(LPVOID p)
226 {
227    return 99;
228 }
229 
230 static DWORD WINAPI threadFunc3(LPVOID p)
231 {
232    HANDLE thread;
233    thread=GetCurrentThread();
234    SuspendThread(thread);
235    return 99;
236 }
237 
238 static DWORD WINAPI threadFunc4(LPVOID p)
239 {
240    HANDLE event = p;
241    if(event != NULL) {
242      SetEvent(event);
243    }
244    Sleep(99000);
245    return 0;
246 }
247 
248 #if CHECK_STACK
249 static DWORD WINAPI threadFunc5(LPVOID p)
250 {
251   DWORD *exitCode = p;
252   SYSTEM_INFO sysInfo;
253   sysInfo.dwPageSize=0;
254   GetSystemInfo(&sysInfo);
255   *exitCode=0;
256    __TRY
257    {
258      alloca(2*sysInfo.dwPageSize);
259    }
260     __EXCEPT(1) {
261      *exitCode=1;
262    }
263    __ENDTRY
264    return 0;
265 }
266 #endif
267 
268 static DWORD WINAPI threadFunc_SetEvent(LPVOID p)
269 {
270     SetEvent(p);
271     return 0;
272 }
273 
274 static DWORD WINAPI threadFunc_CloseHandle(LPVOID p)
275 {
276     CloseHandle(p);
277     return 0;
278 }
279 
280 struct thread_actctx_param
281 {
282     HANDLE thread_context;
283     HANDLE handle;
284 };
285 
286 static DWORD WINAPI thread_actctx_func(void *p)
287 {
288     struct thread_actctx_param *param = (struct thread_actctx_param*)p;
289     HANDLE cur;
290     BOOL ret;
291 
292     cur = (void*)0xdeadbeef;
293     ret = pGetCurrentActCtx(&cur);
294     ok(ret, "thread GetCurrentActCtx failed, %u\n", GetLastError());
295     ok(cur == param->handle, "got %p, expected %p\n", cur, param->handle);
296     param->thread_context = cur;
297 
298     return 0;
299 }
300 
301 static void create_function_addr_events(HANDLE events[2])
302 {
303     char buffer[256];
304 
305     sprintf(buffer, "threadFunc_SetEvent %p", threadFunc_SetEvent);
306     events[0] = CreateEventA(NULL, FALSE, FALSE, buffer);
307 
308     sprintf(buffer, "threadFunc_CloseHandle %p", threadFunc_CloseHandle);
309     events[1] = CreateEventA(NULL, FALSE, FALSE, buffer);
310 }
311 
312 /* check CreateRemoteThread */
313 static VOID test_CreateRemoteThread(void)
314 {
315     HANDLE hProcess, hThread, hEvent, hRemoteEvent;
316     DWORD tid, ret, exitcode;
317     HANDLE hAddrEvents[2];
318 
319     hProcess = create_target_process("sleep");
320     ok(hProcess != NULL, "Can't start process\n");
321 
322     /* ensure threadFunc_SetEvent & threadFunc_CloseHandle are the same
323      * address as in the child process */
324     create_function_addr_events(hAddrEvents);
325     ret = WaitForMultipleObjects(2, hAddrEvents, TRUE, 5000);
326     if (ret == WAIT_TIMEOUT)
327     {
328         skip("child process wasn't mapped at same address, so can't do CreateRemoteThread tests.\n");
329         return;
330     }
331     ok(ret == WAIT_OBJECT_0 || broken(ret == WAIT_OBJECT_0+1 /* nt4,w2k */), "WaitForAllObjects 2 events %d\n", ret);
332 
333     hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
334     ok(hEvent != NULL, "Can't create event, err=%u\n", GetLastError());
335     ret = DuplicateHandle(GetCurrentProcess(), hEvent, hProcess, &hRemoteEvent,
336                           0, FALSE, DUPLICATE_SAME_ACCESS);
337     ok(ret != 0, "DuplicateHandle failed, err=%u\n", GetLastError());
338 
339     /* create suspended remote thread with entry point SetEvent() */
340     SetLastError(0xdeadbeef);
341     hThread = CreateRemoteThread(hProcess, NULL, 0, threadFunc_SetEvent,
342                                  hRemoteEvent, CREATE_SUSPENDED, &tid);
343     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
344     {
345         win_skip("CreateRemoteThread is not implemented\n");
346         goto cleanup;
347     }
348     ok(hThread != NULL, "CreateRemoteThread failed, err=%u\n", GetLastError());
349     ok(tid != 0, "null tid\n");
350     ret = SuspendThread(hThread);
351     ok(ret == 1, "ret=%u, err=%u\n", ret, GetLastError());
352     ret = ResumeThread(hThread);
353     ok(ret == 2, "ret=%u, err=%u\n", ret, GetLastError());
354 
355     /* thread still suspended, so wait times out */
356     ret = WaitForSingleObject(hEvent, 1000);
357     ok(ret == WAIT_TIMEOUT, "wait did not time out, ret=%u\n", ret);
358 
359     ret = ResumeThread(hThread);
360     ok(ret == 1, "ret=%u, err=%u\n", ret, GetLastError());
361 
362     /* wait that doesn't time out */
363     ret = WaitForSingleObject(hEvent, 1000);
364     ok(ret == WAIT_OBJECT_0, "object not signaled, ret=%u\n", ret);
365 
366     /* wait for thread end */
367     ret = WaitForSingleObject(hThread, 1000);
368     ok(ret == WAIT_OBJECT_0, "waiting for thread failed, ret=%u\n", ret);
369     CloseHandle(hThread);
370 
371     /* create and wait for remote thread with entry point CloseHandle() */
372     hThread = CreateRemoteThread(hProcess, NULL, 0,
373                                  threadFunc_CloseHandle,
374                                  hRemoteEvent, 0, &tid);
375     ok(hThread != NULL, "CreateRemoteThread failed, err=%u\n", GetLastError());
376     ret = WaitForSingleObject(hThread, 1000);
377     ok(ret == WAIT_OBJECT_0, "waiting for thread failed, ret=%u\n", ret);
378     CloseHandle(hThread);
379 
380     /* create remote thread with entry point SetEvent() */
381     hThread = CreateRemoteThread(hProcess, NULL, 0,
382                                  threadFunc_SetEvent,
383                                  hRemoteEvent, 0, &tid);
384     ok(hThread != NULL, "CreateRemoteThread failed, err=%u\n", GetLastError());
385 
386     /* closed handle, so wait times out */
387     ret = WaitForSingleObject(hEvent, 1000);
388     ok(ret == WAIT_TIMEOUT, "wait did not time out, ret=%u\n", ret);
389 
390     /* check that remote SetEvent() failed */
391     ret = GetExitCodeThread(hThread, &exitcode);
392     ok(ret != 0, "GetExitCodeThread failed, err=%u\n", GetLastError());
393     if (ret) ok(exitcode == 0, "SetEvent succeeded, expected to fail\n");
394     CloseHandle(hThread);
395 
396 cleanup:
397     TerminateProcess(hProcess, 0);
398     CloseHandle(hEvent);
399     CloseHandle(hProcess);
400 }
401 
402 /* Check basic functionality of CreateThread and Tls* functions */
403 static VOID test_CreateThread_basic(void)
404 {
405    HANDLE thread[NUM_THREADS],event[NUM_THREADS];
406    DWORD threadid[NUM_THREADS],curthreadId;
407    DWORD threadmem[NUM_THREADS];
408    DWORD exitCode;
409    t1Struct tstruct[NUM_THREADS];
410    int error;
411    DWORD i,j;
412    DWORD GLE, ret;
413    DWORD tid;
414    BOOL bRet;
415 
416    /* lstrlenA contains an exception handler so this makes sure exceptions work in the main thread */
417    ok( lstrlenA( (char *)0xdeadbeef ) == 0, "lstrlenA: unexpected success\n" );
418 
419 /* Retrieve current Thread ID for later comparisons */
420   curthreadId=GetCurrentThreadId();
421 /* Allocate some local storage */
422   ok((tlsIndex=TlsAlloc())!=TLS_OUT_OF_INDEXES,"TlsAlloc failed\n");
423 /* Create events for thread synchronization */
424   for(i=0;i<NUM_THREADS;i++) {
425     threadmem[i]=0;
426 /* Note that it doesn't matter what type of event we choose here.  This
427    test isn't trying to thoroughly test events
428 */
429     event[i]=CreateEventA(NULL,TRUE,FALSE,NULL);
430     tstruct[i].threadnum=i;
431     tstruct[i].threadmem=threadmem;
432     tstruct[i].event=event;
433   }
434 
435 /* Test that passing arguments to threads works okay */
436   for(i=0;i<NUM_THREADS;i++) {
437     thread[i] = CreateThread(NULL,0,threadFunc1,
438                              &tstruct[i],0,&threadid[i]);
439     ok(thread[i]!=NULL,"Create Thread failed\n");
440   }
441 /* Test that the threads actually complete */
442   for(i=0;i<NUM_THREADS;i++) {
443     error=WaitForSingleObject(thread[i],5000);
444     ok(error==WAIT_OBJECT_0, "Thread did not complete within timelimit\n");
445     if(error!=WAIT_OBJECT_0) {
446       TerminateThread(thread[i],i+NUM_THREADS);
447     }
448     ok(GetExitCodeThread(thread[i],&exitCode),"Could not retrieve ext code\n");
449     ok(exitCode==i+NUM_THREADS,"Thread returned an incorrect exit code\n");
450   }
451 /* Test that each thread executed in its parent's address space
452    (it was able to change threadmem and pass that change back to its parent)
453    and that each thread id was independent).  Note that we prove that the
454    threads actually execute concurrently by having them block on each other
455    in threadFunc1
456 */
457   for(i=0;i<NUM_THREADS;i++) {
458     error=0;
459     for(j=i+1;j<NUM_THREADS;j++) {
460       if (threadmem[i]==threadmem[j]) {
461         error=1;
462       }
463     }
464     ok(!error && threadmem[i]==threadid[i] && threadmem[i]!=curthreadId,
465          "Thread did not execute successfully\n");
466     ok(CloseHandle(thread[i])!=0,"CloseHandle failed\n");
467   }
468 
469   SetLastError(0xCAFEF00D);
470   bRet = TlsFree(tlsIndex);
471   ok(bRet, "TlsFree failed: %08x\n", GetLastError());
472   ok(GetLastError()==0xCAFEF00D,
473      "GetLastError: expected 0xCAFEF00D, got %08x\n", GetLastError());
474 
475   /* Test freeing an already freed TLS index */
476   SetLastError(0xCAFEF00D);
477   ok(TlsFree(tlsIndex)==0,"TlsFree succeeded\n");
478   ok(GetLastError()==ERROR_INVALID_PARAMETER,
479      "GetLastError: expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
480 
481   /* Test how passing NULL as a pointer to threadid works */
482   SetLastError(0xFACEaBAD);
483   thread[0] = CreateThread(NULL,0,threadFunc2,NULL,0,&tid);
484   GLE = GetLastError();
485   if (thread[0]) { /* NT */
486     ok(GLE==0xFACEaBAD, "CreateThread set last error to %d, expected 4207848365\n", GLE);
487     ret = WaitForSingleObject(thread[0],100);
488     ok(ret==WAIT_OBJECT_0, "threadFunc2 did not exit during 100 ms\n");
489     ret = GetExitCodeThread(thread[0],&exitCode);
490     ok(ret!=0, "GetExitCodeThread returned %d (expected nonzero)\n", ret);
491     ok(exitCode==99, "threadFunc2 exited with code: %d (expected 99)\n", exitCode);
492     ok(CloseHandle(thread[0])!=0,"Error closing thread handle\n");
493   }
494   else { /* 9x */
495     ok(GLE==ERROR_INVALID_PARAMETER, "CreateThread set last error to %d, expected 87\n", GLE);
496   }
497 }
498 
499 /* Check that using the CREATE_SUSPENDED flag works */
500 static VOID test_CreateThread_suspended(void)
501 {
502   HANDLE thread;
503   DWORD threadId;
504   DWORD suspend_count;
505   int error;
506 
507   thread = CreateThread(NULL,0,threadFunc2,NULL,
508                         CREATE_SUSPENDED,&threadId);
509   ok(thread!=NULL,"Create Thread failed\n");
510 /* Check that the thread is suspended */
511   ok(SuspendThread(thread)==1,"Thread did not start suspended\n");
512   ok(ResumeThread(thread)==2,"Resume thread returned an invalid value\n");
513 /* Check that resume thread didn't actually start the thread.  I can't think
514    of a better way of checking this than just waiting.  I am not sure if this
515    will work on slow computers.
516 */
517   ok(WaitForSingleObject(thread,1000)==WAIT_TIMEOUT,
518      "ResumeThread should not have actually started the thread\n");
519 /* Now actually resume the thread and make sure that it actually completes*/
520   ok(ResumeThread(thread)==1,"Resume thread returned an invalid value\n");
521   ok((error=WaitForSingleObject(thread,1000))==WAIT_OBJECT_0,
522      "Thread did not resume\n");
523   if(error!=WAIT_OBJECT_0) {
524     TerminateThread(thread,1);
525   }
526 
527   suspend_count = SuspendThread(thread);
528   ok(suspend_count == -1, "SuspendThread returned %d, expected -1\n", suspend_count);
529 
530   suspend_count = ResumeThread(thread);
531   ok(suspend_count == 0 ||
532      broken(suspend_count == -1), /* win9x */
533      "ResumeThread returned %d, expected 0\n", suspend_count);
534 
535   ok(CloseHandle(thread)!=0,"CloseHandle failed\n");
536 }
537 
538 /* Check that SuspendThread and ResumeThread work */
539 static VOID test_SuspendThread(void)
540 {
541   HANDLE thread,access_thread;
542   DWORD threadId,exitCode,error;
543   int i;
544 
545   thread = CreateThread(NULL,0,threadFunc3,NULL,
546                         0,&threadId);
547   ok(thread!=NULL,"Create Thread failed\n");
548 /* Check that the thread is suspended */
549 /* Note that this is a polling method, and there is a race between
550    SuspendThread being called (in the child, and the loop below timing out,
551    so the test could fail on a heavily loaded or slow computer.
552 */
553   error=0;
554   for(i=0;error==0 && i<100;i++) {
555     error=SuspendThread(thread);
556     ResumeThread(thread);
557     if(error==0) {
558       Sleep(50);
559       i++;
560     }
561   }
562   ok(error==1,"SuspendThread did not work\n");
563 /* check that access restrictions are obeyed */
564   if (pOpenThread) {
565     access_thread=pOpenThread(THREAD_ALL_ACCESS_NT4 & (~THREAD_SUSPEND_RESUME),
566                            0,threadId);
567     ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
568     if (access_thread!=NULL) {
569       obey_ar(SuspendThread(access_thread)==~0U);
570       obey_ar(ResumeThread(access_thread)==~0U);
571       ok(CloseHandle(access_thread)!=0,"CloseHandle Failed\n");
572     }
573   }
574 /* Double check that the thread really is suspended */
575   ok((error=GetExitCodeThread(thread,&exitCode))!=0 && exitCode==STILL_ACTIVE,
576      "Thread did not really suspend\n");
577 /* Resume the thread, and make sure it actually completes */
578   ok(ResumeThread(thread)==1,"Resume thread returned an invalid value\n");
579   ok((error=WaitForSingleObject(thread,1000))==WAIT_OBJECT_0,
580      "Thread did not resume\n");
581   if(error!=WAIT_OBJECT_0) {
582     TerminateThread(thread,1);
583   }
584   /* Trying to suspend a terminated thread should fail */
585   error=SuspendThread(thread);
586   ok(error==~0U, "wrong return code: %d\n", error);
587   ok(GetLastError()==ERROR_ACCESS_DENIED || GetLastError()==ERROR_NO_MORE_ITEMS, "unexpected error code: %d\n", GetLastError());
588 
589   ok(CloseHandle(thread)!=0,"CloseHandle Failed\n");
590 }
591 
592 /* Check that TerminateThread works properly
593 */
594 static VOID test_TerminateThread(void)
595 {
596   HANDLE thread,access_thread,event;
597   DWORD threadId,exitCode;
598   event=CreateEventA(NULL,TRUE,FALSE,NULL);
599   thread = CreateThread(NULL,0,threadFunc4,event,0,&threadId);
600   ok(thread!=NULL,"Create Thread failed\n");
601 /* TerminateThread has a race condition in Wine.  If the thread is terminated
602    before it starts, it leaves a process behind.  Therefore, we wait for the
603    thread to signal that it has started.  There is no easy way to force the
604    race to occur, so we don't try to find it.
605 */
606   ok(WaitForSingleObject(event,5000)==WAIT_OBJECT_0,
607      "TerminateThread didn't work\n");
608 /* check that access restrictions are obeyed */
609   if (pOpenThread) {
610     access_thread=pOpenThread(THREAD_ALL_ACCESS_NT4 & (~THREAD_TERMINATE),
611                              0,threadId);
612     ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
613     if (access_thread!=NULL) {
614       obey_ar(TerminateThread(access_thread,99)==0);
615       ok(CloseHandle(access_thread)!=0,"CloseHandle Failed\n");
616     }
617   }
618 /* terminate a job and make sure it terminates */
619   ok(TerminateThread(thread,99)!=0,"TerminateThread failed\n");
620   ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
621      "TerminateThread didn't work\n");
622   ok(GetExitCodeThread(thread,&exitCode)!=STILL_ACTIVE,
623      "TerminateThread should not leave the thread 'STILL_ACTIVE'\n");
624   ok(exitCode==99, "TerminateThread returned invalid exit code\n");
625   ok(CloseHandle(thread)!=0,"Error Closing thread handle\n");
626 }
627 
628 /* Check if CreateThread obeys the specified stack size.  This code does
629    not work properly, and is currently disabled
630 */
631 static VOID test_CreateThread_stack(void)
632 {
633 #if CHECK_STACK
634 /* The only way I know of to test the stack size is to use alloca
635    and __try/__except.  However, this is probably not portable,
636    and I couldn't get it to work under Wine anyhow.  However, here
637    is the code which should allow for testing that CreateThread
638    respects the stack-size limit
639 */
640      HANDLE thread;
641      DWORD threadId,exitCode;
642 
643      SYSTEM_INFO sysInfo;
644      sysInfo.dwPageSize=0;
645      GetSystemInfo(&sysInfo);
646      ok(sysInfo.dwPageSize>0,"GetSystemInfo should return a valid page size\n");
647      thread = CreateThread(NULL,sysInfo.dwPageSize,
648                            threadFunc5,&exitCode,
649                            0,&threadId);
650      ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
651         "TerminateThread didn't work\n");
652      ok(exitCode==1,"CreateThread did not obey stack-size-limit\n");
653      ok(CloseHandle(thread)!=0,"CloseHandle failed\n");
654 #endif
655 }
656 
657 /* Check whether setting/retrieving thread priorities works */
658 static VOID test_thread_priority(void)
659 {
660    HANDLE curthread,access_thread;
661    DWORD curthreadId,exitCode;
662    int min_priority=-2,max_priority=2;
663    BOOL disabled,rc;
664    int i;
665 
666    curthread=GetCurrentThread();
667    curthreadId=GetCurrentThreadId();
668 /* Check thread priority */
669 /* NOTE: on Win2k/XP priority can be from -7 to 6.  All other platforms it
670          is -2 to 2.  However, even on a real Win2k system, using thread
671          priorities beyond the -2 to 2 range does not work.  If you want to try
672          anyway, enable USE_EXTENDED_PRIORITIES
673 */
674    ok(GetThreadPriority(curthread)==THREAD_PRIORITY_NORMAL,
675       "GetThreadPriority Failed\n");
676 
677    if (pOpenThread) {
678 /* check that access control is obeyed */
679      access_thread=pOpenThread(THREAD_ALL_ACCESS_NT4 &
680                        (~THREAD_QUERY_INFORMATION) & (~THREAD_SET_INFORMATION),
681                        0,curthreadId);
682      ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
683      if (access_thread!=NULL) {
684        obey_ar(SetThreadPriority(access_thread,1)==0);
685        obey_ar(GetThreadPriority(access_thread)==THREAD_PRIORITY_ERROR_RETURN);
686        obey_ar(GetExitCodeThread(access_thread,&exitCode)==0);
687        ok(CloseHandle(access_thread),"Error Closing thread handle\n");
688      }
689    }
690 #if USE_EXTENDED_PRIORITIES
691    min_priority=-7; max_priority=6;
692 #endif
693    for(i=min_priority;i<=max_priority;i++) {
694      ok(SetThreadPriority(curthread,i)!=0,
695         "SetThreadPriority Failed for priority: %d\n",i);
696      ok(GetThreadPriority(curthread)==i,
697         "GetThreadPriority Failed for priority: %d\n",i);
698    }
699    ok(SetThreadPriority(curthread,THREAD_PRIORITY_TIME_CRITICAL)!=0,
700       "SetThreadPriority Failed\n");
701    ok(GetThreadPriority(curthread)==THREAD_PRIORITY_TIME_CRITICAL,
702       "GetThreadPriority Failed\n");
703    ok(SetThreadPriority(curthread,THREAD_PRIORITY_IDLE)!=0,
704        "SetThreadPriority Failed\n");
705    ok(GetThreadPriority(curthread)==THREAD_PRIORITY_IDLE,
706        "GetThreadPriority Failed\n");
707    ok(SetThreadPriority(curthread,0)!=0,"SetThreadPriority Failed\n");
708 
709 /* Check that the thread priority is not changed if SetThreadPriority
710    is called with a value outside of the max/min range */
711    SetThreadPriority(curthread,min_priority);
712    SetLastError(0xdeadbeef);
713    rc = SetThreadPriority(curthread,min_priority-1);
714 
715    ok(rc == FALSE, "SetThreadPriority passed with a bad argument\n");
716    ok(GetLastError() == ERROR_INVALID_PARAMETER ||
717       GetLastError() == ERROR_INVALID_PRIORITY /* Win9x */,
718       "SetThreadPriority error %d, expected ERROR_INVALID_PARAMETER or ERROR_INVALID_PRIORITY\n",
719       GetLastError());
720    ok(GetThreadPriority(curthread)==min_priority,
721       "GetThreadPriority didn't return min_priority\n");
722 
723    SetThreadPriority(curthread,max_priority);
724    SetLastError(0xdeadbeef);
725    rc = SetThreadPriority(curthread,max_priority+1);
726 
727    ok(rc == FALSE, "SetThreadPriority passed with a bad argument\n");
728    ok(GetLastError() == ERROR_INVALID_PARAMETER ||
729       GetLastError() == ERROR_INVALID_PRIORITY /* Win9x */,
730       "SetThreadPriority error %d, expected ERROR_INVALID_PARAMETER or ERROR_INVALID_PRIORITY\n",
731       GetLastError());
732    ok(GetThreadPriority(curthread)==max_priority,
733       "GetThreadPriority didn't return max_priority\n");
734 
735 /* Check thread priority boost */
736    if (!pGetThreadPriorityBoost || !pSetThreadPriorityBoost)
737      return; /* Win9x */
738 
739    SetLastError(0xdeadbeef);
740    rc=pGetThreadPriorityBoost(curthread,&disabled);
741    if (rc==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
742    {
743       win_skip("GetThreadPriorityBoost is not implemented on WinME\n");
744       return;
745    }
746 
747    ok(rc!=0,"error=%d\n",GetLastError());
748 
749    if (pOpenThread) {
750 /* check that access control is obeyed */
751      access_thread=pOpenThread(THREAD_ALL_ACCESS_NT4 &
752                        (~THREAD_QUERY_INFORMATION) & (~THREAD_SET_INFORMATION),
753                        0,curthreadId);
754      ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
755      if (access_thread!=NULL) {
756        todo_wine obey_ar(pSetThreadPriorityBoost(access_thread,1)==0);
757        todo_wine obey_ar(pGetThreadPriorityBoost(access_thread,&disabled)==0);
758        ok(CloseHandle(access_thread),"Error Closing thread handle\n");
759      }
760    }
761 
762    rc = pSetThreadPriorityBoost(curthread,1);
763    ok( rc != 0, "error=%d\n",GetLastError());
764    todo_wine {
765      rc=pGetThreadPriorityBoost(curthread,&disabled);
766      ok(rc!=0 && disabled==1,
767         "rc=%d error=%d disabled=%d\n",rc,GetLastError(),disabled);
768    }
769 
770    rc = pSetThreadPriorityBoost(curthread,0);
771    ok( rc != 0, "error=%d\n",GetLastError());
772    rc=pGetThreadPriorityBoost(curthread,&disabled);
773    ok(rc!=0 && disabled==0,
774       "rc=%d error=%d disabled=%d\n",rc,GetLastError(),disabled);
775 }
776 
777 /* check the GetThreadTimes function */
778 static VOID test_GetThreadTimes(void)
779 {
780      HANDLE thread,access_thread=NULL;
781      FILETIME creationTime,exitTime,kernelTime,userTime;
782      DWORD threadId;
783      int error;
784 
785      thread = CreateThread(NULL,0,threadFunc2,NULL,
786                            CREATE_SUSPENDED,&threadId);
787 
788      ok(thread!=NULL,"Create Thread failed\n");
789 /* check that access control is obeyed */
790      if (pOpenThread) {
791        access_thread=pOpenThread(THREAD_ALL_ACCESS_NT4 &
792                                    (~THREAD_QUERY_INFORMATION), 0,threadId);
793        ok(access_thread!=NULL,
794           "OpenThread returned an invalid handle\n");
795      }
796      ok(ResumeThread(thread)==1,"Resume thread returned an invalid value\n");
797      ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
798         "ResumeThread didn't work\n");
799      creationTime.dwLowDateTime=99; creationTime.dwHighDateTime=99;
800      exitTime.dwLowDateTime=99;     exitTime.dwHighDateTime=99;
801      kernelTime.dwLowDateTime=99;   kernelTime.dwHighDateTime=99;
802      userTime.dwLowDateTime=99;     userTime.dwHighDateTime=99;
803 /* GetThreadTimes should set all of the parameters passed to it */
804      error=GetThreadTimes(thread,&creationTime,&exitTime,
805                           &kernelTime,&userTime);
806 
807      if (error == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
808        win_skip("GetThreadTimes is not implemented\n");
809      else {
810        ok(error!=0,"GetThreadTimes failed\n");
811        ok(creationTime.dwLowDateTime!=99 || creationTime.dwHighDateTime!=99,
812           "creationTime was invalid\n");
813        ok(exitTime.dwLowDateTime!=99 || exitTime.dwHighDateTime!=99,
814           "exitTime was invalid\n");
815        ok(kernelTime.dwLowDateTime!=99 || kernelTime.dwHighDateTime!=99,
816           "kernelTimewas invalid\n");
817        ok(userTime.dwLowDateTime!=99 || userTime.dwHighDateTime!=99,
818           "userTime was invalid\n");
819        ok(CloseHandle(thread)!=0,"CloseHandle failed\n");
820        if(access_thread!=NULL)
821        {
822          error=GetThreadTimes(access_thread,&creationTime,&exitTime,
823                               &kernelTime,&userTime);
824          obey_ar(error==0);
825        }
826      }
827      if(access_thread!=NULL) {
828        ok(CloseHandle(access_thread)!=0,"CloseHandle Failed\n");
829      }
830 }
831 
832 /* Check the processor affinity functions */
833 /* NOTE: These functions should also be checked that they obey access control
834 */
835 static VOID test_thread_processor(void)
836 {
837    HANDLE curthread,curproc;
838    DWORD_PTR processMask,systemMask,retMask;
839    SYSTEM_INFO sysInfo;
840    int error=0;
841    BOOL is_wow64;
842 
843    if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
844 
845    sysInfo.dwNumberOfProcessors=0;
846    GetSystemInfo(&sysInfo);
847    ok(sysInfo.dwNumberOfProcessors>0,
848       "GetSystemInfo failed to return a valid # of processors\n");
849 /* Use the current Thread/process for all tests */
850    curthread=GetCurrentThread();
851    ok(curthread!=NULL,"GetCurrentThread failed\n");
852    curproc=GetCurrentProcess();
853    ok(curproc!=NULL,"GetCurrentProcess failed\n");
854 /* Check the Affinity Mask functions */
855    ok(GetProcessAffinityMask(curproc,&processMask,&systemMask)!=0,
856       "GetProcessAffinityMask failed\n");
857    ok(SetThreadAffinityMask(curthread,processMask)==processMask,
858       "SetThreadAffinityMask failed\n");
859    ok(SetThreadAffinityMask(curthread,processMask+1)==0,
860       "SetThreadAffinityMask passed for an illegal processor\n");
861 /* NOTE: Pre-Vista does not recognize the "all processors" flag (all bits set) */
862    retMask = SetThreadAffinityMask(curthread,~0);
863    ok(broken(retMask==0) || retMask==processMask,
864       "SetThreadAffinityMask(thread,-1) failed to request all processors.\n");
865 
866     if (retMask == processMask)
867     {
868         /* Show that the "all processors" flag is handled in ntdll */
869         DWORD_PTR mask = ~0u;
870         NTSTATUS status = pNtSetInformationThread(curthread, ThreadAffinityMask, &mask, sizeof(mask));
871         ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS in NtSetInformationThread, got %x\n", status);
872     }
873 
874    if (retMask == processMask && sizeof(ULONG_PTR) > sizeof(ULONG))
875    {
876        /* only the low 32-bits matter */
877        retMask = SetThreadAffinityMask(curthread,~(ULONG_PTR)0);
878        ok(retMask == processMask, "SetThreadAffinityMask failed\n");
879        retMask = SetThreadAffinityMask(curthread,~(ULONG_PTR)0 >> 3);
880        ok(retMask == processMask, "SetThreadAffinityMask failed\n");
881    }
882 /* NOTE: This only works on WinNT/2000/XP) */
883     if (pSetThreadIdealProcessor)
884     {
885         SetLastError(0xdeadbeef);
886         error=pSetThreadIdealProcessor(curthread,0);
887         if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
888         {
889             ok(error!=-1, "SetThreadIdealProcessor failed\n");
890 
891             if (is_wow64)
892             {
893                 SetLastError(0xdeadbeef);
894                 error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS+1);
895                 todo_wine
896                 ok(error!=-1, "SetThreadIdealProcessor failed for %u on Wow64\n", MAXIMUM_PROCESSORS+1);
897 
898                 SetLastError(0xdeadbeef);
899                 error=pSetThreadIdealProcessor(curthread,65);
900                 ok(error==-1, "SetThreadIdealProcessor succeeded with an illegal processor #\n");
901                 ok(GetLastError()==ERROR_INVALID_PARAMETER,
902                    "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
903             }
904             else
905             {
906                 SetLastError(0xdeadbeef);
907                 error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS+1);
908                 ok(error==-1, "SetThreadIdealProcessor succeeded with an illegal processor #\n");
909                 ok(GetLastError()==ERROR_INVALID_PARAMETER,
910                    "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
911             }
912 
913             error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS);
914             ok(error!=-1, "SetThreadIdealProcessor failed\n");
915         }
916         else
917             win_skip("SetThreadIdealProcessor is not implemented\n");
918     }
919 
920     if (pGetThreadGroupAffinity && pSetThreadGroupAffinity)
921     {
922         GROUP_AFFINITY affinity, affinity_new;
923         NTSTATUS status;
924 
925         memset(&affinity, 0, sizeof(affinity));
926         ok(pGetThreadGroupAffinity(curthread, &affinity), "GetThreadGroupAffinity failed\n");
927 
928         SetLastError(0xdeadbeef);
929         ok(!pGetThreadGroupAffinity(curthread, NULL), "GetThreadGroupAffinity succeeded\n");
930         ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == ERROR_NOACCESS), /* Win 7 and 8 */
931            "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
932         ok(affinity.Group == 0, "Expected group 0 got %u\n", affinity.Group);
933 
934         memset(&affinity_new, 0, sizeof(affinity_new));
935         affinity_new.Group = 0;
936         affinity_new.Mask  = affinity.Mask;
937         ok(pSetThreadGroupAffinity(curthread, &affinity_new, &affinity), "SetThreadGroupAffinity failed\n");
938         ok(affinity_new.Mask == affinity.Mask, "Expected old affinity mask %lx, got %lx\n",
939            affinity_new.Mask, affinity.Mask);
940 
941         /* show that the "all processors" flag is not supported for SetThreadGroupAffinity */
942         affinity_new.Group = 0;
943         affinity_new.Mask  = ~0u;
944         SetLastError(0xdeadbeef);
945         ok(!pSetThreadGroupAffinity(curthread, &affinity_new, NULL), "SetThreadGroupAffinity succeeded\n");
946         ok(GetLastError() == ERROR_INVALID_PARAMETER,
947            "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
948 
949         affinity_new.Group = 1; /* assumes that you have less than 64 logical processors */
950         affinity_new.Mask  = 0x1;
951         SetLastError(0xdeadbeef);
952         ok(!pSetThreadGroupAffinity(curthread, &affinity_new, NULL), "SetThreadGroupAffinity succeeded\n");
953         ok(GetLastError() == ERROR_INVALID_PARAMETER,
954            "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
955 
956         SetLastError(0xdeadbeef);
957         ok(!pSetThreadGroupAffinity(curthread, NULL, NULL), "SetThreadGroupAffinity succeeded\n");
958         ok(GetLastError() == ERROR_NOACCESS,
959            "Expected ERROR_NOACCESS, got %d\n", GetLastError());
960 
961         /* show that the access violation was detected in ntdll */
962         status = pNtSetInformationThread(curthread, ThreadGroupInformation, NULL, sizeof(affinity_new));
963         ok(status == STATUS_ACCESS_VIOLATION,
964            "Expected STATUS_ACCESS_VIOLATION, got %08x\n", status);
965 
966         /* restore original mask */
967         affinity_new.Group = 0;
968         affinity_new.Mask  = affinity.Mask;
969         SetLastError(0xdeadbeef);
970         ok(pSetThreadGroupAffinity(curthread, &affinity_new, &affinity), "SetThreadGroupAffinity failed\n");
971         ok(affinity_new.Mask == affinity.Mask, "Expected old affinity mask %lx, got %lx\n",
972            affinity_new.Mask, affinity.Mask);
973     }
974     else
975         win_skip("Get/SetThreadGroupAffinity not available\n");
976 }
977 
978 static VOID test_GetThreadExitCode(void)
979 {
980     DWORD exitCode, threadid;
981     DWORD GLE, ret;
982     HANDLE thread;
983 
984     ret = GetExitCodeThread((HANDLE)0x2bad2bad,&exitCode);
985     ok(ret==0, "GetExitCodeThread returned non zero value: %d\n", ret);
986     GLE = GetLastError();
987     ok(GLE==ERROR_INVALID_HANDLE, "GetLastError returned %d (expected 6)\n", GLE);
988 
989     thread = CreateThread(NULL,0,threadFunc2,NULL,0,&threadid);
990     ret = WaitForSingleObject(thread,100);
991     ok(ret==WAIT_OBJECT_0, "threadFunc2 did not exit during 100 ms\n");
992     ret = GetExitCodeThread(thread,&exitCode);
993     ok(ret==exitCode || ret==1,
994        "GetExitCodeThread returned %d (expected 1 or %d)\n", ret, exitCode);
995     ok(exitCode==99, "threadFunc2 exited with code %d (expected 99)\n", exitCode);
996     ok(CloseHandle(thread)!=0,"Error closing thread handle\n");
997 }
998 
999 #ifdef __i386__
1000 
1001 static int test_value = 0;
1002 static HANDLE event;
1003 
1004 static void WINAPI set_test_val( int val )
1005 {
1006     test_value += val;
1007     ExitThread(0);
1008 }
1009 
1010 static DWORD WINAPI threadFunc6(LPVOID p)
1011 {
1012     SetEvent( event );
1013     Sleep( 1000 );
1014     test_value *= (int)p;
1015     return 0;
1016 }
1017 
1018 static void test_SetThreadContext(void)
1019 {
1020     CONTEXT ctx;
1021     int *stack;
1022     HANDLE thread;
1023     DWORD threadid;
1024     DWORD prevcount;
1025     BOOL ret;
1026 
1027     SetLastError(0xdeadbeef);
1028     event = CreateEventW( NULL, TRUE, FALSE, NULL );
1029     thread = CreateThread( NULL, 0, threadFunc6, (void *)2, 0, &threadid );
1030     ok( thread != NULL, "CreateThread failed : (%d)\n", GetLastError() );
1031     if (!thread)
1032     {
1033         trace("Thread creation failed, skipping rest of test\n");
1034         return;
1035     }
1036     WaitForSingleObject( event, INFINITE );
1037     SuspendThread( thread );
1038     CloseHandle( event );
1039 
1040     ctx.ContextFlags = CONTEXT_FULL;
1041     SetLastError(0xdeadbeef);
1042     ret = GetThreadContext( thread, &ctx );
1043     ok( ret, "GetThreadContext failed : (%u)\n", GetLastError() );
1044 
1045     if (ret)
1046     {
1047         /* simulate a call to set_test_val(10) */
1048         stack = (int *)ctx.Esp;
1049         stack[-1] = 10;
1050         stack[-2] = ctx.Eip;
1051         ctx.Esp -= 2 * sizeof(int *);
1052         ctx.Eip = (DWORD)set_test_val;
1053         SetLastError(0xdeadbeef);
1054         ret = SetThreadContext( thread, &ctx );
1055         ok( ret, "SetThreadContext failed : (%d)\n", GetLastError() );
1056     }
1057 
1058     SetLastError(0xdeadbeef);
1059     prevcount = ResumeThread( thread );
1060     ok ( prevcount == 1, "Previous suspend count (%d) instead of 1, last error : (%d)\n",
1061                          prevcount, GetLastError() );
1062 
1063     WaitForSingleObject( thread, INFINITE );
1064     ok( test_value == 10, "test_value %d\n", test_value );
1065 
1066     ctx.ContextFlags = CONTEXT_FULL;
1067     SetLastError(0xdeadbeef);
1068     ret = GetThreadContext( thread, &ctx );
1069     ok( (!ret && ((GetLastError() == ERROR_GEN_FAILURE) || (GetLastError() == ERROR_ACCESS_DENIED))) ||
1070         (!ret && broken(GetLastError() == ERROR_INVALID_HANDLE)) || /* win2k */
1071         broken(ret),   /* 32bit application on NT 5.x 64bit */
1072         "got %d with %u (expected FALSE with ERROR_GEN_FAILURE or ERROR_ACCESS_DENIED)\n",
1073         ret, GetLastError() );
1074 
1075     SetLastError(0xdeadbeef);
1076     ret = SetThreadContext( thread, &ctx );
1077     ok( (!ret && ((GetLastError() == ERROR_GEN_FAILURE) || (GetLastError() == ERROR_ACCESS_DENIED))) ||
1078         (!ret && broken(GetLastError() == ERROR_INVALID_HANDLE)) || /* win2k */
1079         broken(ret),   /* 32bit application on NT 5.x 64bit */
1080         "got %d with %u (expected FALSE with ERROR_GEN_FAILURE or ERROR_ACCESS_DENIED)\n",
1081         ret, GetLastError() );
1082 
1083     CloseHandle( thread );
1084 }
1085 
1086 static void test_GetThreadSelectorEntry(void)
1087 {
1088     LDT_ENTRY entry;
1089     CONTEXT ctx;
1090     DWORD limit;
1091     void *base;
1092     BOOL ret;
1093 
1094     memset(&ctx, 0x11, sizeof(ctx));
1095     ctx.ContextFlags = CONTEXT_SEGMENTS | CONTEXT_CONTROL;
1096     ret = GetThreadContext(GetCurrentThread(), &ctx);
1097     ok(ret, "GetThreadContext error %u\n", GetLastError());
1098     ok(!HIWORD(ctx.SegCs), "expected HIWORD(SegCs) == 0, got %u\n", ctx.SegCs);
1099     ok(!HIWORD(ctx.SegDs), "expected HIWORD(SegDs) == 0, got %u\n", ctx.SegDs);
1100     ok(!HIWORD(ctx.SegFs), "expected HIWORD(SegFs) == 0, got %u\n", ctx.SegFs);
1101 
1102     ret = GetThreadSelectorEntry(GetCurrentThread(), ctx.SegCs, &entry);
1103     ok(ret, "GetThreadSelectorEntry(SegCs) error %u\n", GetLastError());
1104     ret = GetThreadSelectorEntry(GetCurrentThread(), ctx.SegDs, &entry);
1105     ok(ret, "GetThreadSelectorEntry(SegDs) error %u\n", GetLastError());
1106 
1107     memset(&entry, 0x11, sizeof(entry));
1108     ret = GetThreadSelectorEntry(GetCurrentThread(), ctx.SegFs, &entry);
1109     ok(ret, "GetThreadSelectorEntry(SegFs) error %u\n", GetLastError());
1110     entry.HighWord.Bits.Type &= ~1; /* ignore accessed bit */
1111 
1112     base  = (void *)((entry.HighWord.Bits.BaseHi << 24) | (entry.HighWord.Bits.BaseMid << 16) | entry.BaseLow);
1113     limit = (entry.HighWord.Bits.LimitHi << 16) | entry.LimitLow;
1114 
1115     ok(base == NtCurrentTeb(),                "expected %p, got %p\n", NtCurrentTeb(), base);
1116     ok(limit == 0x0fff || limit == 0x4000,    "expected 0x0fff or 0x4000, got %#x\n", limit);
1117     ok(entry.HighWord.Bits.Type == 0x12,      "expected 0x12, got %#x\n", entry.HighWord.Bits.Type);
1118     ok(entry.HighWord.Bits.Dpl == 3,          "expected 3, got %u\n", entry.HighWord.Bits.Dpl);
1119     ok(entry.HighWord.Bits.Pres == 1,         "expected 1, got %u\n", entry.HighWord.Bits.Pres);
1120     ok(entry.HighWord.Bits.Sys == 0,          "expected 0, got %u\n", entry.HighWord.Bits.Sys);
1121     ok(entry.HighWord.Bits.Reserved_0 == 0,   "expected 0, got %u\n", entry.HighWord.Bits.Reserved_0);
1122     ok(entry.HighWord.Bits.Default_Big == 1,  "expected 1, got %u\n", entry.HighWord.Bits.Default_Big);
1123     ok(entry.HighWord.Bits.Granularity == 0,  "expected 0, got %u\n", entry.HighWord.Bits.Granularity);
1124 }
1125 
1126 static void test_NtSetLdtEntries(void)
1127 {
1128     THREAD_DESCRIPTOR_INFORMATION tdi;
1129     LDT_ENTRY ds_entry;
1130     CONTEXT ctx;
1131     DWORD ret;
1132     union
1133     {
1134         LDT_ENTRY entry;
1135         DWORD dw[2];
1136     } sel;
1137 
1138     if (!pNtSetLdtEntries)
1139     {
1140         win_skip("NtSetLdtEntries is not available on this platform\n");
1141         return;
1142     }
1143 
1144     if (pNtSetLdtEntries(0, 0, 0, 0, 0, 0) == STATUS_NOT_IMPLEMENTED) /* WoW64 */
1145     {
1146         win_skip("NtSetLdtEntries is not implemented on this platform\n");
1147         return;
1148     }
1149 
1150     ret = pNtSetLdtEntries(0, 0, 0, 0, 0, 0);
1151     ok(!ret, "NtSetLdtEntries failed: %08x\n", ret);
1152 
1153     ctx.ContextFlags = CONTEXT_SEGMENTS;
1154     ret = GetThreadContext(GetCurrentThread(), &ctx);
1155     ok(ret, "GetThreadContext failed\n");
1156 
1157     tdi.Selector = ctx.SegDs;
1158     ret = pNtQueryInformationThread(GetCurrentThread(), ThreadDescriptorTableEntry, &tdi, sizeof(tdi), &ret);
1159     ok(!ret, "NtQueryInformationThread failed: %08x\n", ret);
1160     ds_entry = tdi.Entry;
1161 
1162     tdi.Selector = 0x000f;
1163     ret = pNtQueryInformationThread(GetCurrentThread(), ThreadDescriptorTableEntry, &tdi, sizeof(tdi), &ret);
1164     ok(ret == STATUS_ACCESS_VIOLATION, "got %08x\n", ret);
1165 
1166     tdi.Selector = 0x001f;
1167     ret = pNtQueryInformationThread(GetCurrentThread(), ThreadDescriptorTableEntry, &tdi, sizeof(tdi), &ret);
1168     ok(ret == STATUS_ACCESS_VIOLATION, "NtQueryInformationThread returned %08x\n", ret);
1169 
1170     ret = GetThreadSelectorEntry(GetCurrentThread(), 0x000f, &sel.entry);
1171     ok(!ret, "GetThreadSelectorEntry should fail\n");
1172 
1173     ret = GetThreadSelectorEntry(GetCurrentThread(), 0x001f, &sel.entry);
1174     ok(!ret, "GetThreadSelectorEntry should fail\n");
1175 
1176     memset(&sel.entry, 0x9a, sizeof(sel.entry));
1177     ret = GetThreadSelectorEntry(GetCurrentThread(), ctx.SegDs, &sel.entry);
1178     ok(ret, "GetThreadSelectorEntry failed\n");
1179     ok(!memcmp(&ds_entry, &sel.entry, sizeof(ds_entry)), "entries do not match\n");
1180 
1181     ret = pNtSetLdtEntries(0x000f, sel.dw[0], sel.dw[1], 0x001f, sel.dw[0], sel.dw[1]);
1182     ok(!ret || broken(ret == STATUS_INVALID_LDT_DESCRIPTOR) /*XP*/, "NtSetLdtEntries failed: %08x\n", ret);
1183 
1184     if (!ret)
1185     {
1186         memset(&sel.entry, 0x9a, sizeof(sel.entry));
1187         ret = GetThreadSelectorEntry(GetCurrentThread(), 0x000f, &sel.entry);
1188         ok(ret, "GetThreadSelectorEntry failed\n");
1189         ok(!memcmp(&ds_entry, &sel.entry, sizeof(ds_entry)), "entries do not match\n");
1190 
1191         memset(&sel.entry, 0x9a, sizeof(sel.entry));
1192         ret = GetThreadSelectorEntry(GetCurrentThread(), 0x001f, &sel.entry);
1193         ok(ret, "GetThreadSelectorEntry failed\n");
1194         ok(!memcmp(&ds_entry, &sel.entry, sizeof(ds_entry)), "entries do not match\n");
1195     }
1196 }
1197 
1198 #endif  /* __i386__ */
1199 
1200 static HANDLE finish_event;
1201 static LONG times_executed;
1202 
1203 static DWORD CALLBACK work_function(void *p)
1204 {
1205     LONG executed = InterlockedIncrement(&times_executed);
1206 
1207     if (executed == 100)
1208         SetEvent(finish_event);
1209     return 0;
1210 }
1211 
1212 static void test_QueueUserWorkItem(void)
1213 {
1214     INT_PTR i;
1215     DWORD wait_result;
1216     DWORD before, after;
1217 
1218     /* QueueUserWorkItem not present on win9x */
1219     if (!pQueueUserWorkItem) return;
1220 
1221     finish_event = CreateEventW(NULL, TRUE, FALSE, NULL);
1222 
1223     before = GetTickCount();
1224 
1225     for (i = 0; i < 100; i++)
1226     {
1227         BOOL ret = pQueueUserWorkItem(work_function, (void *)i, WT_EXECUTEDEFAULT);
1228         ok(ret, "QueueUserWorkItem failed with error %d\n", GetLastError());
1229     }
1230 
1231     wait_result = WaitForSingleObject(finish_event, 10000);
1232 
1233     after = GetTickCount();
1234     trace("100 QueueUserWorkItem calls took %dms\n", after - before);
1235     ok(wait_result == WAIT_OBJECT_0, "wait failed with error 0x%x\n", wait_result);
1236 
1237     ok(times_executed == 100, "didn't execute all of the work items\n");
1238 }
1239 
1240 static void CALLBACK signaled_function(PVOID p, BOOLEAN TimerOrWaitFired)
1241 {
1242     HANDLE event = p;
1243     SetEvent(event);
1244     ok(!TimerOrWaitFired, "wait shouldn't have timed out\n");
1245 }
1246 
1247 static void CALLBACK timeout_function(PVOID p, BOOLEAN TimerOrWaitFired)
1248 {
1249     HANDLE event = p;
1250     SetEvent(event);
1251     ok(TimerOrWaitFired, "wait should have timed out\n");
1252 }
1253 
1254 static void test_RegisterWaitForSingleObject(void)
1255 {
1256     BOOL ret;
1257     HANDLE wait_handle;
1258     HANDLE handle;
1259     HANDLE complete_event;
1260 
1261     if (!pRegisterWaitForSingleObject || !pUnregisterWait)
1262     {
1263         win_skip("RegisterWaitForSingleObject or UnregisterWait not implemented\n");
1264         return;
1265     }
1266 
1267     /* test signaled case */
1268 
1269     handle = CreateEventW(NULL, TRUE, TRUE, NULL);
1270     complete_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1271 
1272     ret = pRegisterWaitForSingleObject(&wait_handle, handle, signaled_function, complete_event, INFINITE, WT_EXECUTEONLYONCE);
1273     ok(ret, "RegisterWaitForSingleObject failed with error %d\n", GetLastError());
1274 
1275     WaitForSingleObject(complete_event, INFINITE);
1276     /* give worker thread chance to complete */
1277     Sleep(100);
1278 
1279     ret = pUnregisterWait(wait_handle);
1280     ok(ret, "UnregisterWait failed with error %d\n", GetLastError());
1281 
1282     /* test cancel case */
1283 
1284     ResetEvent(handle);
1285 
1286     ret = pRegisterWaitForSingleObject(&wait_handle, handle, signaled_function, complete_event, INFINITE, WT_EXECUTEONLYONCE);
1287     ok(ret, "RegisterWaitForSingleObject failed with error %d\n", GetLastError());
1288 
1289     ret = pUnregisterWait(wait_handle);
1290     ok(ret, "UnregisterWait failed with error %d\n", GetLastError());
1291 
1292     /* test timeout case */
1293 
1294     ret = pRegisterWaitForSingleObject(&wait_handle, handle, timeout_function, complete_event, 0, WT_EXECUTEONLYONCE);
1295     ok(ret, "RegisterWaitForSingleObject failed with error %d\n", GetLastError());
1296 
1297     WaitForSingleObject(complete_event, INFINITE);
1298     /* give worker thread chance to complete */
1299     Sleep(100);
1300 
1301     ret = pUnregisterWait(wait_handle);
1302     ok(ret, "UnregisterWait failed with error %d\n", GetLastError());
1303 
1304     SetLastError(0xdeadbeef);
1305     ret = pUnregisterWait(NULL);
1306     ok(!ret, "Expected UnregisterWait to fail\n");
1307     ok(GetLastError() == ERROR_INVALID_HANDLE,
1308        "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
1309 }
1310 
1311 static DWORD LS_main;
1312 static DWORD LS_index0, LS_index1;
1313 static DWORD LS_OutOfIndexesValue;
1314 
1315 /* Function pointers to the FLS/TLS functions to test in LS_ThreadProc() */
1316 static DWORD (WINAPI *LS_AllocFunc)(void);
1317 static PVOID (WINAPI *LS_GetValueFunc)(DWORD);
1318 static BOOL (WINAPI *LS_SetValueFunc)(DWORD, PVOID);
1319 static BOOL (WINAPI *LS_FreeFunc)(DWORD);
1320 
1321 /* Names of the functions tested in LS_ThreadProc(), for error messages */
1322 static const char* LS_AllocFuncName = "";
1323 static const char* LS_GetValueFuncName = "";
1324 static const char* LS_SetValueFuncName = "";
1325 static const char* LS_FreeFuncName = "";
1326 
1327 /* FLS entry points, dynamically loaded in platforms that support them */
1328 static DWORD (WINAPI *pFlsAlloc)(PFLS_CALLBACK_FUNCTION);
1329 static BOOL (WINAPI *pFlsFree)(DWORD);
1330 static PVOID (WINAPI *pFlsGetValue)(DWORD);
1331 static BOOL (WINAPI *pFlsSetValue)(DWORD,PVOID);
1332 
1333 /* A thunk function to make FlsAlloc compatible with the signature of TlsAlloc */
1334 static DWORD WINAPI FLS_AllocFuncThunk(void)
1335 {
1336   return pFlsAlloc(NULL);
1337 }
1338 
1339 static DWORD WINAPI LS_InheritanceProc(LPVOID p)
1340 {
1341   /* We should NOT inherit the FLS/TLS values from our parent or from the
1342      main thread.  */
1343   LPVOID val;
1344 
1345   val = LS_GetValueFunc(LS_main);
1346   ok(val == NULL, "%s inheritance failed\n", LS_GetValueFuncName);
1347 
1348   val = LS_GetValueFunc(LS_index0);
1349   ok(val == NULL, "%s inheritance failed\n", LS_GetValueFuncName);
1350 
1351   val = LS_GetValueFunc(LS_index1);
1352   ok(val == NULL, "%s inheritance failed\n", LS_GetValueFuncName);
1353 
1354   return 0;
1355 }
1356 
1357 /* Basic FLS/TLS usage test.  Make sure we can create slots and the values we
1358    store in them are separate among threads.  Also test FLS/TLS value
1359    inheritance with LS_InheritanceProc.  */
1360 static DWORD WINAPI LS_ThreadProc(LPVOID p)
1361 {
1362   LONG_PTR id = (LONG_PTR) p;
1363   LPVOID val;
1364   BOOL ret;
1365 
1366   if (sync_threads_and_run_one(0, id))
1367   {
1368     LS_index0 = LS_AllocFunc();
1369     ok(LS_index0 != LS_OutOfIndexesValue, "%s failed\n", LS_AllocFuncName);
1370   }
1371   resync_after_run();
1372 
1373   if (sync_threads_and_run_one(1, id))
1374   {
1375     LS_index1 = LS_AllocFunc();
1376     ok(LS_index1 != LS_OutOfIndexesValue, "%s failed\n", LS_AllocFuncName);
1377 
1378     /* Slot indices should be different even if created in different
1379        threads.  */
1380     ok(LS_index0 != LS_index1, "%s failed\n", LS_AllocFuncName);
1381 
1382     /* Both slots should be initialized to NULL */
1383     val = LS_GetValueFunc(LS_index0);
1384     ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName);
1385     ok(val == NULL, "Slot not initialized correctly\n");
1386 
1387     val = LS_GetValueFunc(LS_index1);
1388     ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName);
1389     ok(val == NULL, "Slot not initialized correctly\n");
1390   }
1391   resync_after_run();
1392 
1393   if (sync_threads_and_run_one(0, id))
1394   {
1395     val = LS_GetValueFunc(LS_index0);
1396     ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName);
1397     ok(val == NULL, "Slot not initialized correctly\n");
1398 
1399     val = LS_GetValueFunc(LS_index1);
1400     ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName);
1401     ok(val == NULL, "Slot not initialized correctly\n");
1402 
1403     ret = LS_SetValueFunc(LS_index0, (LPVOID) 1);
1404     ok(ret, "%s failed\n", LS_SetValueFuncName);
1405 
1406     ret = LS_SetValueFunc(LS_index1, (LPVOID) 2);
1407     ok(ret, "%s failed\n", LS_SetValueFuncName);
1408 
1409     val = LS_GetValueFunc(LS_index0);
1410     ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName);
1411     ok(val == (LPVOID) 1, "Slot not initialized correctly\n");
1412 
1413     val = LS_GetValueFunc(LS_index1);
1414     ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName);
1415     ok(val == (LPVOID) 2, "Slot not initialized correctly\n");
1416   }
1417   resync_after_run();
1418 
1419   if (sync_threads_and_run_one(1, id))
1420   {
1421     val = LS_GetValueFunc(LS_index0);
1422     ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName);
1423     ok(val == NULL, "Slot not initialized correctly\n");
1424 
1425     val = LS_GetValueFunc(LS_index1);
1426     ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName);
1427     ok(val == NULL, "Slot not initialized correctly\n");
1428 
1429     ret = LS_SetValueFunc(LS_index0, (LPVOID) 3);
1430     ok(ret, "%s failed\n", LS_SetValueFuncName);
1431 
1432     ret = LS_SetValueFunc(LS_index1, (LPVOID) 4);
1433     ok(ret, "%s failed\n", LS_SetValueFuncName);
1434 
1435     val = LS_GetValueFunc(LS_index0);
1436     ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName);
1437     ok(val == (LPVOID) 3, "Slot not initialized correctly\n");
1438 
1439     val = LS_GetValueFunc(LS_index1);
1440     ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName);
1441     ok(val == (LPVOID) 4, "Slot not initialized correctly\n");
1442   }
1443   resync_after_run();
1444 
1445   if (sync_threads_and_run_one(0, id))
1446   {
1447     HANDLE thread;
1448     DWORD waitret, tid;
1449 
1450     val = LS_GetValueFunc(LS_index0);
1451     ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName);
1452     ok(val == (LPVOID) 1, "Slot not initialized correctly\n");
1453 
1454     val = LS_GetValueFunc(LS_index1);
1455     ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName);
1456     ok(val == (LPVOID) 2, "Slot not initialized correctly\n");
1457 
1458     thread = CreateThread(NULL, 0, LS_InheritanceProc, 0, 0, &tid);
1459     ok(thread != NULL, "CreateThread failed\n");
1460     waitret = WaitForSingleObject(thread, 60000);
1461     ok(waitret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
1462     CloseHandle(thread);
1463 
1464     ret = LS_FreeFunc(LS_index0);
1465     ok(ret, "%s failed\n", LS_FreeFuncName);
1466   }
1467   resync_after_run();
1468 
1469   if (sync_threads_and_run_one(1, id))
1470   {
1471     ret = LS_FreeFunc(LS_index1);
1472     ok(ret, "%s failed\n", LS_FreeFuncName);
1473   }
1474   resync_after_run();
1475 
1476   return 0;
1477 }
1478 
1479 static void run_LS_tests(void)
1480 {
1481   HANDLE threads[2];
1482   LONG_PTR i;
1483   DWORD ret;
1484   BOOL suc;
1485 
1486   init_thread_sync_helpers();
1487 
1488   /* Allocate a slot in the main thread to test for inheritance.  */
1489   LS_main = LS_AllocFunc();
1490   ok(LS_main != LS_OutOfIndexesValue, "%s failed\n", LS_AllocFuncName);
1491   suc = LS_SetValueFunc(LS_main, (LPVOID) 4114);
1492   ok(suc, "%s failed\n", LS_SetValueFuncName);
1493 
1494   for (i = 0; i < 2; ++i)
1495   {
1496     DWORD tid;
1497 
1498     threads[i] = CreateThread(NULL, 0, LS_ThreadProc, (LPVOID) i, 0, &tid);
1499     ok(threads[i] != NULL, "CreateThread failed\n");
1500   }
1501 
1502   ret = WaitForMultipleObjects(2, threads, TRUE, 60000);
1503   ok(ret == WAIT_OBJECT_0 || broken(ret == WAIT_OBJECT_0+1 /* nt4,w2k */), "WaitForAllObjects 2 threads %d\n",ret);
1504 
1505   for (i = 0; i < 2; ++i)
1506     CloseHandle(threads[i]);
1507 
1508   suc = LS_FreeFunc(LS_main);
1509   ok(suc, "%s failed\n", LS_FreeFuncName);
1510   cleanup_thread_sync_helpers();
1511 }
1512 
1513 static void test_TLS(void)
1514 {
1515   LS_OutOfIndexesValue = TLS_OUT_OF_INDEXES;
1516 
1517   LS_AllocFunc = &TlsAlloc;
1518   LS_GetValueFunc = &TlsGetValue;
1519   LS_SetValueFunc = &TlsSetValue;
1520   LS_FreeFunc = &TlsFree;
1521 
1522   LS_AllocFuncName = "TlsAlloc";
1523   LS_GetValueFuncName = "TlsGetValue";
1524   LS_SetValueFuncName = "TlsSetValue";
1525   LS_FreeFuncName = "TlsFree";
1526 
1527   run_LS_tests();
1528 }
1529 
1530 static void test_FLS(void)
1531 {
1532   if (!pFlsAlloc || !pFlsFree || !pFlsGetValue || !pFlsSetValue)
1533   {
1534      win_skip("Fiber Local Storage not supported\n");
1535      return;
1536   }
1537 
1538   LS_OutOfIndexesValue = FLS_OUT_OF_INDEXES;
1539 
1540   LS_AllocFunc = &FLS_AllocFuncThunk;
1541   LS_GetValueFunc = pFlsGetValue;
1542   LS_SetValueFunc = pFlsSetValue;
1543   LS_FreeFunc = pFlsFree;
1544 
1545   LS_AllocFuncName = "FlsAlloc";
1546   LS_GetValueFuncName = "FlsGetValue";
1547   LS_SetValueFuncName = "FlsSetValue";
1548   LS_FreeFuncName = "FlsFree";
1549 
1550   run_LS_tests();
1551 }
1552 
1553 static void test_ThreadErrorMode(void)
1554 {
1555     DWORD oldmode;
1556     DWORD mode;
1557     DWORD rtlmode;
1558     BOOL ret;
1559 
1560     if (!pSetThreadErrorMode || !pGetThreadErrorMode)
1561     {
1562         win_skip("SetThreadErrorMode and/or GetThreadErrorMode unavailable (added in Windows 7)\n");
1563         return;
1564     }
1565 
1566     if (!pRtlGetThreadErrorMode) {
1567         win_skip("RtlGetThreadErrorMode not available\n");
1568         return;
1569     }
1570 
1571     oldmode = pGetThreadErrorMode();
1572 
1573     ret = pSetThreadErrorMode(0, &mode);
1574     ok(ret, "SetThreadErrorMode failed\n");
1575     ok(mode == oldmode,
1576        "SetThreadErrorMode returned old mode 0x%x, expected 0x%x\n",
1577        mode, oldmode);
1578     mode = pGetThreadErrorMode();
1579     ok(mode == 0, "GetThreadErrorMode returned mode 0x%x, expected 0\n", mode);
1580     rtlmode = pRtlGetThreadErrorMode();
1581     ok(rtlmode == 0,
1582        "RtlGetThreadErrorMode returned mode 0x%x, expected 0\n", mode);
1583 
1584     ret = pSetThreadErrorMode(SEM_FAILCRITICALERRORS, &mode);
1585     ok(ret, "SetThreadErrorMode failed\n");
1586     ok(mode == 0,
1587        "SetThreadErrorMode returned old mode 0x%x, expected 0\n", mode);
1588     mode = pGetThreadErrorMode();
1589     ok(mode == SEM_FAILCRITICALERRORS,
1590        "GetThreadErrorMode returned mode 0x%x, expected SEM_FAILCRITICALERRORS\n",
1591        mode);
1592     rtlmode = pRtlGetThreadErrorMode();
1593     ok(rtlmode == 0x10,
1594        "RtlGetThreadErrorMode returned mode 0x%x, expected 0x10\n", mode);
1595 
1596     ret = pSetThreadErrorMode(SEM_NOGPFAULTERRORBOX, &mode);
1597     ok(ret, "SetThreadErrorMode failed\n");
1598     ok(mode == SEM_FAILCRITICALERRORS,
1599        "SetThreadErrorMode returned old mode 0x%x, expected SEM_FAILCRITICALERRORS\n",
1600        mode);
1601     mode = pGetThreadErrorMode();
1602     ok(mode == SEM_NOGPFAULTERRORBOX,
1603        "GetThreadErrorMode returned mode 0x%x, expected SEM_NOGPFAULTERRORBOX\n",
1604        mode);
1605     rtlmode = pRtlGetThreadErrorMode();
1606     ok(rtlmode == 0x20,
1607        "RtlGetThreadErrorMode returned mode 0x%x, expected 0x20\n", mode);
1608 
1609     ret = pSetThreadErrorMode(SEM_NOOPENFILEERRORBOX, NULL);
1610     ok(ret, "SetThreadErrorMode failed\n");
1611     mode = pGetThreadErrorMode();
1612     ok(mode == SEM_NOOPENFILEERRORBOX,
1613        "GetThreadErrorMode returned mode 0x%x, expected SEM_NOOPENFILEERRORBOX\n",
1614        mode);
1615     rtlmode = pRtlGetThreadErrorMode();
1616     ok(rtlmode == 0x40,
1617        "RtlGetThreadErrorMode returned mode 0x%x, expected 0x40\n", rtlmode);
1618 
1619     for (mode = 1; mode; mode <<= 1)
1620     {
1621         ret = pSetThreadErrorMode(mode, NULL);
1622         if (mode & (SEM_FAILCRITICALERRORS |
1623                     SEM_NOGPFAULTERRORBOX |
1624                     SEM_NOOPENFILEERRORBOX))
1625         {
1626             ok(ret,
1627                "SetThreadErrorMode(0x%x,NULL) failed with error %d\n",
1628                mode, GetLastError());
1629         }
1630         else
1631         {
1632             DWORD GLE = GetLastError();
1633             ok(!ret,
1634                "SetThreadErrorMode(0x%x,NULL) succeeded, expected failure\n",
1635                mode);
1636             ok(GLE == ERROR_INVALID_PARAMETER,
1637                "SetThreadErrorMode(0x%x,NULL) failed with %d, "
1638                "expected ERROR_INVALID_PARAMETER\n",
1639                mode, GLE);
1640         }
1641     }
1642 
1643     pSetThreadErrorMode(oldmode, NULL);
1644 }
1645 
1646 #if (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) || (defined(_MSC_VER) && defined(__i386__))
1647 static inline void set_fpu_cw(WORD cw)
1648 {
1649 #ifdef _MSC_VER
1650     __asm { fnclex }
1651     __asm { fldcw [cw] }
1652 #else
1653     __asm__ volatile ("fnclex; fldcw %0" : : "m" (cw));
1654 #endif
1655 }
1656 
1657 static inline WORD get_fpu_cw(void)
1658 {
1659     WORD cw = 0;
1660 #ifdef _MSC_VER
1661     __asm { fnstcw [cw] }
1662 #else
1663     __asm__ volatile ("fnstcw %0" : "=m" (cw));
1664 #endif
1665     return cw;
1666 }
1667 
1668 struct fpu_thread_ctx
1669 {
1670     WORD cw;
1671     HANDLE finished;
1672 };
1673 
1674 static DWORD WINAPI fpu_thread(void *param)
1675 {
1676     struct fpu_thread_ctx *ctx = param;
1677     BOOL ret;
1678 
1679     ctx->cw = get_fpu_cw();
1680 
1681     ret = SetEvent(ctx->finished);
1682     ok(ret, "SetEvent failed, last error %#x.\n", GetLastError());
1683 
1684     return 0;
1685 }
1686 
1687 static WORD get_thread_fpu_cw(void)
1688 {
1689     struct fpu_thread_ctx ctx;
1690     DWORD tid, res;
1691     HANDLE thread;
1692 
1693     ctx.finished = CreateEventW(NULL, FALSE, FALSE, NULL);
1694     ok(!!ctx.finished, "Failed to create event, last error %#x.\n", GetLastError());
1695 
1696     thread = CreateThread(NULL, 0, fpu_thread, &ctx, 0, &tid);
1697     ok(!!thread, "Failed to create thread, last error %#x.\n", GetLastError());
1698 
1699     res = WaitForSingleObject(ctx.finished, INFINITE);
1700     ok(res == WAIT_OBJECT_0, "Wait failed (%#x), last error %#x.\n", res, GetLastError());
1701 
1702     res = CloseHandle(ctx.finished);
1703     ok(!!res, "Failed to close event handle, last error %#x.\n", GetLastError());
1704 
1705     return ctx.cw;
1706 }
1707 
1708 static void test_thread_fpu_cw(void)
1709 {
1710     WORD initial_cw, cw;
1711 
1712     initial_cw = get_fpu_cw();
1713     ok(initial_cw == 0x27f, "Expected FPU control word 0x27f, got %#x.\n", initial_cw);
1714 
1715     cw = get_thread_fpu_cw();
1716     ok(cw == 0x27f, "Expected FPU control word 0x27f, got %#x.\n", cw);
1717 
1718     set_fpu_cw(0xf60);
1719     cw = get_fpu_cw();
1720     ok(cw == 0xf60, "Expected FPU control word 0xf60, got %#x.\n", cw);
1721 
1722     cw = get_thread_fpu_cw();
1723     ok(cw == 0x27f, "Expected FPU control word 0x27f, got %#x.\n", cw);
1724 
1725     cw = get_fpu_cw();
1726     ok(cw == 0xf60, "Expected FPU control word 0xf60, got %#x.\n", cw);
1727 
1728     set_fpu_cw(initial_cw);
1729     cw = get_fpu_cw();
1730     ok(cw == initial_cw, "Expected FPU control word %#x, got %#x.\n", initial_cw, cw);
1731 }
1732 #endif
1733 
1734 static const char manifest_dep[] =
1735 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
1736 "<assemblyIdentity version=\"1.2.3.4\"  name=\"testdep1\" type=\"win32\" processorArchitecture=\"" ARCH "\"/>"
1737 "    <file name=\"testdep.dll\" />"
1738 "</assembly>";
1739 
1740 static const char manifest_main[] =
1741 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
1742 "<assemblyIdentity version=\"1.2.3.4\" name=\"Wine.Test\" type=\"win32\" />"
1743 "<dependency>"
1744 " <dependentAssembly>"
1745 "  <assemblyIdentity type=\"win32\" name=\"testdep1\" version=\"1.2.3.4\" processorArchitecture=\"" ARCH "\" />"
1746 " </dependentAssembly>"
1747 "</dependency>"
1748 "</assembly>";
1749 
1750 static void create_manifest_file(const char *filename, const char *manifest)
1751 {
1752     WCHAR path[MAX_PATH];
1753     HANDLE file;
1754     DWORD size;
1755 
1756     MultiByteToWideChar( CP_ACP, 0, filename, -1, path, MAX_PATH );
1757     file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1758     ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError());
1759     WriteFile(file, manifest, strlen(manifest), &size, NULL);
1760     CloseHandle(file);
1761 }
1762 
1763 static HANDLE test_create(const char *file)
1764 {
1765     WCHAR path[MAX_PATH];
1766     ACTCTXW actctx;
1767     HANDLE handle;
1768 
1769     MultiByteToWideChar(CP_ACP, 0, file, -1, path, MAX_PATH);
1770     memset(&actctx, 0, sizeof(ACTCTXW));
1771     actctx.cbSize = sizeof(ACTCTXW);
1772     actctx.lpSource = path;
1773 
1774     handle = pCreateActCtxW(&actctx);
1775     ok(handle != INVALID_HANDLE_VALUE, "failed to create context, error %u\n", GetLastError());
1776 
1777     ok(actctx.cbSize == sizeof(actctx), "cbSize=%d\n", actctx.cbSize);
1778     ok(actctx.dwFlags == 0, "dwFlags=%d\n", actctx.dwFlags);
1779     ok(actctx.lpSource == path, "lpSource=%p\n", actctx.lpSource);
1780     ok(actctx.wProcessorArchitecture == 0, "wProcessorArchitecture=%d\n", actctx.wProcessorArchitecture);
1781     ok(actctx.wLangId == 0, "wLangId=%d\n", actctx.wLangId);
1782     ok(actctx.lpAssemblyDirectory == NULL, "lpAssemblyDirectory=%p\n", actctx.lpAssemblyDirectory);
1783     ok(actctx.lpResourceName == NULL, "lpResourceName=%p\n", actctx.lpResourceName);
1784     ok(actctx.lpApplicationName == NULL, "lpApplicationName=%p\n", actctx.lpApplicationName);
1785     ok(actctx.hModule == NULL, "hModule=%p\n", actctx.hModule);
1786 
1787     return handle;
1788 }
1789 
1790 static void test_thread_actctx(void)
1791 {
1792     struct thread_actctx_param param;
1793     HANDLE thread, handle, context;
1794     ULONG_PTR cookie;
1795     DWORD tid, ret;
1796     BOOL b;
1797 
1798     if (!pActivateActCtx)
1799     {
1800         win_skip("skipping activation context tests\n");
1801         return;
1802     }
1803 
1804     create_manifest_file("testdep1.manifest", manifest_dep);
1805     create_manifest_file("main.manifest", manifest_main);
1806 
1807     context = test_create("main.manifest");
1808     DeleteFileA("testdep1.manifest");
1809     DeleteFileA("main.manifest");
1810 
1811     handle = (void*)0xdeadbeef;
1812     b = pGetCurrentActCtx(&handle);
1813     ok(b, "GetCurrentActCtx failed: %u\n", GetLastError());
1814     ok(handle == 0, "active context %p\n", handle);
1815 
1816     /* without active context */
1817     param.thread_context = (void*)0xdeadbeef;
1818     param.handle = NULL;
1819     thread = CreateThread(NULL, 0, thread_actctx_func, &param, 0, &tid);
1820     ok(thread != NULL, "failed, got %u\n", GetLastError());
1821 
1822     ret = WaitForSingleObject(thread, 1000);
1823     ok(ret == WAIT_OBJECT_0, "wait timeout\n");
1824     ok(param.thread_context == NULL, "got wrong thread context %p\n", param.thread_context);
1825     CloseHandle(thread);
1826 
1827     b = pActivateActCtx(context, &cookie);
1828     ok(b, "activation failed: %u\n", GetLastError());
1829 
1830     handle = 0;
1831     b = pGetCurrentActCtx(&handle);
1832     ok(b, "GetCurrentActCtx failed: %u\n", GetLastError());
1833     ok(handle != 0, "no active context\n");
1834     pReleaseActCtx(handle);
1835 
1836     param.handle = NULL;
1837     b = pGetCurrentActCtx(&param.handle);
1838     ok(b && param.handle != NULL, "failed to get context, %u\n", GetLastError());
1839 
1840     param.thread_context = (void*)0xdeadbeef;
1841     thread = CreateThread(NULL, 0, thread_actctx_func, &param, 0, &tid);
1842     ok(thread != NULL, "failed, got %u\n", GetLastError());
1843 
1844     ret = WaitForSingleObject(thread, 1000);
1845     ok(ret == WAIT_OBJECT_0, "wait timeout\n");
1846     ok(param.thread_context == context, "got wrong thread context %p, %p\n", param.thread_context, context);
1847     pReleaseActCtx(param.thread_context);
1848     CloseHandle(thread);
1849 
1850     /* similar test for CreateRemoteThread() */
1851     param.thread_context = (void*)0xdeadbeef;
1852     thread = CreateRemoteThread(GetCurrentProcess(), NULL, 0, thread_actctx_func, &param, 0, &tid);
1853     ok(thread != NULL, "failed, got %u\n", GetLastError());
1854 
1855     ret = WaitForSingleObject(thread, 1000);
1856     ok(ret == WAIT_OBJECT_0, "wait timeout\n");
1857     ok(param.thread_context == context, "got wrong thread context %p, %p\n", param.thread_context, context);
1858     pReleaseActCtx(param.thread_context);
1859     CloseHandle(thread);
1860 
1861     pReleaseActCtx(param.handle);
1862 
1863     b = pDeactivateActCtx(0, cookie);
1864     ok(b, "DeactivateActCtx failed: %u\n", GetLastError());
1865     pReleaseActCtx(context);
1866 }
1867 
1868 
1869 static void WINAPI threadpool_workcallback(PTP_CALLBACK_INSTANCE instance, void *context, PTP_WORK work) {
1870     int *foo = (int*)context;
1871 
1872     (*foo)++;
1873 }
1874 
1875 
1876 static void test_threadpool(void)
1877 {
1878     PTP_POOL pool;
1879     PTP_WORK work;
1880     int workcalled = 0;
1881 
1882     if (!pCreateThreadpool) {
1883         win_skip("thread pool apis not supported.\n");
1884         return;
1885     }
1886 
1887     work = pCreateThreadpoolWork(threadpool_workcallback, &workcalled, NULL);
1888     ok (work != NULL, "Error %d in CreateThreadpoolWork\n", GetLastError());
1889     pSubmitThreadpoolWork(work);
1890     pWaitForThreadpoolWorkCallbacks(work, FALSE);
1891     pCloseThreadpoolWork(work);
1892 
1893     ok (workcalled == 1, "expected work to be called once, got %d\n", workcalled);
1894 
1895     pool = pCreateThreadpool(NULL);
1896     ok (pool != NULL, "CreateThreadpool failed\n");
1897     pCloseThreadpool(pool);
1898 }
1899 
1900 static void test_reserved_tls(void)
1901 {
1902     void *val;
1903     DWORD tls;
1904     BOOL ret;
1905 
1906     /* This seems to be a WinXP SP2+ feature. */
1907     if(!pIsWow64Process) {
1908         win_skip("Skipping reserved TLS slot on too old Windows.\n");
1909         return;
1910     }
1911 
1912     val = TlsGetValue(0);
1913     ok(!val, "TlsGetValue(0) = %p\n", val);
1914 
1915     /* Also make sure that there is a TLS allocated. */
1916     tls = TlsAlloc();
1917     ok(tls && tls != TLS_OUT_OF_INDEXES, "tls = %x\n", tls);
1918     TlsSetValue(tls, (void*)1);
1919 
1920     val = TlsGetValue(0);
1921     ok(!val, "TlsGetValue(0) = %p\n", val);
1922 
1923     TlsFree(tls);
1924 
1925     /* The following is too ugly to be run by default */
1926     if(0) {
1927         /* Set TLS index 0 value and see that this works and doesn't cause problems
1928          * for remaining tests. */
1929         ret = TlsSetValue(0, (void*)1);
1930         ok(ret, "TlsSetValue(0, 1) failed: %u\n", GetLastError());
1931 
1932         val = TlsGetValue(0);
1933         ok(val == (void*)1, "TlsGetValue(0) = %p\n", val);
1934     }
1935 }
1936 
1937 static void test_thread_info(void)
1938 {
1939     char buf[4096];
1940     static const ULONG info_size[] =
1941     {
1942         sizeof(THREAD_BASIC_INFORMATION), /* ThreadBasicInformation */
1943         sizeof(KERNEL_USER_TIMES), /* ThreadTimes */
1944         sizeof(ULONG), /* ThreadPriority */
1945         sizeof(ULONG), /* ThreadBasePriority */
1946         sizeof(ULONG_PTR), /* ThreadAffinityMask */
1947         sizeof(HANDLE), /* ThreadImpersonationToken */
1948         sizeof(THREAD_DESCRIPTOR_INFORMATION), /* ThreadDescriptorTableEntry */
1949         sizeof(BOOLEAN), /* ThreadEnableAlignmentFaultFixup */
1950         0, /* ThreadEventPair_Reusable */
1951         sizeof(ULONG_PTR), /* ThreadQuerySetWin32StartAddress */
1952         sizeof(ULONG), /* ThreadZeroTlsCell */
1953         sizeof(LARGE_INTEGER), /* ThreadPerformanceCount */
1954         sizeof(ULONG), /* ThreadAmILastThread */
1955         sizeof(ULONG), /* ThreadIdealProcessor */
1956         sizeof(ULONG), /* ThreadPriorityBoost */
1957         sizeof(ULONG_PTR), /* ThreadSetTlsArrayAddress */
1958         sizeof(ULONG), /* ThreadIsIoPending */
1959         sizeof(BOOLEAN), /* ThreadHideFromDebugger */
1960         /* FIXME: Add remaining classes */
1961     };
1962     HANDLE thread;
1963     ULONG i, status, ret_len;
1964 
1965     if (!pOpenThread)
1966     {
1967         win_skip("OpenThread is not available on this platform\n");
1968         return;
1969     }
1970 
1971     if (!pNtQueryInformationThread)
1972     {
1973         win_skip("NtQueryInformationThread is not available on this platform\n");
1974         return;
1975     }
1976 
1977     thread = pOpenThread(THREAD_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentThreadId());
1978     if (!thread)
1979     {
1980         win_skip("THREAD_QUERY_LIMITED_INFORMATION is not supported on this platform\n");
1981         return;
1982     }
1983 
1984     for (i = 0; i < sizeof(info_size)/sizeof(info_size[0]); i++)
1985     {
1986         memset(buf, 0, sizeof(buf));
1987 
1988 #ifdef __i386__
1989         if (i == ThreadDescriptorTableEntry)
1990         {
1991             CONTEXT ctx;
1992             THREAD_DESCRIPTOR_INFORMATION *tdi = (void *)buf;
1993 
1994             ctx.ContextFlags = CONTEXT_SEGMENTS;
1995             GetThreadContext(GetCurrentThread(), &ctx);
1996             tdi->Selector = ctx.SegDs;
1997         }
1998 #endif
1999         ret_len = 0;
2000         status = pNtQueryInformationThread(thread, i, buf, info_size[i], &ret_len);
2001         if (status == STATUS_NOT_IMPLEMENTED) continue;
2002         if (status == STATUS_INVALID_INFO_CLASS) continue;
2003         if (status == STATUS_UNSUCCESSFUL) continue;
2004 
2005         switch (i)
2006         {
2007         case ThreadBasicInformation:
2008         case ThreadAmILastThread:
2009         case ThreadPriorityBoost:
2010             ok(status == STATUS_SUCCESS, "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i, status, ret_len);
2011             break;
2012 
2013 #ifdef __i386__
2014         case ThreadDescriptorTableEntry:
2015             ok(status == STATUS_SUCCESS || broken(status == STATUS_ACCESS_DENIED) /* testbot VM is broken */,
2016                "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i, status, ret_len);
2017             break;
2018 #endif
2019 
2020         case ThreadTimes:
2021 todo_wine
2022             ok(status == STATUS_SUCCESS, "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i, status, ret_len);
2023             break;
2024 
2025         case ThreadAffinityMask:
2026         case ThreadQuerySetWin32StartAddress:
2027         case ThreadIsIoPending:
2028 todo_wine
2029             ok(status == STATUS_ACCESS_DENIED, "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i, status, ret_len);
2030             break;
2031 
2032         default:
2033             ok(status == STATUS_ACCESS_DENIED, "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i, status, ret_len);
2034             break;
2035         }
2036     }
2037 
2038     CloseHandle(thread);
2039 }
2040 
2041 static void init_funcs(void)
2042 {
2043     HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
2044     HMODULE ntdll = GetModuleHandleA("ntdll.dll");
2045 
2046 /* Neither Cygwin nor mingW export OpenThread, so do a dynamic check
2047    so that the compile passes */
2048 
2049 #define X(f) p##f = (void*)GetProcAddress(hKernel32, #f)
2050     X(GetThreadPriorityBoost);
2051     X(OpenThread);
2052     X(QueueUserWorkItem);
2053     X(SetThreadIdealProcessor);
2054     X(SetThreadPriorityBoost);
2055     X(RegisterWaitForSingleObject);
2056     X(UnregisterWait);
2057     X(IsWow64Process);
2058     X(SetThreadErrorMode);
2059     X(GetThreadErrorMode);
2060     X(ActivateActCtx);
2061     X(CreateActCtxW);
2062     X(DeactivateActCtx);
2063     X(GetCurrentActCtx);
2064     X(ReleaseActCtx);
2065 
2066     X(CreateThreadpool);
2067     X(CloseThreadpool);
2068     X(CreateThreadpoolWork);
2069     X(SubmitThreadpoolWork);
2070     X(WaitForThreadpoolWorkCallbacks);
2071     X(CloseThreadpoolWork);
2072 
2073     X(GetThreadGroupAffinity);
2074     X(SetThreadGroupAffinity);
2075 
2076     X(FlsAlloc);
2077     X(FlsFree);
2078     X(FlsSetValue);
2079     X(FlsGetValue);
2080 #undef X
2081 
2082 #define X(f) p##f = (void*)GetProcAddress(ntdll, #f)
2083    if (ntdll)
2084    {
2085        X(NtQueryInformationThread);
2086        X(RtlGetThreadErrorMode);
2087        X(NtSetInformationThread);
2088        X(NtSetLdtEntries);
2089    }
2090 #undef X
2091 }
2092 
2093 START_TEST(thread)
2094 {
2095    int argc;
2096    char **argv;
2097    argc = winetest_get_mainargs( &argv );
2098 
2099    init_funcs();
2100 
2101    if (argc >= 3)
2102    {
2103        if (!strcmp(argv[2], "sleep"))
2104        {
2105            HANDLE hAddrEvents[2];
2106            create_function_addr_events(hAddrEvents);
2107            SetEvent(hAddrEvents[0]);
2108            SetEvent(hAddrEvents[1]);
2109            Sleep(5000); /* spawned process runs for at most 5 seconds */
2110            return;
2111        }
2112        while (1)
2113        {
2114            HANDLE hThread;
2115            DWORD tid;
2116            hThread = CreateThread(NULL, 0, threadFunc2, NULL, 0, &tid);
2117            ok(hThread != NULL, "CreateThread failed, error %u\n",
2118               GetLastError());
2119            ok(WaitForSingleObject(hThread, 200) == WAIT_OBJECT_0,
2120               "Thread did not exit in time\n");
2121            if (hThread == NULL) break;
2122            CloseHandle(hThread);
2123        }
2124        return;
2125    }
2126 
2127    test_thread_info();
2128    test_reserved_tls();
2129    test_CreateRemoteThread();
2130    test_CreateThread_basic();
2131    test_CreateThread_suspended();
2132    test_SuspendThread();
2133    test_TerminateThread();
2134    test_CreateThread_stack();
2135    test_thread_priority();
2136    test_GetThreadTimes();
2137    test_thread_processor();
2138    test_GetThreadExitCode();
2139 #ifdef __i386__
2140    test_SetThreadContext();
2141    test_GetThreadSelectorEntry();
2142    test_NtSetLdtEntries();
2143 #endif
2144    test_QueueUserWorkItem();
2145    test_RegisterWaitForSingleObject();
2146    test_TLS();
2147    test_FLS();
2148    test_ThreadErrorMode();
2149 #if (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) || (defined(_MSC_VER) && defined(__i386__))
2150    test_thread_fpu_cw();
2151 #endif
2152    test_thread_actctx();
2153 
2154    test_threadpool();
2155 }
2156