server: Only commit SetThreadPriority if new priority is correct.
[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 that the thread priority is not changed if SetThreadPriority
592    is called with a value outside of the max/min range */
593    SetThreadPriority(curthread,min_priority);
594    SetLastError(0xdeadbeef);
595    rc = SetThreadPriority(curthread,min_priority-1);
596
597    ok(rc == FALSE, "SetThreadPriority passed with a bad argument\n");
598    ok(GetLastError() == ERROR_INVALID_PARAMETER,
599       "SetThreadPriority error %d, expected ERROR_INVALID_PARAMETER (87)\n", GetLastError());
600    ok(GetThreadPriority(curthread)==min_priority,
601       "GetThreadPriority didn't return min_priority\n");
602
603    SetThreadPriority(curthread,max_priority);
604    SetLastError(0xdeadbeef);
605    rc = SetThreadPriority(curthread,max_priority+1);
606
607    ok(rc == FALSE, "SetThreadPriority passed with a bad argument\n");
608    ok(GetLastError() == ERROR_INVALID_PARAMETER,
609       "SetThreadPriority error %d, expected ERROR_INVALID_PARAMETER (87)\n", GetLastError());
610    ok(GetThreadPriority(curthread)==max_priority,
611       "GetThreadPriority didn't return max_priority\n");
612
613 /* Check thread priority boost */
614    if (!pGetThreadPriorityBoost || !pSetThreadPriorityBoost) 
615      return; /* Win9x */
616
617    SetLastError(0xdeadbeef);
618    rc=pGetThreadPriorityBoost(curthread,&disabled);
619    if (rc==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
620      return; /* WinME */
621
622    todo_wine
623      ok(rc!=0,"error=%d\n",GetLastError());
624
625    if (pOpenThread) {
626 /* check that access control is obeyed */
627      access_thread=pOpenThread(THREAD_ALL_ACCESS &
628                        (~THREAD_QUERY_INFORMATION) & (~THREAD_SET_INFORMATION),
629                        0,curthreadId);
630      ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
631      if (access_thread!=NULL) {
632        obey_ar(pSetThreadPriorityBoost(access_thread,1)==0);
633        obey_ar(pGetThreadPriorityBoost(access_thread,&disabled)==0);
634        ok(CloseHandle(access_thread),"Error Closing thread handle\n");
635      }
636    }
637
638    todo_wine {
639      rc = pSetThreadPriorityBoost(curthread,1);
640      ok( rc != 0, "error=%d\n",GetLastError());
641      rc=pGetThreadPriorityBoost(curthread,&disabled);
642      ok(rc!=0 && disabled==1,
643         "rc=%d error=%d disabled=%d\n",rc,GetLastError(),disabled);
644
645      rc = pSetThreadPriorityBoost(curthread,0);
646      ok( rc != 0, "error=%d\n",GetLastError());
647      rc=pGetThreadPriorityBoost(curthread,&disabled);
648      ok(rc!=0 && disabled==0,
649         "rc=%d error=%d disabled=%d\n",rc,GetLastError(),disabled);
650    }
651 }
652
653 /* check the GetThreadTimes function */
654 static VOID test_GetThreadTimes(void)
655 {
656      HANDLE thread,access_thread=NULL;
657      FILETIME creationTime,exitTime,kernelTime,userTime;
658      DWORD threadId;
659      int error;
660
661      thread = CreateThread(NULL,0,threadFunc2,NULL,
662                            CREATE_SUSPENDED,&threadId);
663
664      ok(thread!=NULL,"Create Thread failed\n");
665 /* check that access control is obeyed */
666      if (pOpenThread) {
667        access_thread=pOpenThread(THREAD_ALL_ACCESS &
668                                    (~THREAD_QUERY_INFORMATION), 0,threadId);
669        ok(access_thread!=NULL,
670           "OpenThread returned an invalid handle\n");
671      }
672      ok(ResumeThread(thread)==1,"Resume thread returned an invalid value\n");
673      ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
674         "ResumeThread didn't work\n");
675      creationTime.dwLowDateTime=99; creationTime.dwHighDateTime=99;
676      exitTime.dwLowDateTime=99;     exitTime.dwHighDateTime=99;
677      kernelTime.dwLowDateTime=99;   kernelTime.dwHighDateTime=99;
678      userTime.dwLowDateTime=99;     userTime.dwHighDateTime=99;
679 /* GetThreadTimes should set all of the parameters passed to it */
680      error=GetThreadTimes(thread,&creationTime,&exitTime,
681                           &kernelTime,&userTime);
682      if (error!=0 || GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
683        ok(error!=0,"GetThreadTimes failed\n");
684        ok(creationTime.dwLowDateTime!=99 || creationTime.dwHighDateTime!=99,
685           "creationTime was invalid\n");
686        ok(exitTime.dwLowDateTime!=99 || exitTime.dwHighDateTime!=99,
687           "exitTime was invalid\n");
688        ok(kernelTime.dwLowDateTime!=99 || kernelTime.dwHighDateTime!=99,
689           "kernelTimewas invalid\n");
690        ok(userTime.dwLowDateTime!=99 || userTime.dwHighDateTime!=99,
691           "userTime was invalid\n");
692        ok(CloseHandle(thread)!=0,"CloseHandle failed\n");
693        if(access_thread!=NULL)
694        {
695          error=GetThreadTimes(access_thread,&creationTime,&exitTime,
696                               &kernelTime,&userTime);
697          obey_ar(error==0);
698        }
699      }
700      if(access_thread!=NULL) {
701        ok(CloseHandle(access_thread)!=0,"CloseHandle Failed\n");
702      }
703 }
704
705 /* Check the processor affinity functions */
706 /* NOTE: These functions should also be checked that they obey access control
707 */
708 static VOID test_thread_processor(void)
709 {
710    HANDLE curthread,curproc;
711    DWORD_PTR processMask,systemMask;
712    SYSTEM_INFO sysInfo;
713    int error=0;
714
715    sysInfo.dwNumberOfProcessors=0;
716    GetSystemInfo(&sysInfo);
717    ok(sysInfo.dwNumberOfProcessors>0,
718       "GetSystemInfo failed to return a valid # of processors\n");
719 /* Use the current Thread/process for all tests */
720    curthread=GetCurrentThread();
721    ok(curthread!=NULL,"GetCurrentThread failed\n");
722    curproc=GetCurrentProcess();
723    ok(curproc!=NULL,"GetCurrentProcess failed\n");
724 /* Check the Affinity Mask functions */
725    ok(GetProcessAffinityMask(curproc,&processMask,&systemMask)!=0,
726       "GetProcessAffinityMask failed\n");
727    ok(SetThreadAffinityMask(curthread,processMask)==processMask,
728       "SetThreadAffinityMask failed\n");
729    ok(SetThreadAffinityMask(curthread,processMask+1)==0,
730       "SetThreadAffinityMask passed for an illegal processor\n");
731 /* NOTE: This only works on WinNT/2000/XP) */
732    if (pSetThreadIdealProcessor) {
733      todo_wine {
734        SetLastError(0);
735        error=pSetThreadIdealProcessor(curthread,0);
736        if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
737          ok(error!=-1, "SetThreadIdealProcessor failed\n");
738        }
739      }
740      if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
741        error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS+1);
742        ok(error==-1,
743           "SetThreadIdealProcessor succeeded with an illegal processor #\n");
744        todo_wine {
745          error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS);
746          ok(error==0, "SetThreadIdealProcessor returned an incorrect value\n");
747        }
748      }
749    }
750 }
751
752 static VOID test_GetThreadExitCode(void)
753 {
754     DWORD exitCode, threadid;
755     DWORD GLE, ret;
756     HANDLE thread;
757
758     ret = GetExitCodeThread((HANDLE)0x2bad2bad,&exitCode);
759     ok(ret==0, "GetExitCodeThread returned non zero value: %d\n", ret);
760     GLE = GetLastError();
761     ok(GLE==ERROR_INVALID_HANDLE, "GetLastError returned %d (expected 6)\n", GLE);
762
763     thread = CreateThread(NULL,0,threadFunc2,NULL,0,&threadid);
764     ret = WaitForSingleObject(thread,100);
765     ok(ret==WAIT_OBJECT_0, "threadFunc2 did not exit during 100 ms\n");
766     ret = GetExitCodeThread(thread,&exitCode);
767     ok(ret==exitCode || ret==1, 
768        "GetExitCodeThread returned %d (expected 1 or %d)\n", ret, exitCode);
769     ok(exitCode==99, "threadFunc2 exited with code %d (expected 99)\n", exitCode);
770     ok(CloseHandle(thread)!=0,"Error closing thread handle\n");
771 }
772
773 #ifdef __i386__
774
775 static int test_value = 0;
776 static HANDLE event;
777
778 static void WINAPI set_test_val( int val )
779 {
780     test_value += val;
781 }
782
783 static DWORD WINAPI threadFunc6(LPVOID p)
784 {
785     SetEvent( event );
786     Sleep( 1000 );
787     test_value *= (int)p;
788     return 0;
789 }
790
791 static void test_SetThreadContext(void)
792 {
793     CONTEXT ctx;
794     int *stack;
795     HANDLE thread;
796     DWORD threadid;
797     DWORD prevcount;
798
799     SetLastError(0xdeadbeef);
800     event = CreateEvent( NULL, TRUE, FALSE, NULL );
801     thread = CreateThread( NULL, 0, threadFunc6, (void *)2, 0, &threadid );
802     ok( thread != NULL, "CreateThread failed : (%d)\n", GetLastError() );
803     if (!thread)
804     {
805         trace("Thread creation failed, skipping rest of test\n");
806         return;
807     }
808     WaitForSingleObject( event, INFINITE );
809     SuspendThread( thread );
810     CloseHandle( event );
811
812     ctx.ContextFlags = CONTEXT_FULL;
813     SetLastError(0xdeadbeef);
814     ok( GetThreadContext( thread, &ctx ), "GetThreadContext failed : (%d)\n", GetLastError() );
815
816     /* simulate a call to set_test_val(10) */
817     stack = (int *)ctx.Esp;
818     stack[-1] = 10;
819     stack[-2] = ctx.Eip;
820     ctx.Esp -= 2 * sizeof(int *);
821     ctx.Eip = (DWORD)set_test_val;
822     SetLastError(0xdeadbeef);
823     ok( SetThreadContext( thread, &ctx ), "SetThreadContext failed : (%d)\n", GetLastError() );
824
825     SetLastError(0xdeadbeef);
826     prevcount = ResumeThread( thread );
827     ok ( prevcount == 1, "Previous suspend count (%d) instead of 1, last error : (%d)\n",
828                          prevcount, GetLastError() );
829
830     WaitForSingleObject( thread, INFINITE );
831     ok( test_value == 20, "test_value %d instead of 20\n", test_value );
832 }
833
834 #endif  /* __i386__ */
835
836 static HANDLE finish_event;
837 static LONG times_executed;
838
839 static DWORD CALLBACK work_function(void *p)
840 {
841     LONG executed = InterlockedIncrement(&times_executed);
842
843     if (executed == 100)
844         SetEvent(finish_event);
845     return 0;
846 }
847
848 static void test_QueueUserWorkItem(void)
849 {
850     int i;
851     DWORD wait_result;
852     DWORD before, after;
853
854     /* QueueUserWorkItem not present on win9x */
855     if (!pQueueUserWorkItem) return;
856
857     finish_event = CreateEvent(NULL, TRUE, FALSE, NULL);
858
859     before = GetTickCount();
860
861     for (i = 0; i < 100; i++)
862     {
863         BOOL ret = pQueueUserWorkItem(work_function, (void *)i, WT_EXECUTEDEFAULT);
864         ok(ret, "QueueUserWorkItem failed with error %d\n", GetLastError());
865     }
866
867     wait_result = WaitForSingleObject(finish_event, 10000);
868
869     after = GetTickCount();
870     trace("100 QueueUserWorkItem calls took %dms\n", after - before);
871     ok(wait_result == WAIT_OBJECT_0, "wait failed with error 0x%x\n", wait_result);
872
873     ok(times_executed == 100, "didn't execute all of the work items\n");
874 }
875
876 START_TEST(thread)
877 {
878    HINSTANCE lib;
879    int argc;
880    char **argv;
881    argc = winetest_get_mainargs( &argv );
882 /* Neither Cygwin nor mingW export OpenThread, so do a dynamic check
883    so that the compile passes
884 */
885    lib=GetModuleHandleA("kernel32.dll");
886    ok(lib!=NULL,"Couldn't get a handle for kernel32.dll\n");
887    pGetThreadPriorityBoost=(GetThreadPriorityBoost_t)GetProcAddress(lib,"GetThreadPriorityBoost");
888    pOpenThread=(OpenThread_t)GetProcAddress(lib,"OpenThread");
889    pQueueUserWorkItem=(QueueUserWorkItem_t)GetProcAddress(lib,"QueueUserWorkItem");
890    pSetThreadIdealProcessor=(SetThreadIdealProcessor_t)GetProcAddress(lib,"SetThreadIdealProcessor");
891    pSetThreadPriorityBoost=(SetThreadPriorityBoost_t)GetProcAddress(lib,"SetThreadPriorityBoost");
892
893    if (argc >= 3)
894    {
895        if (!strcmp(argv[2], "sleep"))
896        {
897            HANDLE hAddrEvents[2];
898            create_function_addr_events(hAddrEvents);
899            SetEvent(hAddrEvents[0]);
900            SetEvent(hAddrEvents[1]);
901            Sleep(5000); /* spawned process runs for at most 5 seconds */
902            return;
903        }
904        while (1)
905        {
906            HANDLE hThread;
907            hThread = CreateThread(NULL, 0, threadFunc2, NULL, 0, NULL);
908            ok(hThread != NULL, "CreateThread failed, error %u\n",
909               GetLastError());
910            ok(WaitForSingleObject(hThread, 200) == WAIT_OBJECT_0,
911               "Thread did not exit in time\n");
912            if (hThread == NULL) break;
913            CloseHandle(hThread);
914        }
915        return;
916    }
917
918    test_CreateRemoteThread();
919    test_CreateThread_basic();
920    test_CreateThread_suspended();
921    test_SuspendThread();
922    test_TerminateThread();
923    test_CreateThread_stack();
924    test_thread_priority();
925    test_GetThreadTimes();
926    test_thread_processor();
927    test_GetThreadExitCode();
928 #ifdef __i386__
929    test_SetThreadContext();
930 #endif
931    test_QueueUserWorkItem();
932 }