Test CreateThread() for reception of NULL pointer to TID.
[wine.git] / dlls / kernel / tests / thread.c
blobed1224dc33146d802b7b9b68a95161e71850d1bf
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 /* Define _WIN32_WINNT to get SetThreadIdealProcessor on Windows */
22 #define _WIN32_WINNT 0x0500
24 #include <stdarg.h>
26 #include "wine/test.h"
27 #include <windef.h>
28 #include <winbase.h>
29 #include <winnt.h>
30 #include <winerror.h>
32 /* Specify the number of simultaneous threads to test */
33 #define NUM_THREADS 4
34 /* Specify whether to test the extended priorities for Win2k/XP */
35 #define USE_EXTENDED_PRIORITIES 0
36 /* Specify whether to test the stack allocation in CreateThread */
37 #define CHECK_STACK 0
39 /* Set CHECK_STACK to 1 if you want to try to test the stack-limit from
40 CreateThread. So far I have been unable to make this work, and
41 I am in doubt as to how portable it is. Also, according to MSDN,
42 you shouldn't mix C-run-time-libraries (i.e. alloca) with CreateThread.
43 Anyhow, the check is currently commented out
45 #if CHECK_STACK
46 # ifdef __try
47 # define __TRY __try
48 # define __EXCEPT __except
49 # define __ENDTRY
50 # else
51 # include "wine/exception.h"
52 # endif
53 #endif
55 typedef BOOL (WINAPI *GetThreadPriorityBoost_t)(HANDLE,PBOOL);
56 static GetThreadPriorityBoost_t pGetThreadPriorityBoost=NULL;
58 typedef HANDLE (WINAPI *OpenThread_t)(DWORD,BOOL,DWORD);
59 static OpenThread_t pOpenThread=NULL;
61 typedef DWORD (WINAPI *SetThreadIdealProcessor_t)(HANDLE,DWORD);
62 static SetThreadIdealProcessor_t pSetThreadIdealProcessor=NULL;
64 typedef BOOL (WINAPI *SetThreadPriorityBoost_t)(HANDLE,BOOL);
65 static SetThreadPriorityBoost_t pSetThreadPriorityBoost=NULL;
67 /* Functions not tested yet:
68 AttachThreadInput
69 CreateRemoteThread
70 SetThreadContext
71 SwitchToThread
73 In addition there are no checks that the inheritance works properly in
74 CreateThread
77 DWORD tlsIndex;
79 typedef struct {
80 int threadnum;
81 HANDLE *event;
82 DWORD *threadmem;
83 } t1Struct;
85 /* WinME supports OpenThread but doesn't know about access restrictions so
86 we require them to be either completely ignored or always obeyed.
88 INT obeying_ars = 0; /* -1 == no, 0 == dunno yet, 1 == yes */
89 #define obey_ar(x) \
90 (obeying_ars == 0 \
91 ? ((x) \
92 ? (obeying_ars = +1) \
93 : ((obeying_ars = -1), \
94 trace("not restricted, assuming consistent behaviour\n"))) \
95 : (obeying_ars < 0) \
96 ? ok(!(x), "access restrictions obeyed\n") \
97 : ok( (x), "access restrictions not obeyed\n"))
99 /* Basic test that simultaneous threads can access shared memory,
100 that the thread local storage routines work correctly, and that
101 threads actually run concurrently
103 static DWORD WINAPI threadFunc1(LPVOID p)
105 t1Struct *tstruct = (t1Struct *)p;
106 int i;
107 /* write our thread # into shared memory */
108 tstruct->threadmem[tstruct->threadnum]=GetCurrentThreadId();
109 ok(TlsSetValue(tlsIndex,(LPVOID)(tstruct->threadnum+1))!=0,
110 "TlsSetValue failed\n");
111 /* The threads synchronize before terminating. This is done by
112 Signaling an event, and waiting for all events to occur
114 SetEvent(tstruct->event[tstruct->threadnum]);
115 WaitForMultipleObjects(NUM_THREADS,tstruct->event,TRUE,INFINITE);
116 /* Double check that all threads really did run by validating that
117 they have all written to the shared memory. There should be no race
118 here, since all threads were synchronized after the write.*/
119 for(i=0;i<NUM_THREADS;i++) {
120 while(tstruct->threadmem[i]==0) ;
122 /* Check that noone changed our tls memory */
123 ok((int)TlsGetValue(tlsIndex)-1==tstruct->threadnum,
124 "TlsGetValue failed\n");
125 return NUM_THREADS+tstruct->threadnum;
128 static DWORD WINAPI threadFunc2(LPVOID p)
130 return 99;
133 static DWORD WINAPI threadFunc3(LPVOID p)
135 HANDLE thread;
136 thread=GetCurrentThread();
137 SuspendThread(thread);
138 return 99;
141 static DWORD WINAPI threadFunc4(LPVOID p)
143 HANDLE event = (HANDLE)p;
144 if(event != NULL) {
145 SetEvent(event);
147 Sleep(99000);
148 return 0;
151 #if CHECK_STACK
152 static DWORD WINAPI threadFunc5(LPVOID p)
154 DWORD *exitCode = (DWORD *)p;
155 SYSTEM_INFO sysInfo;
156 sysInfo.dwPageSize=0;
157 GetSystemInfo(&sysInfo);
158 *exitCode=0;
159 __TRY
161 alloca(2*sysInfo.dwPageSize);
163 __EXCEPT(1) {
164 *exitCode=1;
166 __ENDTRY
167 return 0;
169 #endif
171 /* Check basic funcationality of CreateThread and Tls* functions */
172 static VOID test_CreateThread_basic(void)
174 HANDLE thread[NUM_THREADS],event[NUM_THREADS];
175 DWORD threadid[NUM_THREADS],curthreadId;
176 DWORD threadmem[NUM_THREADS];
177 DWORD exitCode;
178 t1Struct tstruct[NUM_THREADS];
179 int error;
180 DWORD i,j;
181 DWORD GLE, ret;
183 /* Retrieve current Thread ID for later comparisons */
184 curthreadId=GetCurrentThreadId();
185 /* Allocate some local storage */
186 ok((tlsIndex=TlsAlloc())!=TLS_OUT_OF_INDEXES,"TlsAlloc failed\n");
187 /* Create events for thread synchronization */
188 for(i=0;i<NUM_THREADS;i++) {
189 threadmem[i]=0;
190 /* Note that it doesn't matter what type of event we chose here. This
191 test isn't trying to thoroughly test events
193 event[i]=CreateEventA(NULL,TRUE,FALSE,NULL);
194 tstruct[i].threadnum=i;
195 tstruct[i].threadmem=threadmem;
196 tstruct[i].event=event;
199 /* Test that passing arguments to threads works okay */
200 for(i=0;i<NUM_THREADS;i++) {
201 thread[i] = CreateThread(NULL,0,threadFunc1,
202 &tstruct[i],0,&threadid[i]);
203 ok(thread[i]!=NULL,"Create Thread failed\n");
205 /* Test that the threads actually complete */
206 for(i=0;i<NUM_THREADS;i++) {
207 error=WaitForSingleObject(thread[i],5000);
208 ok(error==WAIT_OBJECT_0, "Thread did not complete within timelimit\n");
209 if(error!=WAIT_OBJECT_0) {
210 TerminateThread(thread[i],i+NUM_THREADS);
212 ok(GetExitCodeThread(thread[i],&exitCode),"Could not retrieve ext code\n");
213 ok(exitCode==i+NUM_THREADS,"Thread returned an incorrect exit code\n");
215 /* Test that each thread executed in its parent's address space
216 (it was able to change threadmem and pass that change back to its parent)
217 and that each thread id was independant). Note that we prove that the
218 threads actually execute concurrently by having them block on each other
219 in threadFunc1
221 for(i=0;i<NUM_THREADS;i++) {
222 error=0;
223 for(j=i+1;j<NUM_THREADS;j++) {
224 if (threadmem[i]==threadmem[j]) {
225 error=1;
228 ok(!error && threadmem[i]==threadid[i] && threadmem[i]!=curthreadId,
229 "Thread did not execute successfully\n");
230 ok(CloseHandle(thread[i])!=0,"CloseHandle failed\n");
232 ok(TlsFree(tlsIndex)!=0,"TlsFree failed\n");
234 /* Test how passing NULL as a pointer to threadid works */
235 SetLastError(0xFACEaBAD);
236 thread[0] = CreateThread(NULL,0,threadFunc2,NULL,0,NULL);
237 GLE = GetLastError();
238 if (thread[0]) { /* NT */
239 ok(GLE==0xFACEaBAD, "CreateThread set last error to %ld, expected 4207848365", GLE);
240 ret = WaitForSingleObject(thread[0],100);
241 ok(ret==WAIT_OBJECT_0, "threadFunc2 did not exit during 100 ms\n");
242 ret = GetExitCodeThread(thread[0],&exitCode);
243 ok(ret!=0, "GetExitCodeThread returned %ld (expected nonzero)\n", ret);
244 ok(exitCode==99, "threadFunc2 exited with code: %ld (expected 99)\n", exitCode);
245 ok(CloseHandle(thread[0])!=0,"Error closing thread handle\n");
247 else { /* 9x */
248 ok(GLE==ERROR_INVALID_PARAMETER, "CreateThread set last error to %ld, expected 87", GLE);
252 /* Check that using the CREATE_SUSPENDED flag works */
253 static VOID test_CreateThread_suspended(void)
255 HANDLE thread;
256 DWORD threadId;
257 int error;
259 thread = CreateThread(NULL,0,threadFunc2,NULL,
260 CREATE_SUSPENDED,&threadId);
261 ok(thread!=NULL,"Create Thread failed\n");
262 /* Check that the thread is suspended */
263 ok(SuspendThread(thread)==1,"Thread did not start suspended\n");
264 ok(ResumeThread(thread)==2,"Resume thread returned an invalid value\n");
265 /* Check that resume thread didn't actually start the thread. I can't think
266 of a better way of checking this than just waiting. I am not sure if this
267 will work on slow computers.
269 ok(WaitForSingleObject(thread,1000)==WAIT_TIMEOUT,
270 "ResumeThread should not have actually started the thread\n");
271 /* Now actually resume the thread and make sure that it actually completes*/
272 ok(ResumeThread(thread)==1,"Resume thread returned an invalid value\n");
273 ok((error=WaitForSingleObject(thread,1000))==WAIT_OBJECT_0,
274 "Thread did not resume\n");
275 if(error!=WAIT_OBJECT_0) {
276 TerminateThread(thread,1);
278 ok(CloseHandle(thread)!=0,"CloseHandle failed\n");
281 /* Check that SuspendThread and ResumeThread work */
282 static VOID test_SuspendThread(void)
284 HANDLE thread,access_thread;
285 DWORD threadId,exitCode,error;
286 int i;
288 thread = CreateThread(NULL,0,threadFunc3,NULL,
289 0,&threadId);
290 ok(thread!=NULL,"Create Thread failed\n");
291 /* Check that the thread is suspended */
292 /* Note that this is a polling method, and there is a race between
293 SuspendThread being called (in the child, and the loop below timing out,
294 so the test could fail on a heavily loaded or slow computer.
296 error=0;
297 for(i=0;error==0 && i<100;i++) {
298 error=SuspendThread(thread);
299 ResumeThread(thread);
300 if(error==0) {
301 Sleep(50);
302 i++;
305 ok(error==1,"SuspendThread did not work\n");
306 /* check that access restrictions are obeyed */
307 if (pOpenThread) {
308 access_thread=pOpenThread(THREAD_ALL_ACCESS & (~THREAD_SUSPEND_RESUME),
309 0,threadId);
310 ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
311 if (access_thread!=NULL) {
312 obey_ar(SuspendThread(access_thread)==~0U);
313 obey_ar(ResumeThread(access_thread)==~0U);
314 ok(CloseHandle(access_thread)!=0,"CloseHandle Failed\n");
317 /* Double check that the thread really is suspended */
318 ok((error=GetExitCodeThread(thread,&exitCode))!=0 && exitCode==STILL_ACTIVE,
319 "Thread did not really suspend\n");
320 /* Resume the thread, and make sure it actually completes */
321 ok(ResumeThread(thread)==1,"Resume thread returned an invalid value\n");
322 ok((error=WaitForSingleObject(thread,1000))==WAIT_OBJECT_0,
323 "Thread did not resume\n");
324 if(error!=WAIT_OBJECT_0) {
325 TerminateThread(thread,1);
327 /* Trying to suspend a terminated thread should fail */
328 error=SuspendThread(thread);
329 ok(error==~0U, "wrong return code: %ld\n", error);
330 ok(GetLastError()==ERROR_ACCESS_DENIED || GetLastError()==ERROR_NO_MORE_ITEMS, "unexpected error code: %ld\n", GetLastError());
332 ok(CloseHandle(thread)!=0,"CloseHandle Failed\n");
335 /* Check that TerminateThread works properly
337 static VOID test_TerminateThread(void)
339 HANDLE thread,access_thread,event;
340 DWORD threadId,exitCode;
341 event=CreateEventA(NULL,TRUE,FALSE,NULL);
342 thread = CreateThread(NULL,0,threadFunc4,
343 (LPVOID)event, 0,&threadId);
344 ok(thread!=NULL,"Create Thread failed\n");
345 /* TerminateThread has a race condition in Wine. If the thread is terminated
346 before it starts, it leaves a process behind. Therefore, we wait for the
347 thread to signal that it has started. There is no easy way to force the
348 race to occur, so we don't try to find it.
350 ok(WaitForSingleObject(event,5000)==WAIT_OBJECT_0,
351 "TerminateThread didn't work\n");
352 /* check that access restrictions are obeyed */
353 if (pOpenThread) {
354 access_thread=pOpenThread(THREAD_ALL_ACCESS & (~THREAD_TERMINATE),
355 0,threadId);
356 ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
357 if (access_thread!=NULL) {
358 obey_ar(TerminateThread(access_thread,99)==0);
359 ok(CloseHandle(access_thread)!=0,"CloseHandle Failed\n");
362 /* terminate a job and make sure it terminates */
363 ok(TerminateThread(thread,99)!=0,"TerminateThread failed\n");
364 ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
365 "TerminateThread didn't work\n");
366 ok(GetExitCodeThread(thread,&exitCode)!=STILL_ACTIVE,
367 "TerminateThread should not leave the thread 'STILL_ACTIVE'\n");
368 ok(exitCode==99, "TerminateThread returned invalid exit code\n");
369 ok(CloseHandle(thread)!=0,"Error Closing thread handle\n");
372 /* Check if CreateThread obeys the specified stack size. This code does
373 not work properly, and is currently disabled
375 static VOID test_CreateThread_stack(void)
377 #if CHECK_STACK
378 /* The only way I know of to test the stack size is to use alloca
379 and __try/__except. However, this is probably not portable,
380 and I couldn't get it to work under Wine anyhow. However, here
381 is the code which should allow for testing that CreateThread
382 respects the stack-size limit
384 HANDLE thread;
385 DWORD threadId,exitCode;
387 SYSTEM_INFO sysInfo;
388 sysInfo.dwPageSize=0;
389 GetSystemInfo(&sysInfo);
390 ok(sysInfo.dwPageSize>0,"GetSystemInfo should return a valid page size\n");
391 thread = CreateThread(NULL,sysInfo.dwPageSize,
392 threadFunc5,&exitCode,
393 0,&threadId);
394 ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
395 "TerminateThread didn't work\n");
396 ok(exitCode==1,"CreateThread did not obey stack-size-limit\n");
397 ok(CloseHandle(thread)!=0,"CloseHandle failed\n");
398 #endif
401 /* Check whether setting/retrieving thread priorities works */
402 static VOID test_thread_priority(void)
404 HANDLE curthread,access_thread;
405 DWORD curthreadId,exitCode;
406 int min_priority=-2,max_priority=2;
407 BOOL disabled,rc;
408 int i;
410 curthread=GetCurrentThread();
411 curthreadId=GetCurrentThreadId();
412 /* Check thread priority */
413 /* NOTE: on Win2k/XP priority can be from -7 to 6. All other platforms it
414 is -2 to 2. However, even on a real Win2k system, using thread
415 priorities beyond the -2 to 2 range does not work. If you want to try
416 anyway, enable USE_EXTENDED_PRIORITIES
418 ok(GetThreadPriority(curthread)==THREAD_PRIORITY_NORMAL,
419 "GetThreadPriority Failed\n");
421 if (pOpenThread) {
422 /* check that access control is obeyed */
423 access_thread=pOpenThread(THREAD_ALL_ACCESS &
424 (~THREAD_QUERY_INFORMATION) & (~THREAD_SET_INFORMATION),
425 0,curthreadId);
426 ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
427 if (access_thread!=NULL) {
428 obey_ar(SetThreadPriority(access_thread,1)==0);
429 obey_ar(GetThreadPriority(access_thread)==THREAD_PRIORITY_ERROR_RETURN);
430 obey_ar(GetExitCodeThread(access_thread,&exitCode)==0);
431 ok(CloseHandle(access_thread),"Error Closing thread handle\n");
433 #if USE_EXTENDED_PRIORITIES
434 min_priority=-7; max_priority=6;
435 #endif
437 for(i=min_priority;i<=max_priority;i++) {
438 ok(SetThreadPriority(curthread,i)!=0,
439 "SetThreadPriority Failed for priority: %d\n",i);
440 ok(GetThreadPriority(curthread)==i,
441 "GetThreadPriority Failed for priority: %d\n",i);
443 ok(SetThreadPriority(curthread,THREAD_PRIORITY_TIME_CRITICAL)!=0,
444 "SetThreadPriority Failed\n");
445 ok(GetThreadPriority(curthread)==THREAD_PRIORITY_TIME_CRITICAL,
446 "GetThreadPriority Failed\n");
447 ok(SetThreadPriority(curthread,THREAD_PRIORITY_IDLE)!=0,
448 "SetThreadPriority Failed\n");
449 ok(GetThreadPriority(curthread)==THREAD_PRIORITY_IDLE,
450 "GetThreadPriority Failed\n");
451 ok(SetThreadPriority(curthread,0)!=0,"SetThreadPriority Failed\n");
453 /* Check thread priority boost */
454 if (!pGetThreadPriorityBoost || !pSetThreadPriorityBoost)
455 return; /* Win9x */
457 SetLastError(0xdeadbeef);
458 rc=pGetThreadPriorityBoost(curthread,&disabled);
459 if (rc==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
460 return; /* WinME */
462 /* check that access control is obeyed */
463 access_thread=pOpenThread(THREAD_ALL_ACCESS &
464 (~THREAD_QUERY_INFORMATION) & (~THREAD_SET_INFORMATION),
465 0,curthreadId);
466 ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
467 if (access_thread!=NULL) {
468 obey_ar(pSetThreadPriorityBoost(access_thread,1)==0);
469 obey_ar(pGetThreadPriorityBoost(access_thread,&disabled)==0);
470 ok(CloseHandle(access_thread),"Error Closing thread handle\n");
473 todo_wine {
474 ok(rc!=0,"error=%ld\n",GetLastError());
476 rc = pSetThreadPriorityBoost(curthread,1);
477 ok( rc != 0, "error=%ld\n",GetLastError());
478 rc=pGetThreadPriorityBoost(curthread,&disabled);
479 ok(rc!=0 && disabled==1,
480 "rc=%d error=%ld disabled=%d\n",rc,GetLastError(),disabled);
482 rc = pSetThreadPriorityBoost(curthread,0);
483 ok( rc != 0, "error=%ld\n",GetLastError());
484 rc=pGetThreadPriorityBoost(curthread,&disabled);
485 ok(rc!=0 && disabled==0,
486 "rc=%d error=%ld disabled=%d\n",rc,GetLastError(),disabled);
490 /* check the GetThreadTimes function */
491 static VOID test_GetThreadTimes(void)
493 HANDLE thread,access_thread=NULL;
494 FILETIME creationTime,exitTime,kernelTime,userTime;
495 DWORD threadId;
496 int error;
498 thread = CreateThread(NULL,0,threadFunc2,NULL,
499 CREATE_SUSPENDED,&threadId);
501 ok(thread!=NULL,"Create Thread failed\n");
502 /* check that access control is obeyed */
503 if (pOpenThread) {
504 access_thread=pOpenThread(THREAD_ALL_ACCESS &
505 (~THREAD_QUERY_INFORMATION), 0,threadId);
506 ok(access_thread!=NULL,
507 "OpenThread returned an invalid handle\n");
509 ok(ResumeThread(thread)==1,"Resume thread returned an invalid value\n");
510 ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
511 "ResumeThread didn't work\n");
512 creationTime.dwLowDateTime=99; creationTime.dwHighDateTime=99;
513 exitTime.dwLowDateTime=99; exitTime.dwHighDateTime=99;
514 kernelTime.dwLowDateTime=99; kernelTime.dwHighDateTime=99;
515 userTime.dwLowDateTime=99; userTime.dwHighDateTime=99;
516 /* GetThreadTimes should set all of the parameters passed to it */
517 error=GetThreadTimes(thread,&creationTime,&exitTime,
518 &kernelTime,&userTime);
519 if (error!=0 || GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
520 ok(error!=0,"GetThreadTimes failed\n");
521 ok(creationTime.dwLowDateTime!=99 || creationTime.dwHighDateTime!=99,
522 "creationTime was invalid\n");
523 ok(exitTime.dwLowDateTime!=99 || exitTime.dwHighDateTime!=99,
524 "exitTime was invalid\n");
525 ok(kernelTime.dwLowDateTime!=99 || kernelTime.dwHighDateTime!=99,
526 "kernelTimewas invalid\n");
527 ok(userTime.dwLowDateTime!=99 || userTime.dwHighDateTime!=99,
528 "userTime was invalid\n");
529 ok(CloseHandle(thread)!=0,"CloseHandle failed\n");
530 if(access_thread!=NULL)
532 error=GetThreadTimes(access_thread,&creationTime,&exitTime,
533 &kernelTime,&userTime);
534 obey_ar(error==0);
537 if(access_thread!=NULL) {
538 ok(CloseHandle(access_thread)!=0,"CloseHandle Failed\n");
542 /* Check the processor affinity functions */
543 /* NOTE: These functions should also be checked that they obey access control
545 static VOID test_thread_processor(void)
547 HANDLE curthread,curproc;
548 DWORD processMask,systemMask;
549 SYSTEM_INFO sysInfo;
550 int error=0;
552 sysInfo.dwNumberOfProcessors=0;
553 GetSystemInfo(&sysInfo);
554 ok(sysInfo.dwNumberOfProcessors>0,
555 "GetSystemInfo failed to return a valid # of processors\n");
556 /* Use the current Thread/process for all tests */
557 curthread=GetCurrentThread();
558 ok(curthread!=NULL,"GetCurrentThread failed\n");
559 curproc=GetCurrentProcess();
560 ok(curproc!=NULL,"GetCurrentProcess failed\n");
561 /* Check the Affinity Mask functions */
562 ok(GetProcessAffinityMask(curproc,&processMask,&systemMask)!=0,
563 "GetProcessAffinityMask failed\n");
564 ok(SetThreadAffinityMask(curthread,processMask)==processMask,
565 "SetThreadAffinityMask failed\n");
566 ok(SetThreadAffinityMask(curthread,processMask+1)==0,
567 "SetThreadAffinityMask passed for an illegal processor\n");
568 /* NOTE: This only works on WinNT/2000/XP) */
569 if (pSetThreadIdealProcessor) {
570 todo_wine {
571 SetLastError(0);
572 error=pSetThreadIdealProcessor(curthread,0);
573 if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
574 ok(error!=-1, "SetThreadIdealProcessor failed\n");
577 if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
578 error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS+1);
579 ok(error==-1,
580 "SetThreadIdealProcessor succeeded with an illegal processor #\n");
581 todo_wine {
582 error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS);
583 ok(error==0, "SetThreadIdealProcessor returned an incorrect value\n");
589 static VOID test_GetThreadExitCode(void)
591 DWORD exitCode, threadid;
592 DWORD GLE, ret;
593 HANDLE thread;
595 ret = GetExitCodeThread((HANDLE)0x2bad2bad,&exitCode);
596 ok(ret==0, "GetExitCodeThread returned non zero value: %ld\n", ret);
597 GLE = GetLastError();
598 ok(GLE==ERROR_INVALID_HANDLE, "GetLastError returned %ld (expected 6)\n", GLE);
600 thread = CreateThread(NULL,0,threadFunc2,NULL,0,&threadid);
601 ret = WaitForSingleObject(thread,100);
602 ok(ret==WAIT_OBJECT_0, "threadFunc2 did not exit during 100 ms\n");
603 ret = GetExitCodeThread(thread,&exitCode);
604 ok(ret==exitCode || ret==1,
605 "GetExitCodeThread returned %ld (expected 1 or %ld)\n", ret, exitCode);
606 ok(exitCode==99, "threadFunc2 exited with code %ld (expected 99)\n", exitCode);
607 ok(CloseHandle(thread)!=0,"Error closing thread handle\n");
610 START_TEST(thread)
612 HINSTANCE lib;
613 /* Neither Cygwin nor mingW export OpenThread, so do a dynamic check
614 so that the compile passes
616 lib=GetModuleHandleA("kernel32.dll");
617 ok(lib!=NULL,"Couldn't get a handle for kernel32.dll\n");
618 pGetThreadPriorityBoost=(GetThreadPriorityBoost_t)GetProcAddress(lib,"GetThreadPriorityBoost");
619 pOpenThread=(OpenThread_t)GetProcAddress(lib,"OpenThread");
620 pSetThreadIdealProcessor=(SetThreadIdealProcessor_t)GetProcAddress(lib,"SetThreadIdealProcessor");
621 pSetThreadPriorityBoost=(SetThreadPriorityBoost_t)GetProcAddress(lib,"SetThreadPriorityBoost");
622 test_CreateThread_basic();
623 test_CreateThread_suspended();
624 test_SuspendThread();
625 test_TerminateThread();
626 test_CreateThread_stack();
627 test_thread_priority();
628 test_GetThreadTimes();
629 test_thread_processor();
630 test_GetThreadExitCode();