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
25 #include "wine/test.h"
31 /* Specify the number of simultaneous threads to test */
33 /* Specify whether to test the extended priorities for Win2k/XP */
34 #define USE_EXTENDED_PRIORITIES 0
35 /* Specify whether to test the stack allocation in CreateThread */
38 /* Set CHECK_STACK to 1 if you want to try to test the stack-limit from
39 CreateThread. So far I have been unable to make this work, and
40 I am in doubt as to how portable it is. Also, according to MSDN,
41 you shouldn't mix C-run-time-libraries (i.e. alloca) with CreateThread.
42 Anyhow, the check is currently commented out
47 # define __EXCEPT __except
50 # include "wine/exception.h"
54 typedef BOOL (WINAPI
*GetThreadPriorityBoost_t
)(HANDLE
,PBOOL
);
55 static GetThreadPriorityBoost_t pGetThreadPriorityBoost
=NULL
;
57 typedef HANDLE (WINAPI
*OpenThread_t
)(DWORD
,BOOL
,DWORD
);
58 static OpenThread_t pOpenThread
=NULL
;
60 typedef BOOL (WINAPI
*QueueUserWorkItem_t
)(LPTHREAD_START_ROUTINE
,PVOID
,ULONG
);
61 static QueueUserWorkItem_t pQueueUserWorkItem
=NULL
;
63 typedef DWORD (WINAPI
*SetThreadIdealProcessor_t
)(HANDLE
,DWORD
);
64 static SetThreadIdealProcessor_t pSetThreadIdealProcessor
=NULL
;
66 typedef BOOL (WINAPI
*SetThreadPriorityBoost_t
)(HANDLE
,BOOL
);
67 static SetThreadPriorityBoost_t pSetThreadPriorityBoost
=NULL
;
69 typedef BOOL (WINAPI
*RegisterWaitForSingleObject_t
)(PHANDLE
,HANDLE
,WAITORTIMERCALLBACK
,PVOID
,ULONG
,ULONG
);
70 static RegisterWaitForSingleObject_t pRegisterWaitForSingleObject
=NULL
;
72 typedef BOOL (WINAPI
*UnregisterWait_t
)(HANDLE
);
73 static UnregisterWait_t pUnregisterWait
=NULL
;
75 static HANDLE
create_target_process(const char *arg
)
78 char cmdline
[MAX_PATH
];
79 PROCESS_INFORMATION pi
;
80 STARTUPINFO si
= { 0 };
83 winetest_get_mainargs( &argv
);
84 sprintf(cmdline
, "%s %s %s", argv
[0], argv
[1], arg
);
85 ok(CreateProcess(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
,
86 &si
, &pi
) != 0, "error: %u\n", GetLastError());
87 ok(CloseHandle(pi
.hThread
) != 0, "error %u\n", GetLastError());
91 /* Functions not tested yet:
96 In addition there are no checks that the inheritance works properly in
100 /* Functions to ensure that from a group of threads, only one executes
101 certain chunks of code at a time, and we know which one is executing
102 it. It basically makes multithreaded execution linear, which defeats
103 the purpose of multiple threads, but makes testing easy. */
104 static HANDLE start_event
, stop_event
;
105 static LONG num_synced
;
107 static void init_thread_sync_helpers(void)
109 start_event
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
110 ok(start_event
!= NULL
, "CreateEvent failed\n");
111 stop_event
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
112 ok(stop_event
!= NULL
, "CreateEvent failed\n");
116 static BOOL
sync_threads_and_run_one(DWORD sync_id
, DWORD my_id
)
118 LONG num
= InterlockedIncrement(&num_synced
);
119 assert(-1 <= num
&& num
<= 1);
122 ResetEvent( stop_event
);
123 SetEvent( start_event
);
127 DWORD ret
= WaitForSingleObject(start_event
, 10000);
128 ok(ret
== WAIT_OBJECT_0
, "WaitForSingleObject failed %x\n",ret
);
130 return sync_id
== my_id
;
133 static void resync_after_run(void)
135 LONG num
= InterlockedDecrement(&num_synced
);
136 assert(-1 <= num
&& num
<= 1);
139 ResetEvent( start_event
);
140 SetEvent( stop_event
);
144 DWORD ret
= WaitForSingleObject(stop_event
, 10000);
145 ok(ret
== WAIT_OBJECT_0
, "WaitForSingleObject failed\n");
149 static void cleanup_thread_sync_helpers(void)
151 CloseHandle(start_event
);
152 CloseHandle(stop_event
);
163 /* WinME supports OpenThread but doesn't know about access restrictions so
164 we require them to be either completely ignored or always obeyed.
166 INT obeying_ars
= 0; /* -1 == no, 0 == dunno yet, 1 == yes */
170 ? (obeying_ars = +1) \
171 : ((obeying_ars = -1), \
172 trace("not restricted, assuming consistent behaviour\n"))) \
173 : (obeying_ars < 0) \
174 ? ok(!(x), "access restrictions obeyed\n") \
175 : ok( (x), "access restrictions not obeyed\n"))
177 /* Basic test that simultaneous threads can access shared memory,
178 that the thread local storage routines work correctly, and that
179 threads actually run concurrently
181 static DWORD WINAPI
threadFunc1(LPVOID p
)
183 t1Struct
*tstruct
= (t1Struct
*)p
;
185 /* write our thread # into shared memory */
186 tstruct
->threadmem
[tstruct
->threadnum
]=GetCurrentThreadId();
187 ok(TlsSetValue(tlsIndex
,(LPVOID
)(tstruct
->threadnum
+1))!=0,
188 "TlsSetValue failed\n");
189 /* The threads synchronize before terminating. This is done by
190 Signaling an event, and waiting for all events to occur
192 SetEvent(tstruct
->event
[tstruct
->threadnum
]);
193 WaitForMultipleObjects(NUM_THREADS
,tstruct
->event
,TRUE
,INFINITE
);
194 /* Double check that all threads really did run by validating that
195 they have all written to the shared memory. There should be no race
196 here, since all threads were synchronized after the write.*/
197 for(i
=0;i
<NUM_THREADS
;i
++) {
198 while(tstruct
->threadmem
[i
]==0) ;
201 /* lstrlenA contains an exception handler so this makes sure exceptions work in threads */
202 ok( lstrlenA( (char *)0xdeadbeef ) == 0, "lstrlenA: unexpected success\n" );
204 /* Check that no one changed our tls memory */
205 ok((int)TlsGetValue(tlsIndex
)-1==tstruct
->threadnum
,
206 "TlsGetValue failed\n");
207 return NUM_THREADS
+tstruct
->threadnum
;
210 static DWORD WINAPI
threadFunc2(LPVOID p
)
215 static DWORD WINAPI
threadFunc3(LPVOID p
)
218 thread
=GetCurrentThread();
219 SuspendThread(thread
);
223 static DWORD WINAPI
threadFunc4(LPVOID p
)
225 HANDLE event
= (HANDLE
)p
;
234 static DWORD WINAPI
threadFunc5(LPVOID p
)
236 DWORD
*exitCode
= (DWORD
*)p
;
238 sysInfo
.dwPageSize
=0;
239 GetSystemInfo(&sysInfo
);
243 alloca(2*sysInfo
.dwPageSize
);
253 static DWORD WINAPI
threadFunc_SetEvent(LPVOID p
)
255 SetEvent((HANDLE
) p
);
259 static DWORD WINAPI
threadFunc_CloseHandle(LPVOID p
)
261 CloseHandle((HANDLE
) p
);
265 static void create_function_addr_events(HANDLE events
[2])
269 sprintf(buffer
, "threadFunc_SetEvent %p", threadFunc_SetEvent
);
270 events
[0] = CreateEvent(NULL
, FALSE
, FALSE
, buffer
);
272 sprintf(buffer
, "threadFunc_CloseHandle %p", threadFunc_CloseHandle
);
273 events
[1] = CreateEvent(NULL
, FALSE
, FALSE
, buffer
);
276 /* check CreateRemoteThread */
277 static VOID
test_CreateRemoteThread(void)
279 HANDLE hProcess
, hThread
, hEvent
, hRemoteEvent
;
280 DWORD tid
, ret
, exitcode
;
281 HANDLE hAddrEvents
[2];
283 hProcess
= create_target_process("sleep");
284 ok(hProcess
!= NULL
, "Can't start process\n");
286 /* ensure threadFunc_SetEvent & threadFunc_CloseHandle are the same
287 * address as in the child process */
288 create_function_addr_events(hAddrEvents
);
289 ret
= WaitForMultipleObjects(2, hAddrEvents
, TRUE
, 5000);
290 if (ret
== WAIT_TIMEOUT
)
292 skip("child process wasn't mapped at same address, so can't do CreateRemoteThread tests.\n");
296 hEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
297 ok(hEvent
!= NULL
, "Can't create event, err=%u\n", GetLastError());
298 ret
= DuplicateHandle(GetCurrentProcess(), hEvent
, hProcess
, &hRemoteEvent
,
299 0, FALSE
, DUPLICATE_SAME_ACCESS
);
300 ok(ret
!= 0, "DuplicateHandle failed, err=%u\n", GetLastError());
302 /* create suspended remote thread with entry point SetEvent() */
303 SetLastError(0xdeadbeef);
304 hThread
= CreateRemoteThread(hProcess
, NULL
, 0, threadFunc_SetEvent
,
305 hRemoteEvent
, CREATE_SUSPENDED
, &tid
);
306 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
308 skip("CreateRemoteThread is not implemented\n");
311 ok(hThread
!= NULL
, "CreateRemoteThread failed, err=%u\n", GetLastError());
312 ok(tid
!= 0, "null tid\n");
313 ret
= SuspendThread(hThread
);
314 ok(ret
== 1, "ret=%u, err=%u\n", ret
, GetLastError());
315 ret
= ResumeThread(hThread
);
316 ok(ret
== 2, "ret=%u, err=%u\n", ret
, GetLastError());
318 /* thread still suspended, so wait times out */
319 ret
= WaitForSingleObject(hEvent
, 100);
320 ok(ret
== WAIT_TIMEOUT
, "wait did not time out, ret=%u\n", ret
);
322 ret
= ResumeThread(hThread
);
323 ok(ret
== 1, "ret=%u, err=%u\n", ret
, GetLastError());
325 /* wait that doesn't time out */
326 ret
= WaitForSingleObject(hEvent
, 100);
327 ok(ret
== WAIT_OBJECT_0
, "object not signaled, ret=%u\n", ret
);
329 /* wait for thread end */
330 ret
= WaitForSingleObject(hThread
, 100);
331 ok(ret
== WAIT_OBJECT_0
, "waiting for thread failed, ret=%u\n", ret
);
332 CloseHandle(hThread
);
334 /* create and wait for remote thread with entry point CloseHandle() */
335 hThread
= CreateRemoteThread(hProcess
, NULL
, 0,
336 threadFunc_CloseHandle
,
337 hRemoteEvent
, 0, &tid
);
338 ok(hThread
!= NULL
, "CreateRemoteThread failed, err=%u\n", GetLastError());
339 ret
= WaitForSingleObject(hThread
, 100);
340 ok(ret
== WAIT_OBJECT_0
, "waiting for thread failed, ret=%u\n", ret
);
341 CloseHandle(hThread
);
343 /* create remote thread with entry point SetEvent() */
344 hThread
= CreateRemoteThread(hProcess
, NULL
, 0,
346 hRemoteEvent
, 0, &tid
);
347 ok(hThread
!= NULL
, "CreateRemoteThread failed, err=%u\n", GetLastError());
349 /* closed handle, so wait times out */
350 ret
= WaitForSingleObject(hEvent
, 100);
351 ok(ret
== WAIT_TIMEOUT
, "wait did not time out, ret=%u\n", ret
);
353 /* check that remote SetEvent() failed */
354 ret
= GetExitCodeThread(hThread
, &exitcode
);
355 ok(ret
!= 0, "GetExitCodeThread failed, err=%u\n", GetLastError());
356 if (ret
) ok(exitcode
== 0, "SetEvent succeeded, expected to fail\n");
357 CloseHandle(hThread
);
360 TerminateProcess(hProcess
, 0);
362 CloseHandle(hProcess
);
365 /* Check basic functionality of CreateThread and Tls* functions */
366 static VOID
test_CreateThread_basic(void)
368 HANDLE thread
[NUM_THREADS
],event
[NUM_THREADS
];
369 DWORD threadid
[NUM_THREADS
],curthreadId
;
370 DWORD threadmem
[NUM_THREADS
];
372 t1Struct tstruct
[NUM_THREADS
];
378 /* lstrlenA contains an exception handler so this makes sure exceptions work in the main thread */
379 ok( lstrlenA( (char *)0xdeadbeef ) == 0, "lstrlenA: unexpected success\n" );
381 /* Retrieve current Thread ID for later comparisons */
382 curthreadId
=GetCurrentThreadId();
383 /* Allocate some local storage */
384 ok((tlsIndex
=TlsAlloc())!=TLS_OUT_OF_INDEXES
,"TlsAlloc failed\n");
385 /* Create events for thread synchronization */
386 for(i
=0;i
<NUM_THREADS
;i
++) {
388 /* Note that it doesn't matter what type of event we choose here. This
389 test isn't trying to thoroughly test events
391 event
[i
]=CreateEventA(NULL
,TRUE
,FALSE
,NULL
);
392 tstruct
[i
].threadnum
=i
;
393 tstruct
[i
].threadmem
=threadmem
;
394 tstruct
[i
].event
=event
;
397 /* Test that passing arguments to threads works okay */
398 for(i
=0;i
<NUM_THREADS
;i
++) {
399 thread
[i
] = CreateThread(NULL
,0,threadFunc1
,
400 &tstruct
[i
],0,&threadid
[i
]);
401 ok(thread
[i
]!=NULL
,"Create Thread failed\n");
403 /* Test that the threads actually complete */
404 for(i
=0;i
<NUM_THREADS
;i
++) {
405 error
=WaitForSingleObject(thread
[i
],5000);
406 ok(error
==WAIT_OBJECT_0
, "Thread did not complete within timelimit\n");
407 if(error
!=WAIT_OBJECT_0
) {
408 TerminateThread(thread
[i
],i
+NUM_THREADS
);
410 ok(GetExitCodeThread(thread
[i
],&exitCode
),"Could not retrieve ext code\n");
411 ok(exitCode
==i
+NUM_THREADS
,"Thread returned an incorrect exit code\n");
413 /* Test that each thread executed in its parent's address space
414 (it was able to change threadmem and pass that change back to its parent)
415 and that each thread id was independent). Note that we prove that the
416 threads actually execute concurrently by having them block on each other
419 for(i
=0;i
<NUM_THREADS
;i
++) {
421 for(j
=i
+1;j
<NUM_THREADS
;j
++) {
422 if (threadmem
[i
]==threadmem
[j
]) {
426 ok(!error
&& threadmem
[i
]==threadid
[i
] && threadmem
[i
]!=curthreadId
,
427 "Thread did not execute successfully\n");
428 ok(CloseHandle(thread
[i
])!=0,"CloseHandle failed\n");
430 ok(TlsFree(tlsIndex
)!=0,"TlsFree failed\n");
432 /* Test how passing NULL as a pointer to threadid works */
433 SetLastError(0xFACEaBAD);
434 thread
[0] = CreateThread(NULL
,0,threadFunc2
,NULL
,0,&tid
);
435 GLE
= GetLastError();
436 if (thread
[0]) { /* NT */
437 ok(GLE
==0xFACEaBAD, "CreateThread set last error to %d, expected 4207848365\n", GLE
);
438 ret
= WaitForSingleObject(thread
[0],100);
439 ok(ret
==WAIT_OBJECT_0
, "threadFunc2 did not exit during 100 ms\n");
440 ret
= GetExitCodeThread(thread
[0],&exitCode
);
441 ok(ret
!=0, "GetExitCodeThread returned %d (expected nonzero)\n", ret
);
442 ok(exitCode
==99, "threadFunc2 exited with code: %d (expected 99)\n", exitCode
);
443 ok(CloseHandle(thread
[0])!=0,"Error closing thread handle\n");
446 ok(GLE
==ERROR_INVALID_PARAMETER
, "CreateThread set last error to %d, expected 87\n", GLE
);
450 /* Check that using the CREATE_SUSPENDED flag works */
451 static VOID
test_CreateThread_suspended(void)
458 thread
= CreateThread(NULL
,0,threadFunc2
,NULL
,
459 CREATE_SUSPENDED
,&threadId
);
460 ok(thread
!=NULL
,"Create Thread failed\n");
461 /* Check that the thread is suspended */
462 ok(SuspendThread(thread
)==1,"Thread did not start suspended\n");
463 ok(ResumeThread(thread
)==2,"Resume thread returned an invalid value\n");
464 /* Check that resume thread didn't actually start the thread. I can't think
465 of a better way of checking this than just waiting. I am not sure if this
466 will work on slow computers.
468 ok(WaitForSingleObject(thread
,1000)==WAIT_TIMEOUT
,
469 "ResumeThread should not have actually started the thread\n");
470 /* Now actually resume the thread and make sure that it actually completes*/
471 ok(ResumeThread(thread
)==1,"Resume thread returned an invalid value\n");
472 ok((error
=WaitForSingleObject(thread
,1000))==WAIT_OBJECT_0
,
473 "Thread did not resume\n");
474 if(error
!=WAIT_OBJECT_0
) {
475 TerminateThread(thread
,1);
478 suspend_count
= SuspendThread(thread
);
479 ok(suspend_count
== -1, "SuspendThread returned %d, expected -1\n", suspend_count
);
481 suspend_count
= ResumeThread(thread
);
482 ok(suspend_count
== 0 ||
483 broken(suspend_count
== -1), /* win9x */
484 "ResumeThread returned %d, expected 0\n", suspend_count
);
486 ok(CloseHandle(thread
)!=0,"CloseHandle failed\n");
489 /* Check that SuspendThread and ResumeThread work */
490 static VOID
test_SuspendThread(void)
492 HANDLE thread
,access_thread
;
493 DWORD threadId
,exitCode
,error
;
496 thread
= CreateThread(NULL
,0,threadFunc3
,NULL
,
498 ok(thread
!=NULL
,"Create Thread failed\n");
499 /* Check that the thread is suspended */
500 /* Note that this is a polling method, and there is a race between
501 SuspendThread being called (in the child, and the loop below timing out,
502 so the test could fail on a heavily loaded or slow computer.
505 for(i
=0;error
==0 && i
<100;i
++) {
506 error
=SuspendThread(thread
);
507 ResumeThread(thread
);
513 ok(error
==1,"SuspendThread did not work\n");
514 /* check that access restrictions are obeyed */
516 access_thread
=pOpenThread(THREAD_ALL_ACCESS
& (~THREAD_SUSPEND_RESUME
),
518 ok(access_thread
!=NULL
,"OpenThread returned an invalid handle\n");
519 if (access_thread
!=NULL
) {
520 obey_ar(SuspendThread(access_thread
)==~0U);
521 obey_ar(ResumeThread(access_thread
)==~0U);
522 ok(CloseHandle(access_thread
)!=0,"CloseHandle Failed\n");
525 /* Double check that the thread really is suspended */
526 ok((error
=GetExitCodeThread(thread
,&exitCode
))!=0 && exitCode
==STILL_ACTIVE
,
527 "Thread did not really suspend\n");
528 /* Resume the thread, and make sure it actually completes */
529 ok(ResumeThread(thread
)==1,"Resume thread returned an invalid value\n");
530 ok((error
=WaitForSingleObject(thread
,1000))==WAIT_OBJECT_0
,
531 "Thread did not resume\n");
532 if(error
!=WAIT_OBJECT_0
) {
533 TerminateThread(thread
,1);
535 /* Trying to suspend a terminated thread should fail */
536 error
=SuspendThread(thread
);
537 ok(error
==~0U, "wrong return code: %d\n", error
);
538 ok(GetLastError()==ERROR_ACCESS_DENIED
|| GetLastError()==ERROR_NO_MORE_ITEMS
, "unexpected error code: %d\n", GetLastError());
540 ok(CloseHandle(thread
)!=0,"CloseHandle Failed\n");
543 /* Check that TerminateThread works properly
545 static VOID
test_TerminateThread(void)
547 HANDLE thread
,access_thread
,event
;
548 DWORD threadId
,exitCode
;
549 event
=CreateEventA(NULL
,TRUE
,FALSE
,NULL
);
550 thread
= CreateThread(NULL
,0,threadFunc4
,
551 (LPVOID
)event
, 0,&threadId
);
552 ok(thread
!=NULL
,"Create Thread failed\n");
553 /* TerminateThread has a race condition in Wine. If the thread is terminated
554 before it starts, it leaves a process behind. Therefore, we wait for the
555 thread to signal that it has started. There is no easy way to force the
556 race to occur, so we don't try to find it.
558 ok(WaitForSingleObject(event
,5000)==WAIT_OBJECT_0
,
559 "TerminateThread didn't work\n");
560 /* check that access restrictions are obeyed */
562 access_thread
=pOpenThread(THREAD_ALL_ACCESS
& (~THREAD_TERMINATE
),
564 ok(access_thread
!=NULL
,"OpenThread returned an invalid handle\n");
565 if (access_thread
!=NULL
) {
566 obey_ar(TerminateThread(access_thread
,99)==0);
567 ok(CloseHandle(access_thread
)!=0,"CloseHandle Failed\n");
570 /* terminate a job and make sure it terminates */
571 ok(TerminateThread(thread
,99)!=0,"TerminateThread failed\n");
572 ok(WaitForSingleObject(thread
,5000)==WAIT_OBJECT_0
,
573 "TerminateThread didn't work\n");
574 ok(GetExitCodeThread(thread
,&exitCode
)!=STILL_ACTIVE
,
575 "TerminateThread should not leave the thread 'STILL_ACTIVE'\n");
576 ok(exitCode
==99, "TerminateThread returned invalid exit code\n");
577 ok(CloseHandle(thread
)!=0,"Error Closing thread handle\n");
580 /* Check if CreateThread obeys the specified stack size. This code does
581 not work properly, and is currently disabled
583 static VOID
test_CreateThread_stack(void)
586 /* The only way I know of to test the stack size is to use alloca
587 and __try/__except. However, this is probably not portable,
588 and I couldn't get it to work under Wine anyhow. However, here
589 is the code which should allow for testing that CreateThread
590 respects the stack-size limit
593 DWORD threadId
,exitCode
;
596 sysInfo
.dwPageSize
=0;
597 GetSystemInfo(&sysInfo
);
598 ok(sysInfo
.dwPageSize
>0,"GetSystemInfo should return a valid page size\n");
599 thread
= CreateThread(NULL
,sysInfo
.dwPageSize
,
600 threadFunc5
,&exitCode
,
602 ok(WaitForSingleObject(thread
,5000)==WAIT_OBJECT_0
,
603 "TerminateThread didn't work\n");
604 ok(exitCode
==1,"CreateThread did not obey stack-size-limit\n");
605 ok(CloseHandle(thread
)!=0,"CloseHandle failed\n");
609 /* Check whether setting/retrieving thread priorities works */
610 static VOID
test_thread_priority(void)
612 HANDLE curthread
,access_thread
;
613 DWORD curthreadId
,exitCode
;
614 int min_priority
=-2,max_priority
=2;
618 curthread
=GetCurrentThread();
619 curthreadId
=GetCurrentThreadId();
620 /* Check thread priority */
621 /* NOTE: on Win2k/XP priority can be from -7 to 6. All other platforms it
622 is -2 to 2. However, even on a real Win2k system, using thread
623 priorities beyond the -2 to 2 range does not work. If you want to try
624 anyway, enable USE_EXTENDED_PRIORITIES
626 ok(GetThreadPriority(curthread
)==THREAD_PRIORITY_NORMAL
,
627 "GetThreadPriority Failed\n");
630 /* check that access control is obeyed */
631 access_thread
=pOpenThread(THREAD_ALL_ACCESS
&
632 (~THREAD_QUERY_INFORMATION
) & (~THREAD_SET_INFORMATION
),
634 ok(access_thread
!=NULL
,"OpenThread returned an invalid handle\n");
635 if (access_thread
!=NULL
) {
636 obey_ar(SetThreadPriority(access_thread
,1)==0);
637 obey_ar(GetThreadPriority(access_thread
)==THREAD_PRIORITY_ERROR_RETURN
);
638 obey_ar(GetExitCodeThread(access_thread
,&exitCode
)==0);
639 ok(CloseHandle(access_thread
),"Error Closing thread handle\n");
642 #if USE_EXTENDED_PRIORITIES
643 min_priority
=-7; max_priority
=6;
645 for(i
=min_priority
;i
<=max_priority
;i
++) {
646 ok(SetThreadPriority(curthread
,i
)!=0,
647 "SetThreadPriority Failed for priority: %d\n",i
);
648 ok(GetThreadPriority(curthread
)==i
,
649 "GetThreadPriority Failed for priority: %d\n",i
);
651 ok(SetThreadPriority(curthread
,THREAD_PRIORITY_TIME_CRITICAL
)!=0,
652 "SetThreadPriority Failed\n");
653 ok(GetThreadPriority(curthread
)==THREAD_PRIORITY_TIME_CRITICAL
,
654 "GetThreadPriority Failed\n");
655 ok(SetThreadPriority(curthread
,THREAD_PRIORITY_IDLE
)!=0,
656 "SetThreadPriority Failed\n");
657 ok(GetThreadPriority(curthread
)==THREAD_PRIORITY_IDLE
,
658 "GetThreadPriority Failed\n");
659 ok(SetThreadPriority(curthread
,0)!=0,"SetThreadPriority Failed\n");
661 /* Check that the thread priority is not changed if SetThreadPriority
662 is called with a value outside of the max/min range */
663 SetThreadPriority(curthread
,min_priority
);
664 SetLastError(0xdeadbeef);
665 rc
= SetThreadPriority(curthread
,min_priority
-1);
667 ok(rc
== FALSE
, "SetThreadPriority passed with a bad argument\n");
668 ok(GetLastError() == ERROR_INVALID_PARAMETER
||
669 GetLastError() == ERROR_INVALID_PRIORITY
/* Win9x */,
670 "SetThreadPriority error %d, expected ERROR_INVALID_PARAMETER or ERROR_INVALID_PRIORITY\n",
672 ok(GetThreadPriority(curthread
)==min_priority
,
673 "GetThreadPriority didn't return min_priority\n");
675 SetThreadPriority(curthread
,max_priority
);
676 SetLastError(0xdeadbeef);
677 rc
= SetThreadPriority(curthread
,max_priority
+1);
679 ok(rc
== FALSE
, "SetThreadPriority passed with a bad argument\n");
680 ok(GetLastError() == ERROR_INVALID_PARAMETER
||
681 GetLastError() == ERROR_INVALID_PRIORITY
/* Win9x */,
682 "SetThreadPriority error %d, expected ERROR_INVALID_PARAMETER or ERROR_INVALID_PRIORITY\n",
684 ok(GetThreadPriority(curthread
)==max_priority
,
685 "GetThreadPriority didn't return max_priority\n");
687 /* Check thread priority boost */
688 if (!pGetThreadPriorityBoost
|| !pSetThreadPriorityBoost
)
691 SetLastError(0xdeadbeef);
692 rc
=pGetThreadPriorityBoost(curthread
,&disabled
);
693 if (rc
==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED
)
697 ok(rc
!=0,"error=%d\n",GetLastError());
700 /* check that access control is obeyed */
701 access_thread
=pOpenThread(THREAD_ALL_ACCESS
&
702 (~THREAD_QUERY_INFORMATION
) & (~THREAD_SET_INFORMATION
),
704 ok(access_thread
!=NULL
,"OpenThread returned an invalid handle\n");
705 if (access_thread
!=NULL
) {
706 obey_ar(pSetThreadPriorityBoost(access_thread
,1)==0);
707 obey_ar(pGetThreadPriorityBoost(access_thread
,&disabled
)==0);
708 ok(CloseHandle(access_thread
),"Error Closing thread handle\n");
713 rc
= pSetThreadPriorityBoost(curthread
,1);
714 ok( rc
!= 0, "error=%d\n",GetLastError());
715 rc
=pGetThreadPriorityBoost(curthread
,&disabled
);
716 ok(rc
!=0 && disabled
==1,
717 "rc=%d error=%d disabled=%d\n",rc
,GetLastError(),disabled
);
719 rc
= pSetThreadPriorityBoost(curthread
,0);
720 ok( rc
!= 0, "error=%d\n",GetLastError());
721 rc
=pGetThreadPriorityBoost(curthread
,&disabled
);
722 ok(rc
!=0 && disabled
==0,
723 "rc=%d error=%d disabled=%d\n",rc
,GetLastError(),disabled
);
727 /* check the GetThreadTimes function */
728 static VOID
test_GetThreadTimes(void)
730 HANDLE thread
,access_thread
=NULL
;
731 FILETIME creationTime
,exitTime
,kernelTime
,userTime
;
735 thread
= CreateThread(NULL
,0,threadFunc2
,NULL
,
736 CREATE_SUSPENDED
,&threadId
);
738 ok(thread
!=NULL
,"Create Thread failed\n");
739 /* check that access control is obeyed */
741 access_thread
=pOpenThread(THREAD_ALL_ACCESS
&
742 (~THREAD_QUERY_INFORMATION
), 0,threadId
);
743 ok(access_thread
!=NULL
,
744 "OpenThread returned an invalid handle\n");
746 ok(ResumeThread(thread
)==1,"Resume thread returned an invalid value\n");
747 ok(WaitForSingleObject(thread
,5000)==WAIT_OBJECT_0
,
748 "ResumeThread didn't work\n");
749 creationTime
.dwLowDateTime
=99; creationTime
.dwHighDateTime
=99;
750 exitTime
.dwLowDateTime
=99; exitTime
.dwHighDateTime
=99;
751 kernelTime
.dwLowDateTime
=99; kernelTime
.dwHighDateTime
=99;
752 userTime
.dwLowDateTime
=99; userTime
.dwHighDateTime
=99;
753 /* GetThreadTimes should set all of the parameters passed to it */
754 error
=GetThreadTimes(thread
,&creationTime
,&exitTime
,
755 &kernelTime
,&userTime
);
756 if (error
!=0 || GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED
) {
757 ok(error
!=0,"GetThreadTimes failed\n");
758 ok(creationTime
.dwLowDateTime
!=99 || creationTime
.dwHighDateTime
!=99,
759 "creationTime was invalid\n");
760 ok(exitTime
.dwLowDateTime
!=99 || exitTime
.dwHighDateTime
!=99,
761 "exitTime was invalid\n");
762 ok(kernelTime
.dwLowDateTime
!=99 || kernelTime
.dwHighDateTime
!=99,
763 "kernelTimewas invalid\n");
764 ok(userTime
.dwLowDateTime
!=99 || userTime
.dwHighDateTime
!=99,
765 "userTime was invalid\n");
766 ok(CloseHandle(thread
)!=0,"CloseHandle failed\n");
767 if(access_thread
!=NULL
)
769 error
=GetThreadTimes(access_thread
,&creationTime
,&exitTime
,
770 &kernelTime
,&userTime
);
774 if(access_thread
!=NULL
) {
775 ok(CloseHandle(access_thread
)!=0,"CloseHandle Failed\n");
779 /* Check the processor affinity functions */
780 /* NOTE: These functions should also be checked that they obey access control
782 static VOID
test_thread_processor(void)
784 HANDLE curthread
,curproc
;
785 DWORD_PTR processMask
,systemMask
;
789 sysInfo
.dwNumberOfProcessors
=0;
790 GetSystemInfo(&sysInfo
);
791 ok(sysInfo
.dwNumberOfProcessors
>0,
792 "GetSystemInfo failed to return a valid # of processors\n");
793 /* Use the current Thread/process for all tests */
794 curthread
=GetCurrentThread();
795 ok(curthread
!=NULL
,"GetCurrentThread failed\n");
796 curproc
=GetCurrentProcess();
797 ok(curproc
!=NULL
,"GetCurrentProcess failed\n");
798 /* Check the Affinity Mask functions */
799 ok(GetProcessAffinityMask(curproc
,&processMask
,&systemMask
)!=0,
800 "GetProcessAffinityMask failed\n");
801 ok(SetThreadAffinityMask(curthread
,processMask
)==processMask
,
802 "SetThreadAffinityMask failed\n");
803 ok(SetThreadAffinityMask(curthread
,processMask
+1)==0,
804 "SetThreadAffinityMask passed for an illegal processor\n");
805 /* NOTE: This only works on WinNT/2000/XP) */
806 if (pSetThreadIdealProcessor
) {
809 error
=pSetThreadIdealProcessor(curthread
,0);
810 if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED
) {
811 ok(error
!=-1, "SetThreadIdealProcessor failed\n");
814 if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED
) {
815 error
=pSetThreadIdealProcessor(curthread
,MAXIMUM_PROCESSORS
+1);
817 "SetThreadIdealProcessor succeeded with an illegal processor #\n");
819 error
=pSetThreadIdealProcessor(curthread
,MAXIMUM_PROCESSORS
);
820 ok(error
==0, "SetThreadIdealProcessor returned an incorrect value\n");
826 static VOID
test_GetThreadExitCode(void)
828 DWORD exitCode
, threadid
;
832 ret
= GetExitCodeThread((HANDLE
)0x2bad2bad,&exitCode
);
833 ok(ret
==0, "GetExitCodeThread returned non zero value: %d\n", ret
);
834 GLE
= GetLastError();
835 ok(GLE
==ERROR_INVALID_HANDLE
, "GetLastError returned %d (expected 6)\n", GLE
);
837 thread
= CreateThread(NULL
,0,threadFunc2
,NULL
,0,&threadid
);
838 ret
= WaitForSingleObject(thread
,100);
839 ok(ret
==WAIT_OBJECT_0
, "threadFunc2 did not exit during 100 ms\n");
840 ret
= GetExitCodeThread(thread
,&exitCode
);
841 ok(ret
==exitCode
|| ret
==1,
842 "GetExitCodeThread returned %d (expected 1 or %d)\n", ret
, exitCode
);
843 ok(exitCode
==99, "threadFunc2 exited with code %d (expected 99)\n", exitCode
);
844 ok(CloseHandle(thread
)!=0,"Error closing thread handle\n");
849 static int test_value
= 0;
852 static void WINAPI
set_test_val( int val
)
857 static DWORD WINAPI
threadFunc6(LPVOID p
)
861 test_value
*= (int)p
;
865 static void test_SetThreadContext(void)
874 SetLastError(0xdeadbeef);
875 event
= CreateEvent( NULL
, TRUE
, FALSE
, NULL
);
876 thread
= CreateThread( NULL
, 0, threadFunc6
, (void *)2, 0, &threadid
);
877 ok( thread
!= NULL
, "CreateThread failed : (%d)\n", GetLastError() );
880 trace("Thread creation failed, skipping rest of test\n");
883 WaitForSingleObject( event
, INFINITE
);
884 SuspendThread( thread
);
885 CloseHandle( event
);
887 ctx
.ContextFlags
= CONTEXT_FULL
;
888 SetLastError(0xdeadbeef);
889 ret
= GetThreadContext( thread
, &ctx
);
890 ok( ret
, "GetThreadContext failed : (%u)\n", GetLastError() );
894 /* simulate a call to set_test_val(10) */
895 stack
= (int *)ctx
.Esp
;
898 ctx
.Esp
-= 2 * sizeof(int *);
899 ctx
.Eip
= (DWORD
)set_test_val
;
900 SetLastError(0xdeadbeef);
901 ok( SetThreadContext( thread
, &ctx
), "SetThreadContext failed : (%d)\n", GetLastError() );
904 SetLastError(0xdeadbeef);
905 prevcount
= ResumeThread( thread
);
906 ok ( prevcount
== 1, "Previous suspend count (%d) instead of 1, last error : (%d)\n",
907 prevcount
, GetLastError() );
909 WaitForSingleObject( thread
, INFINITE
);
910 ok( test_value
== 20, "test_value %d instead of 20\n", test_value
);
913 #endif /* __i386__ */
915 static HANDLE finish_event
;
916 static LONG times_executed
;
918 static DWORD CALLBACK
work_function(void *p
)
920 LONG executed
= InterlockedIncrement(×_executed
);
923 SetEvent(finish_event
);
927 static void test_QueueUserWorkItem(void)
933 /* QueueUserWorkItem not present on win9x */
934 if (!pQueueUserWorkItem
) return;
936 finish_event
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
938 before
= GetTickCount();
940 for (i
= 0; i
< 100; i
++)
942 BOOL ret
= pQueueUserWorkItem(work_function
, (void *)i
, WT_EXECUTEDEFAULT
);
943 ok(ret
, "QueueUserWorkItem failed with error %d\n", GetLastError());
946 wait_result
= WaitForSingleObject(finish_event
, 10000);
948 after
= GetTickCount();
949 trace("100 QueueUserWorkItem calls took %dms\n", after
- before
);
950 ok(wait_result
== WAIT_OBJECT_0
, "wait failed with error 0x%x\n", wait_result
);
952 ok(times_executed
== 100, "didn't execute all of the work items\n");
955 static void CALLBACK
signaled_function(PVOID p
, BOOLEAN TimerOrWaitFired
)
959 ok(!TimerOrWaitFired
, "wait shouldn't have timed out\n");
962 static void CALLBACK
timeout_function(PVOID p
, BOOLEAN TimerOrWaitFired
)
966 ok(TimerOrWaitFired
, "wait should have timed out\n");
969 static void test_RegisterWaitForSingleObject(void)
974 HANDLE complete_event
;
976 if (!pRegisterWaitForSingleObject
|| !pUnregisterWait
)
978 skip("RegisterWaitForSingleObject or UnregisterWait not implemented\n");
982 skip("ROS-HACK: Skipping RegisterWaitForSingleObject tests\n");
985 /* test signaled case */
987 handle
= CreateEvent(NULL
, TRUE
, TRUE
, NULL
);
988 complete_event
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
990 ret
= pRegisterWaitForSingleObject(&wait_handle
, handle
, signaled_function
, complete_event
, INFINITE
, WT_EXECUTEONLYONCE
);
991 ok(ret
, "RegisterWaitForSingleObject failed with error %d\n", GetLastError());
993 WaitForSingleObject(complete_event
, INFINITE
);
994 /* give worker thread chance to complete */
997 ret
= pUnregisterWait(wait_handle
);
998 ok(ret
, "UnregisterWait failed with error %d\n", GetLastError());
1000 /* test cancel case */
1004 ret
= pRegisterWaitForSingleObject(&wait_handle
, handle
, signaled_function
, complete_event
, INFINITE
, WT_EXECUTEONLYONCE
);
1005 ok(ret
, "RegisterWaitForSingleObject failed with error %d\n", GetLastError());
1007 ret
= pUnregisterWait(wait_handle
);
1008 ok(ret
, "UnregisterWait failed with error %d\n", GetLastError());
1010 /* test timeout case */
1012 ret
= pRegisterWaitForSingleObject(&wait_handle
, handle
, timeout_function
, complete_event
, 0, WT_EXECUTEONLYONCE
);
1013 ok(ret
, "RegisterWaitForSingleObject failed with error %d\n", GetLastError());
1015 WaitForSingleObject(complete_event
, INFINITE
);
1016 /* give worker thread chance to complete */
1019 ret
= pUnregisterWait(wait_handle
);
1020 ok(ret
, "UnregisterWait failed with error %d\n", GetLastError());
1023 static DWORD TLS_main
;
1024 static DWORD TLS_index0
, TLS_index1
;
1026 static DWORD WINAPI
TLS_InheritanceProc(LPVOID p
)
1028 /* We should NOT inherit the TLS values from our parent or from the
1032 val
= TlsGetValue(TLS_main
);
1033 ok(val
== NULL
, "TLS inheritance failed\n");
1035 val
= TlsGetValue(TLS_index0
);
1036 ok(val
== NULL
, "TLS inheritance failed\n");
1038 val
= TlsGetValue(TLS_index1
);
1039 ok(val
== NULL
, "TLS inheritance failed\n");
1044 /* Basic TLS usage test. Make sure we can create slots and the values we
1045 store in them are separate among threads. Also test TLS value
1046 inheritance with TLS_InheritanceProc. */
1047 static DWORD WINAPI
TLS_ThreadProc(LPVOID p
)
1053 if (sync_threads_and_run_one(0, id
))
1055 TLS_index0
= TlsAlloc();
1056 ok(TLS_index0
!= TLS_OUT_OF_INDEXES
, "TlsAlloc failed\n");
1060 if (sync_threads_and_run_one(1, id
))
1062 TLS_index1
= TlsAlloc();
1063 ok(TLS_index1
!= TLS_OUT_OF_INDEXES
, "TlsAlloc failed\n");
1065 /* Slot indices should be different even if created in different
1067 ok(TLS_index0
!= TLS_index1
, "TlsAlloc failed\n");
1069 /* Both slots should be initialized to NULL */
1070 val
= TlsGetValue(TLS_index0
);
1071 ok(GetLastError() == ERROR_SUCCESS
, "TlsGetValue failed\n");
1072 ok(val
== NULL
, "TLS slot not initialized correctly\n");
1074 val
= TlsGetValue(TLS_index1
);
1075 ok(GetLastError() == ERROR_SUCCESS
, "TlsGetValue failed\n");
1076 ok(val
== NULL
, "TLS slot not initialized correctly\n");
1080 if (sync_threads_and_run_one(0, id
))
1082 val
= TlsGetValue(TLS_index0
);
1083 ok(GetLastError() == ERROR_SUCCESS
, "TlsGetValue failed\n");
1084 ok(val
== NULL
, "TLS slot not initialized correctly\n");
1086 val
= TlsGetValue(TLS_index1
);
1087 ok(GetLastError() == ERROR_SUCCESS
, "TlsGetValue failed\n");
1088 ok(val
== NULL
, "TLS slot not initialized correctly\n");
1090 ret
= TlsSetValue(TLS_index0
, (LPVOID
) 1);
1091 ok(ret
, "TlsSetValue failed\n");
1093 ret
= TlsSetValue(TLS_index1
, (LPVOID
) 2);
1094 ok(ret
, "TlsSetValue failed\n");
1096 val
= TlsGetValue(TLS_index0
);
1097 ok(GetLastError() == ERROR_SUCCESS
, "TlsGetValue failed\n");
1098 ok(val
== (LPVOID
) 1, "TLS slot not initialized correctly\n");
1100 val
= TlsGetValue(TLS_index1
);
1101 ok(GetLastError() == ERROR_SUCCESS
, "TlsGetValue failed\n");
1102 ok(val
== (LPVOID
) 2, "TLS slot not initialized correctly\n");
1106 if (sync_threads_and_run_one(1, id
))
1108 val
= TlsGetValue(TLS_index0
);
1109 ok(GetLastError() == ERROR_SUCCESS
, "TlsGetValue failed\n");
1110 ok(val
== NULL
, "TLS slot not initialized correctly\n");
1112 val
= TlsGetValue(TLS_index1
);
1113 ok(GetLastError() == ERROR_SUCCESS
, "TlsGetValue failed\n");
1114 ok(val
== NULL
, "TLS slot not initialized correctly\n");
1116 ret
= TlsSetValue(TLS_index0
, (LPVOID
) 3);
1117 ok(ret
, "TlsSetValue failed\n");
1119 ret
= TlsSetValue(TLS_index1
, (LPVOID
) 4);
1120 ok(ret
, "TlsSetValue failed\n");
1122 val
= TlsGetValue(TLS_index0
);
1123 ok(GetLastError() == ERROR_SUCCESS
, "TlsGetValue failed\n");
1124 ok(val
== (LPVOID
) 3, "TLS slot not initialized correctly\n");
1126 val
= TlsGetValue(TLS_index1
);
1127 ok(GetLastError() == ERROR_SUCCESS
, "TlsGetValue failed\n");
1128 ok(val
== (LPVOID
) 4, "TLS slot not initialized correctly\n");
1132 if (sync_threads_and_run_one(0, id
))
1137 val
= TlsGetValue(TLS_index0
);
1138 ok(GetLastError() == ERROR_SUCCESS
, "TlsGetValue failed\n");
1139 ok(val
== (LPVOID
) 1, "TLS slot not initialized correctly\n");
1141 val
= TlsGetValue(TLS_index1
);
1142 ok(GetLastError() == ERROR_SUCCESS
, "TlsGetValue failed\n");
1143 ok(val
== (LPVOID
) 2, "TLS slot not initialized correctly\n");
1145 thread
= CreateThread(NULL
, 0, TLS_InheritanceProc
, 0, 0, &tid
);
1146 ok(thread
!= NULL
, "CreateThread failed\n");
1147 waitret
= WaitForSingleObject(thread
, 60000);
1148 ok(waitret
== WAIT_OBJECT_0
, "WaitForSingleObject failed\n");
1149 CloseHandle(thread
);
1151 ret
= TlsFree(TLS_index0
);
1152 ok(ret
, "TlsFree failed\n");
1156 if (sync_threads_and_run_one(1, id
))
1158 ret
= TlsFree(TLS_index1
);
1159 ok(ret
, "TlsFree failed\n");
1166 static void test_TLS(void)
1173 init_thread_sync_helpers();
1175 /* Allocate a TLS slot in the main thread to test for inheritance. */
1176 TLS_main
= TlsAlloc();
1177 ok(TLS_main
!= TLS_OUT_OF_INDEXES
, "TlsAlloc failed\n");
1178 suc
= TlsSetValue(TLS_main
, (LPVOID
) 4114);
1179 ok(suc
, "TlsSetValue failed\n");
1181 for (i
= 0; i
< 2; ++i
)
1185 threads
[i
] = CreateThread(NULL
, 0, TLS_ThreadProc
, (LPVOID
) i
, 0, &tid
);
1186 ok(threads
[i
] != NULL
, "CreateThread failed\n");
1189 ret
= WaitForMultipleObjects(2, threads
, TRUE
, 60000);
1190 ok(ret
== WAIT_OBJECT_0
|| ret
== WAIT_OBJECT_0
+1 /* nt4 */, "WaitForMultipleObjects failed %u\n",ret
);
1192 for (i
= 0; i
< 2; ++i
)
1193 CloseHandle(threads
[i
]);
1195 suc
= TlsFree(TLS_main
);
1196 ok(suc
, "TlsFree failed\n");
1197 cleanup_thread_sync_helpers();
1205 argc
= winetest_get_mainargs( &argv
);
1206 /* Neither Cygwin nor mingW export OpenThread, so do a dynamic check
1207 so that the compile passes
1209 lib
=GetModuleHandleA("kernel32.dll");
1210 ok(lib
!=NULL
,"Couldn't get a handle for kernel32.dll\n");
1211 pGetThreadPriorityBoost
=(GetThreadPriorityBoost_t
)GetProcAddress(lib
,"GetThreadPriorityBoost");
1212 pOpenThread
=(OpenThread_t
)GetProcAddress(lib
,"OpenThread");
1213 pQueueUserWorkItem
=(QueueUserWorkItem_t
)GetProcAddress(lib
,"QueueUserWorkItem");
1214 pSetThreadIdealProcessor
=(SetThreadIdealProcessor_t
)GetProcAddress(lib
,"SetThreadIdealProcessor");
1215 pSetThreadPriorityBoost
=(SetThreadPriorityBoost_t
)GetProcAddress(lib
,"SetThreadPriorityBoost");
1216 pRegisterWaitForSingleObject
=(RegisterWaitForSingleObject_t
)GetProcAddress(lib
,"RegisterWaitForSingleObject");
1217 pUnregisterWait
=(UnregisterWait_t
)GetProcAddress(lib
,"UnregisterWait");
1221 if (!strcmp(argv
[2], "sleep"))
1223 HANDLE hAddrEvents
[2];
1224 create_function_addr_events(hAddrEvents
);
1225 SetEvent(hAddrEvents
[0]);
1226 SetEvent(hAddrEvents
[1]);
1227 Sleep(5000); /* spawned process runs for at most 5 seconds */
1234 hThread
= CreateThread(NULL
, 0, threadFunc2
, NULL
, 0, &tid
);
1235 ok(hThread
!= NULL
, "CreateThread failed, error %u\n",
1237 ok(WaitForSingleObject(hThread
, 200) == WAIT_OBJECT_0
,
1238 "Thread did not exit in time\n");
1239 if (hThread
== NULL
) break;
1240 CloseHandle(hThread
);
1245 test_CreateRemoteThread();
1246 test_CreateThread_basic();
1247 test_CreateThread_suspended();
1248 test_SuspendThread();
1249 test_TerminateThread();
1250 test_CreateThread_stack();
1251 test_thread_priority();
1252 test_GetThreadTimes();
1253 test_thread_processor();
1254 test_GetThreadExitCode();
1256 test_SetThreadContext();
1258 test_QueueUserWorkItem();
1259 test_RegisterWaitForSingleObject();