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