revert 17709 for it break streach for windows mode. That why I did only got black...
[reactos.git] / reactos / regtests / winetests / kernel32 / thread.c
1 /*
2 * Unit test suite for directory functions.
3 *
4 * Copyright 2002 Geoffrey Hausheer
5 *
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.
10 *
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.
15 *
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
19 */
20
21 /* Define _WIN32_WINNT to get SetThreadIdealProcessor on Windows */
22 #define _WIN32_WINNT 0x0500
23
24 #include <stdarg.h>
25
26 #include "wine/test.h"
27 #include <windef.h>
28 #include <winbase.h>
29 #include <winnt.h>
30 #include <winerror.h>
31
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
38
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
44 */
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
54
55 typedef BOOL (WINAPI *GetThreadPriorityBoost_t)(HANDLE,PBOOL);
56 static GetThreadPriorityBoost_t pGetThreadPriorityBoost=NULL;
57
58 typedef HANDLE (WINAPI *OpenThread_t)(DWORD,BOOL,DWORD);
59 static OpenThread_t pOpenThread=NULL;
60
61 typedef DWORD (WINAPI *SetThreadIdealProcessor_t)(HANDLE,DWORD);
62 static SetThreadIdealProcessor_t pSetThreadIdealProcessor=NULL;
63
64 typedef BOOL (WINAPI *SetThreadPriorityBoost_t)(HANDLE,BOOL);
65 static SetThreadPriorityBoost_t pSetThreadPriorityBoost=NULL;
66
67 /* Functions not tested yet:
68 AttachThreadInput
69 CreateRemoteThread
70 SetThreadContext
71 SwitchToThread
72
73 In addition there are no checks that the inheritance works properly in
74 CreateThread
75 */
76
77 DWORD tlsIndex;
78
79 typedef struct {
80 int threadnum;
81 HANDLE *event;
82 DWORD *threadmem;
83 } t1Struct;
84
85 /* WinME supports OpenThread but doesn't know about access restrictions so
86 we require them to be either completly ignored or always obeyed.
87 */
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"))
98
99 /* Basic test that simulatneous threads can access shared memory,
100 that the thread local storage routines work correctly, and that
101 threads actually run concurrently
102 */
103 static DWORD WINAPI threadFunc1(LPVOID p)
104 {
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
113 */
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) ;
121 }
122 /* Check that noone cahnged our tls memory */
123 ok((int)TlsGetValue(tlsIndex)-1==tstruct->threadnum,
124 "TlsGetValue failed\n");
125 return NUM_THREADS+tstruct->threadnum;
126 }
127
128 static DWORD WINAPI threadFunc2(LPVOID p)
129 {
130 return 99;
131 }
132
133 static DWORD WINAPI threadFunc3(LPVOID p)
134 {
135 HANDLE thread;
136 thread=GetCurrentThread();
137 SuspendThread(thread);
138 return 99;
139 }
140
141 static DWORD WINAPI threadFunc4(LPVOID p)
142 {
143 HANDLE event = (HANDLE)p;
144 if(event != NULL) {
145 SetEvent(event);
146 }
147 Sleep(99000);
148 return 0;
149 }
150
151 #if CHECK_STACK
152 static DWORD WINAPI threadFunc5(LPVOID p)
153 {
154 DWORD *exitCode = (DWORD *)p;
155 SYSTEM_INFO sysInfo;
156 sysInfo.dwPageSize=0;
157 GetSystemInfo(&sysInfo);
158 *exitCode=0;
159 __TRY
160 {
161 alloca(2*sysInfo.dwPageSize);
162 }
163 __EXCEPT(1) {
164 *exitCode=1;
165 }
166 __ENDTRY
167 return 0;
168 }
169 #endif
170
171 /* Check basic funcationality of CreateThread and Tls* functions */
172 static VOID test_CreateThread_basic(void)
173 {
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 /* Retrieve current Thread ID for later comparisons */
182 curthreadId=GetCurrentThreadId();
183 /* Allocate some local storage */
184 ok((tlsIndex=TlsAlloc())!=TLS_OUT_OF_INDEXES,"TlsAlloc failed\n");
185 /* Create events for thread synchronization */
186 for(i=0;i<NUM_THREADS;i++) {
187 threadmem[i]=0;
188 /* Note that it doesn't matter what type of event we chose here. This
189 test isn't trying to thoroughly test events
190 */
191 event[i]=CreateEventA(NULL,TRUE,FALSE,NULL);
192 tstruct[i].threadnum=i;
193 tstruct[i].threadmem=threadmem;
194 tstruct[i].event=event;
195 }
196
197 /* Test that passing arguments to threads works okay */
198 for(i=0;i<NUM_THREADS;i++) {
199 thread[i] = CreateThread(NULL,0,threadFunc1,
200 &tstruct[i],0,&threadid[i]);
201 ok(thread[i]!=NULL,"Create Thread failed\n");
202 }
203 /* Test that the threads actually complete */
204 for(i=0;i<NUM_THREADS;i++) {
205 error=WaitForSingleObject(thread[i],5000);
206 ok(error==WAIT_OBJECT_0, "Thread did not complete within timelimit\n");
207 if(error!=WAIT_OBJECT_0) {
208 TerminateThread(thread[i],i+NUM_THREADS);
209 }
210 ok(GetExitCodeThread(thread[i],&exitCode),"Could not retrieve ext code\n");
211 ok(exitCode==i+NUM_THREADS,"Thread returned an incorrect exit code\n");
212 }
213 /* Test that each thread executed in its parent's address space
214 (it was able to change threadmem and pass that change back to its parent)
215 and that each thread id was independant). Note that we prove that the
216 threads actually execute concurrently by having them block on each other
217 in threadFunc1
218 */
219 for(i=0;i<NUM_THREADS;i++) {
220 error=0;
221 for(j=i+1;j<NUM_THREADS;j++) {
222 if (threadmem[i]==threadmem[j]) {
223 error=1;
224 }
225 }
226 ok(!error && threadmem[i]==threadid[i] && threadmem[i]!=curthreadId,
227 "Thread did not execute successfully\n");
228 ok(CloseHandle(thread[i])!=0,"CloseHandle failed\n");
229 }
230 ok(TlsFree(tlsIndex)!=0,"TlsFree failed\n");
231 }
232
233 /* Check that using the CREATE_SUSPENDED flag works */
234 static VOID test_CreateThread_suspended(void)
235 {
236 HANDLE thread;
237 DWORD threadId;
238 int error;
239
240 thread = CreateThread(NULL,0,threadFunc2,NULL,
241 CREATE_SUSPENDED,&threadId);
242 ok(thread!=NULL,"Create Thread failed\n");
243 /* Check that the thread is suspended */
244 ok(SuspendThread(thread)==1,"Thread did not start suspended\n");
245 ok(ResumeThread(thread)==2,"Resume thread returned an invalid value\n");
246 /* Check that resume thread didn't actually start the thread. I can't think
247 of a better way of checking this than just waiting. I am not sure if this
248 will work on slow computers.
249 */
250 ok(WaitForSingleObject(thread,1000)==WAIT_TIMEOUT,
251 "ResumeThread should not have actually started the thread\n");
252 /* Now actually resume the thread and make sure that it actually completes*/
253 ok(ResumeThread(thread)==1,"Resume thread returned an invalid value\n");
254 ok((error=WaitForSingleObject(thread,1000))==WAIT_OBJECT_0,
255 "Thread did not resume\n");
256 if(error!=WAIT_OBJECT_0) {
257 TerminateThread(thread,1);
258 }
259 ok(CloseHandle(thread)!=0,"CloseHandle failed\n");
260 }
261
262 /* Check that SuspendThread and ResumeThread work */
263 static VOID test_SuspendThread(void)
264 {
265 HANDLE thread,access_thread;
266 DWORD threadId,exitCode,error;
267 int i;
268
269 thread = CreateThread(NULL,0,threadFunc3,NULL,
270 0,&threadId);
271 ok(thread!=NULL,"Create Thread failed\n");
272 /* Check that the thread is suspended */
273 /* Note that this is a polling method, and there is a race between
274 SuspendThread being called (in the child, and the loop below timing out,
275 so the test could fail on a heavily loaded or slow computer.
276 */
277 error=0;
278 for(i=0;error==0 && i<100;i++) {
279 error=SuspendThread(thread);
280 ResumeThread(thread);
281 if(error==0) {
282 Sleep(50);
283 i++;
284 }
285 }
286 ok(error==1,"SuspendThread did not work\n");
287 /* check that access restrictions are obeyed */
288 if (pOpenThread) {
289 access_thread=pOpenThread(THREAD_ALL_ACCESS & (~THREAD_SUSPEND_RESUME),
290 0,threadId);
291 ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
292 if (access_thread!=NULL) {
293 obey_ar(SuspendThread(access_thread)==~0UL);
294 obey_ar(ResumeThread(access_thread)==~0UL);
295 ok(CloseHandle(access_thread)!=0,"CloseHandle Failed\n");
296 }
297 }
298 /* Double check that the thread really is suspended */
299 ok((error=GetExitCodeThread(thread,&exitCode))!=0 && exitCode==STILL_ACTIVE,
300 "Thread did not really suspend\n");
301 /* Resume the thread, and make sure it actually completes */
302 ok(ResumeThread(thread)==1,"Resume thread returned an invalid value\n");
303 ok((error=WaitForSingleObject(thread,1000))==WAIT_OBJECT_0,
304 "Thread did not resume\n");
305 if(error!=WAIT_OBJECT_0) {
306 TerminateThread(thread,1);
307 }
308 /* Trying to suspend a terminated thread should fail */
309 error=SuspendThread(thread);
310 ok(error==~0UL, "wrong return code: %ld\n", error);
311 ok(GetLastError()==ERROR_ACCESS_DENIED || GetLastError()==ERROR_NO_MORE_ITEMS, "unexpected error code: %ld\n", GetLastError());
312
313 ok(CloseHandle(thread)!=0,"CloseHandle Failed\n");
314 }
315
316 /* Check that TerminateThread works properly
317 */
318 static VOID test_TerminateThread(void)
319 {
320 HANDLE thread,access_thread,event;
321 DWORD threadId,exitCode;
322 event=CreateEventA(NULL,TRUE,FALSE,NULL);
323 thread = CreateThread(NULL,0,threadFunc4,
324 (LPVOID)event, 0,&threadId);
325 ok(thread!=NULL,"Create Thread failed\n");
326 /* Terminate thread has a race condition in Wine. If the thread is terminated
327 before it starts, it leaves a process behind. Therefore, we wait for the
328 thread to signal that it has started. There is no easy way to force the
329 race to occur, so we don't try to find it.
330 */
331 ok(WaitForSingleObject(event,5000)==WAIT_OBJECT_0,
332 "TerminateThread didn't work\n");
333 /* check that access restrictions are obeyed */
334 if (pOpenThread) {
335 access_thread=pOpenThread(THREAD_ALL_ACCESS & (~THREAD_TERMINATE),
336 0,threadId);
337 ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
338 if (access_thread!=NULL) {
339 obey_ar(TerminateThread(access_thread,99)==0);
340 ok(CloseHandle(access_thread)!=0,"CloseHandle Failed\n");
341 }
342 }
343 /* terminate a job and make sure it terminates */
344 ok(TerminateThread(thread,99)!=0,"TerminateThread failed\n");
345 ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
346 "TerminateThread didn't work\n");
347 ok(GetExitCodeThread(thread,&exitCode)!=STILL_ACTIVE,
348 "TerminateThread should not leave the thread 'STILL_ACTIVE'\n");
349 ok(exitCode==99, "TerminateThread returned invalid exit code\n");
350 ok(CloseHandle(thread)!=0,"Error Closing thread handle\n");
351 }
352
353 /* Check if CreateThread obeys the specified stack size. This code does
354 not work properly, and is currently disabled
355 */
356 static VOID test_CreateThread_stack(void)
357 {
358 #if CHECK_STACK
359 /* The only way I know of to test the stack size is to use alloca
360 and __try/__except. However, this is probably not portable,
361 and I couldn't get it to work under Wine anyhow. However, here
362 is the code which should allow for testing that CreateThread
363 respects the stack-size limit
364 */
365 HANDLE thread;
366 DWORD threadId,exitCode;
367
368 SYSTEM_INFO sysInfo;
369 sysInfo.dwPageSize=0;
370 GetSystemInfo(&sysInfo);
371 ok(sysInfo.dwPageSize>0,"GetSystemInfo should return a valid page size\n");
372 thread = CreateThread(NULL,sysInfo.dwPageSize,
373 threadFunc5,&exitCode,
374 0,&threadId);
375 ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
376 "TerminateThread didn't work\n");
377 ok(exitCode==1,"CreateThread did not obey stack-size-limit\n");
378 ok(CloseHandle(thread)!=0,"CloseHandle failed\n");
379 #endif
380 }
381
382 /* Check whether setting/retrieving thread priorities works */
383 static VOID test_thread_priority(void)
384 {
385 HANDLE curthread,access_thread;
386 DWORD curthreadId,exitCode;
387 int min_priority=-2,max_priority=2;
388 BOOL disabled,rc;
389 int i;
390
391 curthread=GetCurrentThread();
392 curthreadId=GetCurrentThreadId();
393 /* Check thread priority */
394 /* NOTE: on Win2k/XP priority can be from -7 to 6. All other platforms it
395 is -2 to 2. However, even on a real Win2k system, using thread
396 priorities beyond the -2 to 2 range does not work. If you want to try
397 anyway, enable USE_EXTENDED_PRIORITIES
398 */
399 ok(GetThreadPriority(curthread)==THREAD_PRIORITY_NORMAL,
400 "GetThreadPriority Failed\n");
401
402 if (pOpenThread) {
403 /* check that access control is obeyed */
404 access_thread=pOpenThread(THREAD_ALL_ACCESS &
405 (~THREAD_QUERY_INFORMATION) & (~THREAD_SET_INFORMATION),
406 0,curthreadId);
407 ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
408 if (access_thread!=NULL) {
409 obey_ar(SetThreadPriority(access_thread,1)==0);
410 obey_ar(GetThreadPriority(access_thread)==THREAD_PRIORITY_ERROR_RETURN);
411 obey_ar(GetExitCodeThread(access_thread,&exitCode)==0);
412 ok(CloseHandle(access_thread),"Error Closing thread handle\n");
413 }
414 #if USE_EXTENDED_PRIORITIES
415 min_priority=-7; max_priority=6;
416 #endif
417 }
418 for(i=min_priority;i<=max_priority;i++) {
419 ok(SetThreadPriority(curthread,i)!=0,
420 "SetThreadPriority Failed for priority: %d\n",i);
421 ok(GetThreadPriority(curthread)==i,
422 "GetThreadPriority Failed for priority: %d\n",i);
423 }
424 ok(SetThreadPriority(curthread,THREAD_PRIORITY_TIME_CRITICAL)!=0,
425 "SetThreadPriority Failed\n");
426 ok(GetThreadPriority(curthread)==THREAD_PRIORITY_TIME_CRITICAL,
427 "GetThreadPriority Failed\n");
428 //ok(SetThreadPriority(curthread,THREAD_PRIORITY_IDLE)!=0,
429 //"SetThreadPriority Failed\n");
430 //ok(GetThreadPriority(curthread)==THREAD_PRIORITY_IDLE,
431 //"GetThreadPriority Failed\n");
432 ok(SetThreadPriority(curthread,0)!=0,"SetThreadPriority Failed\n");
433
434 /* Check thread priority boost */
435 if (!pGetThreadPriorityBoost || !pSetThreadPriorityBoost)
436 return; /* Win9x */
437
438 SetLastError(0xdeadbeef);
439 rc=pGetThreadPriorityBoost(curthread,&disabled);
440 if (rc==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
441 return; /* WinME */
442
443 /* check that access control is obeyed */
444 access_thread=pOpenThread(THREAD_ALL_ACCESS &
445 (~THREAD_QUERY_INFORMATION) & (~THREAD_SET_INFORMATION),
446 0,curthreadId);
447 ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
448 if (access_thread!=NULL) {
449 obey_ar(pSetThreadPriorityBoost(access_thread,1)==0);
450 obey_ar(pGetThreadPriorityBoost(access_thread,&disabled)==0);
451 ok(CloseHandle(access_thread),"Error Closing thread handle\n");
452 }
453
454 todo_wine {
455 ok(rc!=0,"error=%ld\n",GetLastError());
456
457 rc = pSetThreadPriorityBoost(curthread,1);
458 ok( rc != 0, "error=%ld\n",GetLastError());
459 rc=pGetThreadPriorityBoost(curthread,&disabled);
460 ok(rc!=0 && disabled==1,
461 "rc=%d error=%ld disabled=%d\n",rc,GetLastError(),disabled);
462
463 rc = pSetThreadPriorityBoost(curthread,0);
464 ok( rc != 0, "error=%ld\n",GetLastError());
465 rc=pGetThreadPriorityBoost(curthread,&disabled);
466 ok(rc!=0 && disabled==0,
467 "rc=%d error=%ld disabled=%d\n",rc,GetLastError(),disabled);
468 }
469 }
470
471 /* check the GetThreadTimes function */
472 static VOID test_GetThreadTimes(void)
473 {
474 HANDLE thread,access_thread=NULL;
475 FILETIME creationTime,exitTime,kernelTime,userTime;
476 DWORD threadId;
477 int error;
478
479 thread = CreateThread(NULL,0,threadFunc2,NULL,
480 CREATE_SUSPENDED,&threadId);
481
482 ok(thread!=NULL,"Create Thread failed\n");
483 /* check that access control is obeyed */
484 if (pOpenThread) {
485 access_thread=pOpenThread(THREAD_ALL_ACCESS &
486 (~THREAD_QUERY_INFORMATION), 0,threadId);
487 ok(access_thread!=NULL,
488 "OpenThread returned an invalid handle\n");
489 }
490 ok(ResumeThread(thread)==1,"Resume thread returned an invalid value\n");
491 ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
492 "ResumeThread didn't work\n");
493 creationTime.dwLowDateTime=99; creationTime.dwHighDateTime=99;
494 exitTime.dwLowDateTime=99; exitTime.dwHighDateTime=99;
495 kernelTime.dwLowDateTime=99; kernelTime.dwHighDateTime=99;
496 userTime.dwLowDateTime=99; userTime.dwHighDateTime=99;
497 /* GetThreadTimes should set all of the parameters passed to it */
498 error=GetThreadTimes(thread,&creationTime,&exitTime,
499 &kernelTime,&userTime);
500 if (error!=0 || GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
501 ok(error!=0,"GetThreadTimes failed\n");
502 ok(creationTime.dwLowDateTime!=99 || creationTime.dwHighDateTime!=99,
503 "creationTime was invalid\n");
504 ok(exitTime.dwLowDateTime!=99 || exitTime.dwHighDateTime!=99,
505 "exitTime was invalid\n");
506 ok(kernelTime.dwLowDateTime!=99 || kernelTime.dwHighDateTime!=99,
507 "kernelTimewas invalid\n");
508 ok(userTime.dwLowDateTime!=99 || userTime.dwHighDateTime!=99,
509 "userTime was invalid\n");
510 ok(CloseHandle(thread)!=0,"CloseHandle failed\n");
511 if(access_thread!=NULL)
512 {
513 error=GetThreadTimes(access_thread,&creationTime,&exitTime,
514 &kernelTime,&userTime);
515 obey_ar(error==0);
516 }
517 }
518 if(access_thread!=NULL) {
519 ok(CloseHandle(access_thread)!=0,"CloseHandle Failed\n");
520 }
521 }
522
523 /* Check the processor affinity functions */
524 /* NOTE: These functions should also be checked that they obey access control
525 */
526 static VOID test_thread_processor(void)
527 {
528 HANDLE curthread,curproc;
529 DWORD processMask,systemMask;
530 SYSTEM_INFO sysInfo;
531 int error=0;
532
533 sysInfo.dwNumberOfProcessors=0;
534 GetSystemInfo(&sysInfo);
535 ok(sysInfo.dwNumberOfProcessors>0,
536 "GetSystemInfo failed to return a valid # of processors\n");
537 /* Use the current Thread/process for all tests */
538 curthread=GetCurrentThread();
539 ok(curthread!=NULL,"GetCurrentThread failed\n");
540 curproc=GetCurrentProcess();
541 ok(curproc!=NULL,"GetCurrentProcess failed\n");
542 /* Check the Affinity Mask functions */
543 ok(GetProcessAffinityMask(curproc,&processMask,&systemMask)!=0,
544 "GetProcessAffinityMask failed\n");
545 ok(SetThreadAffinityMask(curthread,processMask)==processMask,
546 "SetThreadAffinityMask failed\n");
547 ok(SetThreadAffinityMask(curthread,processMask+1)==0,
548 "SetThreadAffinityMask passed for an illegal processor\n");
549 /* NOTE: This only works on WinNT/2000/XP) */
550 if (pSetThreadIdealProcessor) {
551 todo_wine {
552 SetLastError(0);
553 error=pSetThreadIdealProcessor(curthread,0);
554 if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
555 ok(error!=-1, "SetThreadIdealProcessor failed\n");
556 }
557 }
558 if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
559 error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS+1);
560 ok(error==-1,
561 "SetThreadIdealProcessor succeeded with an illegal processor #\n");
562 todo_wine {
563 error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS);
564 ok(error==0, "SetThreadIdealProcessor returned an incorrect value\n");
565 }
566 }
567 }
568 }
569
570 START_TEST(thread)
571 {
572 HINSTANCE lib;
573 /* Neither Cygwin nor mingW export OpenThread, so do a dynamic check
574 so that the compile passes
575 */
576 lib=LoadLibraryA("kernel32");
577 ok(lib!=NULL,"Couldn't load kernel32.dll\n");
578 pGetThreadPriorityBoost=(GetThreadPriorityBoost_t)GetProcAddress(lib,"GetThreadPriorityBoost");
579 pOpenThread=(OpenThread_t)GetProcAddress(lib,"OpenThread");
580 pSetThreadIdealProcessor=(SetThreadIdealProcessor_t)GetProcAddress(lib,"SetThreadIdealProcessor");
581 pSetThreadPriorityBoost=(SetThreadPriorityBoost_t)GetProcAddress(lib,"SetThreadPriorityBoost");
582 test_CreateThread_basic();
583 test_CreateThread_suspended();
584 test_SuspendThread();
585 test_TerminateThread();
586 test_CreateThread_stack();
587 test_thread_priority();
588 test_GetThreadTimes();
589 test_thread_processor();
590 }