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