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 all_synced
;
108 static LONG num_syncing_threads
, num_synced
;
110 static void init_thread_sync_helpers(LONG num_threads
)
112 all_synced
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
113 ok(all_synced
!= NULL
, "CreateEvent failed\n");
114 num_syncing_threads
= num_threads
;
118 static BOOL
sync_threads_and_run_one(DWORD sync_id
, DWORD my_id
)
120 LONG num
= InterlockedIncrement(&num_synced
);
121 assert(0 < num
&& num
<= num_syncing_threads
);
122 if (num
== num_syncing_threads
)
123 /* FIXME: MSDN claims PulseEvent is unreliable. For a test this isn't
124 so important, but we could use condition variables with more effort.
125 The given approach is clearer, though. */
126 PulseEvent(all_synced
);
129 DWORD ret
= WaitForSingleObject(all_synced
, 60000);
130 ok(ret
== WAIT_OBJECT_0
, "WaitForSingleObject failed\n");
132 return sync_id
== my_id
;
135 static void resync_after_run(void)
137 LONG num
= InterlockedDecrement(&num_synced
);
138 assert(0 <= num
&& num
< num_syncing_threads
);
140 PulseEvent(all_synced
);
143 DWORD ret
= WaitForSingleObject(all_synced
, 60000);
144 ok(ret
== WAIT_OBJECT_0
, "WaitForSingleObject failed\n");
148 static void cleanup_thread_sync_helpers(void)
150 CloseHandle(all_synced
);
162 /* WinME supports OpenThread but doesn't know about access restrictions so
163 we require them to be either completely ignored or always obeyed.
165 INT obeying_ars
= 0; /* -1 == no, 0 == dunno yet, 1 == yes */
169 ? (obeying_ars = +1) \
170 : ((obeying_ars = -1), \
171 trace("not restricted, assuming consistent behaviour\n"))) \
172 : (obeying_ars < 0) \
173 ? ok(!(x), "access restrictions obeyed\n") \
174 : ok( (x), "access restrictions not obeyed\n"))
176 /* Basic test that simultaneous threads can access shared memory,
177 that the thread local storage routines work correctly, and that
178 threads actually run concurrently
180 static DWORD WINAPI
threadFunc1(LPVOID p
)
182 t1Struct
*tstruct
= (t1Struct
*)p
;
184 /* write our thread # into shared memory */
185 tstruct
->threadmem
[tstruct
->threadnum
]=GetCurrentThreadId();
186 ok(TlsSetValue(tlsIndex
,(LPVOID
)(tstruct
->threadnum
+1))!=0,
187 "TlsSetValue failed\n");
188 /* The threads synchronize before terminating. This is done by
189 Signaling an event, and waiting for all events to occur
191 SetEvent(tstruct
->event
[tstruct
->threadnum
]);
192 WaitForMultipleObjects(NUM_THREADS
,tstruct
->event
,TRUE
,INFINITE
);
193 /* Double check that all threads really did run by validating that
194 they have all written to the shared memory. There should be no race
195 here, since all threads were synchronized after the write.*/
196 for(i
=0;i
<NUM_THREADS
;i
++) {
197 while(tstruct
->threadmem
[i
]==0) ;
200 /* lstrlenA contains an exception handler so this makes sure exceptions work in threads */
201 ok( lstrlenA( (char *)0xdeadbeef ) == 0, "lstrlenA: unexpected success\n" );
203 /* Check that no one changed our tls memory */
204 ok((int)TlsGetValue(tlsIndex
)-1==tstruct
->threadnum
,
205 "TlsGetValue failed\n");
206 return NUM_THREADS
+tstruct
->threadnum
;
209 static DWORD WINAPI
threadFunc2(LPVOID p
)
214 static DWORD WINAPI
threadFunc3(LPVOID p
)
217 thread
=GetCurrentThread();
218 SuspendThread(thread
);
222 static DWORD WINAPI
threadFunc4(LPVOID p
)
224 HANDLE event
= (HANDLE
)p
;
233 static DWORD WINAPI
threadFunc5(LPVOID p
)
235 DWORD
*exitCode
= (DWORD
*)p
;
237 sysInfo
.dwPageSize
=0;
238 GetSystemInfo(&sysInfo
);
242 alloca(2*sysInfo
.dwPageSize
);
252 static DWORD WINAPI
threadFunc_SetEvent(LPVOID p
)
254 SetEvent((HANDLE
) p
);
258 static DWORD WINAPI
threadFunc_CloseHandle(LPVOID p
)
260 CloseHandle((HANDLE
) p
);
264 static void create_function_addr_events(HANDLE events
[2])
268 sprintf(buffer
, "threadFunc_SetEvent %p", threadFunc_SetEvent
);
269 events
[0] = CreateEvent(NULL
, FALSE
, FALSE
, buffer
);
271 sprintf(buffer
, "threadFunc_CloseHandle %p", threadFunc_CloseHandle
);
272 events
[1] = CreateEvent(NULL
, FALSE
, FALSE
, buffer
);
275 /* check CreateRemoteThread */
276 static VOID
test_CreateRemoteThread(void)
278 HANDLE hProcess
, hThread
, hEvent
, hRemoteEvent
;
279 DWORD tid
, ret
, exitcode
;
280 HANDLE hAddrEvents
[2];
282 hProcess
= create_target_process("sleep");
283 ok(hProcess
!= NULL
, "Can't start process\n");
285 /* ensure threadFunc_SetEvent & threadFunc_CloseHandle are the same
286 * address as in the child process */
287 create_function_addr_events(hAddrEvents
);
288 ret
= WaitForMultipleObjects(2, hAddrEvents
, TRUE
, 5000);
289 if (ret
== WAIT_TIMEOUT
)
291 skip("child process wasn't mapped at same address, so can't do CreateRemoteThread tests.\n");
295 hEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
296 ok(hEvent
!= NULL
, "Can't create event, err=%u\n", GetLastError());
297 ret
= DuplicateHandle(GetCurrentProcess(), hEvent
, hProcess
, &hRemoteEvent
,
298 0, FALSE
, DUPLICATE_SAME_ACCESS
);
299 ok(ret
!= 0, "DuplicateHandle failed, err=%u\n", GetLastError());
301 /* create suspended remote thread with entry point SetEvent() */
302 SetLastError(0xdeadbeef);
303 hThread
= CreateRemoteThread(hProcess
, NULL
, 0, threadFunc_SetEvent
,
304 hRemoteEvent
, CREATE_SUSPENDED
, &tid
);
305 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
307 skip("CreateRemoteThread is not implemented\n");
310 ok(hThread
!= NULL
, "CreateRemoteThread failed, err=%u\n", GetLastError());
311 ok(tid
!= 0, "null tid\n");
312 ret
= SuspendThread(hThread
);
313 ok(ret
== 1, "ret=%u, err=%u\n", ret
, GetLastError());
314 ret
= ResumeThread(hThread
);
315 ok(ret
== 2, "ret=%u, err=%u\n", ret
, GetLastError());
317 /* thread still suspended, so wait times out */
318 ret
= WaitForSingleObject(hEvent
, 100);
319 ok(ret
== WAIT_TIMEOUT
, "wait did not time out, ret=%u\n", ret
);
321 ret
= ResumeThread(hThread
);
322 ok(ret
== 1, "ret=%u, err=%u\n", ret
, GetLastError());
324 /* wait that doesn't time out */
325 ret
= WaitForSingleObject(hEvent
, 100);
326 ok(ret
== WAIT_OBJECT_0
, "object not signaled, ret=%u\n", ret
);
328 /* wait for thread end */
329 ret
= WaitForSingleObject(hThread
, 100);
330 ok(ret
== WAIT_OBJECT_0
, "waiting for thread failed, ret=%u\n", ret
);
331 CloseHandle(hThread
);
333 /* create and wait for remote thread with entry point CloseHandle() */
334 hThread
= CreateRemoteThread(hProcess
, NULL
, 0,
335 threadFunc_CloseHandle
,
336 hRemoteEvent
, 0, &tid
);
337 ok(hThread
!= NULL
, "CreateRemoteThread failed, err=%u\n", GetLastError());
338 ret
= WaitForSingleObject(hThread
, 100);
339 ok(ret
== WAIT_OBJECT_0
, "waiting for thread failed, ret=%u\n", ret
);
340 CloseHandle(hThread
);
342 /* create remote thread with entry point SetEvent() */
343 hThread
= CreateRemoteThread(hProcess
, NULL
, 0,
345 hRemoteEvent
, 0, &tid
);
346 ok(hThread
!= NULL
, "CreateRemoteThread failed, err=%u\n", GetLastError());
348 /* closed handle, so wait times out */
349 ret
= WaitForSingleObject(hEvent
, 100);
350 ok(ret
== WAIT_TIMEOUT
, "wait did not time out, ret=%u\n", ret
);
352 /* check that remote SetEvent() failed */
353 ret
= GetExitCodeThread(hThread
, &exitcode
);
354 ok(ret
!= 0, "GetExitCodeThread failed, err=%u\n", GetLastError());
355 if (ret
) ok(exitcode
== 0, "SetEvent succeeded, expected to fail\n");
356 CloseHandle(hThread
);
359 TerminateProcess(hProcess
, 0);
361 CloseHandle(hProcess
);
364 /* Check basic functionality of CreateThread and Tls* functions */
365 static VOID
test_CreateThread_basic(void)
367 HANDLE thread
[NUM_THREADS
],event
[NUM_THREADS
];
368 DWORD threadid
[NUM_THREADS
],curthreadId
;
369 DWORD threadmem
[NUM_THREADS
];
371 t1Struct tstruct
[NUM_THREADS
];
376 /* lstrlenA contains an exception handler so this makes sure exceptions work in the main thread */
377 ok( lstrlenA( (char *)0xdeadbeef ) == 0, "lstrlenA: unexpected success\n" );
379 /* Retrieve current Thread ID for later comparisons */
380 curthreadId
=GetCurrentThreadId();
381 /* Allocate some local storage */
382 ok((tlsIndex
=TlsAlloc())!=TLS_OUT_OF_INDEXES
,"TlsAlloc failed\n");
383 /* Create events for thread synchronization */
384 for(i
=0;i
<NUM_THREADS
;i
++) {
386 /* Note that it doesn't matter what type of event we choose here. This
387 test isn't trying to thoroughly test events
389 event
[i
]=CreateEventA(NULL
,TRUE
,FALSE
,NULL
);
390 tstruct
[i
].threadnum
=i
;
391 tstruct
[i
].threadmem
=threadmem
;
392 tstruct
[i
].event
=event
;
395 /* Test that passing arguments to threads works okay */
396 for(i
=0;i
<NUM_THREADS
;i
++) {
397 thread
[i
] = CreateThread(NULL
,0,threadFunc1
,
398 &tstruct
[i
],0,&threadid
[i
]);
399 ok(thread
[i
]!=NULL
,"Create Thread failed\n");
401 /* Test that the threads actually complete */
402 for(i
=0;i
<NUM_THREADS
;i
++) {
403 error
=WaitForSingleObject(thread
[i
],5000);
404 ok(error
==WAIT_OBJECT_0
, "Thread did not complete within timelimit\n");
405 if(error
!=WAIT_OBJECT_0
) {
406 TerminateThread(thread
[i
],i
+NUM_THREADS
);
408 ok(GetExitCodeThread(thread
[i
],&exitCode
),"Could not retrieve ext code\n");
409 ok(exitCode
==i
+NUM_THREADS
,"Thread returned an incorrect exit code\n");
411 /* Test that each thread executed in its parent's address space
412 (it was able to change threadmem and pass that change back to its parent)
413 and that each thread id was independent). Note that we prove that the
414 threads actually execute concurrently by having them block on each other
417 for(i
=0;i
<NUM_THREADS
;i
++) {
419 for(j
=i
+1;j
<NUM_THREADS
;j
++) {
420 if (threadmem
[i
]==threadmem
[j
]) {
424 ok(!error
&& threadmem
[i
]==threadid
[i
] && threadmem
[i
]!=curthreadId
,
425 "Thread did not execute successfully\n");
426 ok(CloseHandle(thread
[i
])!=0,"CloseHandle failed\n");
428 ok(TlsFree(tlsIndex
)!=0,"TlsFree failed\n");
430 /* Test how passing NULL as a pointer to threadid works */
431 SetLastError(0xFACEaBAD);
432 thread
[0] = CreateThread(NULL
,0,threadFunc2
,NULL
,0,NULL
);
433 GLE
= GetLastError();
434 if (thread
[0]) { /* NT */
435 ok(GLE
==0xFACEaBAD, "CreateThread set last error to %d, expected 4207848365\n", GLE
);
436 ret
= WaitForSingleObject(thread
[0],100);
437 ok(ret
==WAIT_OBJECT_0
, "threadFunc2 did not exit during 100 ms\n");
438 ret
= GetExitCodeThread(thread
[0],&exitCode
);
439 ok(ret
!=0, "GetExitCodeThread returned %d (expected nonzero)\n", ret
);
440 ok(exitCode
==99, "threadFunc2 exited with code: %d (expected 99)\n", exitCode
);
441 ok(CloseHandle(thread
[0])!=0,"Error closing thread handle\n");
444 ok(GLE
==ERROR_INVALID_PARAMETER
, "CreateThread set last error to %d, expected 87\n", GLE
);
448 /* Check that using the CREATE_SUSPENDED flag works */
449 static VOID
test_CreateThread_suspended(void)
456 thread
= CreateThread(NULL
,0,threadFunc2
,NULL
,
457 CREATE_SUSPENDED
,&threadId
);
458 ok(thread
!=NULL
,"Create Thread failed\n");
459 /* Check that the thread is suspended */
460 ok(SuspendThread(thread
)==1,"Thread did not start suspended\n");
461 ok(ResumeThread(thread
)==2,"Resume thread returned an invalid value\n");
462 /* Check that resume thread didn't actually start the thread. I can't think
463 of a better way of checking this than just waiting. I am not sure if this
464 will work on slow computers.
466 ok(WaitForSingleObject(thread
,1000)==WAIT_TIMEOUT
,
467 "ResumeThread should not have actually started the thread\n");
468 /* Now actually resume the thread and make sure that it actually completes*/
469 ok(ResumeThread(thread
)==1,"Resume thread returned an invalid value\n");
470 ok((error
=WaitForSingleObject(thread
,1000))==WAIT_OBJECT_0
,
471 "Thread did not resume\n");
472 if(error
!=WAIT_OBJECT_0
) {
473 TerminateThread(thread
,1);
476 suspend_count
= SuspendThread(thread
);
477 ok(suspend_count
== -1, "SuspendThread returned %d, expected -1\n", suspend_count
);
479 suspend_count
= ResumeThread(thread
);
480 ok(suspend_count
== 0, "ResumeThread returned %d, expected 0\n", suspend_count
);
482 ok(CloseHandle(thread
)!=0,"CloseHandle failed\n");
485 /* Check that SuspendThread and ResumeThread work */
486 static VOID
test_SuspendThread(void)
488 HANDLE thread
,access_thread
;
489 DWORD threadId
,exitCode
,error
;
492 thread
= CreateThread(NULL
,0,threadFunc3
,NULL
,
494 ok(thread
!=NULL
,"Create Thread failed\n");
495 /* Check that the thread is suspended */
496 /* Note that this is a polling method, and there is a race between
497 SuspendThread being called (in the child, and the loop below timing out,
498 so the test could fail on a heavily loaded or slow computer.
501 for(i
=0;error
==0 && i
<100;i
++) {
502 error
=SuspendThread(thread
);
503 ResumeThread(thread
);
509 ok(error
==1,"SuspendThread did not work\n");
510 /* check that access restrictions are obeyed */
512 access_thread
=pOpenThread(THREAD_ALL_ACCESS
& (~THREAD_SUSPEND_RESUME
),
514 ok(access_thread
!=NULL
,"OpenThread returned an invalid handle\n");
515 if (access_thread
!=NULL
) {
516 obey_ar(SuspendThread(access_thread
)==~0U);
517 obey_ar(ResumeThread(access_thread
)==~0U);
518 ok(CloseHandle(access_thread
)!=0,"CloseHandle Failed\n");
521 /* Double check that the thread really is suspended */
522 ok((error
=GetExitCodeThread(thread
,&exitCode
))!=0 && exitCode
==STILL_ACTIVE
,
523 "Thread did not really suspend\n");
524 /* Resume the thread, and make sure it actually completes */
525 ok(ResumeThread(thread
)==1,"Resume thread returned an invalid value\n");
526 ok((error
=WaitForSingleObject(thread
,1000))==WAIT_OBJECT_0
,
527 "Thread did not resume\n");
528 if(error
!=WAIT_OBJECT_0
) {
529 TerminateThread(thread
,1);
531 /* Trying to suspend a terminated thread should fail */
532 error
=SuspendThread(thread
);
533 ok(error
==~0U, "wrong return code: %d\n", error
);
534 ok(GetLastError()==ERROR_ACCESS_DENIED
|| GetLastError()==ERROR_NO_MORE_ITEMS
, "unexpected error code: %d\n", GetLastError());
536 ok(CloseHandle(thread
)!=0,"CloseHandle Failed\n");
539 /* Check that TerminateThread works properly
541 static VOID
test_TerminateThread(void)
543 HANDLE thread
,access_thread
,event
;
544 DWORD threadId
,exitCode
;
545 event
=CreateEventA(NULL
,TRUE
,FALSE
,NULL
);
546 thread
= CreateThread(NULL
,0,threadFunc4
,
547 (LPVOID
)event
, 0,&threadId
);
548 ok(thread
!=NULL
,"Create Thread failed\n");
549 /* TerminateThread has a race condition in Wine. If the thread is terminated
550 before it starts, it leaves a process behind. Therefore, we wait for the
551 thread to signal that it has started. There is no easy way to force the
552 race to occur, so we don't try to find it.
554 ok(WaitForSingleObject(event
,5000)==WAIT_OBJECT_0
,
555 "TerminateThread didn't work\n");
556 /* check that access restrictions are obeyed */
558 access_thread
=pOpenThread(THREAD_ALL_ACCESS
& (~THREAD_TERMINATE
),
560 ok(access_thread
!=NULL
,"OpenThread returned an invalid handle\n");
561 if (access_thread
!=NULL
) {
562 obey_ar(TerminateThread(access_thread
,99)==0);
563 ok(CloseHandle(access_thread
)!=0,"CloseHandle Failed\n");
566 /* terminate a job and make sure it terminates */
567 ok(TerminateThread(thread
,99)!=0,"TerminateThread failed\n");
568 ok(WaitForSingleObject(thread
,5000)==WAIT_OBJECT_0
,
569 "TerminateThread didn't work\n");
570 ok(GetExitCodeThread(thread
,&exitCode
)!=STILL_ACTIVE
,
571 "TerminateThread should not leave the thread 'STILL_ACTIVE'\n");
572 ok(exitCode
==99, "TerminateThread returned invalid exit code\n");
573 ok(CloseHandle(thread
)!=0,"Error Closing thread handle\n");
576 /* Check if CreateThread obeys the specified stack size. This code does
577 not work properly, and is currently disabled
579 static VOID
test_CreateThread_stack(void)
582 /* The only way I know of to test the stack size is to use alloca
583 and __try/__except. However, this is probably not portable,
584 and I couldn't get it to work under Wine anyhow. However, here
585 is the code which should allow for testing that CreateThread
586 respects the stack-size limit
589 DWORD threadId
,exitCode
;
592 sysInfo
.dwPageSize
=0;
593 GetSystemInfo(&sysInfo
);
594 ok(sysInfo
.dwPageSize
>0,"GetSystemInfo should return a valid page size\n");
595 thread
= CreateThread(NULL
,sysInfo
.dwPageSize
,
596 threadFunc5
,&exitCode
,
598 ok(WaitForSingleObject(thread
,5000)==WAIT_OBJECT_0
,
599 "TerminateThread didn't work\n");
600 ok(exitCode
==1,"CreateThread did not obey stack-size-limit\n");
601 ok(CloseHandle(thread
)!=0,"CloseHandle failed\n");
605 /* Check whether setting/retrieving thread priorities works */
606 static VOID
test_thread_priority(void)
608 HANDLE curthread
,access_thread
;
609 DWORD curthreadId
,exitCode
;
610 int min_priority
=-2,max_priority
=2;
614 curthread
=GetCurrentThread();
615 curthreadId
=GetCurrentThreadId();
616 /* Check thread priority */
617 /* NOTE: on Win2k/XP priority can be from -7 to 6. All other platforms it
618 is -2 to 2. However, even on a real Win2k system, using thread
619 priorities beyond the -2 to 2 range does not work. If you want to try
620 anyway, enable USE_EXTENDED_PRIORITIES
622 ok(GetThreadPriority(curthread
)==THREAD_PRIORITY_NORMAL
,
623 "GetThreadPriority Failed\n");
626 /* check that access control is obeyed */
627 access_thread
=pOpenThread(THREAD_ALL_ACCESS
&
628 (~THREAD_QUERY_INFORMATION
) & (~THREAD_SET_INFORMATION
),
630 ok(access_thread
!=NULL
,"OpenThread returned an invalid handle\n");
631 if (access_thread
!=NULL
) {
632 obey_ar(SetThreadPriority(access_thread
,1)==0);
633 obey_ar(GetThreadPriority(access_thread
)==THREAD_PRIORITY_ERROR_RETURN
);
634 obey_ar(GetExitCodeThread(access_thread
,&exitCode
)==0);
635 ok(CloseHandle(access_thread
),"Error Closing thread handle\n");
638 #if USE_EXTENDED_PRIORITIES
639 min_priority
=-7; max_priority
=6;
641 for(i
=min_priority
;i
<=max_priority
;i
++) {
642 ok(SetThreadPriority(curthread
,i
)!=0,
643 "SetThreadPriority Failed for priority: %d\n",i
);
644 ok(GetThreadPriority(curthread
)==i
,
645 "GetThreadPriority Failed for priority: %d\n",i
);
647 ok(SetThreadPriority(curthread
,THREAD_PRIORITY_TIME_CRITICAL
)!=0,
648 "SetThreadPriority Failed\n");
649 ok(GetThreadPriority(curthread
)==THREAD_PRIORITY_TIME_CRITICAL
,
650 "GetThreadPriority Failed\n");
651 ok(SetThreadPriority(curthread
,THREAD_PRIORITY_IDLE
)!=0,
652 "SetThreadPriority Failed\n");
653 ok(GetThreadPriority(curthread
)==THREAD_PRIORITY_IDLE
,
654 "GetThreadPriority Failed\n");
655 ok(SetThreadPriority(curthread
,0)!=0,"SetThreadPriority Failed\n");
657 /* Check that the thread priority is not changed if SetThreadPriority
658 is called with a value outside of the max/min range */
659 SetThreadPriority(curthread
,min_priority
);
660 SetLastError(0xdeadbeef);
661 rc
= SetThreadPriority(curthread
,min_priority
-1);
663 ok(rc
== FALSE
, "SetThreadPriority passed with a bad argument\n");
664 ok(GetLastError() == ERROR_INVALID_PARAMETER
||
665 GetLastError() == ERROR_INVALID_PRIORITY
/* Win9x */,
666 "SetThreadPriority error %d, expected ERROR_INVALID_PARAMETER or ERROR_INVALID_PRIORITY\n",
668 ok(GetThreadPriority(curthread
)==min_priority
,
669 "GetThreadPriority didn't return min_priority\n");
671 SetThreadPriority(curthread
,max_priority
);
672 SetLastError(0xdeadbeef);
673 rc
= SetThreadPriority(curthread
,max_priority
+1);
675 ok(rc
== FALSE
, "SetThreadPriority passed with a bad argument\n");
676 ok(GetLastError() == ERROR_INVALID_PARAMETER
||
677 GetLastError() == ERROR_INVALID_PRIORITY
/* Win9x */,
678 "SetThreadPriority error %d, expected ERROR_INVALID_PARAMETER or ERROR_INVALID_PRIORITY\n",
680 ok(GetThreadPriority(curthread
)==max_priority
,
681 "GetThreadPriority didn't return max_priority\n");
683 /* Check thread priority boost */
684 if (!pGetThreadPriorityBoost
|| !pSetThreadPriorityBoost
)
687 SetLastError(0xdeadbeef);
688 rc
=pGetThreadPriorityBoost(curthread
,&disabled
);
689 if (rc
==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED
)
693 ok(rc
!=0,"error=%d\n",GetLastError());
696 /* check that access control is obeyed */
697 access_thread
=pOpenThread(THREAD_ALL_ACCESS
&
698 (~THREAD_QUERY_INFORMATION
) & (~THREAD_SET_INFORMATION
),
700 ok(access_thread
!=NULL
,"OpenThread returned an invalid handle\n");
701 if (access_thread
!=NULL
) {
702 obey_ar(pSetThreadPriorityBoost(access_thread
,1)==0);
703 obey_ar(pGetThreadPriorityBoost(access_thread
,&disabled
)==0);
704 ok(CloseHandle(access_thread
),"Error Closing thread handle\n");
709 rc
= pSetThreadPriorityBoost(curthread
,1);
710 ok( rc
!= 0, "error=%d\n",GetLastError());
711 rc
=pGetThreadPriorityBoost(curthread
,&disabled
);
712 ok(rc
!=0 && disabled
==1,
713 "rc=%d error=%d disabled=%d\n",rc
,GetLastError(),disabled
);
715 rc
= pSetThreadPriorityBoost(curthread
,0);
716 ok( rc
!= 0, "error=%d\n",GetLastError());
717 rc
=pGetThreadPriorityBoost(curthread
,&disabled
);
718 ok(rc
!=0 && disabled
==0,
719 "rc=%d error=%d disabled=%d\n",rc
,GetLastError(),disabled
);
723 /* check the GetThreadTimes function */
724 static VOID
test_GetThreadTimes(void)
726 HANDLE thread
,access_thread
=NULL
;
727 FILETIME creationTime
,exitTime
,kernelTime
,userTime
;
731 thread
= CreateThread(NULL
,0,threadFunc2
,NULL
,
732 CREATE_SUSPENDED
,&threadId
);
734 ok(thread
!=NULL
,"Create Thread failed\n");
735 /* check that access control is obeyed */
737 access_thread
=pOpenThread(THREAD_ALL_ACCESS
&
738 (~THREAD_QUERY_INFORMATION
), 0,threadId
);
739 ok(access_thread
!=NULL
,
740 "OpenThread returned an invalid handle\n");
742 ok(ResumeThread(thread
)==1,"Resume thread returned an invalid value\n");
743 ok(WaitForSingleObject(thread
,5000)==WAIT_OBJECT_0
,
744 "ResumeThread didn't work\n");
745 creationTime
.dwLowDateTime
=99; creationTime
.dwHighDateTime
=99;
746 exitTime
.dwLowDateTime
=99; exitTime
.dwHighDateTime
=99;
747 kernelTime
.dwLowDateTime
=99; kernelTime
.dwHighDateTime
=99;
748 userTime
.dwLowDateTime
=99; userTime
.dwHighDateTime
=99;
749 /* GetThreadTimes should set all of the parameters passed to it */
750 error
=GetThreadTimes(thread
,&creationTime
,&exitTime
,
751 &kernelTime
,&userTime
);
752 if (error
!=0 || GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED
) {
753 ok(error
!=0,"GetThreadTimes failed\n");
754 ok(creationTime
.dwLowDateTime
!=99 || creationTime
.dwHighDateTime
!=99,
755 "creationTime was invalid\n");
756 ok(exitTime
.dwLowDateTime
!=99 || exitTime
.dwHighDateTime
!=99,
757 "exitTime was invalid\n");
758 ok(kernelTime
.dwLowDateTime
!=99 || kernelTime
.dwHighDateTime
!=99,
759 "kernelTimewas invalid\n");
760 ok(userTime
.dwLowDateTime
!=99 || userTime
.dwHighDateTime
!=99,
761 "userTime was invalid\n");
762 ok(CloseHandle(thread
)!=0,"CloseHandle failed\n");
763 if(access_thread
!=NULL
)
765 error
=GetThreadTimes(access_thread
,&creationTime
,&exitTime
,
766 &kernelTime
,&userTime
);
770 if(access_thread
!=NULL
) {
771 ok(CloseHandle(access_thread
)!=0,"CloseHandle Failed\n");
775 /* Check the processor affinity functions */
776 /* NOTE: These functions should also be checked that they obey access control
778 static VOID
test_thread_processor(void)
780 HANDLE curthread
,curproc
;
781 DWORD_PTR processMask
,systemMask
;
785 sysInfo
.dwNumberOfProcessors
=0;
786 GetSystemInfo(&sysInfo
);
787 ok(sysInfo
.dwNumberOfProcessors
>0,
788 "GetSystemInfo failed to return a valid # of processors\n");
789 /* Use the current Thread/process for all tests */
790 curthread
=GetCurrentThread();
791 ok(curthread
!=NULL
,"GetCurrentThread failed\n");
792 curproc
=GetCurrentProcess();
793 ok(curproc
!=NULL
,"GetCurrentProcess failed\n");
794 /* Check the Affinity Mask functions */
795 ok(GetProcessAffinityMask(curproc
,&processMask
,&systemMask
)!=0,
796 "GetProcessAffinityMask failed\n");
797 ok(SetThreadAffinityMask(curthread
,processMask
)==processMask
,
798 "SetThreadAffinityMask failed\n");
799 ok(SetThreadAffinityMask(curthread
,processMask
+1)==0,
800 "SetThreadAffinityMask passed for an illegal processor\n");
801 /* NOTE: This only works on WinNT/2000/XP) */
802 if (pSetThreadIdealProcessor
) {
805 error
=pSetThreadIdealProcessor(curthread
,0);
806 if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED
) {
807 ok(error
!=-1, "SetThreadIdealProcessor failed\n");
810 if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED
) {
811 error
=pSetThreadIdealProcessor(curthread
,MAXIMUM_PROCESSORS
+1);
813 "SetThreadIdealProcessor succeeded with an illegal processor #\n");
815 error
=pSetThreadIdealProcessor(curthread
,MAXIMUM_PROCESSORS
);
816 ok(error
==0, "SetThreadIdealProcessor returned an incorrect value\n");
822 static VOID
test_GetThreadExitCode(void)
824 DWORD exitCode
, threadid
;
828 ret
= GetExitCodeThread((HANDLE
)0x2bad2bad,&exitCode
);
829 ok(ret
==0, "GetExitCodeThread returned non zero value: %d\n", ret
);
830 GLE
= GetLastError();
831 ok(GLE
==ERROR_INVALID_HANDLE
, "GetLastError returned %d (expected 6)\n", GLE
);
833 thread
= CreateThread(NULL
,0,threadFunc2
,NULL
,0,&threadid
);
834 ret
= WaitForSingleObject(thread
,100);
835 ok(ret
==WAIT_OBJECT_0
, "threadFunc2 did not exit during 100 ms\n");
836 ret
= GetExitCodeThread(thread
,&exitCode
);
837 ok(ret
==exitCode
|| ret
==1,
838 "GetExitCodeThread returned %d (expected 1 or %d)\n", ret
, exitCode
);
839 ok(exitCode
==99, "threadFunc2 exited with code %d (expected 99)\n", exitCode
);
840 ok(CloseHandle(thread
)!=0,"Error closing thread handle\n");
845 static int test_value
= 0;
848 static void WINAPI
set_test_val( int val
)
853 static DWORD WINAPI
threadFunc6(LPVOID p
)
857 test_value
*= (int)p
;
861 static void test_SetThreadContext(void)
870 SetLastError(0xdeadbeef);
871 event
= CreateEvent( NULL
, TRUE
, FALSE
, NULL
);
872 thread
= CreateThread( NULL
, 0, threadFunc6
, (void *)2, 0, &threadid
);
873 ok( thread
!= NULL
, "CreateThread failed : (%d)\n", GetLastError() );
876 trace("Thread creation failed, skipping rest of test\n");
879 WaitForSingleObject( event
, INFINITE
);
880 SuspendThread( thread
);
881 CloseHandle( event
);
883 ctx
.ContextFlags
= CONTEXT_FULL
;
884 SetLastError(0xdeadbeef);
885 ret
= GetThreadContext( thread
, &ctx
);
886 ok( ret
, "GetThreadContext failed : (%u)\n", GetLastError() );
890 /* simulate a call to set_test_val(10) */
891 stack
= (int *)ctx
.Esp
;
894 ctx
.Esp
-= 2 * sizeof(int *);
895 ctx
.Eip
= (DWORD
)set_test_val
;
896 SetLastError(0xdeadbeef);
897 ok( SetThreadContext( thread
, &ctx
), "SetThreadContext failed : (%d)\n", GetLastError() );
900 SetLastError(0xdeadbeef);
901 prevcount
= ResumeThread( thread
);
902 ok ( prevcount
== 1, "Previous suspend count (%d) instead of 1, last error : (%d)\n",
903 prevcount
, GetLastError() );
905 WaitForSingleObject( thread
, INFINITE
);
906 ok( test_value
== 20, "test_value %d instead of 20\n", test_value
);
909 #endif /* __i386__ */
911 static HANDLE finish_event
;
912 static LONG times_executed
;
914 static DWORD CALLBACK
work_function(void *p
)
916 LONG executed
= InterlockedIncrement(×_executed
);
919 SetEvent(finish_event
);
923 static void test_QueueUserWorkItem(void)
929 /* QueueUserWorkItem not present on win9x */
930 if (!pQueueUserWorkItem
) return;
932 finish_event
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
934 before
= GetTickCount();
936 for (i
= 0; i
< 100; i
++)
938 BOOL ret
= pQueueUserWorkItem(work_function
, (void *)i
, WT_EXECUTEDEFAULT
);
939 ok(ret
, "QueueUserWorkItem failed with error %d\n", GetLastError());
942 wait_result
= WaitForSingleObject(finish_event
, 10000);
944 after
= GetTickCount();
945 trace("100 QueueUserWorkItem calls took %dms\n", after
- before
);
946 ok(wait_result
== WAIT_OBJECT_0
, "wait failed with error 0x%x\n", wait_result
);
948 ok(times_executed
== 100, "didn't execute all of the work items\n");
951 static void CALLBACK
signaled_function(PVOID p
, BOOLEAN TimerOrWaitFired
)
955 ok(!TimerOrWaitFired
, "wait shouldn't have timed out\n");
958 static void CALLBACK
timeout_function(PVOID p
, BOOLEAN TimerOrWaitFired
)
962 ok(TimerOrWaitFired
, "wait should have timed out\n");
965 static void test_RegisterWaitForSingleObject(void)
970 HANDLE complete_event
;
972 if (!pRegisterWaitForSingleObject
|| !pUnregisterWait
)
974 skip("RegisterWaitForSingleObject or UnregisterWait not implemented\n");
978 /* test signaled case */
980 handle
= CreateEvent(NULL
, TRUE
, TRUE
, NULL
);
981 complete_event
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
983 ret
= pRegisterWaitForSingleObject(&wait_handle
, handle
, signaled_function
, complete_event
, INFINITE
, WT_EXECUTEONLYONCE
);
984 ok(ret
, "RegisterWaitForSingleObject failed with error %d\n", GetLastError());
986 WaitForSingleObject(complete_event
, INFINITE
);
987 /* give worker thread chance to complete */
990 ret
= pUnregisterWait(wait_handle
);
991 ok(ret
, "UnregisterWait failed with error %d\n", GetLastError());
993 /* test cancel case */
997 ret
= pRegisterWaitForSingleObject(&wait_handle
, handle
, signaled_function
, complete_event
, INFINITE
, WT_EXECUTEONLYONCE
);
998 ok(ret
, "RegisterWaitForSingleObject failed with error %d\n", GetLastError());
1000 ret
= pUnregisterWait(wait_handle
);
1001 ok(ret
, "UnregisterWait failed with error %d\n", GetLastError());
1003 /* test timeout case */
1005 ret
= pRegisterWaitForSingleObject(&wait_handle
, handle
, timeout_function
, complete_event
, 0, WT_EXECUTEONLYONCE
);
1006 ok(ret
, "RegisterWaitForSingleObject failed with error %d\n", GetLastError());
1008 WaitForSingleObject(complete_event
, INFINITE
);
1009 /* give worker thread chance to complete */
1012 ret
= pUnregisterWait(wait_handle
);
1013 ok(ret
, "UnregisterWait failed with error %d\n", GetLastError());
1016 static DWORD TLS_main
;
1017 static DWORD TLS_index0
, TLS_index1
;
1019 static DWORD WINAPI
TLS_InheritanceProc(LPVOID p
)
1021 /* We should NOT inherit the TLS values from our parent or from the
1025 val
= TlsGetValue(TLS_main
);
1026 ok(val
== NULL
, "TLS inheritance failed\n");
1028 val
= TlsGetValue(TLS_index0
);
1029 ok(val
== NULL
, "TLS inheritance failed\n");
1031 val
= TlsGetValue(TLS_index1
);
1032 ok(val
== NULL
, "TLS inheritance failed\n");
1037 /* Basic TLS usage test. Make sure we can create slots and the values we
1038 store in them are separate among threads. Also test TLS value
1039 inheritance with TLS_InheritanceProc. */
1040 static DWORD WINAPI
TLS_ThreadProc(LPVOID p
)
1046 if (sync_threads_and_run_one(0, id
))
1048 TLS_index0
= TlsAlloc();
1049 ok(TLS_index0
!= TLS_OUT_OF_INDEXES
, "TlsAlloc failed\n");
1053 if (sync_threads_and_run_one(1, id
))
1055 TLS_index1
= TlsAlloc();
1056 ok(TLS_index1
!= TLS_OUT_OF_INDEXES
, "TlsAlloc failed\n");
1058 /* Slot indices should be different even if created in different
1060 ok(TLS_index0
!= TLS_index1
, "TlsAlloc failed\n");
1062 /* Both slots should be initialized to NULL */
1063 val
= TlsGetValue(TLS_index0
);
1064 ok(GetLastError() == ERROR_SUCCESS
, "TlsGetValue failed\n");
1065 ok(val
== NULL
, "TLS slot not initialized correctly\n");
1067 val
= TlsGetValue(TLS_index1
);
1068 ok(GetLastError() == ERROR_SUCCESS
, "TlsGetValue failed\n");
1069 ok(val
== NULL
, "TLS slot not initialized correctly\n");
1073 if (sync_threads_and_run_one(0, id
))
1075 val
= TlsGetValue(TLS_index0
);
1076 ok(GetLastError() == ERROR_SUCCESS
, "TlsGetValue failed\n");
1077 ok(val
== NULL
, "TLS slot not initialized correctly\n");
1079 val
= TlsGetValue(TLS_index1
);
1080 ok(GetLastError() == ERROR_SUCCESS
, "TlsGetValue failed\n");
1081 ok(val
== NULL
, "TLS slot not initialized correctly\n");
1083 ret
= TlsSetValue(TLS_index0
, (LPVOID
) 1);
1084 ok(ret
, "TlsSetValue failed\n");
1086 ret
= TlsSetValue(TLS_index1
, (LPVOID
) 2);
1087 ok(ret
, "TlsSetValue failed\n");
1089 val
= TlsGetValue(TLS_index0
);
1090 ok(GetLastError() == ERROR_SUCCESS
, "TlsGetValue failed\n");
1091 ok(val
== (LPVOID
) 1, "TLS slot not initialized correctly\n");
1093 val
= TlsGetValue(TLS_index1
);
1094 ok(GetLastError() == ERROR_SUCCESS
, "TlsGetValue failed\n");
1095 ok(val
== (LPVOID
) 2, "TLS slot not initialized correctly\n");
1099 if (sync_threads_and_run_one(1, id
))
1101 val
= TlsGetValue(TLS_index0
);
1102 ok(GetLastError() == ERROR_SUCCESS
, "TlsGetValue failed\n");
1103 ok(val
== NULL
, "TLS slot not initialized correctly\n");
1105 val
= TlsGetValue(TLS_index1
);
1106 ok(GetLastError() == ERROR_SUCCESS
, "TlsGetValue failed\n");
1107 ok(val
== NULL
, "TLS slot not initialized correctly\n");
1109 ret
= TlsSetValue(TLS_index0
, (LPVOID
) 3);
1110 ok(ret
, "TlsSetValue failed\n");
1112 ret
= TlsSetValue(TLS_index1
, (LPVOID
) 4);
1113 ok(ret
, "TlsSetValue failed\n");
1115 val
= TlsGetValue(TLS_index0
);
1116 ok(GetLastError() == ERROR_SUCCESS
, "TlsGetValue failed\n");
1117 ok(val
== (LPVOID
) 3, "TLS slot not initialized correctly\n");
1119 val
= TlsGetValue(TLS_index1
);
1120 ok(GetLastError() == ERROR_SUCCESS
, "TlsGetValue failed\n");
1121 ok(val
== (LPVOID
) 4, "TLS slot not initialized correctly\n");
1125 if (sync_threads_and_run_one(0, id
))
1130 val
= TlsGetValue(TLS_index0
);
1131 ok(GetLastError() == ERROR_SUCCESS
, "TlsGetValue failed\n");
1132 ok(val
== (LPVOID
) 1, "TLS slot not initialized correctly\n");
1134 val
= TlsGetValue(TLS_index1
);
1135 ok(GetLastError() == ERROR_SUCCESS
, "TlsGetValue failed\n");
1136 ok(val
== (LPVOID
) 2, "TLS slot not initialized correctly\n");
1138 thread
= CreateThread(NULL
, 0, TLS_InheritanceProc
, 0, 0, NULL
);
1139 ok(thread
!= NULL
, "CreateThread failed\n");
1140 waitret
= WaitForSingleObject(thread
, 60000);
1141 ok(waitret
== WAIT_OBJECT_0
, "WaitForSingleObject failed\n");
1142 CloseHandle(thread
);
1144 ret
= TlsFree(TLS_index0
);
1145 ok(ret
, "TlsFree failed\n");
1149 if (sync_threads_and_run_one(1, id
))
1151 ret
= TlsFree(TLS_index1
);
1152 ok(ret
, "TlsFree failed\n");
1159 static void test_TLS(void)
1166 init_thread_sync_helpers(2);
1168 /* Allocate a TLS slot in the main thread to test for inheritance. */
1169 TLS_main
= TlsAlloc();
1170 ok(TLS_main
!= TLS_OUT_OF_INDEXES
, "TlsAlloc failed\n");
1171 suc
= TlsSetValue(TLS_main
, (LPVOID
) 4114);
1172 ok(suc
, "TlsSetValue failed\n");
1174 for (i
= 0; i
< 2; ++i
)
1176 threads
[i
] = CreateThread(NULL
, 0, TLS_ThreadProc
, (LPVOID
) i
, 0, NULL
);
1177 ok(threads
[i
] != NULL
, "CreateThread failed\n");
1180 ret
= WaitForMultipleObjects(2, threads
, TRUE
, 60000);
1181 ok(ret
== WAIT_OBJECT_0
, "WaitForMultipleObjects failed\n");
1183 for (i
= 0; i
< 2; ++i
)
1184 CloseHandle(threads
[i
]);
1186 suc
= TlsFree(TLS_main
);
1187 ok(suc
, "TlsFree failed\n");
1188 cleanup_thread_sync_helpers();
1196 argc
= winetest_get_mainargs( &argv
);
1197 /* Neither Cygwin nor mingW export OpenThread, so do a dynamic check
1198 so that the compile passes
1200 lib
=GetModuleHandleA("kernel32.dll");
1201 ok(lib
!=NULL
,"Couldn't get a handle for kernel32.dll\n");
1202 pGetThreadPriorityBoost
=(GetThreadPriorityBoost_t
)GetProcAddress(lib
,"GetThreadPriorityBoost");
1203 pOpenThread
=(OpenThread_t
)GetProcAddress(lib
,"OpenThread");
1204 pQueueUserWorkItem
=(QueueUserWorkItem_t
)GetProcAddress(lib
,"QueueUserWorkItem");
1205 pSetThreadIdealProcessor
=(SetThreadIdealProcessor_t
)GetProcAddress(lib
,"SetThreadIdealProcessor");
1206 pSetThreadPriorityBoost
=(SetThreadPriorityBoost_t
)GetProcAddress(lib
,"SetThreadPriorityBoost");
1207 pRegisterWaitForSingleObject
=(RegisterWaitForSingleObject_t
)GetProcAddress(lib
,"RegisterWaitForSingleObject");
1208 pUnregisterWait
=(UnregisterWait_t
)GetProcAddress(lib
,"UnregisterWait");
1212 if (!strcmp(argv
[2], "sleep"))
1214 HANDLE hAddrEvents
[2];
1215 create_function_addr_events(hAddrEvents
);
1216 SetEvent(hAddrEvents
[0]);
1217 SetEvent(hAddrEvents
[1]);
1218 Sleep(5000); /* spawned process runs for at most 5 seconds */
1224 hThread
= CreateThread(NULL
, 0, threadFunc2
, NULL
, 0, NULL
);
1225 ok(hThread
!= NULL
, "CreateThread failed, error %u\n",
1227 ok(WaitForSingleObject(hThread
, 200) == WAIT_OBJECT_0
,
1228 "Thread did not exit in time\n");
1229 if (hThread
== NULL
) break;
1230 CloseHandle(hThread
);
1235 test_CreateRemoteThread();
1236 test_CreateThread_basic();
1237 test_CreateThread_suspended();
1238 test_SuspendThread();
1239 test_TerminateThread();
1240 test_CreateThread_stack();
1241 test_thread_priority();
1242 test_GetThreadTimes();
1243 test_thread_processor();
1244 test_GetThreadExitCode();
1246 test_SetThreadContext();
1248 test_QueueUserWorkItem();
1249 test_RegisterWaitForSingleObject();