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
28 #include "wine/test.h"
34 /* Specify the number of simultaneous threads to test */
36 /* Specify whether to test the extended priorities for Win2k/XP */
37 #define USE_EXTENDED_PRIORITIES 0
38 /* Specify whether to test the stack allocation in CreateThread */
41 /* Set CHECK_STACK to 1 if you want to try to test the stack-limit from
42 CreateThread. So far I have been unable to make this work, and
43 I am in doubt as to how portable it is. Also, according to MSDN,
44 you shouldn't mix C-run-time-libraries (i.e. alloca) with CreateThread.
45 Anyhow, the check is currently commented out
50 # define __EXCEPT __except
53 # include "wine/exception.h"
57 typedef BOOL (WINAPI
*GetThreadPriorityBoost_t
)(HANDLE
,PBOOL
);
58 static GetThreadPriorityBoost_t pGetThreadPriorityBoost
=NULL
;
60 typedef HANDLE (WINAPI
*OpenThread_t
)(DWORD
,BOOL
,DWORD
);
61 static OpenThread_t pOpenThread
=NULL
;
63 typedef BOOL (WINAPI
*QueueUserWorkItem_t
)(LPTHREAD_START_ROUTINE
,PVOID
,ULONG
);
64 static QueueUserWorkItem_t pQueueUserWorkItem
=NULL
;
66 typedef DWORD (WINAPI
*SetThreadIdealProcessor_t
)(HANDLE
,DWORD
);
67 static SetThreadIdealProcessor_t pSetThreadIdealProcessor
=NULL
;
69 typedef BOOL (WINAPI
*SetThreadPriorityBoost_t
)(HANDLE
,BOOL
);
70 static SetThreadPriorityBoost_t pSetThreadPriorityBoost
=NULL
;
72 typedef BOOL (WINAPI
*RegisterWaitForSingleObject_t
)(PHANDLE
,HANDLE
,WAITORTIMERCALLBACK
,PVOID
,ULONG
,ULONG
);
73 static RegisterWaitForSingleObject_t pRegisterWaitForSingleObject
=NULL
;
75 typedef BOOL (WINAPI
*UnregisterWait_t
)(HANDLE
);
76 static UnregisterWait_t pUnregisterWait
=NULL
;
78 static HANDLE
create_target_process(const char *arg
)
81 char cmdline
[MAX_PATH
];
82 PROCESS_INFORMATION pi
;
83 STARTUPINFO si
= { 0 };
86 winetest_get_mainargs( &argv
);
87 sprintf(cmdline
, "%s %s %s", argv
[0], argv
[1], arg
);
88 ok(CreateProcess(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
,
89 &si
, &pi
) != 0, "error: %u\n", GetLastError());
90 ok(CloseHandle(pi
.hThread
) != 0, "error %u\n", GetLastError());
94 /* Functions not tested yet:
99 In addition there are no checks that the inheritance works properly in
103 /* Functions to ensure that from a group of threads, only one executes
104 certain chunks of code at a time, and we know which one is executing
105 it. It basically makes multithreaded execution linear, which defeats
106 the purpose of multiple threads, but makes testing easy. */
107 static HANDLE start_event
, stop_event
;
108 static LONG num_synced
;
110 static void init_thread_sync_helpers(void)
112 start_event
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
113 ok(start_event
!= NULL
, "CreateEvent failed\n");
114 stop_event
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
115 ok(stop_event
!= NULL
, "CreateEvent failed\n");
119 static BOOL
sync_threads_and_run_one(DWORD sync_id
, DWORD my_id
)
121 LONG num
= InterlockedIncrement(&num_synced
);
122 assert(-1 <= num
&& num
<= 1);
125 ResetEvent( stop_event
);
126 SetEvent( start_event
);
130 DWORD ret
= WaitForSingleObject(start_event
, 10000);
131 ok(ret
== WAIT_OBJECT_0
, "WaitForSingleObject failed %x\n",ret
);
133 return sync_id
== my_id
;
136 static void resync_after_run(void)
138 LONG num
= InterlockedDecrement(&num_synced
);
139 assert(-1 <= num
&& num
<= 1);
142 ResetEvent( start_event
);
143 SetEvent( stop_event
);
147 DWORD ret
= WaitForSingleObject(stop_event
, 10000);
148 ok(ret
== WAIT_OBJECT_0
, "WaitForSingleObject failed\n");
152 static void cleanup_thread_sync_helpers(void)
154 CloseHandle(start_event
);
155 CloseHandle(stop_event
);
166 /* WinME supports OpenThread but doesn't know about access restrictions so
167 we require them to be either completely ignored or always obeyed.
169 INT obeying_ars
= 0; /* -1 == no, 0 == dunno yet, 1 == yes */
173 ? (obeying_ars = +1) \
174 : ((obeying_ars = -1), \
175 trace("not restricted, assuming consistent behaviour\n"))) \
176 : (obeying_ars < 0) \
177 ? ok(!(x), "access restrictions obeyed\n") \
178 : ok( (x), "access restrictions not obeyed\n"))
180 /* Basic test that simultaneous threads can access shared memory,
181 that the thread local storage routines work correctly, and that
182 threads actually run concurrently
184 static DWORD WINAPI
threadFunc1(LPVOID p
)
186 t1Struct
*tstruct
= p
;
188 /* write our thread # into shared memory */
189 tstruct
->threadmem
[tstruct
->threadnum
]=GetCurrentThreadId();
190 ok(TlsSetValue(tlsIndex
,(LPVOID
)(INT_PTR
)(tstruct
->threadnum
+1))!=0,
191 "TlsSetValue failed\n");
192 /* The threads synchronize before terminating. This is done by
193 Signaling an event, and waiting for all events to occur
195 SetEvent(tstruct
->event
[tstruct
->threadnum
]);
196 WaitForMultipleObjects(NUM_THREADS
,tstruct
->event
,TRUE
,INFINITE
);
197 /* Double check that all threads really did run by validating that
198 they have all written to the shared memory. There should be no race
199 here, since all threads were synchronized after the write.*/
200 for(i
=0;i
<NUM_THREADS
;i
++) {
201 while(tstruct
->threadmem
[i
]==0) ;
204 /* lstrlenA contains an exception handler so this makes sure exceptions work in threads */
205 ok( lstrlenA( (char *)0xdeadbeef ) == 0, "lstrlenA: unexpected success\n" );
207 /* Check that no one changed our tls memory */
208 ok((INT_PTR
)TlsGetValue(tlsIndex
)-1==tstruct
->threadnum
,
209 "TlsGetValue failed\n");
210 return NUM_THREADS
+tstruct
->threadnum
;
213 static DWORD WINAPI
threadFunc2(LPVOID p
)
218 static DWORD WINAPI
threadFunc3(LPVOID p
)
221 thread
=GetCurrentThread();
222 SuspendThread(thread
);
226 static DWORD WINAPI
threadFunc4(LPVOID p
)
237 static DWORD WINAPI
threadFunc5(LPVOID p
)
241 sysInfo
.dwPageSize
=0;
242 GetSystemInfo(&sysInfo
);
246 alloca(2*sysInfo
.dwPageSize
);
256 static DWORD WINAPI
threadFunc_SetEvent(LPVOID p
)
262 static DWORD WINAPI
threadFunc_CloseHandle(LPVOID p
)
268 static void create_function_addr_events(HANDLE events
[2])
272 sprintf(buffer
, "threadFunc_SetEvent %p", threadFunc_SetEvent
);
273 events
[0] = CreateEvent(NULL
, FALSE
, FALSE
, buffer
);
275 sprintf(buffer
, "threadFunc_CloseHandle %p", threadFunc_CloseHandle
);
276 events
[1] = CreateEvent(NULL
, FALSE
, FALSE
, buffer
);
279 /* check CreateRemoteThread */
280 static VOID
test_CreateRemoteThread(void)
282 HANDLE hProcess
, hThread
, hEvent
, hRemoteEvent
;
283 DWORD tid
, ret
, exitcode
;
284 HANDLE hAddrEvents
[2];
286 hProcess
= create_target_process("sleep");
287 ok(hProcess
!= NULL
, "Can't start process\n");
289 /* ensure threadFunc_SetEvent & threadFunc_CloseHandle are the same
290 * address as in the child process */
291 create_function_addr_events(hAddrEvents
);
292 ret
= WaitForMultipleObjects(2, hAddrEvents
, TRUE
, 5000);
293 if (ret
== WAIT_TIMEOUT
)
295 skip("child process wasn't mapped at same address, so can't do CreateRemoteThread tests.\n");
299 hEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
300 ok(hEvent
!= NULL
, "Can't create event, err=%u\n", GetLastError());
301 ret
= DuplicateHandle(GetCurrentProcess(), hEvent
, hProcess
, &hRemoteEvent
,
302 0, FALSE
, DUPLICATE_SAME_ACCESS
);
303 ok(ret
!= 0, "DuplicateHandle failed, err=%u\n", GetLastError());
305 /* create suspended remote thread with entry point SetEvent() */
306 SetLastError(0xdeadbeef);
307 hThread
= CreateRemoteThread(hProcess
, NULL
, 0, threadFunc_SetEvent
,
308 hRemoteEvent
, CREATE_SUSPENDED
, &tid
);
309 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
311 win_skip("CreateRemoteThread is not implemented\n");
314 ok(hThread
!= NULL
, "CreateRemoteThread failed, err=%u\n", GetLastError());
315 ok(tid
!= 0, "null tid\n");
316 ret
= SuspendThread(hThread
);
317 ok(ret
== 1, "ret=%u, err=%u\n", ret
, GetLastError());
318 ret
= ResumeThread(hThread
);
319 ok(ret
== 2, "ret=%u, err=%u\n", ret
, GetLastError());
321 /* thread still suspended, so wait times out */
322 ret
= WaitForSingleObject(hEvent
, 100);
323 ok(ret
== WAIT_TIMEOUT
, "wait did not time out, ret=%u\n", ret
);
325 ret
= ResumeThread(hThread
);
326 ok(ret
== 1, "ret=%u, err=%u\n", ret
, GetLastError());
328 /* wait that doesn't time out */
329 ret
= WaitForSingleObject(hEvent
, 100);
330 ok(ret
== WAIT_OBJECT_0
, "object not signaled, ret=%u\n", ret
);
332 /* wait for thread end */
333 ret
= WaitForSingleObject(hThread
, 100);
334 ok(ret
== WAIT_OBJECT_0
, "waiting for thread failed, ret=%u\n", ret
);
335 CloseHandle(hThread
);
337 /* create and wait for remote thread with entry point CloseHandle() */
338 hThread
= CreateRemoteThread(hProcess
, NULL
, 0,
339 threadFunc_CloseHandle
,
340 hRemoteEvent
, 0, &tid
);
341 ok(hThread
!= NULL
, "CreateRemoteThread failed, err=%u\n", GetLastError());
342 ret
= WaitForSingleObject(hThread
, 100);
343 ok(ret
== WAIT_OBJECT_0
, "waiting for thread failed, ret=%u\n", ret
);
344 CloseHandle(hThread
);
346 /* create remote thread with entry point SetEvent() */
347 hThread
= CreateRemoteThread(hProcess
, NULL
, 0,
349 hRemoteEvent
, 0, &tid
);
350 ok(hThread
!= NULL
, "CreateRemoteThread failed, err=%u\n", GetLastError());
352 /* closed handle, so wait times out */
353 ret
= WaitForSingleObject(hEvent
, 100);
354 ok(ret
== WAIT_TIMEOUT
, "wait did not time out, ret=%u\n", ret
);
356 /* check that remote SetEvent() failed */
357 ret
= GetExitCodeThread(hThread
, &exitcode
);
358 ok(ret
!= 0, "GetExitCodeThread failed, err=%u\n", GetLastError());
359 if (ret
) ok(exitcode
== 0, "SetEvent succeeded, expected to fail\n");
360 CloseHandle(hThread
);
363 TerminateProcess(hProcess
, 0);
365 CloseHandle(hProcess
);
368 /* Check basic functionality of CreateThread and Tls* functions */
369 static VOID
test_CreateThread_basic(void)
371 HANDLE thread
[NUM_THREADS
],event
[NUM_THREADS
];
372 DWORD threadid
[NUM_THREADS
],curthreadId
;
373 DWORD threadmem
[NUM_THREADS
];
375 t1Struct tstruct
[NUM_THREADS
];
381 /* lstrlenA contains an exception handler so this makes sure exceptions work in the main thread */
382 ok( lstrlenA( (char *)0xdeadbeef ) == 0, "lstrlenA: unexpected success\n" );
384 /* Retrieve current Thread ID for later comparisons */
385 curthreadId
=GetCurrentThreadId();
386 /* Allocate some local storage */
387 ok((tlsIndex
=TlsAlloc())!=TLS_OUT_OF_INDEXES
,"TlsAlloc failed\n");
388 /* Create events for thread synchronization */
389 for(i
=0;i
<NUM_THREADS
;i
++) {
391 /* Note that it doesn't matter what type of event we choose here. This
392 test isn't trying to thoroughly test events
394 event
[i
]=CreateEventA(NULL
,TRUE
,FALSE
,NULL
);
395 tstruct
[i
].threadnum
=i
;
396 tstruct
[i
].threadmem
=threadmem
;
397 tstruct
[i
].event
=event
;
400 /* Test that passing arguments to threads works okay */
401 for(i
=0;i
<NUM_THREADS
;i
++) {
402 thread
[i
] = CreateThread(NULL
,0,threadFunc1
,
403 &tstruct
[i
],0,&threadid
[i
]);
404 ok(thread
[i
]!=NULL
,"Create Thread failed\n");
406 /* Test that the threads actually complete */
407 for(i
=0;i
<NUM_THREADS
;i
++) {
408 error
=WaitForSingleObject(thread
[i
],5000);
409 ok(error
==WAIT_OBJECT_0
, "Thread did not complete within timelimit\n");
410 if(error
!=WAIT_OBJECT_0
) {
411 TerminateThread(thread
[i
],i
+NUM_THREADS
);
413 ok(GetExitCodeThread(thread
[i
],&exitCode
),"Could not retrieve ext code\n");
414 ok(exitCode
==i
+NUM_THREADS
,"Thread returned an incorrect exit code\n");
416 /* Test that each thread executed in its parent's address space
417 (it was able to change threadmem and pass that change back to its parent)
418 and that each thread id was independent). Note that we prove that the
419 threads actually execute concurrently by having them block on each other
422 for(i
=0;i
<NUM_THREADS
;i
++) {
424 for(j
=i
+1;j
<NUM_THREADS
;j
++) {
425 if (threadmem
[i
]==threadmem
[j
]) {
429 ok(!error
&& threadmem
[i
]==threadid
[i
] && threadmem
[i
]!=curthreadId
,
430 "Thread did not execute successfully\n");
431 ok(CloseHandle(thread
[i
])!=0,"CloseHandle failed\n");
433 ok(TlsFree(tlsIndex
)!=0,"TlsFree failed\n");
435 /* Test how passing NULL as a pointer to threadid works */
436 SetLastError(0xFACEaBAD);
437 thread
[0] = CreateThread(NULL
,0,threadFunc2
,NULL
,0,&tid
);
438 GLE
= GetLastError();
439 if (thread
[0]) { /* NT */
440 ok(GLE
==0xFACEaBAD, "CreateThread set last error to %d, expected 4207848365\n", GLE
);
441 ret
= WaitForSingleObject(thread
[0],100);
442 ok(ret
==WAIT_OBJECT_0
, "threadFunc2 did not exit during 100 ms\n");
443 ret
= GetExitCodeThread(thread
[0],&exitCode
);
444 ok(ret
!=0, "GetExitCodeThread returned %d (expected nonzero)\n", ret
);
445 ok(exitCode
==99, "threadFunc2 exited with code: %d (expected 99)\n", exitCode
);
446 ok(CloseHandle(thread
[0])!=0,"Error closing thread handle\n");
449 ok(GLE
==ERROR_INVALID_PARAMETER
, "CreateThread set last error to %d, expected 87\n", GLE
);
453 /* Check that using the CREATE_SUSPENDED flag works */
454 static VOID
test_CreateThread_suspended(void)
461 thread
= CreateThread(NULL
,0,threadFunc2
,NULL
,
462 CREATE_SUSPENDED
,&threadId
);
463 ok(thread
!=NULL
,"Create Thread failed\n");
464 /* Check that the thread is suspended */
465 ok(SuspendThread(thread
)==1,"Thread did not start suspended\n");
466 ok(ResumeThread(thread
)==2,"Resume thread returned an invalid value\n");
467 /* Check that resume thread didn't actually start the thread. I can't think
468 of a better way of checking this than just waiting. I am not sure if this
469 will work on slow computers.
471 ok(WaitForSingleObject(thread
,1000)==WAIT_TIMEOUT
,
472 "ResumeThread should not have actually started the thread\n");
473 /* Now actually resume the thread and make sure that it actually completes*/
474 ok(ResumeThread(thread
)==1,"Resume thread returned an invalid value\n");
475 ok((error
=WaitForSingleObject(thread
,1000))==WAIT_OBJECT_0
,
476 "Thread did not resume\n");
477 if(error
!=WAIT_OBJECT_0
) {
478 TerminateThread(thread
,1);
481 suspend_count
= SuspendThread(thread
);
482 ok(suspend_count
== -1, "SuspendThread returned %d, expected -1\n", suspend_count
);
484 suspend_count
= ResumeThread(thread
);
485 ok(suspend_count
== 0 ||
486 broken(suspend_count
== -1), /* win9x */
487 "ResumeThread returned %d, expected 0\n", suspend_count
);
489 ok(CloseHandle(thread
)!=0,"CloseHandle failed\n");
492 /* Check that SuspendThread and ResumeThread work */
493 static VOID
test_SuspendThread(void)
495 HANDLE thread
,access_thread
;
496 DWORD threadId
,exitCode
,error
;
499 thread
= CreateThread(NULL
,0,threadFunc3
,NULL
,
501 ok(thread
!=NULL
,"Create Thread failed\n");
502 /* Check that the thread is suspended */
503 /* Note that this is a polling method, and there is a race between
504 SuspendThread being called (in the child, and the loop below timing out,
505 so the test could fail on a heavily loaded or slow computer.
508 for(i
=0;error
==0 && i
<100;i
++) {
509 error
=SuspendThread(thread
);
510 ResumeThread(thread
);
516 ok(error
==1,"SuspendThread did not work\n");
517 /* check that access restrictions are obeyed */
519 access_thread
=pOpenThread(THREAD_ALL_ACCESS
& (~THREAD_SUSPEND_RESUME
),
521 ok(access_thread
!=NULL
,"OpenThread returned an invalid handle\n");
522 if (access_thread
!=NULL
) {
523 obey_ar(SuspendThread(access_thread
)==~0U);
524 obey_ar(ResumeThread(access_thread
)==~0U);
525 ok(CloseHandle(access_thread
)!=0,"CloseHandle Failed\n");
528 /* Double check that the thread really is suspended */
529 ok((error
=GetExitCodeThread(thread
,&exitCode
))!=0 && exitCode
==STILL_ACTIVE
,
530 "Thread did not really suspend\n");
531 /* Resume the thread, and make sure it actually completes */
532 ok(ResumeThread(thread
)==1,"Resume thread returned an invalid value\n");
533 ok((error
=WaitForSingleObject(thread
,1000))==WAIT_OBJECT_0
,
534 "Thread did not resume\n");
535 if(error
!=WAIT_OBJECT_0
) {
536 TerminateThread(thread
,1);
538 /* Trying to suspend a terminated thread should fail */
539 error
=SuspendThread(thread
);
540 ok(error
==~0U, "wrong return code: %d\n", error
);
541 ok(GetLastError()==ERROR_ACCESS_DENIED
|| GetLastError()==ERROR_NO_MORE_ITEMS
, "unexpected error code: %d\n", GetLastError());
543 ok(CloseHandle(thread
)!=0,"CloseHandle Failed\n");
546 /* Check that TerminateThread works properly
548 static VOID
test_TerminateThread(void)
550 HANDLE thread
,access_thread
,event
;
551 DWORD threadId
,exitCode
;
552 event
=CreateEventA(NULL
,TRUE
,FALSE
,NULL
);
553 thread
= CreateThread(NULL
,0,threadFunc4
,event
,0,&threadId
);
554 ok(thread
!=NULL
,"Create Thread failed\n");
555 /* TerminateThread has a race condition in Wine. If the thread is terminated
556 before it starts, it leaves a process behind. Therefore, we wait for the
557 thread to signal that it has started. There is no easy way to force the
558 race to occur, so we don't try to find it.
560 ok(WaitForSingleObject(event
,5000)==WAIT_OBJECT_0
,
561 "TerminateThread didn't work\n");
562 /* check that access restrictions are obeyed */
564 access_thread
=pOpenThread(THREAD_ALL_ACCESS
& (~THREAD_TERMINATE
),
566 ok(access_thread
!=NULL
,"OpenThread returned an invalid handle\n");
567 if (access_thread
!=NULL
) {
568 obey_ar(TerminateThread(access_thread
,99)==0);
569 ok(CloseHandle(access_thread
)!=0,"CloseHandle Failed\n");
572 /* terminate a job and make sure it terminates */
573 ok(TerminateThread(thread
,99)!=0,"TerminateThread failed\n");
574 ok(WaitForSingleObject(thread
,5000)==WAIT_OBJECT_0
,
575 "TerminateThread didn't work\n");
576 ok(GetExitCodeThread(thread
,&exitCode
)!=STILL_ACTIVE
,
577 "TerminateThread should not leave the thread 'STILL_ACTIVE'\n");
578 ok(exitCode
==99, "TerminateThread returned invalid exit code\n");
579 ok(CloseHandle(thread
)!=0,"Error Closing thread handle\n");
582 /* Check if CreateThread obeys the specified stack size. This code does
583 not work properly, and is currently disabled
585 static VOID
test_CreateThread_stack(void)
588 /* The only way I know of to test the stack size is to use alloca
589 and __try/__except. However, this is probably not portable,
590 and I couldn't get it to work under Wine anyhow. However, here
591 is the code which should allow for testing that CreateThread
592 respects the stack-size limit
595 DWORD threadId
,exitCode
;
598 sysInfo
.dwPageSize
=0;
599 GetSystemInfo(&sysInfo
);
600 ok(sysInfo
.dwPageSize
>0,"GetSystemInfo should return a valid page size\n");
601 thread
= CreateThread(NULL
,sysInfo
.dwPageSize
,
602 threadFunc5
,&exitCode
,
604 ok(WaitForSingleObject(thread
,5000)==WAIT_OBJECT_0
,
605 "TerminateThread didn't work\n");
606 ok(exitCode
==1,"CreateThread did not obey stack-size-limit\n");
607 ok(CloseHandle(thread
)!=0,"CloseHandle failed\n");
611 /* Check whether setting/retrieving thread priorities works */
612 static VOID
test_thread_priority(void)
614 HANDLE curthread
,access_thread
;
615 DWORD curthreadId
,exitCode
;
616 int min_priority
=-2,max_priority
=2;
620 curthread
=GetCurrentThread();
621 curthreadId
=GetCurrentThreadId();
622 /* Check thread priority */
623 /* NOTE: on Win2k/XP priority can be from -7 to 6. All other platforms it
624 is -2 to 2. However, even on a real Win2k system, using thread
625 priorities beyond the -2 to 2 range does not work. If you want to try
626 anyway, enable USE_EXTENDED_PRIORITIES
628 ok(GetThreadPriority(curthread
)==THREAD_PRIORITY_NORMAL
,
629 "GetThreadPriority Failed\n");
632 /* check that access control is obeyed */
633 access_thread
=pOpenThread(THREAD_ALL_ACCESS
&
634 (~THREAD_QUERY_INFORMATION
) & (~THREAD_SET_INFORMATION
),
636 ok(access_thread
!=NULL
,"OpenThread returned an invalid handle\n");
637 if (access_thread
!=NULL
) {
638 obey_ar(SetThreadPriority(access_thread
,1)==0);
639 obey_ar(GetThreadPriority(access_thread
)==THREAD_PRIORITY_ERROR_RETURN
);
640 obey_ar(GetExitCodeThread(access_thread
,&exitCode
)==0);
641 ok(CloseHandle(access_thread
),"Error Closing thread handle\n");
644 #if USE_EXTENDED_PRIORITIES
645 min_priority
=-7; max_priority
=6;
647 for(i
=min_priority
;i
<=max_priority
;i
++) {
648 ok(SetThreadPriority(curthread
,i
)!=0,
649 "SetThreadPriority Failed for priority: %d\n",i
);
650 ok(GetThreadPriority(curthread
)==i
,
651 "GetThreadPriority Failed for priority: %d\n",i
);
653 ok(SetThreadPriority(curthread
,THREAD_PRIORITY_TIME_CRITICAL
)!=0,
654 "SetThreadPriority Failed\n");
655 ok(GetThreadPriority(curthread
)==THREAD_PRIORITY_TIME_CRITICAL
,
656 "GetThreadPriority Failed\n");
657 ok(SetThreadPriority(curthread
,THREAD_PRIORITY_IDLE
)!=0,
658 "SetThreadPriority Failed\n");
659 ok(GetThreadPriority(curthread
)==THREAD_PRIORITY_IDLE
,
660 "GetThreadPriority Failed\n");
661 ok(SetThreadPriority(curthread
,0)!=0,"SetThreadPriority Failed\n");
663 /* Check that the thread priority is not changed if SetThreadPriority
664 is called with a value outside of the max/min range */
665 SetThreadPriority(curthread
,min_priority
);
666 SetLastError(0xdeadbeef);
667 rc
= SetThreadPriority(curthread
,min_priority
-1);
669 ok(rc
== FALSE
, "SetThreadPriority passed with a bad argument\n");
670 ok(GetLastError() == ERROR_INVALID_PARAMETER
||
671 GetLastError() == ERROR_INVALID_PRIORITY
/* Win9x */,
672 "SetThreadPriority error %d, expected ERROR_INVALID_PARAMETER or ERROR_INVALID_PRIORITY\n",
674 ok(GetThreadPriority(curthread
)==min_priority
,
675 "GetThreadPriority didn't return min_priority\n");
677 SetThreadPriority(curthread
,max_priority
);
678 SetLastError(0xdeadbeef);
679 rc
= SetThreadPriority(curthread
,max_priority
+1);
681 ok(rc
== FALSE
, "SetThreadPriority passed with a bad argument\n");
682 ok(GetLastError() == ERROR_INVALID_PARAMETER
||
683 GetLastError() == ERROR_INVALID_PRIORITY
/* Win9x */,
684 "SetThreadPriority error %d, expected ERROR_INVALID_PARAMETER or ERROR_INVALID_PRIORITY\n",
686 ok(GetThreadPriority(curthread
)==max_priority
,
687 "GetThreadPriority didn't return max_priority\n");
689 /* Check thread priority boost */
690 if (!pGetThreadPriorityBoost
|| !pSetThreadPriorityBoost
)
693 SetLastError(0xdeadbeef);
694 rc
=pGetThreadPriorityBoost(curthread
,&disabled
);
695 if (rc
==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED
)
697 win_skip("GetThreadPriorityBoost is not implemented on WinME\n");
702 ok(rc
!=0,"error=%d\n",GetLastError());
705 /* check that access control is obeyed */
706 access_thread
=pOpenThread(THREAD_ALL_ACCESS
&
707 (~THREAD_QUERY_INFORMATION
) & (~THREAD_SET_INFORMATION
),
709 ok(access_thread
!=NULL
,"OpenThread returned an invalid handle\n");
710 if (access_thread
!=NULL
) {
711 obey_ar(pSetThreadPriorityBoost(access_thread
,1)==0);
712 obey_ar(pGetThreadPriorityBoost(access_thread
,&disabled
)==0);
713 ok(CloseHandle(access_thread
),"Error Closing thread handle\n");
718 rc
= pSetThreadPriorityBoost(curthread
,1);
719 ok( rc
!= 0, "error=%d\n",GetLastError());
720 rc
=pGetThreadPriorityBoost(curthread
,&disabled
);
721 ok(rc
!=0 && disabled
==1,
722 "rc=%d error=%d disabled=%d\n",rc
,GetLastError(),disabled
);
724 rc
= pSetThreadPriorityBoost(curthread
,0);
725 ok( rc
!= 0, "error=%d\n",GetLastError());
726 rc
=pGetThreadPriorityBoost(curthread
,&disabled
);
727 ok(rc
!=0 && disabled
==0,
728 "rc=%d error=%d disabled=%d\n",rc
,GetLastError(),disabled
);
732 /* check the GetThreadTimes function */
733 static VOID
test_GetThreadTimes(void)
735 HANDLE thread
,access_thread
=NULL
;
736 FILETIME creationTime
,exitTime
,kernelTime
,userTime
;
740 thread
= CreateThread(NULL
,0,threadFunc2
,NULL
,
741 CREATE_SUSPENDED
,&threadId
);
743 ok(thread
!=NULL
,"Create Thread failed\n");
744 /* check that access control is obeyed */
746 access_thread
=pOpenThread(THREAD_ALL_ACCESS
&
747 (~THREAD_QUERY_INFORMATION
), 0,threadId
);
748 ok(access_thread
!=NULL
,
749 "OpenThread returned an invalid handle\n");
751 ok(ResumeThread(thread
)==1,"Resume thread returned an invalid value\n");
752 ok(WaitForSingleObject(thread
,5000)==WAIT_OBJECT_0
,
753 "ResumeThread didn't work\n");
754 creationTime
.dwLowDateTime
=99; creationTime
.dwHighDateTime
=99;
755 exitTime
.dwLowDateTime
=99; exitTime
.dwHighDateTime
=99;
756 kernelTime
.dwLowDateTime
=99; kernelTime
.dwHighDateTime
=99;
757 userTime
.dwLowDateTime
=99; userTime
.dwHighDateTime
=99;
758 /* GetThreadTimes should set all of the parameters passed to it */
759 error
=GetThreadTimes(thread
,&creationTime
,&exitTime
,
760 &kernelTime
,&userTime
);
762 if (error
== 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
763 win_skip("GetThreadTimes is not implemented\n");
765 ok(error
!=0,"GetThreadTimes failed\n");
766 ok(creationTime
.dwLowDateTime
!=99 || creationTime
.dwHighDateTime
!=99,
767 "creationTime was invalid\n");
768 ok(exitTime
.dwLowDateTime
!=99 || exitTime
.dwHighDateTime
!=99,
769 "exitTime was invalid\n");
770 ok(kernelTime
.dwLowDateTime
!=99 || kernelTime
.dwHighDateTime
!=99,
771 "kernelTimewas invalid\n");
772 ok(userTime
.dwLowDateTime
!=99 || userTime
.dwHighDateTime
!=99,
773 "userTime was invalid\n");
774 ok(CloseHandle(thread
)!=0,"CloseHandle failed\n");
775 if(access_thread
!=NULL
)
777 error
=GetThreadTimes(access_thread
,&creationTime
,&exitTime
,
778 &kernelTime
,&userTime
);
782 if(access_thread
!=NULL
) {
783 ok(CloseHandle(access_thread
)!=0,"CloseHandle Failed\n");
787 /* Check the processor affinity functions */
788 /* NOTE: These functions should also be checked that they obey access control
790 static VOID
test_thread_processor(void)
792 HANDLE curthread
,curproc
;
793 DWORD_PTR processMask
,systemMask
;
797 sysInfo
.dwNumberOfProcessors
=0;
798 GetSystemInfo(&sysInfo
);
799 ok(sysInfo
.dwNumberOfProcessors
>0,
800 "GetSystemInfo failed to return a valid # of processors\n");
801 /* Use the current Thread/process for all tests */
802 curthread
=GetCurrentThread();
803 ok(curthread
!=NULL
,"GetCurrentThread failed\n");
804 curproc
=GetCurrentProcess();
805 ok(curproc
!=NULL
,"GetCurrentProcess failed\n");
806 /* Check the Affinity Mask functions */
807 ok(GetProcessAffinityMask(curproc
,&processMask
,&systemMask
)!=0,
808 "GetProcessAffinityMask failed\n");
809 ok(SetThreadAffinityMask(curthread
,processMask
)==processMask
,
810 "SetThreadAffinityMask failed\n");
811 ok(SetThreadAffinityMask(curthread
,processMask
+1)==0,
812 "SetThreadAffinityMask passed for an illegal processor\n");
813 /* NOTE: This only works on WinNT/2000/XP) */
814 if (pSetThreadIdealProcessor
) {
815 SetLastError(0xdeadbeef);
816 error
=pSetThreadIdealProcessor(curthread
,0);
817 if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED
)
819 win_skip("SetThreadIdealProcessor is not implemented\n");
822 ok(error
!=-1, "SetThreadIdealProcessor failed\n");
824 SetLastError(0xdeadbeef);
825 error
=pSetThreadIdealProcessor(curthread
,MAXIMUM_PROCESSORS
+1);
827 "SetThreadIdealProcessor succeeded with an illegal processor #\n");
828 ok(GetLastError()==ERROR_INVALID_PARAMETER
,
829 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
831 error
=pSetThreadIdealProcessor(curthread
,MAXIMUM_PROCESSORS
);
832 ok(error
==0, "SetThreadIdealProcessor returned an incorrect value\n");
836 static VOID
test_GetThreadExitCode(void)
838 DWORD exitCode
, threadid
;
842 ret
= GetExitCodeThread((HANDLE
)0x2bad2bad,&exitCode
);
843 ok(ret
==0, "GetExitCodeThread returned non zero value: %d\n", ret
);
844 GLE
= GetLastError();
845 ok(GLE
==ERROR_INVALID_HANDLE
, "GetLastError returned %d (expected 6)\n", GLE
);
847 thread
= CreateThread(NULL
,0,threadFunc2
,NULL
,0,&threadid
);
848 ret
= WaitForSingleObject(thread
,100);
849 ok(ret
==WAIT_OBJECT_0
, "threadFunc2 did not exit during 100 ms\n");
850 ret
= GetExitCodeThread(thread
,&exitCode
);
851 ok(ret
==exitCode
|| ret
==1,
852 "GetExitCodeThread returned %d (expected 1 or %d)\n", ret
, exitCode
);
853 ok(exitCode
==99, "threadFunc2 exited with code %d (expected 99)\n", exitCode
);
854 ok(CloseHandle(thread
)!=0,"Error closing thread handle\n");
859 static int test_value
= 0;
862 static void WINAPI
set_test_val( int val
)
867 static DWORD WINAPI
threadFunc6(LPVOID p
)
871 test_value
*= (int)p
;
875 static void test_SetThreadContext(void)
884 SetLastError(0xdeadbeef);
885 event
= CreateEvent( NULL
, TRUE
, FALSE
, NULL
);
886 thread
= CreateThread( NULL
, 0, threadFunc6
, (void *)2, 0, &threadid
);
887 ok( thread
!= NULL
, "CreateThread failed : (%d)\n", GetLastError() );
890 trace("Thread creation failed, skipping rest of test\n");
893 WaitForSingleObject( event
, INFINITE
);
894 SuspendThread( thread
);
895 CloseHandle( event
);
897 ctx
.ContextFlags
= CONTEXT_FULL
;
898 SetLastError(0xdeadbeef);
899 ret
= GetThreadContext( thread
, &ctx
);
900 ok( ret
, "GetThreadContext failed : (%u)\n", GetLastError() );
904 /* simulate a call to set_test_val(10) */
905 stack
= (int *)ctx
.Esp
;
908 ctx
.Esp
-= 2 * sizeof(int *);
909 ctx
.Eip
= (DWORD
)set_test_val
;
910 SetLastError(0xdeadbeef);
911 ok( SetThreadContext( thread
, &ctx
), "SetThreadContext failed : (%d)\n", GetLastError() );
914 SetLastError(0xdeadbeef);
915 prevcount
= ResumeThread( thread
);
916 ok ( prevcount
== 1, "Previous suspend count (%d) instead of 1, last error : (%d)\n",
917 prevcount
, GetLastError() );
919 WaitForSingleObject( thread
, INFINITE
);
920 ok( test_value
== 20, "test_value %d instead of 20\n", test_value
);
923 #endif /* __i386__ */
925 static HANDLE finish_event
;
926 static LONG times_executed
;
928 static DWORD CALLBACK
work_function(void *p
)
930 LONG executed
= InterlockedIncrement(×_executed
);
933 SetEvent(finish_event
);
937 static void test_QueueUserWorkItem(void)
943 /* QueueUserWorkItem not present on win9x */
944 if (!pQueueUserWorkItem
) return;
946 finish_event
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
948 before
= GetTickCount();
950 for (i
= 0; i
< 100; i
++)
952 BOOL ret
= pQueueUserWorkItem(work_function
, (void *)i
, WT_EXECUTEDEFAULT
);
953 ok(ret
, "QueueUserWorkItem failed with error %d\n", GetLastError());
956 wait_result
= WaitForSingleObject(finish_event
, 10000);
958 after
= GetTickCount();
959 trace("100 QueueUserWorkItem calls took %dms\n", after
- before
);
960 ok(wait_result
== WAIT_OBJECT_0
, "wait failed with error 0x%x\n", wait_result
);
962 ok(times_executed
== 100, "didn't execute all of the work items\n");
965 static void CALLBACK
signaled_function(PVOID p
, BOOLEAN TimerOrWaitFired
)
969 ok(!TimerOrWaitFired
, "wait shouldn't have timed out\n");
972 static void CALLBACK
timeout_function(PVOID p
, BOOLEAN TimerOrWaitFired
)
976 ok(TimerOrWaitFired
, "wait should have timed out\n");
979 static void test_RegisterWaitForSingleObject(void)
984 HANDLE complete_event
;
986 if (!pRegisterWaitForSingleObject
|| !pUnregisterWait
)
988 win_skip("RegisterWaitForSingleObject or UnregisterWait not implemented\n");
992 /* test signaled case */
994 handle
= CreateEvent(NULL
, TRUE
, TRUE
, NULL
);
995 complete_event
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
997 ret
= pRegisterWaitForSingleObject(&wait_handle
, handle
, signaled_function
, complete_event
, INFINITE
, WT_EXECUTEONLYONCE
);
998 ok(ret
, "RegisterWaitForSingleObject failed with error %d\n", GetLastError());
1000 WaitForSingleObject(complete_event
, INFINITE
);
1001 /* give worker thread chance to complete */
1004 ret
= pUnregisterWait(wait_handle
);
1005 ok(ret
, "UnregisterWait failed with error %d\n", GetLastError());
1007 /* test cancel case */
1011 ret
= pRegisterWaitForSingleObject(&wait_handle
, handle
, signaled_function
, complete_event
, INFINITE
, WT_EXECUTEONLYONCE
);
1012 ok(ret
, "RegisterWaitForSingleObject failed with error %d\n", GetLastError());
1014 ret
= pUnregisterWait(wait_handle
);
1015 ok(ret
, "UnregisterWait failed with error %d\n", GetLastError());
1017 /* test timeout case */
1019 ret
= pRegisterWaitForSingleObject(&wait_handle
, handle
, timeout_function
, complete_event
, 0, WT_EXECUTEONLYONCE
);
1020 ok(ret
, "RegisterWaitForSingleObject failed with error %d\n", GetLastError());
1022 WaitForSingleObject(complete_event
, INFINITE
);
1023 /* give worker thread chance to complete */
1026 ret
= pUnregisterWait(wait_handle
);
1027 ok(ret
, "UnregisterWait failed with error %d\n", GetLastError());
1030 static DWORD TLS_main
;
1031 static DWORD TLS_index0
, TLS_index1
;
1033 static DWORD WINAPI
TLS_InheritanceProc(LPVOID p
)
1035 /* We should NOT inherit the TLS values from our parent or from the
1039 val
= TlsGetValue(TLS_main
);
1040 ok(val
== NULL
, "TLS inheritance failed\n");
1042 val
= TlsGetValue(TLS_index0
);
1043 ok(val
== NULL
, "TLS inheritance failed\n");
1045 val
= TlsGetValue(TLS_index1
);
1046 ok(val
== NULL
, "TLS inheritance failed\n");
1051 /* Basic TLS usage test. Make sure we can create slots and the values we
1052 store in them are separate among threads. Also test TLS value
1053 inheritance with TLS_InheritanceProc. */
1054 static DWORD WINAPI
TLS_ThreadProc(LPVOID p
)
1056 LONG_PTR id
= (LONG_PTR
) p
;
1060 if (sync_threads_and_run_one(0, id
))
1062 TLS_index0
= TlsAlloc();
1063 ok(TLS_index0
!= TLS_OUT_OF_INDEXES
, "TlsAlloc failed\n");
1067 if (sync_threads_and_run_one(1, id
))
1069 TLS_index1
= TlsAlloc();
1070 ok(TLS_index1
!= TLS_OUT_OF_INDEXES
, "TlsAlloc failed\n");
1072 /* Slot indices should be different even if created in different
1074 ok(TLS_index0
!= TLS_index1
, "TlsAlloc failed\n");
1076 /* Both slots should be initialized to NULL */
1077 val
= TlsGetValue(TLS_index0
);
1078 ok(GetLastError() == ERROR_SUCCESS
, "TlsGetValue failed\n");
1079 ok(val
== NULL
, "TLS slot not initialized correctly\n");
1081 val
= TlsGetValue(TLS_index1
);
1082 ok(GetLastError() == ERROR_SUCCESS
, "TlsGetValue failed\n");
1083 ok(val
== NULL
, "TLS slot not initialized correctly\n");
1087 if (sync_threads_and_run_one(0, id
))
1089 val
= TlsGetValue(TLS_index0
);
1090 ok(GetLastError() == ERROR_SUCCESS
, "TlsGetValue failed\n");
1091 ok(val
== NULL
, "TLS slot not initialized correctly\n");
1093 val
= TlsGetValue(TLS_index1
);
1094 ok(GetLastError() == ERROR_SUCCESS
, "TlsGetValue failed\n");
1095 ok(val
== NULL
, "TLS slot not initialized correctly\n");
1097 ret
= TlsSetValue(TLS_index0
, (LPVOID
) 1);
1098 ok(ret
, "TlsSetValue failed\n");
1100 ret
= TlsSetValue(TLS_index1
, (LPVOID
) 2);
1101 ok(ret
, "TlsSetValue failed\n");
1103 val
= TlsGetValue(TLS_index0
);
1104 ok(GetLastError() == ERROR_SUCCESS
, "TlsGetValue failed\n");
1105 ok(val
== (LPVOID
) 1, "TLS slot not initialized correctly\n");
1107 val
= TlsGetValue(TLS_index1
);
1108 ok(GetLastError() == ERROR_SUCCESS
, "TlsGetValue failed\n");
1109 ok(val
== (LPVOID
) 2, "TLS slot not initialized correctly\n");
1113 if (sync_threads_and_run_one(1, id
))
1115 val
= TlsGetValue(TLS_index0
);
1116 ok(GetLastError() == ERROR_SUCCESS
, "TlsGetValue failed\n");
1117 ok(val
== NULL
, "TLS slot not initialized correctly\n");
1119 val
= TlsGetValue(TLS_index1
);
1120 ok(GetLastError() == ERROR_SUCCESS
, "TlsGetValue failed\n");
1121 ok(val
== NULL
, "TLS slot not initialized correctly\n");
1123 ret
= TlsSetValue(TLS_index0
, (LPVOID
) 3);
1124 ok(ret
, "TlsSetValue failed\n");
1126 ret
= TlsSetValue(TLS_index1
, (LPVOID
) 4);
1127 ok(ret
, "TlsSetValue failed\n");
1129 val
= TlsGetValue(TLS_index0
);
1130 ok(GetLastError() == ERROR_SUCCESS
, "TlsGetValue failed\n");
1131 ok(val
== (LPVOID
) 3, "TLS slot not initialized correctly\n");
1133 val
= TlsGetValue(TLS_index1
);
1134 ok(GetLastError() == ERROR_SUCCESS
, "TlsGetValue failed\n");
1135 ok(val
== (LPVOID
) 4, "TLS slot not initialized correctly\n");
1139 if (sync_threads_and_run_one(0, id
))
1144 val
= TlsGetValue(TLS_index0
);
1145 ok(GetLastError() == ERROR_SUCCESS
, "TlsGetValue failed\n");
1146 ok(val
== (LPVOID
) 1, "TLS slot not initialized correctly\n");
1148 val
= TlsGetValue(TLS_index1
);
1149 ok(GetLastError() == ERROR_SUCCESS
, "TlsGetValue failed\n");
1150 ok(val
== (LPVOID
) 2, "TLS slot not initialized correctly\n");
1152 thread
= CreateThread(NULL
, 0, TLS_InheritanceProc
, 0, 0, &tid
);
1153 ok(thread
!= NULL
, "CreateThread failed\n");
1154 waitret
= WaitForSingleObject(thread
, 60000);
1155 ok(waitret
== WAIT_OBJECT_0
, "WaitForSingleObject failed\n");
1156 CloseHandle(thread
);
1158 ret
= TlsFree(TLS_index0
);
1159 ok(ret
, "TlsFree failed\n");
1163 if (sync_threads_and_run_one(1, id
))
1165 ret
= TlsFree(TLS_index1
);
1166 ok(ret
, "TlsFree failed\n");
1173 static void test_TLS(void)
1180 init_thread_sync_helpers();
1182 /* Allocate a TLS slot in the main thread to test for inheritance. */
1183 TLS_main
= TlsAlloc();
1184 ok(TLS_main
!= TLS_OUT_OF_INDEXES
, "TlsAlloc failed\n");
1185 suc
= TlsSetValue(TLS_main
, (LPVOID
) 4114);
1186 ok(suc
, "TlsSetValue failed\n");
1188 for (i
= 0; i
< 2; ++i
)
1192 threads
[i
] = CreateThread(NULL
, 0, TLS_ThreadProc
, (LPVOID
) i
, 0, &tid
);
1193 ok(threads
[i
] != NULL
, "CreateThread failed\n");
1196 ret
= WaitForMultipleObjects(2, threads
, TRUE
, 60000);
1197 ok(ret
== WAIT_OBJECT_0
|| ret
== WAIT_OBJECT_0
+1 /* nt4 */, "WaitForMultipleObjects failed %u\n",ret
);
1199 for (i
= 0; i
< 2; ++i
)
1200 CloseHandle(threads
[i
]);
1202 suc
= TlsFree(TLS_main
);
1203 ok(suc
, "TlsFree failed\n");
1204 cleanup_thread_sync_helpers();
1212 argc
= winetest_get_mainargs( &argv
);
1213 /* Neither Cygwin nor mingW export OpenThread, so do a dynamic check
1214 so that the compile passes
1216 lib
=GetModuleHandleA("kernel32.dll");
1217 ok(lib
!=NULL
,"Couldn't get a handle for kernel32.dll\n");
1218 pGetThreadPriorityBoost
=(GetThreadPriorityBoost_t
)GetProcAddress(lib
,"GetThreadPriorityBoost");
1219 pOpenThread
=(OpenThread_t
)GetProcAddress(lib
,"OpenThread");
1220 pQueueUserWorkItem
=(QueueUserWorkItem_t
)GetProcAddress(lib
,"QueueUserWorkItem");
1221 pSetThreadIdealProcessor
=(SetThreadIdealProcessor_t
)GetProcAddress(lib
,"SetThreadIdealProcessor");
1222 pSetThreadPriorityBoost
=(SetThreadPriorityBoost_t
)GetProcAddress(lib
,"SetThreadPriorityBoost");
1223 pRegisterWaitForSingleObject
=(RegisterWaitForSingleObject_t
)GetProcAddress(lib
,"RegisterWaitForSingleObject");
1224 pUnregisterWait
=(UnregisterWait_t
)GetProcAddress(lib
,"UnregisterWait");
1228 if (!strcmp(argv
[2], "sleep"))
1230 HANDLE hAddrEvents
[2];
1231 create_function_addr_events(hAddrEvents
);
1232 SetEvent(hAddrEvents
[0]);
1233 SetEvent(hAddrEvents
[1]);
1234 Sleep(5000); /* spawned process runs for at most 5 seconds */
1241 hThread
= CreateThread(NULL
, 0, threadFunc2
, NULL
, 0, &tid
);
1242 ok(hThread
!= NULL
, "CreateThread failed, error %u\n",
1244 ok(WaitForSingleObject(hThread
, 200) == WAIT_OBJECT_0
,
1245 "Thread did not exit in time\n");
1246 if (hThread
== NULL
) break;
1247 CloseHandle(hThread
);
1252 test_CreateRemoteThread();
1253 test_CreateThread_basic();
1254 test_CreateThread_suspended();
1255 test_SuspendThread();
1256 test_TerminateThread();
1257 test_CreateThread_stack();
1258 test_thread_priority();
1259 test_GetThreadTimes();
1260 test_thread_processor();
1261 test_GetThreadExitCode();
1263 test_SetThreadContext();
1265 test_QueueUserWorkItem();
1266 test_RegisterWaitForSingleObject();