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