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