push a2e7360632735b5a2be8f61a9725e4e6969c5533
[wine/hacks.git] / dlls / kernel32 / tests / thread.c
blob649c49c09d0a52b871b1f079981602f8ead81c83
1 /*
2 * Unit test suite for directory functions.
4 * Copyright 2002 Geoffrey Hausheer
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 /* Define _WIN32_WINNT to get SetThreadIdealProcessor on Windows */
22 #define _WIN32_WINNT 0x0500
24 #include <assert.h>
25 #include <stdarg.h>
26 #include <stdio.h>
28 #include "wine/test.h"
29 #include <windef.h>
30 #include <winbase.h>
31 #include <winnt.h>
32 #include <winerror.h>
34 /* Specify the number of simultaneous threads to test */
35 #define NUM_THREADS 4
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 */
39 #define CHECK_STACK 0
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
47 #if CHECK_STACK
48 # ifdef __try
49 # define __TRY __try
50 # define __EXCEPT __except
51 # define __ENDTRY
52 # else
53 # include "wine/exception.h"
54 # endif
55 #endif
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)
80 char **argv;
81 char cmdline[MAX_PATH];
82 PROCESS_INFORMATION pi;
83 STARTUPINFO si = { 0 };
84 si.cb = sizeof(si);
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());
91 return pi.hProcess;
94 /* Functions not tested yet:
95 AttachThreadInput
96 SetThreadContext
97 SwitchToThread
99 In addition there are no checks that the inheritance works properly in
100 CreateThread
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_syncing_threads, num_synced;
110 static void init_thread_sync_helpers(LONG num_threads)
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");
116 num_syncing_threads = num_threads;
117 num_synced = 0;
120 static BOOL sync_threads_and_run_one(DWORD sync_id, DWORD my_id)
122 LONG num = InterlockedIncrement(&num_synced);
123 assert(0 < num && num <= num_syncing_threads);
124 if (num == num_syncing_threads)
126 ResetEvent( stop_event );
127 SetEvent( start_event );
129 else
131 DWORD ret = WaitForSingleObject(start_event, 10000);
132 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
134 return sync_id == my_id;
137 static void resync_after_run(void)
139 LONG num = InterlockedDecrement(&num_synced);
140 assert(0 <= num && num < num_syncing_threads);
141 if (num == 0)
143 ResetEvent( start_event );
144 SetEvent( stop_event );
146 else
148 DWORD ret = WaitForSingleObject(stop_event, 10000);
149 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
153 static void cleanup_thread_sync_helpers(void)
155 CloseHandle(start_event);
156 CloseHandle(stop_event);
159 DWORD tlsIndex;
161 typedef struct {
162 int threadnum;
163 HANDLE *event;
164 DWORD *threadmem;
165 } t1Struct;
167 /* WinME supports OpenThread but doesn't know about access restrictions so
168 we require them to be either completely ignored or always obeyed.
170 INT obeying_ars = 0; /* -1 == no, 0 == dunno yet, 1 == yes */
171 #define obey_ar(x) \
172 (obeying_ars == 0 \
173 ? ((x) \
174 ? (obeying_ars = +1) \
175 : ((obeying_ars = -1), \
176 trace("not restricted, assuming consistent behaviour\n"))) \
177 : (obeying_ars < 0) \
178 ? ok(!(x), "access restrictions obeyed\n") \
179 : ok( (x), "access restrictions not obeyed\n"))
181 /* Basic test that simultaneous threads can access shared memory,
182 that the thread local storage routines work correctly, and that
183 threads actually run concurrently
185 static DWORD WINAPI threadFunc1(LPVOID p)
187 t1Struct *tstruct = (t1Struct *)p;
188 int i;
189 /* write our thread # into shared memory */
190 tstruct->threadmem[tstruct->threadnum]=GetCurrentThreadId();
191 ok(TlsSetValue(tlsIndex,(LPVOID)(tstruct->threadnum+1))!=0,
192 "TlsSetValue failed\n");
193 /* The threads synchronize before terminating. This is done by
194 Signaling an event, and waiting for all events to occur
196 SetEvent(tstruct->event[tstruct->threadnum]);
197 WaitForMultipleObjects(NUM_THREADS,tstruct->event,TRUE,INFINITE);
198 /* Double check that all threads really did run by validating that
199 they have all written to the shared memory. There should be no race
200 here, since all threads were synchronized after the write.*/
201 for(i=0;i<NUM_THREADS;i++) {
202 while(tstruct->threadmem[i]==0) ;
205 /* lstrlenA contains an exception handler so this makes sure exceptions work in threads */
206 ok( lstrlenA( (char *)0xdeadbeef ) == 0, "lstrlenA: unexpected success\n" );
208 /* Check that no one changed our tls memory */
209 ok((int)TlsGetValue(tlsIndex)-1==tstruct->threadnum,
210 "TlsGetValue failed\n");
211 return NUM_THREADS+tstruct->threadnum;
214 static DWORD WINAPI threadFunc2(LPVOID p)
216 return 99;
219 static DWORD WINAPI threadFunc3(LPVOID p)
221 HANDLE thread;
222 thread=GetCurrentThread();
223 SuspendThread(thread);
224 return 99;
227 static DWORD WINAPI threadFunc4(LPVOID p)
229 HANDLE event = (HANDLE)p;
230 if(event != NULL) {
231 SetEvent(event);
233 Sleep(99000);
234 return 0;
237 #if CHECK_STACK
238 static DWORD WINAPI threadFunc5(LPVOID p)
240 DWORD *exitCode = (DWORD *)p;
241 SYSTEM_INFO sysInfo;
242 sysInfo.dwPageSize=0;
243 GetSystemInfo(&sysInfo);
244 *exitCode=0;
245 __TRY
247 alloca(2*sysInfo.dwPageSize);
249 __EXCEPT(1) {
250 *exitCode=1;
252 __ENDTRY
253 return 0;
255 #endif
257 static DWORD WINAPI threadFunc_SetEvent(LPVOID p)
259 SetEvent((HANDLE) p);
260 return 0;
263 static DWORD WINAPI threadFunc_CloseHandle(LPVOID p)
265 CloseHandle((HANDLE) p);
266 return 0;
269 static void create_function_addr_events(HANDLE events[2])
271 char buffer[256];
273 sprintf(buffer, "threadFunc_SetEvent %p", threadFunc_SetEvent);
274 events[0] = CreateEvent(NULL, FALSE, FALSE, buffer);
276 sprintf(buffer, "threadFunc_CloseHandle %p", threadFunc_CloseHandle);
277 events[1] = CreateEvent(NULL, FALSE, FALSE, buffer);
280 /* check CreateRemoteThread */
281 static VOID test_CreateRemoteThread(void)
283 HANDLE hProcess, hThread, hEvent, hRemoteEvent;
284 DWORD tid, ret, exitcode;
285 HANDLE hAddrEvents[2];
287 hProcess = create_target_process("sleep");
288 ok(hProcess != NULL, "Can't start process\n");
290 /* ensure threadFunc_SetEvent & threadFunc_CloseHandle are the same
291 * address as in the child process */
292 create_function_addr_events(hAddrEvents);
293 ret = WaitForMultipleObjects(2, hAddrEvents, TRUE, 5000);
294 if (ret == WAIT_TIMEOUT)
296 skip("child process wasn't mapped at same address, so can't do CreateRemoteThread tests.\n");
297 return;
300 hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
301 ok(hEvent != NULL, "Can't create event, err=%u\n", GetLastError());
302 ret = DuplicateHandle(GetCurrentProcess(), hEvent, hProcess, &hRemoteEvent,
303 0, FALSE, DUPLICATE_SAME_ACCESS);
304 ok(ret != 0, "DuplicateHandle failed, err=%u\n", GetLastError());
306 /* create suspended remote thread with entry point SetEvent() */
307 SetLastError(0xdeadbeef);
308 hThread = CreateRemoteThread(hProcess, NULL, 0, threadFunc_SetEvent,
309 hRemoteEvent, CREATE_SUSPENDED, &tid);
310 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
312 skip("CreateRemoteThread is not implemented\n");
313 goto cleanup;
315 ok(hThread != NULL, "CreateRemoteThread failed, err=%u\n", GetLastError());
316 ok(tid != 0, "null tid\n");
317 ret = SuspendThread(hThread);
318 ok(ret == 1, "ret=%u, err=%u\n", ret, GetLastError());
319 ret = ResumeThread(hThread);
320 ok(ret == 2, "ret=%u, err=%u\n", ret, GetLastError());
322 /* thread still suspended, so wait times out */
323 ret = WaitForSingleObject(hEvent, 100);
324 ok(ret == WAIT_TIMEOUT, "wait did not time out, ret=%u\n", ret);
326 ret = ResumeThread(hThread);
327 ok(ret == 1, "ret=%u, err=%u\n", ret, GetLastError());
329 /* wait that doesn't time out */
330 ret = WaitForSingleObject(hEvent, 100);
331 ok(ret == WAIT_OBJECT_0, "object not signaled, ret=%u\n", ret);
333 /* wait for thread end */
334 ret = WaitForSingleObject(hThread, 100);
335 ok(ret == WAIT_OBJECT_0, "waiting for thread failed, ret=%u\n", ret);
336 CloseHandle(hThread);
338 /* create and wait for remote thread with entry point CloseHandle() */
339 hThread = CreateRemoteThread(hProcess, NULL, 0,
340 threadFunc_CloseHandle,
341 hRemoteEvent, 0, &tid);
342 ok(hThread != NULL, "CreateRemoteThread failed, err=%u\n", GetLastError());
343 ret = WaitForSingleObject(hThread, 100);
344 ok(ret == WAIT_OBJECT_0, "waiting for thread failed, ret=%u\n", ret);
345 CloseHandle(hThread);
347 /* create remote thread with entry point SetEvent() */
348 hThread = CreateRemoteThread(hProcess, NULL, 0,
349 threadFunc_SetEvent,
350 hRemoteEvent, 0, &tid);
351 ok(hThread != NULL, "CreateRemoteThread failed, err=%u\n", GetLastError());
353 /* closed handle, so wait times out */
354 ret = WaitForSingleObject(hEvent, 100);
355 ok(ret == WAIT_TIMEOUT, "wait did not time out, ret=%u\n", ret);
357 /* check that remote SetEvent() failed */
358 ret = GetExitCodeThread(hThread, &exitcode);
359 ok(ret != 0, "GetExitCodeThread failed, err=%u\n", GetLastError());
360 if (ret) ok(exitcode == 0, "SetEvent succeeded, expected to fail\n");
361 CloseHandle(hThread);
363 cleanup:
364 TerminateProcess(hProcess, 0);
365 CloseHandle(hEvent);
366 CloseHandle(hProcess);
369 /* Check basic functionality of CreateThread and Tls* functions */
370 static VOID test_CreateThread_basic(void)
372 HANDLE thread[NUM_THREADS],event[NUM_THREADS];
373 DWORD threadid[NUM_THREADS],curthreadId;
374 DWORD threadmem[NUM_THREADS];
375 DWORD exitCode;
376 t1Struct tstruct[NUM_THREADS];
377 int error;
378 DWORD i,j;
379 DWORD GLE, ret;
380 DWORD tid;
382 /* lstrlenA contains an exception handler so this makes sure exceptions work in the main thread */
383 ok( lstrlenA( (char *)0xdeadbeef ) == 0, "lstrlenA: unexpected success\n" );
385 /* Retrieve current Thread ID for later comparisons */
386 curthreadId=GetCurrentThreadId();
387 /* Allocate some local storage */
388 ok((tlsIndex=TlsAlloc())!=TLS_OUT_OF_INDEXES,"TlsAlloc failed\n");
389 /* Create events for thread synchronization */
390 for(i=0;i<NUM_THREADS;i++) {
391 threadmem[i]=0;
392 /* Note that it doesn't matter what type of event we choose here. This
393 test isn't trying to thoroughly test events
395 event[i]=CreateEventA(NULL,TRUE,FALSE,NULL);
396 tstruct[i].threadnum=i;
397 tstruct[i].threadmem=threadmem;
398 tstruct[i].event=event;
401 /* Test that passing arguments to threads works okay */
402 for(i=0;i<NUM_THREADS;i++) {
403 thread[i] = CreateThread(NULL,0,threadFunc1,
404 &tstruct[i],0,&threadid[i]);
405 ok(thread[i]!=NULL,"Create Thread failed\n");
407 /* Test that the threads actually complete */
408 for(i=0;i<NUM_THREADS;i++) {
409 error=WaitForSingleObject(thread[i],5000);
410 ok(error==WAIT_OBJECT_0, "Thread did not complete within timelimit\n");
411 if(error!=WAIT_OBJECT_0) {
412 TerminateThread(thread[i],i+NUM_THREADS);
414 ok(GetExitCodeThread(thread[i],&exitCode),"Could not retrieve ext code\n");
415 ok(exitCode==i+NUM_THREADS,"Thread returned an incorrect exit code\n");
417 /* Test that each thread executed in its parent's address space
418 (it was able to change threadmem and pass that change back to its parent)
419 and that each thread id was independent). Note that we prove that the
420 threads actually execute concurrently by having them block on each other
421 in threadFunc1
423 for(i=0;i<NUM_THREADS;i++) {
424 error=0;
425 for(j=i+1;j<NUM_THREADS;j++) {
426 if (threadmem[i]==threadmem[j]) {
427 error=1;
430 ok(!error && threadmem[i]==threadid[i] && threadmem[i]!=curthreadId,
431 "Thread did not execute successfully\n");
432 ok(CloseHandle(thread[i])!=0,"CloseHandle failed\n");
434 ok(TlsFree(tlsIndex)!=0,"TlsFree failed\n");
436 /* Test how passing NULL as a pointer to threadid works */
437 SetLastError(0xFACEaBAD);
438 thread[0] = CreateThread(NULL,0,threadFunc2,NULL,0,&tid);
439 GLE = GetLastError();
440 if (thread[0]) { /* NT */
441 ok(GLE==0xFACEaBAD, "CreateThread set last error to %d, expected 4207848365\n", GLE);
442 ret = WaitForSingleObject(thread[0],100);
443 ok(ret==WAIT_OBJECT_0, "threadFunc2 did not exit during 100 ms\n");
444 ret = GetExitCodeThread(thread[0],&exitCode);
445 ok(ret!=0, "GetExitCodeThread returned %d (expected nonzero)\n", ret);
446 ok(exitCode==99, "threadFunc2 exited with code: %d (expected 99)\n", exitCode);
447 ok(CloseHandle(thread[0])!=0,"Error closing thread handle\n");
449 else { /* 9x */
450 ok(GLE==ERROR_INVALID_PARAMETER, "CreateThread set last error to %d, expected 87\n", GLE);
454 /* Check that using the CREATE_SUSPENDED flag works */
455 static VOID test_CreateThread_suspended(void)
457 HANDLE thread;
458 DWORD threadId;
459 DWORD suspend_count;
460 int error;
462 thread = CreateThread(NULL,0,threadFunc2,NULL,
463 CREATE_SUSPENDED,&threadId);
464 ok(thread!=NULL,"Create Thread failed\n");
465 /* Check that the thread is suspended */
466 ok(SuspendThread(thread)==1,"Thread did not start suspended\n");
467 ok(ResumeThread(thread)==2,"Resume thread returned an invalid value\n");
468 /* Check that resume thread didn't actually start the thread. I can't think
469 of a better way of checking this than just waiting. I am not sure if this
470 will work on slow computers.
472 ok(WaitForSingleObject(thread,1000)==WAIT_TIMEOUT,
473 "ResumeThread should not have actually started the thread\n");
474 /* Now actually resume the thread and make sure that it actually completes*/
475 ok(ResumeThread(thread)==1,"Resume thread returned an invalid value\n");
476 ok((error=WaitForSingleObject(thread,1000))==WAIT_OBJECT_0,
477 "Thread did not resume\n");
478 if(error!=WAIT_OBJECT_0) {
479 TerminateThread(thread,1);
482 suspend_count = SuspendThread(thread);
483 ok(suspend_count == -1, "SuspendThread returned %d, expected -1\n", suspend_count);
485 suspend_count = ResumeThread(thread);
486 ok(suspend_count == 0 ||
487 broken(suspend_count == -1), /* win9x */
488 "ResumeThread returned %d, expected 0\n", suspend_count);
490 ok(CloseHandle(thread)!=0,"CloseHandle failed\n");
493 /* Check that SuspendThread and ResumeThread work */
494 static VOID test_SuspendThread(void)
496 HANDLE thread,access_thread;
497 DWORD threadId,exitCode,error;
498 int i;
500 thread = CreateThread(NULL,0,threadFunc3,NULL,
501 0,&threadId);
502 ok(thread!=NULL,"Create Thread failed\n");
503 /* Check that the thread is suspended */
504 /* Note that this is a polling method, and there is a race between
505 SuspendThread being called (in the child, and the loop below timing out,
506 so the test could fail on a heavily loaded or slow computer.
508 error=0;
509 for(i=0;error==0 && i<100;i++) {
510 error=SuspendThread(thread);
511 ResumeThread(thread);
512 if(error==0) {
513 Sleep(50);
514 i++;
517 ok(error==1,"SuspendThread did not work\n");
518 /* check that access restrictions are obeyed */
519 if (pOpenThread) {
520 access_thread=pOpenThread(THREAD_ALL_ACCESS & (~THREAD_SUSPEND_RESUME),
521 0,threadId);
522 ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
523 if (access_thread!=NULL) {
524 obey_ar(SuspendThread(access_thread)==~0U);
525 obey_ar(ResumeThread(access_thread)==~0U);
526 ok(CloseHandle(access_thread)!=0,"CloseHandle Failed\n");
529 /* Double check that the thread really is suspended */
530 ok((error=GetExitCodeThread(thread,&exitCode))!=0 && exitCode==STILL_ACTIVE,
531 "Thread did not really suspend\n");
532 /* Resume the thread, and make sure it actually completes */
533 ok(ResumeThread(thread)==1,"Resume thread returned an invalid value\n");
534 ok((error=WaitForSingleObject(thread,1000))==WAIT_OBJECT_0,
535 "Thread did not resume\n");
536 if(error!=WAIT_OBJECT_0) {
537 TerminateThread(thread,1);
539 /* Trying to suspend a terminated thread should fail */
540 error=SuspendThread(thread);
541 ok(error==~0U, "wrong return code: %d\n", error);
542 ok(GetLastError()==ERROR_ACCESS_DENIED || GetLastError()==ERROR_NO_MORE_ITEMS, "unexpected error code: %d\n", GetLastError());
544 ok(CloseHandle(thread)!=0,"CloseHandle Failed\n");
547 /* Check that TerminateThread works properly
549 static VOID test_TerminateThread(void)
551 HANDLE thread,access_thread,event;
552 DWORD threadId,exitCode;
553 event=CreateEventA(NULL,TRUE,FALSE,NULL);
554 thread = CreateThread(NULL,0,threadFunc4,
555 (LPVOID)event, 0,&threadId);
556 ok(thread!=NULL,"Create Thread failed\n");
557 /* TerminateThread has a race condition in Wine. If the thread is terminated
558 before it starts, it leaves a process behind. Therefore, we wait for the
559 thread to signal that it has started. There is no easy way to force the
560 race to occur, so we don't try to find it.
562 ok(WaitForSingleObject(event,5000)==WAIT_OBJECT_0,
563 "TerminateThread didn't work\n");
564 /* check that access restrictions are obeyed */
565 if (pOpenThread) {
566 access_thread=pOpenThread(THREAD_ALL_ACCESS & (~THREAD_TERMINATE),
567 0,threadId);
568 ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
569 if (access_thread!=NULL) {
570 obey_ar(TerminateThread(access_thread,99)==0);
571 ok(CloseHandle(access_thread)!=0,"CloseHandle Failed\n");
574 /* terminate a job and make sure it terminates */
575 ok(TerminateThread(thread,99)!=0,"TerminateThread failed\n");
576 ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
577 "TerminateThread didn't work\n");
578 ok(GetExitCodeThread(thread,&exitCode)!=STILL_ACTIVE,
579 "TerminateThread should not leave the thread 'STILL_ACTIVE'\n");
580 ok(exitCode==99, "TerminateThread returned invalid exit code\n");
581 ok(CloseHandle(thread)!=0,"Error Closing thread handle\n");
584 /* Check if CreateThread obeys the specified stack size. This code does
585 not work properly, and is currently disabled
587 static VOID test_CreateThread_stack(void)
589 #if CHECK_STACK
590 /* The only way I know of to test the stack size is to use alloca
591 and __try/__except. However, this is probably not portable,
592 and I couldn't get it to work under Wine anyhow. However, here
593 is the code which should allow for testing that CreateThread
594 respects the stack-size limit
596 HANDLE thread;
597 DWORD threadId,exitCode;
599 SYSTEM_INFO sysInfo;
600 sysInfo.dwPageSize=0;
601 GetSystemInfo(&sysInfo);
602 ok(sysInfo.dwPageSize>0,"GetSystemInfo should return a valid page size\n");
603 thread = CreateThread(NULL,sysInfo.dwPageSize,
604 threadFunc5,&exitCode,
605 0,&threadId);
606 ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
607 "TerminateThread didn't work\n");
608 ok(exitCode==1,"CreateThread did not obey stack-size-limit\n");
609 ok(CloseHandle(thread)!=0,"CloseHandle failed\n");
610 #endif
613 /* Check whether setting/retrieving thread priorities works */
614 static VOID test_thread_priority(void)
616 HANDLE curthread,access_thread;
617 DWORD curthreadId,exitCode;
618 int min_priority=-2,max_priority=2;
619 BOOL disabled,rc;
620 int i;
622 curthread=GetCurrentThread();
623 curthreadId=GetCurrentThreadId();
624 /* Check thread priority */
625 /* NOTE: on Win2k/XP priority can be from -7 to 6. All other platforms it
626 is -2 to 2. However, even on a real Win2k system, using thread
627 priorities beyond the -2 to 2 range does not work. If you want to try
628 anyway, enable USE_EXTENDED_PRIORITIES
630 ok(GetThreadPriority(curthread)==THREAD_PRIORITY_NORMAL,
631 "GetThreadPriority Failed\n");
633 if (pOpenThread) {
634 /* check that access control is obeyed */
635 access_thread=pOpenThread(THREAD_ALL_ACCESS &
636 (~THREAD_QUERY_INFORMATION) & (~THREAD_SET_INFORMATION),
637 0,curthreadId);
638 ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
639 if (access_thread!=NULL) {
640 obey_ar(SetThreadPriority(access_thread,1)==0);
641 obey_ar(GetThreadPriority(access_thread)==THREAD_PRIORITY_ERROR_RETURN);
642 obey_ar(GetExitCodeThread(access_thread,&exitCode)==0);
643 ok(CloseHandle(access_thread),"Error Closing thread handle\n");
646 #if USE_EXTENDED_PRIORITIES
647 min_priority=-7; max_priority=6;
648 #endif
649 for(i=min_priority;i<=max_priority;i++) {
650 ok(SetThreadPriority(curthread,i)!=0,
651 "SetThreadPriority Failed for priority: %d\n",i);
652 ok(GetThreadPriority(curthread)==i,
653 "GetThreadPriority Failed for priority: %d\n",i);
655 ok(SetThreadPriority(curthread,THREAD_PRIORITY_TIME_CRITICAL)!=0,
656 "SetThreadPriority Failed\n");
657 ok(GetThreadPriority(curthread)==THREAD_PRIORITY_TIME_CRITICAL,
658 "GetThreadPriority Failed\n");
659 ok(SetThreadPriority(curthread,THREAD_PRIORITY_IDLE)!=0,
660 "SetThreadPriority Failed\n");
661 ok(GetThreadPriority(curthread)==THREAD_PRIORITY_IDLE,
662 "GetThreadPriority Failed\n");
663 ok(SetThreadPriority(curthread,0)!=0,"SetThreadPriority Failed\n");
665 /* Check that the thread priority is not changed if SetThreadPriority
666 is called with a value outside of the max/min range */
667 SetThreadPriority(curthread,min_priority);
668 SetLastError(0xdeadbeef);
669 rc = SetThreadPriority(curthread,min_priority-1);
671 ok(rc == FALSE, "SetThreadPriority passed with a bad argument\n");
672 ok(GetLastError() == ERROR_INVALID_PARAMETER ||
673 GetLastError() == ERROR_INVALID_PRIORITY /* Win9x */,
674 "SetThreadPriority error %d, expected ERROR_INVALID_PARAMETER or ERROR_INVALID_PRIORITY\n",
675 GetLastError());
676 ok(GetThreadPriority(curthread)==min_priority,
677 "GetThreadPriority didn't return min_priority\n");
679 SetThreadPriority(curthread,max_priority);
680 SetLastError(0xdeadbeef);
681 rc = SetThreadPriority(curthread,max_priority+1);
683 ok(rc == FALSE, "SetThreadPriority passed with a bad argument\n");
684 ok(GetLastError() == ERROR_INVALID_PARAMETER ||
685 GetLastError() == ERROR_INVALID_PRIORITY /* Win9x */,
686 "SetThreadPriority error %d, expected ERROR_INVALID_PARAMETER or ERROR_INVALID_PRIORITY\n",
687 GetLastError());
688 ok(GetThreadPriority(curthread)==max_priority,
689 "GetThreadPriority didn't return max_priority\n");
691 /* Check thread priority boost */
692 if (!pGetThreadPriorityBoost || !pSetThreadPriorityBoost)
693 return; /* Win9x */
695 SetLastError(0xdeadbeef);
696 rc=pGetThreadPriorityBoost(curthread,&disabled);
697 if (rc==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
698 return; /* WinME */
700 todo_wine
701 ok(rc!=0,"error=%d\n",GetLastError());
703 if (pOpenThread) {
704 /* check that access control is obeyed */
705 access_thread=pOpenThread(THREAD_ALL_ACCESS &
706 (~THREAD_QUERY_INFORMATION) & (~THREAD_SET_INFORMATION),
707 0,curthreadId);
708 ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
709 if (access_thread!=NULL) {
710 obey_ar(pSetThreadPriorityBoost(access_thread,1)==0);
711 obey_ar(pGetThreadPriorityBoost(access_thread,&disabled)==0);
712 ok(CloseHandle(access_thread),"Error Closing thread handle\n");
716 todo_wine {
717 rc = pSetThreadPriorityBoost(curthread,1);
718 ok( rc != 0, "error=%d\n",GetLastError());
719 rc=pGetThreadPriorityBoost(curthread,&disabled);
720 ok(rc!=0 && disabled==1,
721 "rc=%d error=%d disabled=%d\n",rc,GetLastError(),disabled);
723 rc = pSetThreadPriorityBoost(curthread,0);
724 ok( rc != 0, "error=%d\n",GetLastError());
725 rc=pGetThreadPriorityBoost(curthread,&disabled);
726 ok(rc!=0 && disabled==0,
727 "rc=%d error=%d disabled=%d\n",rc,GetLastError(),disabled);
731 /* check the GetThreadTimes function */
732 static VOID test_GetThreadTimes(void)
734 HANDLE thread,access_thread=NULL;
735 FILETIME creationTime,exitTime,kernelTime,userTime;
736 DWORD threadId;
737 int error;
739 thread = CreateThread(NULL,0,threadFunc2,NULL,
740 CREATE_SUSPENDED,&threadId);
742 ok(thread!=NULL,"Create Thread failed\n");
743 /* check that access control is obeyed */
744 if (pOpenThread) {
745 access_thread=pOpenThread(THREAD_ALL_ACCESS &
746 (~THREAD_QUERY_INFORMATION), 0,threadId);
747 ok(access_thread!=NULL,
748 "OpenThread returned an invalid handle\n");
750 ok(ResumeThread(thread)==1,"Resume thread returned an invalid value\n");
751 ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
752 "ResumeThread didn't work\n");
753 creationTime.dwLowDateTime=99; creationTime.dwHighDateTime=99;
754 exitTime.dwLowDateTime=99; exitTime.dwHighDateTime=99;
755 kernelTime.dwLowDateTime=99; kernelTime.dwHighDateTime=99;
756 userTime.dwLowDateTime=99; userTime.dwHighDateTime=99;
757 /* GetThreadTimes should set all of the parameters passed to it */
758 error=GetThreadTimes(thread,&creationTime,&exitTime,
759 &kernelTime,&userTime);
760 if (error!=0 || GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
761 ok(error!=0,"GetThreadTimes failed\n");
762 ok(creationTime.dwLowDateTime!=99 || creationTime.dwHighDateTime!=99,
763 "creationTime was invalid\n");
764 ok(exitTime.dwLowDateTime!=99 || exitTime.dwHighDateTime!=99,
765 "exitTime was invalid\n");
766 ok(kernelTime.dwLowDateTime!=99 || kernelTime.dwHighDateTime!=99,
767 "kernelTimewas invalid\n");
768 ok(userTime.dwLowDateTime!=99 || userTime.dwHighDateTime!=99,
769 "userTime was invalid\n");
770 ok(CloseHandle(thread)!=0,"CloseHandle failed\n");
771 if(access_thread!=NULL)
773 error=GetThreadTimes(access_thread,&creationTime,&exitTime,
774 &kernelTime,&userTime);
775 obey_ar(error==0);
778 if(access_thread!=NULL) {
779 ok(CloseHandle(access_thread)!=0,"CloseHandle Failed\n");
783 /* Check the processor affinity functions */
784 /* NOTE: These functions should also be checked that they obey access control
786 static VOID test_thread_processor(void)
788 HANDLE curthread,curproc;
789 DWORD_PTR processMask,systemMask;
790 SYSTEM_INFO sysInfo;
791 int error=0;
793 sysInfo.dwNumberOfProcessors=0;
794 GetSystemInfo(&sysInfo);
795 ok(sysInfo.dwNumberOfProcessors>0,
796 "GetSystemInfo failed to return a valid # of processors\n");
797 /* Use the current Thread/process for all tests */
798 curthread=GetCurrentThread();
799 ok(curthread!=NULL,"GetCurrentThread failed\n");
800 curproc=GetCurrentProcess();
801 ok(curproc!=NULL,"GetCurrentProcess failed\n");
802 /* Check the Affinity Mask functions */
803 ok(GetProcessAffinityMask(curproc,&processMask,&systemMask)!=0,
804 "GetProcessAffinityMask failed\n");
805 ok(SetThreadAffinityMask(curthread,processMask)==processMask,
806 "SetThreadAffinityMask failed\n");
807 ok(SetThreadAffinityMask(curthread,processMask+1)==0,
808 "SetThreadAffinityMask passed for an illegal processor\n");
809 /* NOTE: This only works on WinNT/2000/XP) */
810 if (pSetThreadIdealProcessor) {
811 todo_wine {
812 SetLastError(0);
813 error=pSetThreadIdealProcessor(curthread,0);
814 if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
815 ok(error!=-1, "SetThreadIdealProcessor failed\n");
818 if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
819 error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS+1);
820 ok(error==-1,
821 "SetThreadIdealProcessor succeeded with an illegal processor #\n");
822 todo_wine {
823 error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS);
824 ok(error==0, "SetThreadIdealProcessor returned an incorrect value\n");
830 static VOID test_GetThreadExitCode(void)
832 DWORD exitCode, threadid;
833 DWORD GLE, ret;
834 HANDLE thread;
836 ret = GetExitCodeThread((HANDLE)0x2bad2bad,&exitCode);
837 ok(ret==0, "GetExitCodeThread returned non zero value: %d\n", ret);
838 GLE = GetLastError();
839 ok(GLE==ERROR_INVALID_HANDLE, "GetLastError returned %d (expected 6)\n", GLE);
841 thread = CreateThread(NULL,0,threadFunc2,NULL,0,&threadid);
842 ret = WaitForSingleObject(thread,100);
843 ok(ret==WAIT_OBJECT_0, "threadFunc2 did not exit during 100 ms\n");
844 ret = GetExitCodeThread(thread,&exitCode);
845 ok(ret==exitCode || ret==1,
846 "GetExitCodeThread returned %d (expected 1 or %d)\n", ret, exitCode);
847 ok(exitCode==99, "threadFunc2 exited with code %d (expected 99)\n", exitCode);
848 ok(CloseHandle(thread)!=0,"Error closing thread handle\n");
851 #ifdef __i386__
853 static int test_value = 0;
854 static HANDLE event;
856 static void WINAPI set_test_val( int val )
858 test_value += val;
861 static DWORD WINAPI threadFunc6(LPVOID p)
863 SetEvent( event );
864 Sleep( 1000 );
865 test_value *= (int)p;
866 return 0;
869 static void test_SetThreadContext(void)
871 CONTEXT ctx;
872 int *stack;
873 HANDLE thread;
874 DWORD threadid;
875 DWORD prevcount;
876 BOOL ret;
878 SetLastError(0xdeadbeef);
879 event = CreateEvent( NULL, TRUE, FALSE, NULL );
880 thread = CreateThread( NULL, 0, threadFunc6, (void *)2, 0, &threadid );
881 ok( thread != NULL, "CreateThread failed : (%d)\n", GetLastError() );
882 if (!thread)
884 trace("Thread creation failed, skipping rest of test\n");
885 return;
887 WaitForSingleObject( event, INFINITE );
888 SuspendThread( thread );
889 CloseHandle( event );
891 ctx.ContextFlags = CONTEXT_FULL;
892 SetLastError(0xdeadbeef);
893 ret = GetThreadContext( thread, &ctx );
894 ok( ret, "GetThreadContext failed : (%u)\n", GetLastError() );
896 if (ret)
898 /* simulate a call to set_test_val(10) */
899 stack = (int *)ctx.Esp;
900 stack[-1] = 10;
901 stack[-2] = ctx.Eip;
902 ctx.Esp -= 2 * sizeof(int *);
903 ctx.Eip = (DWORD)set_test_val;
904 SetLastError(0xdeadbeef);
905 ok( SetThreadContext( thread, &ctx ), "SetThreadContext failed : (%d)\n", GetLastError() );
908 SetLastError(0xdeadbeef);
909 prevcount = ResumeThread( thread );
910 ok ( prevcount == 1, "Previous suspend count (%d) instead of 1, last error : (%d)\n",
911 prevcount, GetLastError() );
913 WaitForSingleObject( thread, INFINITE );
914 ok( test_value == 20, "test_value %d instead of 20\n", test_value );
917 #endif /* __i386__ */
919 static HANDLE finish_event;
920 static LONG times_executed;
922 static DWORD CALLBACK work_function(void *p)
924 LONG executed = InterlockedIncrement(&times_executed);
926 if (executed == 100)
927 SetEvent(finish_event);
928 return 0;
931 static void test_QueueUserWorkItem(void)
933 int i;
934 DWORD wait_result;
935 DWORD before, after;
937 /* QueueUserWorkItem not present on win9x */
938 if (!pQueueUserWorkItem) return;
940 finish_event = CreateEvent(NULL, TRUE, FALSE, NULL);
942 before = GetTickCount();
944 for (i = 0; i < 100; i++)
946 BOOL ret = pQueueUserWorkItem(work_function, (void *)i, WT_EXECUTEDEFAULT);
947 ok(ret, "QueueUserWorkItem failed with error %d\n", GetLastError());
950 wait_result = WaitForSingleObject(finish_event, 10000);
952 after = GetTickCount();
953 trace("100 QueueUserWorkItem calls took %dms\n", after - before);
954 ok(wait_result == WAIT_OBJECT_0, "wait failed with error 0x%x\n", wait_result);
956 ok(times_executed == 100, "didn't execute all of the work items\n");
959 static void CALLBACK signaled_function(PVOID p, BOOLEAN TimerOrWaitFired)
961 HANDLE event = p;
962 SetEvent(event);
963 ok(!TimerOrWaitFired, "wait shouldn't have timed out\n");
966 static void CALLBACK timeout_function(PVOID p, BOOLEAN TimerOrWaitFired)
968 HANDLE event = p;
969 SetEvent(event);
970 ok(TimerOrWaitFired, "wait should have timed out\n");
973 static void test_RegisterWaitForSingleObject(void)
975 BOOL ret;
976 HANDLE wait_handle;
977 HANDLE handle;
978 HANDLE complete_event;
980 if (!pRegisterWaitForSingleObject || !pUnregisterWait)
982 skip("RegisterWaitForSingleObject or UnregisterWait not implemented\n");
983 return;
986 /* test signaled case */
988 handle = CreateEvent(NULL, TRUE, TRUE, NULL);
989 complete_event = CreateEvent(NULL, FALSE, FALSE, NULL);
991 ret = pRegisterWaitForSingleObject(&wait_handle, handle, signaled_function, complete_event, INFINITE, WT_EXECUTEONLYONCE);
992 ok(ret, "RegisterWaitForSingleObject failed with error %d\n", GetLastError());
994 WaitForSingleObject(complete_event, INFINITE);
995 /* give worker thread chance to complete */
996 Sleep(100);
998 ret = pUnregisterWait(wait_handle);
999 ok(ret, "UnregisterWait failed with error %d\n", GetLastError());
1001 /* test cancel case */
1003 ResetEvent(handle);
1005 ret = pRegisterWaitForSingleObject(&wait_handle, handle, signaled_function, complete_event, INFINITE, WT_EXECUTEONLYONCE);
1006 ok(ret, "RegisterWaitForSingleObject failed with error %d\n", GetLastError());
1008 ret = pUnregisterWait(wait_handle);
1009 ok(ret, "UnregisterWait failed with error %d\n", GetLastError());
1011 /* test timeout case */
1013 ret = pRegisterWaitForSingleObject(&wait_handle, handle, timeout_function, complete_event, 0, WT_EXECUTEONLYONCE);
1014 ok(ret, "RegisterWaitForSingleObject failed with error %d\n", GetLastError());
1016 WaitForSingleObject(complete_event, INFINITE);
1017 /* give worker thread chance to complete */
1018 Sleep(100);
1020 ret = pUnregisterWait(wait_handle);
1021 ok(ret, "UnregisterWait failed with error %d\n", GetLastError());
1024 static DWORD TLS_main;
1025 static DWORD TLS_index0, TLS_index1;
1027 static DWORD WINAPI TLS_InheritanceProc(LPVOID p)
1029 /* We should NOT inherit the TLS values from our parent or from the
1030 main thread. */
1031 LPVOID val;
1033 val = TlsGetValue(TLS_main);
1034 ok(val == NULL, "TLS inheritance failed\n");
1036 val = TlsGetValue(TLS_index0);
1037 ok(val == NULL, "TLS inheritance failed\n");
1039 val = TlsGetValue(TLS_index1);
1040 ok(val == NULL, "TLS inheritance failed\n");
1042 return 0;
1045 /* Basic TLS usage test. Make sure we can create slots and the values we
1046 store in them are separate among threads. Also test TLS value
1047 inheritance with TLS_InheritanceProc. */
1048 static DWORD WINAPI TLS_ThreadProc(LPVOID p)
1050 LONG id = (LONG) p;
1051 LPVOID val;
1052 BOOL ret;
1054 if (sync_threads_and_run_one(0, id))
1056 TLS_index0 = TlsAlloc();
1057 ok(TLS_index0 != TLS_OUT_OF_INDEXES, "TlsAlloc failed\n");
1059 resync_after_run();
1061 if (sync_threads_and_run_one(1, id))
1063 TLS_index1 = TlsAlloc();
1064 ok(TLS_index1 != TLS_OUT_OF_INDEXES, "TlsAlloc failed\n");
1066 /* Slot indices should be different even if created in different
1067 threads. */
1068 ok(TLS_index0 != TLS_index1, "TlsAlloc failed\n");
1070 /* Both slots should be initialized to NULL */
1071 val = TlsGetValue(TLS_index0);
1072 ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
1073 ok(val == NULL, "TLS slot not initialized correctly\n");
1075 val = TlsGetValue(TLS_index1);
1076 ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
1077 ok(val == NULL, "TLS slot not initialized correctly\n");
1079 resync_after_run();
1081 if (sync_threads_and_run_one(0, id))
1083 val = TlsGetValue(TLS_index0);
1084 ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
1085 ok(val == NULL, "TLS slot not initialized correctly\n");
1087 val = TlsGetValue(TLS_index1);
1088 ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
1089 ok(val == NULL, "TLS slot not initialized correctly\n");
1091 ret = TlsSetValue(TLS_index0, (LPVOID) 1);
1092 ok(ret, "TlsSetValue failed\n");
1094 ret = TlsSetValue(TLS_index1, (LPVOID) 2);
1095 ok(ret, "TlsSetValue failed\n");
1097 val = TlsGetValue(TLS_index0);
1098 ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
1099 ok(val == (LPVOID) 1, "TLS slot not initialized correctly\n");
1101 val = TlsGetValue(TLS_index1);
1102 ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
1103 ok(val == (LPVOID) 2, "TLS slot not initialized correctly\n");
1105 resync_after_run();
1107 if (sync_threads_and_run_one(1, id))
1109 val = TlsGetValue(TLS_index0);
1110 ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
1111 ok(val == NULL, "TLS slot not initialized correctly\n");
1113 val = TlsGetValue(TLS_index1);
1114 ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
1115 ok(val == NULL, "TLS slot not initialized correctly\n");
1117 ret = TlsSetValue(TLS_index0, (LPVOID) 3);
1118 ok(ret, "TlsSetValue failed\n");
1120 ret = TlsSetValue(TLS_index1, (LPVOID) 4);
1121 ok(ret, "TlsSetValue failed\n");
1123 val = TlsGetValue(TLS_index0);
1124 ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
1125 ok(val == (LPVOID) 3, "TLS slot not initialized correctly\n");
1127 val = TlsGetValue(TLS_index1);
1128 ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
1129 ok(val == (LPVOID) 4, "TLS slot not initialized correctly\n");
1131 resync_after_run();
1133 if (sync_threads_and_run_one(0, id))
1135 HANDLE thread;
1136 DWORD waitret, tid;
1138 val = TlsGetValue(TLS_index0);
1139 ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
1140 ok(val == (LPVOID) 1, "TLS slot not initialized correctly\n");
1142 val = TlsGetValue(TLS_index1);
1143 ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
1144 ok(val == (LPVOID) 2, "TLS slot not initialized correctly\n");
1146 thread = CreateThread(NULL, 0, TLS_InheritanceProc, 0, 0, &tid);
1147 ok(thread != NULL, "CreateThread failed\n");
1148 waitret = WaitForSingleObject(thread, 60000);
1149 ok(waitret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
1150 CloseHandle(thread);
1152 ret = TlsFree(TLS_index0);
1153 ok(ret, "TlsFree failed\n");
1155 resync_after_run();
1157 if (sync_threads_and_run_one(1, id))
1159 ret = TlsFree(TLS_index1);
1160 ok(ret, "TlsFree failed\n");
1162 resync_after_run();
1164 return 0;
1167 static void test_TLS(void)
1169 HANDLE threads[2];
1170 LONG i;
1171 DWORD ret;
1172 BOOL suc;
1174 init_thread_sync_helpers(2);
1176 /* Allocate a TLS slot in the main thread to test for inheritance. */
1177 TLS_main = TlsAlloc();
1178 ok(TLS_main != TLS_OUT_OF_INDEXES, "TlsAlloc failed\n");
1179 suc = TlsSetValue(TLS_main, (LPVOID) 4114);
1180 ok(suc, "TlsSetValue failed\n");
1182 for (i = 0; i < 2; ++i)
1184 DWORD tid;
1186 threads[i] = CreateThread(NULL, 0, TLS_ThreadProc, (LPVOID) i, 0, &tid);
1187 ok(threads[i] != NULL, "CreateThread failed\n");
1190 ret = WaitForMultipleObjects(2, threads, TRUE, 60000);
1191 ok(ret == WAIT_OBJECT_0, "WaitForMultipleObjects failed\n");
1193 for (i = 0; i < 2; ++i)
1194 CloseHandle(threads[i]);
1196 suc = TlsFree(TLS_main);
1197 ok(suc, "TlsFree failed\n");
1198 cleanup_thread_sync_helpers();
1201 START_TEST(thread)
1203 HINSTANCE lib;
1204 int argc;
1205 char **argv;
1206 argc = winetest_get_mainargs( &argv );
1207 /* Neither Cygwin nor mingW export OpenThread, so do a dynamic check
1208 so that the compile passes
1210 lib=GetModuleHandleA("kernel32.dll");
1211 ok(lib!=NULL,"Couldn't get a handle for kernel32.dll\n");
1212 pGetThreadPriorityBoost=(GetThreadPriorityBoost_t)GetProcAddress(lib,"GetThreadPriorityBoost");
1213 pOpenThread=(OpenThread_t)GetProcAddress(lib,"OpenThread");
1214 pQueueUserWorkItem=(QueueUserWorkItem_t)GetProcAddress(lib,"QueueUserWorkItem");
1215 pSetThreadIdealProcessor=(SetThreadIdealProcessor_t)GetProcAddress(lib,"SetThreadIdealProcessor");
1216 pSetThreadPriorityBoost=(SetThreadPriorityBoost_t)GetProcAddress(lib,"SetThreadPriorityBoost");
1217 pRegisterWaitForSingleObject=(RegisterWaitForSingleObject_t)GetProcAddress(lib,"RegisterWaitForSingleObject");
1218 pUnregisterWait=(UnregisterWait_t)GetProcAddress(lib,"UnregisterWait");
1220 if (argc >= 3)
1222 if (!strcmp(argv[2], "sleep"))
1224 HANDLE hAddrEvents[2];
1225 create_function_addr_events(hAddrEvents);
1226 SetEvent(hAddrEvents[0]);
1227 SetEvent(hAddrEvents[1]);
1228 Sleep(5000); /* spawned process runs for at most 5 seconds */
1229 return;
1231 while (1)
1233 HANDLE hThread;
1234 DWORD tid;
1235 hThread = CreateThread(NULL, 0, threadFunc2, NULL, 0, &tid);
1236 ok(hThread != NULL, "CreateThread failed, error %u\n",
1237 GetLastError());
1238 ok(WaitForSingleObject(hThread, 200) == WAIT_OBJECT_0,
1239 "Thread did not exit in time\n");
1240 if (hThread == NULL) break;
1241 CloseHandle(hThread);
1243 return;
1246 test_CreateRemoteThread();
1247 test_CreateThread_basic();
1248 test_CreateThread_suspended();
1249 test_SuspendThread();
1250 test_TerminateThread();
1251 test_CreateThread_stack();
1252 test_thread_priority();
1253 test_GetThreadTimes();
1254 test_thread_processor();
1255 test_GetThreadExitCode();
1256 #ifdef __i386__
1257 test_SetThreadContext();
1258 #endif
1259 test_QueueUserWorkItem();
1260 test_RegisterWaitForSingleObject();
1261 test_TLS();