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