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