kernel32/tests: Add a few skips instead of just returning.
[wine] / dlls / kernel32 / tests / thread.c
1 /*
2  * Unit test suite for directory 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 /* Define _WIN32_WINNT to get SetThreadIdealProcessor on Windows */
22 #define _WIN32_WINNT 0x0500
23
24 #include <stdarg.h>
25 #include <stdio.h>
26
27 #include "wine/test.h"
28 #include <windef.h>
29 #include <winbase.h>
30 #include <winnt.h>
31 #include <winerror.h>
32
33 /* Specify the number of simultaneous threads to test */
34 #define NUM_THREADS 4
35 /* Specify whether to test the extended priorities for Win2k/XP */
36 #define USE_EXTENDED_PRIORITIES 0
37 /* Specify whether to test the stack allocation in CreateThread */
38 #define CHECK_STACK 0
39
40 /* Set CHECK_STACK to 1 if you want to try to test the stack-limit from
41    CreateThread.  So far I have been unable to make this work, and
42    I am in doubt as to how portable it is.  Also, according to MSDN,
43    you shouldn't mix C-run-time-libraries (i.e. alloca) with CreateThread.
44    Anyhow, the check is currently commented out
45 */
46 #if CHECK_STACK
47 # ifdef __try
48 #  define __TRY __try
49 #  define __EXCEPT __except
50 #  define __ENDTRY
51 # else
52 #  include "wine/exception.h"
53 # endif
54 #endif
55
56 typedef BOOL (WINAPI *GetThreadPriorityBoost_t)(HANDLE,PBOOL);
57 static GetThreadPriorityBoost_t pGetThreadPriorityBoost=NULL;
58
59 typedef HANDLE (WINAPI *OpenThread_t)(DWORD,BOOL,DWORD);
60 static OpenThread_t pOpenThread=NULL;
61
62 typedef BOOL (WINAPI *QueueUserWorkItem_t)(LPTHREAD_START_ROUTINE,PVOID,ULONG);
63 static QueueUserWorkItem_t pQueueUserWorkItem=NULL;
64
65 typedef DWORD (WINAPI *SetThreadIdealProcessor_t)(HANDLE,DWORD);
66 static SetThreadIdealProcessor_t pSetThreadIdealProcessor=NULL;
67
68 typedef BOOL (WINAPI *SetThreadPriorityBoost_t)(HANDLE,BOOL);
69 static SetThreadPriorityBoost_t pSetThreadPriorityBoost=NULL;
70
71 typedef BOOL (WINAPI *RegisterWaitForSingleObject_t)(PHANDLE,HANDLE,WAITORTIMERCALLBACK,PVOID,ULONG,ULONG);
72 static RegisterWaitForSingleObject_t pRegisterWaitForSingleObject=NULL;
73
74 typedef BOOL (WINAPI *UnregisterWait_t)(HANDLE);
75 static UnregisterWait_t pUnregisterWait=NULL;
76
77 static HANDLE create_target_process(const char *arg)
78 {
79     char **argv;
80     char cmdline[MAX_PATH];
81     PROCESS_INFORMATION pi;
82     STARTUPINFO si = { 0 };
83     si.cb = sizeof(si);
84
85     winetest_get_mainargs( &argv );
86     sprintf(cmdline, "%s %s %s", argv[0], argv[1], arg);
87     ok(CreateProcess(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL,
88                      &si, &pi) != 0, "error: %u\n", GetLastError());
89     ok(CloseHandle(pi.hThread) != 0, "error %u\n", GetLastError());
90     return pi.hProcess;
91 }
92
93 /* Functions not tested yet:
94   AttachThreadInput
95   SetThreadContext
96   SwitchToThread
97
98 In addition there are no checks that the inheritance works properly in
99 CreateThread
100 */
101
102 DWORD tlsIndex;
103
104 typedef struct {
105   int threadnum;
106   HANDLE *event;
107   DWORD *threadmem;
108 } t1Struct;
109
110 /* WinME supports OpenThread but doesn't know about access restrictions so
111    we require them to be either completely ignored or always obeyed.
112 */
113 INT obeying_ars = 0; /* -1 == no, 0 == dunno yet, 1 == yes */
114 #define obey_ar(x) \
115   (obeying_ars == 0 \
116     ? ((x) \
117       ? (obeying_ars = +1) \
118       : ((obeying_ars = -1), \
119          trace("not restricted, assuming consistent behaviour\n"))) \
120     : (obeying_ars < 0) \
121       ? ok(!(x), "access restrictions obeyed\n") \
122       : ok( (x), "access restrictions not obeyed\n"))
123
124 /* Basic test that simultaneous threads can access shared memory,
125    that the thread local storage routines work correctly, and that
126    threads actually run concurrently
127 */
128 static DWORD WINAPI threadFunc1(LPVOID p)
129 {
130     t1Struct *tstruct = (t1Struct *)p;
131    int i;
132 /* write our thread # into shared memory */
133    tstruct->threadmem[tstruct->threadnum]=GetCurrentThreadId();
134    ok(TlsSetValue(tlsIndex,(LPVOID)(tstruct->threadnum+1))!=0,
135       "TlsSetValue failed\n");
136 /* The threads synchronize before terminating.  This is done by
137    Signaling an event, and waiting for all events to occur
138 */
139    SetEvent(tstruct->event[tstruct->threadnum]);
140    WaitForMultipleObjects(NUM_THREADS,tstruct->event,TRUE,INFINITE);
141 /* Double check that all threads really did run by validating that
142    they have all written to the shared memory. There should be no race
143    here, since all threads were synchronized after the write.*/
144    for(i=0;i<NUM_THREADS;i++) {
145      while(tstruct->threadmem[i]==0) ;
146    }
147
148    /* lstrlenA contains an exception handler so this makes sure exceptions work in threads */
149    ok( lstrlenA( (char *)0xdeadbeef ) == 0, "lstrlenA: unexpected success\n" );
150
151 /* Check that no one changed our tls memory */
152    ok((int)TlsGetValue(tlsIndex)-1==tstruct->threadnum,
153       "TlsGetValue failed\n");
154    return NUM_THREADS+tstruct->threadnum;
155 }
156
157 static DWORD WINAPI threadFunc2(LPVOID p)
158 {
159    return 99;
160 }
161
162 static DWORD WINAPI threadFunc3(LPVOID p)
163 {
164    HANDLE thread;
165    thread=GetCurrentThread();
166    SuspendThread(thread);
167    return 99;
168 }
169
170 static DWORD WINAPI threadFunc4(LPVOID p)
171 {
172     HANDLE event = (HANDLE)p;
173    if(event != NULL) {
174      SetEvent(event);
175    }
176    Sleep(99000);
177    return 0;
178 }
179
180 #if CHECK_STACK
181 static DWORD WINAPI threadFunc5(LPVOID p)
182 {
183   DWORD *exitCode = (DWORD *)p;
184   SYSTEM_INFO sysInfo;
185   sysInfo.dwPageSize=0;
186   GetSystemInfo(&sysInfo);
187   *exitCode=0;
188    __TRY
189    {
190      alloca(2*sysInfo.dwPageSize);
191    }
192     __EXCEPT(1) {
193      *exitCode=1;
194    }
195    __ENDTRY
196    return 0;
197 }
198 #endif
199
200 static DWORD WINAPI threadFunc_SetEvent(LPVOID p)
201 {
202     SetEvent((HANDLE) p);
203     return 0;
204 }
205
206 static DWORD WINAPI threadFunc_CloseHandle(LPVOID p)
207 {
208     CloseHandle((HANDLE) p);
209     return 0;
210 }
211
212 static void create_function_addr_events(HANDLE events[2])
213 {
214     char buffer[256];
215
216     sprintf(buffer, "threadFunc_SetEvent %p", threadFunc_SetEvent);
217     events[0] = CreateEvent(NULL, FALSE, FALSE, buffer);
218
219     sprintf(buffer, "threadFunc_CloseHandle %p", threadFunc_CloseHandle);
220     events[1] = CreateEvent(NULL, FALSE, FALSE, buffer);
221 }
222
223 /* check CreateRemoteThread */
224 static VOID test_CreateRemoteThread(void)
225 {
226     HANDLE hProcess, hThread, hEvent, hRemoteEvent;
227     DWORD tid, ret, exitcode;
228     HANDLE hAddrEvents[2];
229
230     hProcess = create_target_process("sleep");
231     ok(hProcess != NULL, "Can't start process\n");
232
233     /* ensure threadFunc_SetEvent & threadFunc_CloseHandle are the same
234      * address as in the child process */
235     create_function_addr_events(hAddrEvents);
236     ret = WaitForMultipleObjects(2, hAddrEvents, TRUE, 5000);
237     if (ret == WAIT_TIMEOUT)
238     {
239         skip("child process wasn't mapped at same address, so can't do CreateRemoteThread tests.\n");
240         return;
241     }
242
243     hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
244     ok(hEvent != NULL, "Can't create event, err=%u\n", GetLastError());
245     ret = DuplicateHandle(GetCurrentProcess(), hEvent, hProcess, &hRemoteEvent,
246                           0, FALSE, DUPLICATE_SAME_ACCESS);
247     ok(ret != 0, "DuplicateHandle failed, err=%u\n", GetLastError());
248
249     /* create suspended remote thread with entry point SetEvent() */
250     SetLastError(0xdeadbeef);
251     hThread = CreateRemoteThread(hProcess, NULL, 0, threadFunc_SetEvent,
252                                  hRemoteEvent, CREATE_SUSPENDED, &tid);
253     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
254     {
255         skip("CreateRemoteThread is not implemented\n");
256         goto cleanup;
257     }
258     ok(hThread != NULL, "CreateRemoteThread failed, err=%u\n", GetLastError());
259     ok(tid != 0, "null tid\n");
260     ret = SuspendThread(hThread);
261     ok(ret == 1, "ret=%u, err=%u\n", ret, GetLastError());
262     ret = ResumeThread(hThread);
263     ok(ret == 2, "ret=%u, err=%u\n", ret, GetLastError());
264
265     /* thread still suspended, so wait times out */
266     ret = WaitForSingleObject(hEvent, 100);
267     ok(ret == WAIT_TIMEOUT, "wait did not time out, ret=%u\n", ret);
268
269     ret = ResumeThread(hThread);
270     ok(ret == 1, "ret=%u, err=%u\n", ret, GetLastError());
271
272     /* wait that doesn't time out */
273     ret = WaitForSingleObject(hEvent, 100);
274     ok(ret == WAIT_OBJECT_0, "object not signaled, ret=%u\n", ret);
275
276     /* wait for thread end */
277     ret = WaitForSingleObject(hThread, 100);
278     ok(ret == WAIT_OBJECT_0, "waiting for thread failed, ret=%u\n", ret);
279     CloseHandle(hThread);
280
281     /* create and wait for remote thread with entry point CloseHandle() */
282     hThread = CreateRemoteThread(hProcess, NULL, 0,
283                                  threadFunc_CloseHandle,
284                                  hRemoteEvent, 0, &tid);
285     ok(hThread != NULL, "CreateRemoteThread failed, err=%u\n", GetLastError());
286     ret = WaitForSingleObject(hThread, 100);
287     ok(ret == WAIT_OBJECT_0, "waiting for thread failed, ret=%u\n", ret);
288     CloseHandle(hThread);
289
290     /* create remote thread with entry point SetEvent() */
291     hThread = CreateRemoteThread(hProcess, NULL, 0,
292                                  threadFunc_SetEvent,
293                                  hRemoteEvent, 0, &tid);
294     ok(hThread != NULL, "CreateRemoteThread failed, err=%u\n", GetLastError());
295
296     /* closed handle, so wait times out */
297     ret = WaitForSingleObject(hEvent, 100);
298     ok(ret == WAIT_TIMEOUT, "wait did not time out, ret=%u\n", ret);
299
300     /* check that remote SetEvent() failed */
301     ret = GetExitCodeThread(hThread, &exitcode);
302     ok(ret != 0, "GetExitCodeThread failed, err=%u\n", GetLastError());
303     if (ret) ok(exitcode == 0, "SetEvent succeeded, expected to fail\n");
304     CloseHandle(hThread);
305
306 cleanup:
307     TerminateProcess(hProcess, 0);
308     CloseHandle(hEvent);
309     CloseHandle(hProcess);
310 }
311
312 /* Check basic funcationality of CreateThread and Tls* functions */
313 static VOID test_CreateThread_basic(void)
314 {
315    HANDLE thread[NUM_THREADS],event[NUM_THREADS];
316    DWORD threadid[NUM_THREADS],curthreadId;
317    DWORD threadmem[NUM_THREADS];
318    DWORD exitCode;
319    t1Struct tstruct[NUM_THREADS];
320    int error;
321    DWORD i,j;
322    DWORD GLE, ret;
323
324    /* lstrlenA contains an exception handler so this makes sure exceptions work in the main thread */
325    ok( lstrlenA( (char *)0xdeadbeef ) == 0, "lstrlenA: unexpected success\n" );
326
327 /* Retrieve current Thread ID for later comparisons */
328   curthreadId=GetCurrentThreadId();
329 /* Allocate some local storage */
330   ok((tlsIndex=TlsAlloc())!=TLS_OUT_OF_INDEXES,"TlsAlloc failed\n");
331 /* Create events for thread synchronization */
332   for(i=0;i<NUM_THREADS;i++) {
333     threadmem[i]=0;
334 /* Note that it doesn't matter what type of event we chose here.  This
335    test isn't trying to thoroughly test events
336 */
337     event[i]=CreateEventA(NULL,TRUE,FALSE,NULL);
338     tstruct[i].threadnum=i;
339     tstruct[i].threadmem=threadmem;
340     tstruct[i].event=event;
341   }
342
343 /* Test that passing arguments to threads works okay */
344   for(i=0;i<NUM_THREADS;i++) {
345     thread[i] = CreateThread(NULL,0,threadFunc1,
346                              &tstruct[i],0,&threadid[i]);
347     ok(thread[i]!=NULL,"Create Thread failed\n");
348   }
349 /* Test that the threads actually complete */
350   for(i=0;i<NUM_THREADS;i++) {
351     error=WaitForSingleObject(thread[i],5000);
352     ok(error==WAIT_OBJECT_0, "Thread did not complete within timelimit\n");
353     if(error!=WAIT_OBJECT_0) {
354       TerminateThread(thread[i],i+NUM_THREADS);
355     }
356     ok(GetExitCodeThread(thread[i],&exitCode),"Could not retrieve ext code\n");
357     ok(exitCode==i+NUM_THREADS,"Thread returned an incorrect exit code\n");
358   }
359 /* Test that each thread executed in its parent's address space
360    (it was able to change threadmem and pass that change back to its parent)
361    and that each thread id was independent).  Note that we prove that the
362    threads actually execute concurrently by having them block on each other
363    in threadFunc1
364 */
365   for(i=0;i<NUM_THREADS;i++) {
366     error=0;
367     for(j=i+1;j<NUM_THREADS;j++) {
368       if (threadmem[i]==threadmem[j]) {
369         error=1;
370       }
371     }
372     ok(!error && threadmem[i]==threadid[i] && threadmem[i]!=curthreadId,
373          "Thread did not execute successfully\n");
374     ok(CloseHandle(thread[i])!=0,"CloseHandle failed\n");
375   }
376   ok(TlsFree(tlsIndex)!=0,"TlsFree failed\n");
377
378   /* Test how passing NULL as a pointer to threadid works */
379   SetLastError(0xFACEaBAD);
380   thread[0] = CreateThread(NULL,0,threadFunc2,NULL,0,NULL);
381   GLE = GetLastError();
382   if (thread[0]) { /* NT */
383     ok(GLE==0xFACEaBAD, "CreateThread set last error to %d, expected 4207848365\n", GLE);
384     ret = WaitForSingleObject(thread[0],100);
385     ok(ret==WAIT_OBJECT_0, "threadFunc2 did not exit during 100 ms\n");
386     ret = GetExitCodeThread(thread[0],&exitCode);
387     ok(ret!=0, "GetExitCodeThread returned %d (expected nonzero)\n", ret);
388     ok(exitCode==99, "threadFunc2 exited with code: %d (expected 99)\n", exitCode);
389     ok(CloseHandle(thread[0])!=0,"Error closing thread handle\n");
390   }
391   else { /* 9x */
392     ok(GLE==ERROR_INVALID_PARAMETER, "CreateThread set last error to %d, expected 87\n", GLE);
393   }
394 }
395
396 /* Check that using the CREATE_SUSPENDED flag works */
397 static VOID test_CreateThread_suspended(void)
398 {
399   HANDLE thread;
400   DWORD threadId;
401   int error;
402
403   thread = CreateThread(NULL,0,threadFunc2,NULL,
404                         CREATE_SUSPENDED,&threadId);
405   ok(thread!=NULL,"Create Thread failed\n");
406 /* Check that the thread is suspended */
407   ok(SuspendThread(thread)==1,"Thread did not start suspended\n");
408   ok(ResumeThread(thread)==2,"Resume thread returned an invalid value\n");
409 /* Check that resume thread didn't actually start the thread.  I can't think
410    of a better way of checking this than just waiting.  I am not sure if this
411    will work on slow computers.
412 */
413   ok(WaitForSingleObject(thread,1000)==WAIT_TIMEOUT,
414      "ResumeThread should not have actually started the thread\n");
415 /* Now actually resume the thread and make sure that it actually completes*/
416   ok(ResumeThread(thread)==1,"Resume thread returned an invalid value\n");
417   ok((error=WaitForSingleObject(thread,1000))==WAIT_OBJECT_0,
418      "Thread did not resume\n");
419   if(error!=WAIT_OBJECT_0) {
420     TerminateThread(thread,1);
421   }
422   ok(CloseHandle(thread)!=0,"CloseHandle failed\n");
423 }
424
425 /* Check that SuspendThread and ResumeThread work */
426 static VOID test_SuspendThread(void)
427 {
428   HANDLE thread,access_thread;
429   DWORD threadId,exitCode,error;
430   int i;
431
432   thread = CreateThread(NULL,0,threadFunc3,NULL,
433                         0,&threadId);
434   ok(thread!=NULL,"Create Thread failed\n");
435 /* Check that the thread is suspended */
436 /* Note that this is a polling method, and there is a race between
437    SuspendThread being called (in the child, and the loop below timing out,
438    so the test could fail on a heavily loaded or slow computer.
439 */
440   error=0;
441   for(i=0;error==0 && i<100;i++) {
442     error=SuspendThread(thread);
443     ResumeThread(thread);
444     if(error==0) {
445       Sleep(50);
446       i++;
447     }
448   }
449   ok(error==1,"SuspendThread did not work\n");
450 /* check that access restrictions are obeyed */
451   if (pOpenThread) {
452     access_thread=pOpenThread(THREAD_ALL_ACCESS & (~THREAD_SUSPEND_RESUME),
453                            0,threadId);
454     ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
455     if (access_thread!=NULL) {
456       obey_ar(SuspendThread(access_thread)==~0U);
457       obey_ar(ResumeThread(access_thread)==~0U);
458       ok(CloseHandle(access_thread)!=0,"CloseHandle Failed\n");
459     }
460   }
461 /* Double check that the thread really is suspended */
462   ok((error=GetExitCodeThread(thread,&exitCode))!=0 && exitCode==STILL_ACTIVE,
463      "Thread did not really suspend\n");
464 /* Resume the thread, and make sure it actually completes */
465   ok(ResumeThread(thread)==1,"Resume thread returned an invalid value\n");
466   ok((error=WaitForSingleObject(thread,1000))==WAIT_OBJECT_0,
467      "Thread did not resume\n");
468   if(error!=WAIT_OBJECT_0) {
469     TerminateThread(thread,1);
470   }
471   /* Trying to suspend a terminated thread should fail */
472   error=SuspendThread(thread);
473   ok(error==~0U, "wrong return code: %d\n", error);
474   ok(GetLastError()==ERROR_ACCESS_DENIED || GetLastError()==ERROR_NO_MORE_ITEMS, "unexpected error code: %d\n", GetLastError());
475
476   ok(CloseHandle(thread)!=0,"CloseHandle Failed\n");
477 }
478
479 /* Check that TerminateThread works properly
480 */
481 static VOID test_TerminateThread(void)
482 {
483   HANDLE thread,access_thread,event;
484   DWORD threadId,exitCode;
485   event=CreateEventA(NULL,TRUE,FALSE,NULL);
486   thread = CreateThread(NULL,0,threadFunc4,
487                         (LPVOID)event, 0,&threadId);
488   ok(thread!=NULL,"Create Thread failed\n");
489 /* TerminateThread has a race condition in Wine.  If the thread is terminated
490    before it starts, it leaves a process behind.  Therefore, we wait for the
491    thread to signal that it has started.  There is no easy way to force the
492    race to occur, so we don't try to find it.
493 */
494   ok(WaitForSingleObject(event,5000)==WAIT_OBJECT_0,
495      "TerminateThread didn't work\n");
496 /* check that access restrictions are obeyed */
497   if (pOpenThread) {
498     access_thread=pOpenThread(THREAD_ALL_ACCESS & (~THREAD_TERMINATE),
499                              0,threadId);
500     ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
501     if (access_thread!=NULL) {
502       obey_ar(TerminateThread(access_thread,99)==0);
503       ok(CloseHandle(access_thread)!=0,"CloseHandle Failed\n");
504     }
505   }
506 /* terminate a job and make sure it terminates */
507   ok(TerminateThread(thread,99)!=0,"TerminateThread failed\n");
508   ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
509      "TerminateThread didn't work\n");
510   ok(GetExitCodeThread(thread,&exitCode)!=STILL_ACTIVE,
511      "TerminateThread should not leave the thread 'STILL_ACTIVE'\n");
512   ok(exitCode==99, "TerminateThread returned invalid exit code\n");
513   ok(CloseHandle(thread)!=0,"Error Closing thread handle\n");
514 }
515
516 /* Check if CreateThread obeys the specified stack size.  This code does
517    not work properly, and is currently disabled
518 */
519 static VOID test_CreateThread_stack(void)
520 {
521 #if CHECK_STACK
522 /* The only way I know of to test the stack size is to use alloca
523    and __try/__except.  However, this is probably not portable,
524    and I couldn't get it to work under Wine anyhow.  However, here
525    is the code which should allow for testing that CreateThread
526    respects the stack-size limit
527 */
528      HANDLE thread;
529      DWORD threadId,exitCode;
530
531      SYSTEM_INFO sysInfo;
532      sysInfo.dwPageSize=0;
533      GetSystemInfo(&sysInfo);
534      ok(sysInfo.dwPageSize>0,"GetSystemInfo should return a valid page size\n");
535      thread = CreateThread(NULL,sysInfo.dwPageSize,
536                            threadFunc5,&exitCode,
537                            0,&threadId);
538      ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
539         "TerminateThread didn't work\n");
540      ok(exitCode==1,"CreateThread did not obey stack-size-limit\n");
541      ok(CloseHandle(thread)!=0,"CloseHandle failed\n");
542 #endif
543 }
544
545 /* Check whether setting/retrieving thread priorities works */
546 static VOID test_thread_priority(void)
547 {
548    HANDLE curthread,access_thread;
549    DWORD curthreadId,exitCode;
550    int min_priority=-2,max_priority=2;
551    BOOL disabled,rc;
552    int i;
553
554    curthread=GetCurrentThread();
555    curthreadId=GetCurrentThreadId();
556 /* Check thread priority */
557 /* NOTE: on Win2k/XP priority can be from -7 to 6.  All other platforms it
558          is -2 to 2.  However, even on a real Win2k system, using thread
559          priorities beyond the -2 to 2 range does not work.  If you want to try
560          anyway, enable USE_EXTENDED_PRIORITIES
561 */
562    ok(GetThreadPriority(curthread)==THREAD_PRIORITY_NORMAL,
563       "GetThreadPriority Failed\n");
564
565    if (pOpenThread) {
566 /* check that access control is obeyed */
567      access_thread=pOpenThread(THREAD_ALL_ACCESS &
568                        (~THREAD_QUERY_INFORMATION) & (~THREAD_SET_INFORMATION),
569                        0,curthreadId);
570      ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
571      if (access_thread!=NULL) {
572        obey_ar(SetThreadPriority(access_thread,1)==0);
573        obey_ar(GetThreadPriority(access_thread)==THREAD_PRIORITY_ERROR_RETURN);
574        obey_ar(GetExitCodeThread(access_thread,&exitCode)==0);
575        ok(CloseHandle(access_thread),"Error Closing thread handle\n");
576      }
577    }
578 #if USE_EXTENDED_PRIORITIES
579    min_priority=-7; max_priority=6;
580 #endif
581    for(i=min_priority;i<=max_priority;i++) {
582      ok(SetThreadPriority(curthread,i)!=0,
583         "SetThreadPriority Failed for priority: %d\n",i);
584      ok(GetThreadPriority(curthread)==i,
585         "GetThreadPriority Failed for priority: %d\n",i);
586    }
587    ok(SetThreadPriority(curthread,THREAD_PRIORITY_TIME_CRITICAL)!=0,
588       "SetThreadPriority Failed\n");
589    ok(GetThreadPriority(curthread)==THREAD_PRIORITY_TIME_CRITICAL,
590       "GetThreadPriority Failed\n");
591    ok(SetThreadPriority(curthread,THREAD_PRIORITY_IDLE)!=0,
592        "SetThreadPriority Failed\n");
593    ok(GetThreadPriority(curthread)==THREAD_PRIORITY_IDLE,
594        "GetThreadPriority Failed\n");
595    ok(SetThreadPriority(curthread,0)!=0,"SetThreadPriority Failed\n");
596
597 /* Check that the thread priority is not changed if SetThreadPriority
598    is called with a value outside of the max/min range */
599    SetThreadPriority(curthread,min_priority);
600    SetLastError(0xdeadbeef);
601    rc = SetThreadPriority(curthread,min_priority-1);
602
603    ok(rc == FALSE, "SetThreadPriority passed with a bad argument\n");
604    ok(GetLastError() == ERROR_INVALID_PARAMETER ||
605       GetLastError() == ERROR_INVALID_PRIORITY /* Win9x */,
606       "SetThreadPriority error %d, expected ERROR_INVALID_PARAMETER or ERROR_INVALID_PRIORITY\n",
607       GetLastError());
608    ok(GetThreadPriority(curthread)==min_priority,
609       "GetThreadPriority didn't return min_priority\n");
610
611    SetThreadPriority(curthread,max_priority);
612    SetLastError(0xdeadbeef);
613    rc = SetThreadPriority(curthread,max_priority+1);
614
615    ok(rc == FALSE, "SetThreadPriority passed with a bad argument\n");
616    ok(GetLastError() == ERROR_INVALID_PARAMETER ||
617       GetLastError() == ERROR_INVALID_PRIORITY /* Win9x */,
618       "SetThreadPriority error %d, expected ERROR_INVALID_PARAMETER or ERROR_INVALID_PRIORITY\n",
619       GetLastError());
620    ok(GetThreadPriority(curthread)==max_priority,
621       "GetThreadPriority didn't return max_priority\n");
622
623 /* Check thread priority boost */
624    if (!pGetThreadPriorityBoost || !pSetThreadPriorityBoost) 
625      return; /* Win9x */
626
627    SetLastError(0xdeadbeef);
628    rc=pGetThreadPriorityBoost(curthread,&disabled);
629    if (rc==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
630      return; /* WinME */
631
632    todo_wine
633      ok(rc!=0,"error=%d\n",GetLastError());
634
635    if (pOpenThread) {
636 /* check that access control is obeyed */
637      access_thread=pOpenThread(THREAD_ALL_ACCESS &
638                        (~THREAD_QUERY_INFORMATION) & (~THREAD_SET_INFORMATION),
639                        0,curthreadId);
640      ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
641      if (access_thread!=NULL) {
642        obey_ar(pSetThreadPriorityBoost(access_thread,1)==0);
643        obey_ar(pGetThreadPriorityBoost(access_thread,&disabled)==0);
644        ok(CloseHandle(access_thread),"Error Closing thread handle\n");
645      }
646    }
647
648    todo_wine {
649      rc = pSetThreadPriorityBoost(curthread,1);
650      ok( rc != 0, "error=%d\n",GetLastError());
651      rc=pGetThreadPriorityBoost(curthread,&disabled);
652      ok(rc!=0 && disabled==1,
653         "rc=%d error=%d disabled=%d\n",rc,GetLastError(),disabled);
654
655      rc = pSetThreadPriorityBoost(curthread,0);
656      ok( rc != 0, "error=%d\n",GetLastError());
657      rc=pGetThreadPriorityBoost(curthread,&disabled);
658      ok(rc!=0 && disabled==0,
659         "rc=%d error=%d disabled=%d\n",rc,GetLastError(),disabled);
660    }
661 }
662
663 /* check the GetThreadTimes function */
664 static VOID test_GetThreadTimes(void)
665 {
666      HANDLE thread,access_thread=NULL;
667      FILETIME creationTime,exitTime,kernelTime,userTime;
668      DWORD threadId;
669      int error;
670
671      thread = CreateThread(NULL,0,threadFunc2,NULL,
672                            CREATE_SUSPENDED,&threadId);
673
674      ok(thread!=NULL,"Create Thread failed\n");
675 /* check that access control is obeyed */
676      if (pOpenThread) {
677        access_thread=pOpenThread(THREAD_ALL_ACCESS &
678                                    (~THREAD_QUERY_INFORMATION), 0,threadId);
679        ok(access_thread!=NULL,
680           "OpenThread returned an invalid handle\n");
681      }
682      ok(ResumeThread(thread)==1,"Resume thread returned an invalid value\n");
683      ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
684         "ResumeThread didn't work\n");
685      creationTime.dwLowDateTime=99; creationTime.dwHighDateTime=99;
686      exitTime.dwLowDateTime=99;     exitTime.dwHighDateTime=99;
687      kernelTime.dwLowDateTime=99;   kernelTime.dwHighDateTime=99;
688      userTime.dwLowDateTime=99;     userTime.dwHighDateTime=99;
689 /* GetThreadTimes should set all of the parameters passed to it */
690      error=GetThreadTimes(thread,&creationTime,&exitTime,
691                           &kernelTime,&userTime);
692      if (error!=0 || GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
693        ok(error!=0,"GetThreadTimes failed\n");
694        ok(creationTime.dwLowDateTime!=99 || creationTime.dwHighDateTime!=99,
695           "creationTime was invalid\n");
696        ok(exitTime.dwLowDateTime!=99 || exitTime.dwHighDateTime!=99,
697           "exitTime was invalid\n");
698        ok(kernelTime.dwLowDateTime!=99 || kernelTime.dwHighDateTime!=99,
699           "kernelTimewas invalid\n");
700        ok(userTime.dwLowDateTime!=99 || userTime.dwHighDateTime!=99,
701           "userTime was invalid\n");
702        ok(CloseHandle(thread)!=0,"CloseHandle failed\n");
703        if(access_thread!=NULL)
704        {
705          error=GetThreadTimes(access_thread,&creationTime,&exitTime,
706                               &kernelTime,&userTime);
707          obey_ar(error==0);
708        }
709      }
710      if(access_thread!=NULL) {
711        ok(CloseHandle(access_thread)!=0,"CloseHandle Failed\n");
712      }
713 }
714
715 /* Check the processor affinity functions */
716 /* NOTE: These functions should also be checked that they obey access control
717 */
718 static VOID test_thread_processor(void)
719 {
720    HANDLE curthread,curproc;
721    DWORD_PTR processMask,systemMask;
722    SYSTEM_INFO sysInfo;
723    int error=0;
724
725    sysInfo.dwNumberOfProcessors=0;
726    GetSystemInfo(&sysInfo);
727    ok(sysInfo.dwNumberOfProcessors>0,
728       "GetSystemInfo failed to return a valid # of processors\n");
729 /* Use the current Thread/process for all tests */
730    curthread=GetCurrentThread();
731    ok(curthread!=NULL,"GetCurrentThread failed\n");
732    curproc=GetCurrentProcess();
733    ok(curproc!=NULL,"GetCurrentProcess failed\n");
734 /* Check the Affinity Mask functions */
735    ok(GetProcessAffinityMask(curproc,&processMask,&systemMask)!=0,
736       "GetProcessAffinityMask failed\n");
737    ok(SetThreadAffinityMask(curthread,processMask)==processMask,
738       "SetThreadAffinityMask failed\n");
739    ok(SetThreadAffinityMask(curthread,processMask+1)==0,
740       "SetThreadAffinityMask passed for an illegal processor\n");
741 /* NOTE: This only works on WinNT/2000/XP) */
742    if (pSetThreadIdealProcessor) {
743      todo_wine {
744        SetLastError(0);
745        error=pSetThreadIdealProcessor(curthread,0);
746        if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
747          ok(error!=-1, "SetThreadIdealProcessor failed\n");
748        }
749      }
750      if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
751        error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS+1);
752        ok(error==-1,
753           "SetThreadIdealProcessor succeeded with an illegal processor #\n");
754        todo_wine {
755          error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS);
756          ok(error==0, "SetThreadIdealProcessor returned an incorrect value\n");
757        }
758      }
759    }
760 }
761
762 static VOID test_GetThreadExitCode(void)
763 {
764     DWORD exitCode, threadid;
765     DWORD GLE, ret;
766     HANDLE thread;
767
768     ret = GetExitCodeThread((HANDLE)0x2bad2bad,&exitCode);
769     ok(ret==0, "GetExitCodeThread returned non zero value: %d\n", ret);
770     GLE = GetLastError();
771     ok(GLE==ERROR_INVALID_HANDLE, "GetLastError returned %d (expected 6)\n", GLE);
772
773     thread = CreateThread(NULL,0,threadFunc2,NULL,0,&threadid);
774     ret = WaitForSingleObject(thread,100);
775     ok(ret==WAIT_OBJECT_0, "threadFunc2 did not exit during 100 ms\n");
776     ret = GetExitCodeThread(thread,&exitCode);
777     ok(ret==exitCode || ret==1, 
778        "GetExitCodeThread returned %d (expected 1 or %d)\n", ret, exitCode);
779     ok(exitCode==99, "threadFunc2 exited with code %d (expected 99)\n", exitCode);
780     ok(CloseHandle(thread)!=0,"Error closing thread handle\n");
781 }
782
783 #ifdef __i386__
784
785 static int test_value = 0;
786 static HANDLE event;
787
788 static void WINAPI set_test_val( int val )
789 {
790     test_value += val;
791 }
792
793 static DWORD WINAPI threadFunc6(LPVOID p)
794 {
795     SetEvent( event );
796     Sleep( 1000 );
797     test_value *= (int)p;
798     return 0;
799 }
800
801 static void test_SetThreadContext(void)
802 {
803     CONTEXT ctx;
804     int *stack;
805     HANDLE thread;
806     DWORD threadid;
807     DWORD prevcount;
808     BOOL ret;
809
810     SetLastError(0xdeadbeef);
811     event = CreateEvent( NULL, TRUE, FALSE, NULL );
812     thread = CreateThread( NULL, 0, threadFunc6, (void *)2, 0, &threadid );
813     ok( thread != NULL, "CreateThread failed : (%d)\n", GetLastError() );
814     if (!thread)
815     {
816         trace("Thread creation failed, skipping rest of test\n");
817         return;
818     }
819     WaitForSingleObject( event, INFINITE );
820     SuspendThread( thread );
821     CloseHandle( event );
822
823     ctx.ContextFlags = CONTEXT_FULL;
824     SetLastError(0xdeadbeef);
825     ret = GetThreadContext( thread, &ctx );
826     ok( ret, "GetThreadContext failed : (%u)\n", GetLastError() );
827
828     if (ret)
829     {
830         /* simulate a call to set_test_val(10) */
831         stack = (int *)ctx.Esp;
832         stack[-1] = 10;
833         stack[-2] = ctx.Eip;
834         ctx.Esp -= 2 * sizeof(int *);
835         ctx.Eip = (DWORD)set_test_val;
836         SetLastError(0xdeadbeef);
837         ok( SetThreadContext( thread, &ctx ), "SetThreadContext failed : (%d)\n", GetLastError() );
838     }
839
840     SetLastError(0xdeadbeef);
841     prevcount = ResumeThread( thread );
842     ok ( prevcount == 1, "Previous suspend count (%d) instead of 1, last error : (%d)\n",
843                          prevcount, GetLastError() );
844
845     WaitForSingleObject( thread, INFINITE );
846     ok( test_value == 20, "test_value %d instead of 20\n", test_value );
847 }
848
849 #endif  /* __i386__ */
850
851 static HANDLE finish_event;
852 static LONG times_executed;
853
854 static DWORD CALLBACK work_function(void *p)
855 {
856     LONG executed = InterlockedIncrement(&times_executed);
857
858     if (executed == 100)
859         SetEvent(finish_event);
860     return 0;
861 }
862
863 static void test_QueueUserWorkItem(void)
864 {
865     int i;
866     DWORD wait_result;
867     DWORD before, after;
868
869     /* QueueUserWorkItem not present on win9x */
870     if (!pQueueUserWorkItem) return;
871
872     finish_event = CreateEvent(NULL, TRUE, FALSE, NULL);
873
874     before = GetTickCount();
875
876     for (i = 0; i < 100; i++)
877     {
878         BOOL ret = pQueueUserWorkItem(work_function, (void *)i, WT_EXECUTEDEFAULT);
879         ok(ret, "QueueUserWorkItem failed with error %d\n", GetLastError());
880     }
881
882     wait_result = WaitForSingleObject(finish_event, 10000);
883
884     after = GetTickCount();
885     trace("100 QueueUserWorkItem calls took %dms\n", after - before);
886     ok(wait_result == WAIT_OBJECT_0, "wait failed with error 0x%x\n", wait_result);
887
888     ok(times_executed == 100, "didn't execute all of the work items\n");
889 }
890
891 static void CALLBACK signaled_function(PVOID p, BOOLEAN TimerOrWaitFired)
892 {
893     HANDLE event = p;
894     SetEvent(event);
895     ok(!TimerOrWaitFired, "wait shouldn't have timed out\n");
896 }
897
898 static void CALLBACK timeout_function(PVOID p, BOOLEAN TimerOrWaitFired)
899 {
900     HANDLE event = p;
901     SetEvent(event);
902     ok(TimerOrWaitFired, "wait should have timed out\n");
903 }
904
905 static void test_RegisterWaitForSingleObject(void)
906 {
907     BOOL ret;
908     HANDLE wait_handle;
909     HANDLE handle;
910     HANDLE complete_event;
911
912     if (!pRegisterWaitForSingleObject || !pUnregisterWait)
913     {
914         skip("RegisterWaitForSingleObject or UnregisterWait not implemented\n");
915         return;
916     }
917
918     /* test signaled case */
919
920     handle = CreateEvent(NULL, TRUE, TRUE, NULL);
921     complete_event = CreateEvent(NULL, FALSE, FALSE, NULL);
922
923     ret = pRegisterWaitForSingleObject(&wait_handle, handle, signaled_function, complete_event, INFINITE, WT_EXECUTEONLYONCE);
924     ok(ret, "RegisterWaitForSingleObject failed with error %d\n", GetLastError());
925
926     WaitForSingleObject(complete_event, INFINITE);
927     /* give worker thread chance to complete */
928     Sleep(100);
929
930     ret = pUnregisterWait(wait_handle);
931     ok(ret, "UnregisterWait failed with error %d\n", GetLastError());
932
933     /* test cancel case */
934
935     ResetEvent(handle);
936
937     ret = pRegisterWaitForSingleObject(&wait_handle, handle, signaled_function, complete_event, INFINITE, WT_EXECUTEONLYONCE);
938     ok(ret, "RegisterWaitForSingleObject failed with error %d\n", GetLastError());
939
940     ret = pUnregisterWait(wait_handle);
941     ok(ret, "UnregisterWait failed with error %d\n", GetLastError());
942
943     /* test timeout case */
944
945     ret = pRegisterWaitForSingleObject(&wait_handle, handle, timeout_function, complete_event, 0, WT_EXECUTEONLYONCE);
946     ok(ret, "RegisterWaitForSingleObject failed with error %d\n", GetLastError());
947
948     WaitForSingleObject(complete_event, INFINITE);
949     /* give worker thread chance to complete */
950     Sleep(100);
951
952     ret = pUnregisterWait(wait_handle);
953     ok(ret, "UnregisterWait failed with error %d\n", GetLastError());
954 }
955
956 START_TEST(thread)
957 {
958    HINSTANCE lib;
959    int argc;
960    char **argv;
961    argc = winetest_get_mainargs( &argv );
962 /* Neither Cygwin nor mingW export OpenThread, so do a dynamic check
963    so that the compile passes
964 */
965    lib=GetModuleHandleA("kernel32.dll");
966    ok(lib!=NULL,"Couldn't get a handle for kernel32.dll\n");
967    pGetThreadPriorityBoost=(GetThreadPriorityBoost_t)GetProcAddress(lib,"GetThreadPriorityBoost");
968    pOpenThread=(OpenThread_t)GetProcAddress(lib,"OpenThread");
969    pQueueUserWorkItem=(QueueUserWorkItem_t)GetProcAddress(lib,"QueueUserWorkItem");
970    pSetThreadIdealProcessor=(SetThreadIdealProcessor_t)GetProcAddress(lib,"SetThreadIdealProcessor");
971    pSetThreadPriorityBoost=(SetThreadPriorityBoost_t)GetProcAddress(lib,"SetThreadPriorityBoost");
972    pRegisterWaitForSingleObject=(RegisterWaitForSingleObject_t)GetProcAddress(lib,"RegisterWaitForSingleObject");
973    pUnregisterWait=(UnregisterWait_t)GetProcAddress(lib,"UnregisterWait");
974
975    if (argc >= 3)
976    {
977        if (!strcmp(argv[2], "sleep"))
978        {
979            HANDLE hAddrEvents[2];
980            create_function_addr_events(hAddrEvents);
981            SetEvent(hAddrEvents[0]);
982            SetEvent(hAddrEvents[1]);
983            Sleep(5000); /* spawned process runs for at most 5 seconds */
984            return;
985        }
986        while (1)
987        {
988            HANDLE hThread;
989            hThread = CreateThread(NULL, 0, threadFunc2, NULL, 0, NULL);
990            ok(hThread != NULL, "CreateThread failed, error %u\n",
991               GetLastError());
992            ok(WaitForSingleObject(hThread, 200) == WAIT_OBJECT_0,
993               "Thread did not exit in time\n");
994            if (hThread == NULL) break;
995            CloseHandle(hThread);
996        }
997        return;
998    }
999
1000    test_CreateRemoteThread();
1001    test_CreateThread_basic();
1002    test_CreateThread_suspended();
1003    test_SuspendThread();
1004    test_TerminateThread();
1005    test_CreateThread_stack();
1006    test_thread_priority();
1007    test_GetThreadTimes();
1008    test_thread_processor();
1009    test_GetThreadExitCode();
1010 #ifdef __i386__
1011    test_SetThreadContext();
1012 #endif
1013    test_QueueUserWorkItem();
1014    test_RegisterWaitForSingleObject();
1015 }