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