kernel32/tests: Fix a few failures on win98.
[wine/multimedia.git] / dlls / kernel32 / tests / thread.c
blob697f34b6521de4523260ac31893c669b5f65db93
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 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;
115 num_synced = 0;
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);
127 else
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);
139 if (num == 0)
140 PulseEvent(all_synced);
141 else
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);
151 all_synced = NULL;
154 DWORD tlsIndex;
156 typedef struct {
157 int threadnum;
158 HANDLE *event;
159 DWORD *threadmem;
160 } t1Struct;
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 */
166 #define obey_ar(x) \
167 (obeying_ars == 0 \
168 ? ((x) \
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;
183 int i;
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)
211 return 99;
214 static DWORD WINAPI threadFunc3(LPVOID p)
216 HANDLE thread;
217 thread=GetCurrentThread();
218 SuspendThread(thread);
219 return 99;
222 static DWORD WINAPI threadFunc4(LPVOID p)
224 HANDLE event = (HANDLE)p;
225 if(event != NULL) {
226 SetEvent(event);
228 Sleep(99000);
229 return 0;
232 #if CHECK_STACK
233 static DWORD WINAPI threadFunc5(LPVOID p)
235 DWORD *exitCode = (DWORD *)p;
236 SYSTEM_INFO sysInfo;
237 sysInfo.dwPageSize=0;
238 GetSystemInfo(&sysInfo);
239 *exitCode=0;
240 __TRY
242 alloca(2*sysInfo.dwPageSize);
244 __EXCEPT(1) {
245 *exitCode=1;
247 __ENDTRY
248 return 0;
250 #endif
252 static DWORD WINAPI threadFunc_SetEvent(LPVOID p)
254 SetEvent((HANDLE) p);
255 return 0;
258 static DWORD WINAPI threadFunc_CloseHandle(LPVOID p)
260 CloseHandle((HANDLE) p);
261 return 0;
264 static void create_function_addr_events(HANDLE events[2])
266 char buffer[256];
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");
292 return;
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");
308 goto cleanup;
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,
344 threadFunc_SetEvent,
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);
358 cleanup:
359 TerminateProcess(hProcess, 0);
360 CloseHandle(hEvent);
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];
370 DWORD exitCode;
371 t1Struct tstruct[NUM_THREADS];
372 int error;
373 DWORD i,j;
374 DWORD GLE, ret;
375 DWORD tid;
377 /* lstrlenA contains an exception handler so this makes sure exceptions work in the main thread */
378 ok( lstrlenA( (char *)0xdeadbeef ) == 0, "lstrlenA: unexpected success\n" );
380 /* Retrieve current Thread ID for later comparisons */
381 curthreadId=GetCurrentThreadId();
382 /* Allocate some local storage */
383 ok((tlsIndex=TlsAlloc())!=TLS_OUT_OF_INDEXES,"TlsAlloc failed\n");
384 /* Create events for thread synchronization */
385 for(i=0;i<NUM_THREADS;i++) {
386 threadmem[i]=0;
387 /* Note that it doesn't matter what type of event we choose here. This
388 test isn't trying to thoroughly test events
390 event[i]=CreateEventA(NULL,TRUE,FALSE,NULL);
391 tstruct[i].threadnum=i;
392 tstruct[i].threadmem=threadmem;
393 tstruct[i].event=event;
396 /* Test that passing arguments to threads works okay */
397 for(i=0;i<NUM_THREADS;i++) {
398 thread[i] = CreateThread(NULL,0,threadFunc1,
399 &tstruct[i],0,&threadid[i]);
400 ok(thread[i]!=NULL,"Create Thread failed\n");
402 /* Test that the threads actually complete */
403 for(i=0;i<NUM_THREADS;i++) {
404 error=WaitForSingleObject(thread[i],5000);
405 ok(error==WAIT_OBJECT_0, "Thread did not complete within timelimit\n");
406 if(error!=WAIT_OBJECT_0) {
407 TerminateThread(thread[i],i+NUM_THREADS);
409 ok(GetExitCodeThread(thread[i],&exitCode),"Could not retrieve ext code\n");
410 ok(exitCode==i+NUM_THREADS,"Thread returned an incorrect exit code\n");
412 /* Test that each thread executed in its parent's address space
413 (it was able to change threadmem and pass that change back to its parent)
414 and that each thread id was independent). Note that we prove that the
415 threads actually execute concurrently by having them block on each other
416 in threadFunc1
418 for(i=0;i<NUM_THREADS;i++) {
419 error=0;
420 for(j=i+1;j<NUM_THREADS;j++) {
421 if (threadmem[i]==threadmem[j]) {
422 error=1;
425 ok(!error && threadmem[i]==threadid[i] && threadmem[i]!=curthreadId,
426 "Thread did not execute successfully\n");
427 ok(CloseHandle(thread[i])!=0,"CloseHandle failed\n");
429 ok(TlsFree(tlsIndex)!=0,"TlsFree failed\n");
431 /* Test how passing NULL as a pointer to threadid works */
432 SetLastError(0xFACEaBAD);
433 thread[0] = CreateThread(NULL,0,threadFunc2,NULL,0,&tid);
434 GLE = GetLastError();
435 if (thread[0]) { /* NT */
436 ok(GLE==0xFACEaBAD, "CreateThread set last error to %d, expected 4207848365\n", GLE);
437 ret = WaitForSingleObject(thread[0],100);
438 ok(ret==WAIT_OBJECT_0, "threadFunc2 did not exit during 100 ms\n");
439 ret = GetExitCodeThread(thread[0],&exitCode);
440 ok(ret!=0, "GetExitCodeThread returned %d (expected nonzero)\n", ret);
441 ok(exitCode==99, "threadFunc2 exited with code: %d (expected 99)\n", exitCode);
442 ok(CloseHandle(thread[0])!=0,"Error closing thread handle\n");
444 else { /* 9x */
445 ok(GLE==ERROR_INVALID_PARAMETER, "CreateThread set last error to %d, expected 87\n", GLE);
449 /* Check that using the CREATE_SUSPENDED flag works */
450 static VOID test_CreateThread_suspended(void)
452 HANDLE thread;
453 DWORD threadId;
454 DWORD suspend_count;
455 int error;
457 thread = CreateThread(NULL,0,threadFunc2,NULL,
458 CREATE_SUSPENDED,&threadId);
459 ok(thread!=NULL,"Create Thread failed\n");
460 /* Check that the thread is suspended */
461 ok(SuspendThread(thread)==1,"Thread did not start suspended\n");
462 ok(ResumeThread(thread)==2,"Resume thread returned an invalid value\n");
463 /* Check that resume thread didn't actually start the thread. I can't think
464 of a better way of checking this than just waiting. I am not sure if this
465 will work on slow computers.
467 ok(WaitForSingleObject(thread,1000)==WAIT_TIMEOUT,
468 "ResumeThread should not have actually started the thread\n");
469 /* Now actually resume the thread and make sure that it actually completes*/
470 ok(ResumeThread(thread)==1,"Resume thread returned an invalid value\n");
471 ok((error=WaitForSingleObject(thread,1000))==WAIT_OBJECT_0,
472 "Thread did not resume\n");
473 if(error!=WAIT_OBJECT_0) {
474 TerminateThread(thread,1);
477 suspend_count = SuspendThread(thread);
478 ok(suspend_count == -1, "SuspendThread returned %d, expected -1\n", suspend_count);
480 suspend_count = ResumeThread(thread);
481 ok(suspend_count == 0, "ResumeThread returned %d, expected 0\n", suspend_count);
483 ok(CloseHandle(thread)!=0,"CloseHandle failed\n");
486 /* Check that SuspendThread and ResumeThread work */
487 static VOID test_SuspendThread(void)
489 HANDLE thread,access_thread;
490 DWORD threadId,exitCode,error;
491 int i;
493 thread = CreateThread(NULL,0,threadFunc3,NULL,
494 0,&threadId);
495 ok(thread!=NULL,"Create Thread failed\n");
496 /* Check that the thread is suspended */
497 /* Note that this is a polling method, and there is a race between
498 SuspendThread being called (in the child, and the loop below timing out,
499 so the test could fail on a heavily loaded or slow computer.
501 error=0;
502 for(i=0;error==0 && i<100;i++) {
503 error=SuspendThread(thread);
504 ResumeThread(thread);
505 if(error==0) {
506 Sleep(50);
507 i++;
510 ok(error==1,"SuspendThread did not work\n");
511 /* check that access restrictions are obeyed */
512 if (pOpenThread) {
513 access_thread=pOpenThread(THREAD_ALL_ACCESS & (~THREAD_SUSPEND_RESUME),
514 0,threadId);
515 ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
516 if (access_thread!=NULL) {
517 obey_ar(SuspendThread(access_thread)==~0U);
518 obey_ar(ResumeThread(access_thread)==~0U);
519 ok(CloseHandle(access_thread)!=0,"CloseHandle Failed\n");
522 /* Double check that the thread really is suspended */
523 ok((error=GetExitCodeThread(thread,&exitCode))!=0 && exitCode==STILL_ACTIVE,
524 "Thread did not really suspend\n");
525 /* Resume the thread, and make sure it actually completes */
526 ok(ResumeThread(thread)==1,"Resume thread returned an invalid value\n");
527 ok((error=WaitForSingleObject(thread,1000))==WAIT_OBJECT_0,
528 "Thread did not resume\n");
529 if(error!=WAIT_OBJECT_0) {
530 TerminateThread(thread,1);
532 /* Trying to suspend a terminated thread should fail */
533 error=SuspendThread(thread);
534 ok(error==~0U, "wrong return code: %d\n", error);
535 ok(GetLastError()==ERROR_ACCESS_DENIED || GetLastError()==ERROR_NO_MORE_ITEMS, "unexpected error code: %d\n", GetLastError());
537 ok(CloseHandle(thread)!=0,"CloseHandle Failed\n");
540 /* Check that TerminateThread works properly
542 static VOID test_TerminateThread(void)
544 HANDLE thread,access_thread,event;
545 DWORD threadId,exitCode;
546 event=CreateEventA(NULL,TRUE,FALSE,NULL);
547 thread = CreateThread(NULL,0,threadFunc4,
548 (LPVOID)event, 0,&threadId);
549 ok(thread!=NULL,"Create Thread failed\n");
550 /* TerminateThread has a race condition in Wine. If the thread is terminated
551 before it starts, it leaves a process behind. Therefore, we wait for the
552 thread to signal that it has started. There is no easy way to force the
553 race to occur, so we don't try to find it.
555 ok(WaitForSingleObject(event,5000)==WAIT_OBJECT_0,
556 "TerminateThread didn't work\n");
557 /* check that access restrictions are obeyed */
558 if (pOpenThread) {
559 access_thread=pOpenThread(THREAD_ALL_ACCESS & (~THREAD_TERMINATE),
560 0,threadId);
561 ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
562 if (access_thread!=NULL) {
563 obey_ar(TerminateThread(access_thread,99)==0);
564 ok(CloseHandle(access_thread)!=0,"CloseHandle Failed\n");
567 /* terminate a job and make sure it terminates */
568 ok(TerminateThread(thread,99)!=0,"TerminateThread failed\n");
569 ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
570 "TerminateThread didn't work\n");
571 ok(GetExitCodeThread(thread,&exitCode)!=STILL_ACTIVE,
572 "TerminateThread should not leave the thread 'STILL_ACTIVE'\n");
573 ok(exitCode==99, "TerminateThread returned invalid exit code\n");
574 ok(CloseHandle(thread)!=0,"Error Closing thread handle\n");
577 /* Check if CreateThread obeys the specified stack size. This code does
578 not work properly, and is currently disabled
580 static VOID test_CreateThread_stack(void)
582 #if CHECK_STACK
583 /* The only way I know of to test the stack size is to use alloca
584 and __try/__except. However, this is probably not portable,
585 and I couldn't get it to work under Wine anyhow. However, here
586 is the code which should allow for testing that CreateThread
587 respects the stack-size limit
589 HANDLE thread;
590 DWORD threadId,exitCode;
592 SYSTEM_INFO sysInfo;
593 sysInfo.dwPageSize=0;
594 GetSystemInfo(&sysInfo);
595 ok(sysInfo.dwPageSize>0,"GetSystemInfo should return a valid page size\n");
596 thread = CreateThread(NULL,sysInfo.dwPageSize,
597 threadFunc5,&exitCode,
598 0,&threadId);
599 ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
600 "TerminateThread didn't work\n");
601 ok(exitCode==1,"CreateThread did not obey stack-size-limit\n");
602 ok(CloseHandle(thread)!=0,"CloseHandle failed\n");
603 #endif
606 /* Check whether setting/retrieving thread priorities works */
607 static VOID test_thread_priority(void)
609 HANDLE curthread,access_thread;
610 DWORD curthreadId,exitCode;
611 int min_priority=-2,max_priority=2;
612 BOOL disabled,rc;
613 int i;
615 curthread=GetCurrentThread();
616 curthreadId=GetCurrentThreadId();
617 /* Check thread priority */
618 /* NOTE: on Win2k/XP priority can be from -7 to 6. All other platforms it
619 is -2 to 2. However, even on a real Win2k system, using thread
620 priorities beyond the -2 to 2 range does not work. If you want to try
621 anyway, enable USE_EXTENDED_PRIORITIES
623 ok(GetThreadPriority(curthread)==THREAD_PRIORITY_NORMAL,
624 "GetThreadPriority Failed\n");
626 if (pOpenThread) {
627 /* check that access control is obeyed */
628 access_thread=pOpenThread(THREAD_ALL_ACCESS &
629 (~THREAD_QUERY_INFORMATION) & (~THREAD_SET_INFORMATION),
630 0,curthreadId);
631 ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
632 if (access_thread!=NULL) {
633 obey_ar(SetThreadPriority(access_thread,1)==0);
634 obey_ar(GetThreadPriority(access_thread)==THREAD_PRIORITY_ERROR_RETURN);
635 obey_ar(GetExitCodeThread(access_thread,&exitCode)==0);
636 ok(CloseHandle(access_thread),"Error Closing thread handle\n");
639 #if USE_EXTENDED_PRIORITIES
640 min_priority=-7; max_priority=6;
641 #endif
642 for(i=min_priority;i<=max_priority;i++) {
643 ok(SetThreadPriority(curthread,i)!=0,
644 "SetThreadPriority Failed for priority: %d\n",i);
645 ok(GetThreadPriority(curthread)==i,
646 "GetThreadPriority Failed for priority: %d\n",i);
648 ok(SetThreadPriority(curthread,THREAD_PRIORITY_TIME_CRITICAL)!=0,
649 "SetThreadPriority Failed\n");
650 ok(GetThreadPriority(curthread)==THREAD_PRIORITY_TIME_CRITICAL,
651 "GetThreadPriority Failed\n");
652 ok(SetThreadPriority(curthread,THREAD_PRIORITY_IDLE)!=0,
653 "SetThreadPriority Failed\n");
654 ok(GetThreadPriority(curthread)==THREAD_PRIORITY_IDLE,
655 "GetThreadPriority Failed\n");
656 ok(SetThreadPriority(curthread,0)!=0,"SetThreadPriority Failed\n");
658 /* Check that the thread priority is not changed if SetThreadPriority
659 is called with a value outside of the max/min range */
660 SetThreadPriority(curthread,min_priority);
661 SetLastError(0xdeadbeef);
662 rc = SetThreadPriority(curthread,min_priority-1);
664 ok(rc == FALSE, "SetThreadPriority passed with a bad argument\n");
665 ok(GetLastError() == ERROR_INVALID_PARAMETER ||
666 GetLastError() == ERROR_INVALID_PRIORITY /* Win9x */,
667 "SetThreadPriority error %d, expected ERROR_INVALID_PARAMETER or ERROR_INVALID_PRIORITY\n",
668 GetLastError());
669 ok(GetThreadPriority(curthread)==min_priority,
670 "GetThreadPriority didn't return min_priority\n");
672 SetThreadPriority(curthread,max_priority);
673 SetLastError(0xdeadbeef);
674 rc = SetThreadPriority(curthread,max_priority+1);
676 ok(rc == FALSE, "SetThreadPriority passed with a bad argument\n");
677 ok(GetLastError() == ERROR_INVALID_PARAMETER ||
678 GetLastError() == ERROR_INVALID_PRIORITY /* Win9x */,
679 "SetThreadPriority error %d, expected ERROR_INVALID_PARAMETER or ERROR_INVALID_PRIORITY\n",
680 GetLastError());
681 ok(GetThreadPriority(curthread)==max_priority,
682 "GetThreadPriority didn't return max_priority\n");
684 /* Check thread priority boost */
685 if (!pGetThreadPriorityBoost || !pSetThreadPriorityBoost)
686 return; /* Win9x */
688 SetLastError(0xdeadbeef);
689 rc=pGetThreadPriorityBoost(curthread,&disabled);
690 if (rc==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
691 return; /* WinME */
693 todo_wine
694 ok(rc!=0,"error=%d\n",GetLastError());
696 if (pOpenThread) {
697 /* check that access control is obeyed */
698 access_thread=pOpenThread(THREAD_ALL_ACCESS &
699 (~THREAD_QUERY_INFORMATION) & (~THREAD_SET_INFORMATION),
700 0,curthreadId);
701 ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
702 if (access_thread!=NULL) {
703 obey_ar(pSetThreadPriorityBoost(access_thread,1)==0);
704 obey_ar(pGetThreadPriorityBoost(access_thread,&disabled)==0);
705 ok(CloseHandle(access_thread),"Error Closing thread handle\n");
709 todo_wine {
710 rc = pSetThreadPriorityBoost(curthread,1);
711 ok( rc != 0, "error=%d\n",GetLastError());
712 rc=pGetThreadPriorityBoost(curthread,&disabled);
713 ok(rc!=0 && disabled==1,
714 "rc=%d error=%d disabled=%d\n",rc,GetLastError(),disabled);
716 rc = pSetThreadPriorityBoost(curthread,0);
717 ok( rc != 0, "error=%d\n",GetLastError());
718 rc=pGetThreadPriorityBoost(curthread,&disabled);
719 ok(rc!=0 && disabled==0,
720 "rc=%d error=%d disabled=%d\n",rc,GetLastError(),disabled);
724 /* check the GetThreadTimes function */
725 static VOID test_GetThreadTimes(void)
727 HANDLE thread,access_thread=NULL;
728 FILETIME creationTime,exitTime,kernelTime,userTime;
729 DWORD threadId;
730 int error;
732 thread = CreateThread(NULL,0,threadFunc2,NULL,
733 CREATE_SUSPENDED,&threadId);
735 ok(thread!=NULL,"Create Thread failed\n");
736 /* check that access control is obeyed */
737 if (pOpenThread) {
738 access_thread=pOpenThread(THREAD_ALL_ACCESS &
739 (~THREAD_QUERY_INFORMATION), 0,threadId);
740 ok(access_thread!=NULL,
741 "OpenThread returned an invalid handle\n");
743 ok(ResumeThread(thread)==1,"Resume thread returned an invalid value\n");
744 ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
745 "ResumeThread didn't work\n");
746 creationTime.dwLowDateTime=99; creationTime.dwHighDateTime=99;
747 exitTime.dwLowDateTime=99; exitTime.dwHighDateTime=99;
748 kernelTime.dwLowDateTime=99; kernelTime.dwHighDateTime=99;
749 userTime.dwLowDateTime=99; userTime.dwHighDateTime=99;
750 /* GetThreadTimes should set all of the parameters passed to it */
751 error=GetThreadTimes(thread,&creationTime,&exitTime,
752 &kernelTime,&userTime);
753 if (error!=0 || GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
754 ok(error!=0,"GetThreadTimes failed\n");
755 ok(creationTime.dwLowDateTime!=99 || creationTime.dwHighDateTime!=99,
756 "creationTime was invalid\n");
757 ok(exitTime.dwLowDateTime!=99 || exitTime.dwHighDateTime!=99,
758 "exitTime was invalid\n");
759 ok(kernelTime.dwLowDateTime!=99 || kernelTime.dwHighDateTime!=99,
760 "kernelTimewas invalid\n");
761 ok(userTime.dwLowDateTime!=99 || userTime.dwHighDateTime!=99,
762 "userTime was invalid\n");
763 ok(CloseHandle(thread)!=0,"CloseHandle failed\n");
764 if(access_thread!=NULL)
766 error=GetThreadTimes(access_thread,&creationTime,&exitTime,
767 &kernelTime,&userTime);
768 obey_ar(error==0);
771 if(access_thread!=NULL) {
772 ok(CloseHandle(access_thread)!=0,"CloseHandle Failed\n");
776 /* Check the processor affinity functions */
777 /* NOTE: These functions should also be checked that they obey access control
779 static VOID test_thread_processor(void)
781 HANDLE curthread,curproc;
782 DWORD_PTR processMask,systemMask;
783 SYSTEM_INFO sysInfo;
784 int error=0;
786 sysInfo.dwNumberOfProcessors=0;
787 GetSystemInfo(&sysInfo);
788 ok(sysInfo.dwNumberOfProcessors>0,
789 "GetSystemInfo failed to return a valid # of processors\n");
790 /* Use the current Thread/process for all tests */
791 curthread=GetCurrentThread();
792 ok(curthread!=NULL,"GetCurrentThread failed\n");
793 curproc=GetCurrentProcess();
794 ok(curproc!=NULL,"GetCurrentProcess failed\n");
795 /* Check the Affinity Mask functions */
796 ok(GetProcessAffinityMask(curproc,&processMask,&systemMask)!=0,
797 "GetProcessAffinityMask failed\n");
798 ok(SetThreadAffinityMask(curthread,processMask)==processMask,
799 "SetThreadAffinityMask failed\n");
800 ok(SetThreadAffinityMask(curthread,processMask+1)==0,
801 "SetThreadAffinityMask passed for an illegal processor\n");
802 /* NOTE: This only works on WinNT/2000/XP) */
803 if (pSetThreadIdealProcessor) {
804 todo_wine {
805 SetLastError(0);
806 error=pSetThreadIdealProcessor(curthread,0);
807 if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
808 ok(error!=-1, "SetThreadIdealProcessor failed\n");
811 if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
812 error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS+1);
813 ok(error==-1,
814 "SetThreadIdealProcessor succeeded with an illegal processor #\n");
815 todo_wine {
816 error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS);
817 ok(error==0, "SetThreadIdealProcessor returned an incorrect value\n");
823 static VOID test_GetThreadExitCode(void)
825 DWORD exitCode, threadid;
826 DWORD GLE, ret;
827 HANDLE thread;
829 ret = GetExitCodeThread((HANDLE)0x2bad2bad,&exitCode);
830 ok(ret==0, "GetExitCodeThread returned non zero value: %d\n", ret);
831 GLE = GetLastError();
832 ok(GLE==ERROR_INVALID_HANDLE, "GetLastError returned %d (expected 6)\n", GLE);
834 thread = CreateThread(NULL,0,threadFunc2,NULL,0,&threadid);
835 ret = WaitForSingleObject(thread,100);
836 ok(ret==WAIT_OBJECT_0, "threadFunc2 did not exit during 100 ms\n");
837 ret = GetExitCodeThread(thread,&exitCode);
838 ok(ret==exitCode || ret==1,
839 "GetExitCodeThread returned %d (expected 1 or %d)\n", ret, exitCode);
840 ok(exitCode==99, "threadFunc2 exited with code %d (expected 99)\n", exitCode);
841 ok(CloseHandle(thread)!=0,"Error closing thread handle\n");
844 #ifdef __i386__
846 static int test_value = 0;
847 static HANDLE event;
849 static void WINAPI set_test_val( int val )
851 test_value += val;
854 static DWORD WINAPI threadFunc6(LPVOID p)
856 SetEvent( event );
857 Sleep( 1000 );
858 test_value *= (int)p;
859 return 0;
862 static void test_SetThreadContext(void)
864 CONTEXT ctx;
865 int *stack;
866 HANDLE thread;
867 DWORD threadid;
868 DWORD prevcount;
869 BOOL ret;
871 SetLastError(0xdeadbeef);
872 event = CreateEvent( NULL, TRUE, FALSE, NULL );
873 thread = CreateThread( NULL, 0, threadFunc6, (void *)2, 0, &threadid );
874 ok( thread != NULL, "CreateThread failed : (%d)\n", GetLastError() );
875 if (!thread)
877 trace("Thread creation failed, skipping rest of test\n");
878 return;
880 WaitForSingleObject( event, INFINITE );
881 SuspendThread( thread );
882 CloseHandle( event );
884 ctx.ContextFlags = CONTEXT_FULL;
885 SetLastError(0xdeadbeef);
886 ret = GetThreadContext( thread, &ctx );
887 ok( ret, "GetThreadContext failed : (%u)\n", GetLastError() );
889 if (ret)
891 /* simulate a call to set_test_val(10) */
892 stack = (int *)ctx.Esp;
893 stack[-1] = 10;
894 stack[-2] = ctx.Eip;
895 ctx.Esp -= 2 * sizeof(int *);
896 ctx.Eip = (DWORD)set_test_val;
897 SetLastError(0xdeadbeef);
898 ok( SetThreadContext( thread, &ctx ), "SetThreadContext failed : (%d)\n", GetLastError() );
901 SetLastError(0xdeadbeef);
902 prevcount = ResumeThread( thread );
903 ok ( prevcount == 1, "Previous suspend count (%d) instead of 1, last error : (%d)\n",
904 prevcount, GetLastError() );
906 WaitForSingleObject( thread, INFINITE );
907 ok( test_value == 20, "test_value %d instead of 20\n", test_value );
910 #endif /* __i386__ */
912 static HANDLE finish_event;
913 static LONG times_executed;
915 static DWORD CALLBACK work_function(void *p)
917 LONG executed = InterlockedIncrement(&times_executed);
919 if (executed == 100)
920 SetEvent(finish_event);
921 return 0;
924 static void test_QueueUserWorkItem(void)
926 int i;
927 DWORD wait_result;
928 DWORD before, after;
930 /* QueueUserWorkItem not present on win9x */
931 if (!pQueueUserWorkItem) return;
933 finish_event = CreateEvent(NULL, TRUE, FALSE, NULL);
935 before = GetTickCount();
937 for (i = 0; i < 100; i++)
939 BOOL ret = pQueueUserWorkItem(work_function, (void *)i, WT_EXECUTEDEFAULT);
940 ok(ret, "QueueUserWorkItem failed with error %d\n", GetLastError());
943 wait_result = WaitForSingleObject(finish_event, 10000);
945 after = GetTickCount();
946 trace("100 QueueUserWorkItem calls took %dms\n", after - before);
947 ok(wait_result == WAIT_OBJECT_0, "wait failed with error 0x%x\n", wait_result);
949 ok(times_executed == 100, "didn't execute all of the work items\n");
952 static void CALLBACK signaled_function(PVOID p, BOOLEAN TimerOrWaitFired)
954 HANDLE event = p;
955 SetEvent(event);
956 ok(!TimerOrWaitFired, "wait shouldn't have timed out\n");
959 static void CALLBACK timeout_function(PVOID p, BOOLEAN TimerOrWaitFired)
961 HANDLE event = p;
962 SetEvent(event);
963 ok(TimerOrWaitFired, "wait should have timed out\n");
966 static void test_RegisterWaitForSingleObject(void)
968 BOOL ret;
969 HANDLE wait_handle;
970 HANDLE handle;
971 HANDLE complete_event;
973 if (!pRegisterWaitForSingleObject || !pUnregisterWait)
975 skip("RegisterWaitForSingleObject or UnregisterWait not implemented\n");
976 return;
979 /* test signaled case */
981 handle = CreateEvent(NULL, TRUE, TRUE, NULL);
982 complete_event = CreateEvent(NULL, FALSE, FALSE, NULL);
984 ret = pRegisterWaitForSingleObject(&wait_handle, handle, signaled_function, complete_event, INFINITE, WT_EXECUTEONLYONCE);
985 ok(ret, "RegisterWaitForSingleObject failed with error %d\n", GetLastError());
987 WaitForSingleObject(complete_event, INFINITE);
988 /* give worker thread chance to complete */
989 Sleep(100);
991 ret = pUnregisterWait(wait_handle);
992 ok(ret, "UnregisterWait failed with error %d\n", GetLastError());
994 /* test cancel case */
996 ResetEvent(handle);
998 ret = pRegisterWaitForSingleObject(&wait_handle, handle, signaled_function, complete_event, INFINITE, WT_EXECUTEONLYONCE);
999 ok(ret, "RegisterWaitForSingleObject failed with error %d\n", GetLastError());
1001 ret = pUnregisterWait(wait_handle);
1002 ok(ret, "UnregisterWait failed with error %d\n", GetLastError());
1004 /* test timeout case */
1006 ret = pRegisterWaitForSingleObject(&wait_handle, handle, timeout_function, complete_event, 0, WT_EXECUTEONLYONCE);
1007 ok(ret, "RegisterWaitForSingleObject failed with error %d\n", GetLastError());
1009 WaitForSingleObject(complete_event, INFINITE);
1010 /* give worker thread chance to complete */
1011 Sleep(100);
1013 ret = pUnregisterWait(wait_handle);
1014 ok(ret, "UnregisterWait failed with error %d\n", GetLastError());
1017 static DWORD TLS_main;
1018 static DWORD TLS_index0, TLS_index1;
1020 static DWORD WINAPI TLS_InheritanceProc(LPVOID p)
1022 /* We should NOT inherit the TLS values from our parent or from the
1023 main thread. */
1024 LPVOID val;
1026 val = TlsGetValue(TLS_main);
1027 ok(val == NULL, "TLS inheritance failed\n");
1029 val = TlsGetValue(TLS_index0);
1030 ok(val == NULL, "TLS inheritance failed\n");
1032 val = TlsGetValue(TLS_index1);
1033 ok(val == NULL, "TLS inheritance failed\n");
1035 return 0;
1038 /* Basic TLS usage test. Make sure we can create slots and the values we
1039 store in them are separate among threads. Also test TLS value
1040 inheritance with TLS_InheritanceProc. */
1041 static DWORD WINAPI TLS_ThreadProc(LPVOID p)
1043 LONG id = (LONG) p;
1044 LPVOID val;
1045 BOOL ret;
1047 if (sync_threads_and_run_one(0, id))
1049 TLS_index0 = TlsAlloc();
1050 ok(TLS_index0 != TLS_OUT_OF_INDEXES, "TlsAlloc failed\n");
1052 resync_after_run();
1054 if (sync_threads_and_run_one(1, id))
1056 TLS_index1 = TlsAlloc();
1057 ok(TLS_index1 != TLS_OUT_OF_INDEXES, "TlsAlloc failed\n");
1059 /* Slot indices should be different even if created in different
1060 threads. */
1061 ok(TLS_index0 != TLS_index1, "TlsAlloc failed\n");
1063 /* Both slots should be initialized to NULL */
1064 val = TlsGetValue(TLS_index0);
1065 ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
1066 ok(val == NULL, "TLS slot not initialized correctly\n");
1068 val = TlsGetValue(TLS_index1);
1069 ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
1070 ok(val == NULL, "TLS slot not initialized correctly\n");
1072 resync_after_run();
1074 if (sync_threads_and_run_one(0, id))
1076 val = TlsGetValue(TLS_index0);
1077 ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
1078 ok(val == NULL, "TLS slot not initialized correctly\n");
1080 val = TlsGetValue(TLS_index1);
1081 ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
1082 ok(val == NULL, "TLS slot not initialized correctly\n");
1084 ret = TlsSetValue(TLS_index0, (LPVOID) 1);
1085 ok(ret, "TlsSetValue failed\n");
1087 ret = TlsSetValue(TLS_index1, (LPVOID) 2);
1088 ok(ret, "TlsSetValue failed\n");
1090 val = TlsGetValue(TLS_index0);
1091 ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
1092 ok(val == (LPVOID) 1, "TLS slot not initialized correctly\n");
1094 val = TlsGetValue(TLS_index1);
1095 ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
1096 ok(val == (LPVOID) 2, "TLS slot not initialized correctly\n");
1098 resync_after_run();
1100 if (sync_threads_and_run_one(1, id))
1102 val = TlsGetValue(TLS_index0);
1103 ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
1104 ok(val == NULL, "TLS slot not initialized correctly\n");
1106 val = TlsGetValue(TLS_index1);
1107 ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
1108 ok(val == NULL, "TLS slot not initialized correctly\n");
1110 ret = TlsSetValue(TLS_index0, (LPVOID) 3);
1111 ok(ret, "TlsSetValue failed\n");
1113 ret = TlsSetValue(TLS_index1, (LPVOID) 4);
1114 ok(ret, "TlsSetValue failed\n");
1116 val = TlsGetValue(TLS_index0);
1117 ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
1118 ok(val == (LPVOID) 3, "TLS slot not initialized correctly\n");
1120 val = TlsGetValue(TLS_index1);
1121 ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
1122 ok(val == (LPVOID) 4, "TLS slot not initialized correctly\n");
1124 resync_after_run();
1126 if (sync_threads_and_run_one(0, id))
1128 HANDLE thread;
1129 DWORD waitret, tid;
1131 val = TlsGetValue(TLS_index0);
1132 ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
1133 ok(val == (LPVOID) 1, "TLS slot not initialized correctly\n");
1135 val = TlsGetValue(TLS_index1);
1136 ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
1137 ok(val == (LPVOID) 2, "TLS slot not initialized correctly\n");
1139 thread = CreateThread(NULL, 0, TLS_InheritanceProc, 0, 0, &tid);
1140 ok(thread != NULL, "CreateThread failed\n");
1141 waitret = WaitForSingleObject(thread, 60000);
1142 ok(waitret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
1143 CloseHandle(thread);
1145 ret = TlsFree(TLS_index0);
1146 ok(ret, "TlsFree failed\n");
1148 resync_after_run();
1150 if (sync_threads_and_run_one(1, id))
1152 ret = TlsFree(TLS_index1);
1153 ok(ret, "TlsFree failed\n");
1155 resync_after_run();
1157 return 0;
1160 static void test_TLS(void)
1162 HANDLE threads[2];
1163 LONG i;
1164 DWORD ret;
1165 BOOL suc;
1167 init_thread_sync_helpers(2);
1169 /* Allocate a TLS slot in the main thread to test for inheritance. */
1170 TLS_main = TlsAlloc();
1171 ok(TLS_main != TLS_OUT_OF_INDEXES, "TlsAlloc failed\n");
1172 suc = TlsSetValue(TLS_main, (LPVOID) 4114);
1173 ok(suc, "TlsSetValue failed\n");
1175 for (i = 0; i < 2; ++i)
1177 DWORD tid;
1179 threads[i] = CreateThread(NULL, 0, TLS_ThreadProc, (LPVOID) i, 0, &tid);
1180 ok(threads[i] != NULL, "CreateThread failed\n");
1183 ret = WaitForMultipleObjects(2, threads, TRUE, 60000);
1184 ok(ret == WAIT_OBJECT_0, "WaitForMultipleObjects failed\n");
1186 for (i = 0; i < 2; ++i)
1187 CloseHandle(threads[i]);
1189 suc = TlsFree(TLS_main);
1190 ok(suc, "TlsFree failed\n");
1191 cleanup_thread_sync_helpers();
1194 START_TEST(thread)
1196 HINSTANCE lib;
1197 int argc;
1198 char **argv;
1199 argc = winetest_get_mainargs( &argv );
1200 /* Neither Cygwin nor mingW export OpenThread, so do a dynamic check
1201 so that the compile passes
1203 lib=GetModuleHandleA("kernel32.dll");
1204 ok(lib!=NULL,"Couldn't get a handle for kernel32.dll\n");
1205 pGetThreadPriorityBoost=(GetThreadPriorityBoost_t)GetProcAddress(lib,"GetThreadPriorityBoost");
1206 pOpenThread=(OpenThread_t)GetProcAddress(lib,"OpenThread");
1207 pQueueUserWorkItem=(QueueUserWorkItem_t)GetProcAddress(lib,"QueueUserWorkItem");
1208 pSetThreadIdealProcessor=(SetThreadIdealProcessor_t)GetProcAddress(lib,"SetThreadIdealProcessor");
1209 pSetThreadPriorityBoost=(SetThreadPriorityBoost_t)GetProcAddress(lib,"SetThreadPriorityBoost");
1210 pRegisterWaitForSingleObject=(RegisterWaitForSingleObject_t)GetProcAddress(lib,"RegisterWaitForSingleObject");
1211 pUnregisterWait=(UnregisterWait_t)GetProcAddress(lib,"UnregisterWait");
1213 if (argc >= 3)
1215 if (!strcmp(argv[2], "sleep"))
1217 HANDLE hAddrEvents[2];
1218 create_function_addr_events(hAddrEvents);
1219 SetEvent(hAddrEvents[0]);
1220 SetEvent(hAddrEvents[1]);
1221 Sleep(5000); /* spawned process runs for at most 5 seconds */
1222 return;
1224 while (1)
1226 HANDLE hThread;
1227 DWORD tid;
1228 hThread = CreateThread(NULL, 0, threadFunc2, NULL, 0, &tid);
1229 ok(hThread != NULL, "CreateThread failed, error %u\n",
1230 GetLastError());
1231 ok(WaitForSingleObject(hThread, 200) == WAIT_OBJECT_0,
1232 "Thread did not exit in time\n");
1233 if (hThread == NULL) break;
1234 CloseHandle(hThread);
1236 return;
1239 test_CreateRemoteThread();
1240 test_CreateThread_basic();
1241 test_CreateThread_suspended();
1242 test_SuspendThread();
1243 test_TerminateThread();
1244 test_CreateThread_stack();
1245 test_thread_priority();
1246 test_GetThreadTimes();
1247 test_thread_processor();
1248 test_GetThreadExitCode();
1249 #ifdef __i386__
1250 test_SetThreadContext();
1251 #endif
1252 test_QueueUserWorkItem();
1253 test_RegisterWaitForSingleObject();
1254 test_TLS();