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