Release 0.9.39.
[wine/gsoc-2012-control.git] / dlls / kernel32 / tests / thread.c
blobbbda00e9e643c296123443b3b647bd655d3541ad
1 /*
2 * Unit test suite for directory functions.
4 * Copyright 2002 Geoffrey Hausheer
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.
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.
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
21 /* Define _WIN32_WINNT to get SetThreadIdealProcessor on Windows */
22 #define _WIN32_WINNT 0x0500
24 #include <stdarg.h>
25 #include <stdio.h>
27 #include "wine/test.h"
28 #include <windef.h>
29 #include <winbase.h>
30 #include <winnt.h>
31 #include <winerror.h>
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
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
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
56 typedef BOOL (WINAPI *GetThreadPriorityBoost_t)(HANDLE,PBOOL);
57 static GetThreadPriorityBoost_t pGetThreadPriorityBoost=NULL;
59 typedef HANDLE (WINAPI *OpenThread_t)(DWORD,BOOL,DWORD);
60 static OpenThread_t pOpenThread=NULL;
62 typedef BOOL (WINAPI *QueueUserWorkItem_t)(LPTHREAD_START_ROUTINE,PVOID,ULONG);
63 static QueueUserWorkItem_t pQueueUserWorkItem=NULL;
65 typedef DWORD (WINAPI *SetThreadIdealProcessor_t)(HANDLE,DWORD);
66 static SetThreadIdealProcessor_t pSetThreadIdealProcessor=NULL;
68 typedef BOOL (WINAPI *SetThreadPriorityBoost_t)(HANDLE,BOOL);
69 static SetThreadPriorityBoost_t pSetThreadPriorityBoost=NULL;
71 static HANDLE create_target_process(const char *arg)
73 char **argv;
74 char cmdline[MAX_PATH];
75 PROCESS_INFORMATION pi;
76 STARTUPINFO si = { 0 };
77 si.cb = sizeof(si);
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;
87 /* Functions not tested yet:
88 AttachThreadInput
89 SetThreadContext
90 SwitchToThread
92 In addition there are no checks that the inheritance works properly in
93 CreateThread
96 DWORD tlsIndex;
98 typedef struct {
99 int threadnum;
100 HANDLE *event;
101 DWORD *threadmem;
102 } t1Struct;
104 /* WinME supports OpenThread but doesn't know about access restrictions so
105 we require them to be either completely ignored or always obeyed.
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"))
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
122 static DWORD WINAPI threadFunc1(LPVOID p)
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
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) ;
142 /* lstrlenA contains an exception handler so this makes sure exceptions work in threads */
143 ok( lstrlenA( (char *)0xdeadbeef ) == 0, "lstrlenA: unexpected success\n" );
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;
151 static DWORD WINAPI threadFunc2(LPVOID p)
153 return 99;
156 static DWORD WINAPI threadFunc3(LPVOID p)
158 HANDLE thread;
159 thread=GetCurrentThread();
160 SuspendThread(thread);
161 return 99;
164 static DWORD WINAPI threadFunc4(LPVOID p)
166 HANDLE event = (HANDLE)p;
167 if(event != NULL) {
168 SetEvent(event);
170 Sleep(99000);
171 return 0;
174 #if CHECK_STACK
175 static DWORD WINAPI threadFunc5(LPVOID p)
177 DWORD *exitCode = (DWORD *)p;
178 SYSTEM_INFO sysInfo;
179 sysInfo.dwPageSize=0;
180 GetSystemInfo(&sysInfo);
181 *exitCode=0;
182 __TRY
184 alloca(2*sysInfo.dwPageSize);
186 __EXCEPT(1) {
187 *exitCode=1;
189 __ENDTRY
190 return 0;
192 #endif
194 static DWORD WINAPI threadFunc_SetEvent(LPVOID p)
196 SetEvent((HANDLE) p);
197 return 0;
200 static DWORD WINAPI threadFunc_CloseHandle(LPVOID p)
202 CloseHandle((HANDLE) p);
203 return 0;
206 static void create_function_addr_events(HANDLE events[2])
208 char buffer[256];
210 sprintf(buffer, "threadFunc_SetEvent %p", threadFunc_SetEvent);
211 events[0] = CreateEvent(NULL, FALSE, FALSE, buffer);
213 sprintf(buffer, "threadFunc_CloseHandle %p", threadFunc_CloseHandle);
214 events[1] = CreateEvent(NULL, FALSE, FALSE, buffer);
217 /* check CreateRemoteThread */
218 static VOID test_CreateRemoteThread(void)
220 HANDLE hProcess, hThread, hEvent, hRemoteEvent;
221 DWORD tid, ret, exitcode;
222 HANDLE hAddrEvents[2];
224 hProcess = create_target_process("sleep");
225 ok(hProcess != NULL, "Can't start process\n");
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)
233 skip("child process wasn't mapped at same address, so can't do CreateRemoteThread tests.\n");
234 return;
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());
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)
249 skip("CreateRemoteThread is not implemented\n");
250 goto cleanup;
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());
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);
263 ret = ResumeThread(hThread);
264 ok(ret == 1, "ret=%u, err=%u\n", ret, GetLastError());
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);
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);
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);
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());
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);
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);
300 cleanup:
301 TerminateProcess(hProcess, 0);
302 CloseHandle(hEvent);
303 CloseHandle(hProcess);
306 /* Check basic funcationality of CreateThread and Tls* functions */
307 static VOID test_CreateThread_basic(void)
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;
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" );
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
331 event[i]=CreateEventA(NULL,TRUE,FALSE,NULL);
332 tstruct[i].threadnum=i;
333 tstruct[i].threadmem=threadmem;
334 tstruct[i].event=event;
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");
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);
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");
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
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;
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");
370 ok(TlsFree(tlsIndex)!=0,"TlsFree failed\n");
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");
385 else { /* 9x */
386 ok(GLE==ERROR_INVALID_PARAMETER, "CreateThread set last error to %d, expected 87\n", GLE);
390 /* Check that using the CREATE_SUSPENDED flag works */
391 static VOID test_CreateThread_suspended(void)
393 HANDLE thread;
394 DWORD threadId;
395 int error;
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.
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);
416 ok(CloseHandle(thread)!=0,"CloseHandle failed\n");
419 /* Check that SuspendThread and ResumeThread work */
420 static VOID test_SuspendThread(void)
422 HANDLE thread,access_thread;
423 DWORD threadId,exitCode,error;
424 int i;
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.
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++;
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");
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);
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());
470 ok(CloseHandle(thread)!=0,"CloseHandle Failed\n");
473 /* Check that TerminateThread works properly
475 static VOID test_TerminateThread(void)
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.
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");
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");
510 /* Check if CreateThread obeys the specified stack size. This code does
511 not work properly, and is currently disabled
513 static VOID test_CreateThread_stack(void)
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
522 HANDLE thread;
523 DWORD threadId,exitCode;
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
539 /* Check whether setting/retrieving thread priorities works */
540 static VOID test_thread_priority(void)
542 HANDLE curthread,access_thread;
543 DWORD curthreadId,exitCode;
544 int min_priority=-2,max_priority=2;
545 BOOL disabled,rc;
546 int i;
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
556 ok(GetThreadPriority(curthread)==THREAD_PRIORITY_NORMAL,
557 "GetThreadPriority Failed\n");
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");
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);
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");
591 /* Check thread priority boost */
592 if (!pGetThreadPriorityBoost || !pSetThreadPriorityBoost)
593 return; /* Win9x */
595 SetLastError(0xdeadbeef);
596 rc=pGetThreadPriorityBoost(curthread,&disabled);
597 if (rc==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
598 return; /* WinME */
600 todo_wine
601 ok(rc!=0,"error=%d\n",GetLastError());
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");
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);
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);
631 /* check the GetThreadTimes function */
632 static VOID test_GetThreadTimes(void)
634 HANDLE thread,access_thread=NULL;
635 FILETIME creationTime,exitTime,kernelTime,userTime;
636 DWORD threadId;
637 int error;
639 thread = CreateThread(NULL,0,threadFunc2,NULL,
640 CREATE_SUSPENDED,&threadId);
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");
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)
673 error=GetThreadTimes(access_thread,&creationTime,&exitTime,
674 &kernelTime,&userTime);
675 obey_ar(error==0);
678 if(access_thread!=NULL) {
679 ok(CloseHandle(access_thread)!=0,"CloseHandle Failed\n");
683 /* Check the processor affinity functions */
684 /* NOTE: These functions should also be checked that they obey access control
686 static VOID test_thread_processor(void)
688 HANDLE curthread,curproc;
689 DWORD_PTR processMask,systemMask;
690 SYSTEM_INFO sysInfo;
691 int error=0;
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");
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");
730 static VOID test_GetThreadExitCode(void)
732 DWORD exitCode, threadid;
733 DWORD GLE, ret;
734 HANDLE thread;
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);
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");
751 #ifdef __i386__
753 static int test_value = 0;
754 static HANDLE event;
756 static void WINAPI set_test_val( int val )
758 test_value += val;
761 static DWORD WINAPI threadFunc6(LPVOID p)
763 SetEvent( event );
764 Sleep( 1000 );
765 test_value *= (int)p;
766 return 0;
769 static void test_SetThreadContext(void)
771 CONTEXT ctx;
772 int *stack;
773 HANDLE thread;
774 DWORD threadid;
775 DWORD prevcount;
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)
783 trace("Thread creation failed, skipping rest of test\n");
784 return;
786 WaitForSingleObject( event, INFINITE );
787 SuspendThread( thread );
788 CloseHandle( event );
790 ctx.ContextFlags = CONTEXT_FULL;
791 SetLastError(0xdeadbeef);
792 ok( GetThreadContext( thread, &ctx ), "GetThreadContext failed : (%d)\n", GetLastError() );
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() );
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() );
808 WaitForSingleObject( thread, INFINITE );
809 ok( test_value == 20, "test_value %d instead of 20\n", test_value );
812 #endif /* __i386__ */
814 static HANDLE finish_event;
815 static LONG times_executed;
817 static DWORD CALLBACK work_function(void *p)
819 LONG executed = InterlockedIncrement(&times_executed);
821 if (executed == 100)
822 SetEvent(finish_event);
823 return 0;
826 static void test_QueueUserWorkItem(void)
828 int i;
829 DWORD wait_result;
830 DWORD before, after;
832 /* QueueUserWorkItem not present on win9x */
833 if (!pQueueUserWorkItem) return;
835 finish_event = CreateEvent(NULL, TRUE, FALSE, NULL);
837 before = GetTickCount();
839 for (i = 0; i < 100; i++)
841 BOOL ret = pQueueUserWorkItem(work_function, (void *)i, WT_EXECUTEDEFAULT);
842 ok(ret, "QueueUserWorkItem failed with error %d\n", GetLastError());
845 wait_result = WaitForSingleObject(finish_event, 10000);
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);
851 ok(times_executed == 100, "didn't execute all of the work items\n");
854 START_TEST(thread)
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
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");
871 if (argc >= 3)
873 if (!strcmp(argv[2], "sleep"))
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;
882 while (1)
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);
893 return;
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();