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
26 #include "wine/test.h"
32 /* Specify the number of simultaneous threads to test */
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 */
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
48 # define __EXCEPT __except
51 # include "wine/exception.h"
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 BOOL (WINAPI
*QueueUserWorkItem_t
)(LPTHREAD_START_ROUTINE
,PVOID
,ULONG
);
62 static QueueUserWorkItem_t pQueueUserWorkItem
=NULL
;
64 typedef DWORD (WINAPI
*SetThreadIdealProcessor_t
)(HANDLE
,DWORD
);
65 static SetThreadIdealProcessor_t pSetThreadIdealProcessor
=NULL
;
67 typedef BOOL (WINAPI
*SetThreadPriorityBoost_t
)(HANDLE
,BOOL
);
68 static SetThreadPriorityBoost_t pSetThreadPriorityBoost
=NULL
;
70 /* Functions not tested yet:
76 In addition there are no checks that the inheritance works properly in
88 /* WinME supports OpenThread but doesn't know about access restrictions so
89 we require them to be either completely ignored or always obeyed.
91 INT obeying_ars
= 0; /* -1 == no, 0 == dunno yet, 1 == yes */
95 ? (obeying_ars = +1) \
96 : ((obeying_ars = -1), \
97 trace("not restricted, assuming consistent behaviour\n"))) \
99 ? ok(!(x), "access restrictions obeyed\n") \
100 : ok( (x), "access restrictions not obeyed\n"))
102 /* Basic test that simultaneous threads can access shared memory,
103 that the thread local storage routines work correctly, and that
104 threads actually run concurrently
106 static DWORD WINAPI
threadFunc1(LPVOID p
)
108 t1Struct
*tstruct
= (t1Struct
*)p
;
110 /* write our thread # into shared memory */
111 tstruct
->threadmem
[tstruct
->threadnum
]=GetCurrentThreadId();
112 ok(TlsSetValue(tlsIndex
,(LPVOID
)(tstruct
->threadnum
+1))!=0,
113 "TlsSetValue failed\n");
114 /* The threads synchronize before terminating. This is done by
115 Signaling an event, and waiting for all events to occur
117 SetEvent(tstruct
->event
[tstruct
->threadnum
]);
118 WaitForMultipleObjects(NUM_THREADS
,tstruct
->event
,TRUE
,INFINITE
);
119 /* Double check that all threads really did run by validating that
120 they have all written to the shared memory. There should be no race
121 here, since all threads were synchronized after the write.*/
122 for(i
=0;i
<NUM_THREADS
;i
++) {
123 while(tstruct
->threadmem
[i
]==0) ;
126 /* lstrlenA contains an exception handler so this makes sure exceptions work in threads */
127 ok( lstrlenA( (char *)0xdeadbeef ) == 0, "lstrlenA: unexpected success\n" );
129 /* Check that noone changed our tls memory */
130 ok((int)TlsGetValue(tlsIndex
)-1==tstruct
->threadnum
,
131 "TlsGetValue failed\n");
132 return NUM_THREADS
+tstruct
->threadnum
;
135 static DWORD WINAPI
threadFunc2(LPVOID p
)
140 static DWORD WINAPI
threadFunc3(LPVOID p
)
143 thread
=GetCurrentThread();
144 SuspendThread(thread
);
148 static DWORD WINAPI
threadFunc4(LPVOID p
)
150 HANDLE event
= (HANDLE
)p
;
159 static DWORD WINAPI
threadFunc5(LPVOID p
)
161 DWORD
*exitCode
= (DWORD
*)p
;
163 sysInfo
.dwPageSize
=0;
164 GetSystemInfo(&sysInfo
);
168 alloca(2*sysInfo
.dwPageSize
);
178 /* Check basic funcationality of CreateThread and Tls* functions */
179 static VOID
test_CreateThread_basic(void)
181 HANDLE thread
[NUM_THREADS
],event
[NUM_THREADS
];
182 DWORD threadid
[NUM_THREADS
],curthreadId
;
183 DWORD threadmem
[NUM_THREADS
];
185 t1Struct tstruct
[NUM_THREADS
];
190 /* lstrlenA contains an exception handler so this makes sure exceptions work in the main thread */
191 ok( lstrlenA( (char *)0xdeadbeef ) == 0, "lstrlenA: unexpected success\n" );
193 /* Retrieve current Thread ID for later comparisons */
194 curthreadId
=GetCurrentThreadId();
195 /* Allocate some local storage */
196 ok((tlsIndex
=TlsAlloc())!=TLS_OUT_OF_INDEXES
,"TlsAlloc failed\n");
197 /* Create events for thread synchronization */
198 for(i
=0;i
<NUM_THREADS
;i
++) {
200 /* Note that it doesn't matter what type of event we chose here. This
201 test isn't trying to thoroughly test events
203 event
[i
]=CreateEventA(NULL
,TRUE
,FALSE
,NULL
);
204 tstruct
[i
].threadnum
=i
;
205 tstruct
[i
].threadmem
=threadmem
;
206 tstruct
[i
].event
=event
;
209 /* Test that passing arguments to threads works okay */
210 for(i
=0;i
<NUM_THREADS
;i
++) {
211 thread
[i
] = CreateThread(NULL
,0,threadFunc1
,
212 &tstruct
[i
],0,&threadid
[i
]);
213 ok(thread
[i
]!=NULL
,"Create Thread failed\n");
215 /* Test that the threads actually complete */
216 for(i
=0;i
<NUM_THREADS
;i
++) {
217 error
=WaitForSingleObject(thread
[i
],5000);
218 ok(error
==WAIT_OBJECT_0
, "Thread did not complete within timelimit\n");
219 if(error
!=WAIT_OBJECT_0
) {
220 TerminateThread(thread
[i
],i
+NUM_THREADS
);
222 ok(GetExitCodeThread(thread
[i
],&exitCode
),"Could not retrieve ext code\n");
223 ok(exitCode
==i
+NUM_THREADS
,"Thread returned an incorrect exit code\n");
225 /* Test that each thread executed in its parent's address space
226 (it was able to change threadmem and pass that change back to its parent)
227 and that each thread id was independant). Note that we prove that the
228 threads actually execute concurrently by having them block on each other
231 for(i
=0;i
<NUM_THREADS
;i
++) {
233 for(j
=i
+1;j
<NUM_THREADS
;j
++) {
234 if (threadmem
[i
]==threadmem
[j
]) {
238 ok(!error
&& threadmem
[i
]==threadid
[i
] && threadmem
[i
]!=curthreadId
,
239 "Thread did not execute successfully\n");
240 ok(CloseHandle(thread
[i
])!=0,"CloseHandle failed\n");
242 ok(TlsFree(tlsIndex
)!=0,"TlsFree failed\n");
244 /* Test how passing NULL as a pointer to threadid works */
245 SetLastError(0xFACEaBAD);
246 thread
[0] = CreateThread(NULL
,0,threadFunc2
,NULL
,0,NULL
);
247 GLE
= GetLastError();
248 if (thread
[0]) { /* NT */
249 ok(GLE
==0xFACEaBAD, "CreateThread set last error to %ld, expected 4207848365\n", GLE
);
250 ret
= WaitForSingleObject(thread
[0],100);
251 ok(ret
==WAIT_OBJECT_0
, "threadFunc2 did not exit during 100 ms\n");
252 ret
= GetExitCodeThread(thread
[0],&exitCode
);
253 ok(ret
!=0, "GetExitCodeThread returned %ld (expected nonzero)\n", ret
);
254 ok(exitCode
==99, "threadFunc2 exited with code: %ld (expected 99)\n", exitCode
);
255 ok(CloseHandle(thread
[0])!=0,"Error closing thread handle\n");
258 ok(GLE
==ERROR_INVALID_PARAMETER
, "CreateThread set last error to %ld, expected 87\n", GLE
);
262 /* Check that using the CREATE_SUSPENDED flag works */
263 static VOID
test_CreateThread_suspended(void)
269 thread
= CreateThread(NULL
,0,threadFunc2
,NULL
,
270 CREATE_SUSPENDED
,&threadId
);
271 ok(thread
!=NULL
,"Create Thread failed\n");
272 /* Check that the thread is suspended */
273 ok(SuspendThread(thread
)==1,"Thread did not start suspended\n");
274 ok(ResumeThread(thread
)==2,"Resume thread returned an invalid value\n");
275 /* Check that resume thread didn't actually start the thread. I can't think
276 of a better way of checking this than just waiting. I am not sure if this
277 will work on slow computers.
279 ok(WaitForSingleObject(thread
,1000)==WAIT_TIMEOUT
,
280 "ResumeThread should not have actually started the thread\n");
281 /* Now actually resume the thread and make sure that it actually completes*/
282 ok(ResumeThread(thread
)==1,"Resume thread returned an invalid value\n");
283 ok((error
=WaitForSingleObject(thread
,1000))==WAIT_OBJECT_0
,
284 "Thread did not resume\n");
285 if(error
!=WAIT_OBJECT_0
) {
286 TerminateThread(thread
,1);
288 ok(CloseHandle(thread
)!=0,"CloseHandle failed\n");
291 /* Check that SuspendThread and ResumeThread work */
292 static VOID
test_SuspendThread(void)
294 HANDLE thread
,access_thread
;
295 DWORD threadId
,exitCode
,error
;
298 thread
= CreateThread(NULL
,0,threadFunc3
,NULL
,
300 ok(thread
!=NULL
,"Create Thread failed\n");
301 /* Check that the thread is suspended */
302 /* Note that this is a polling method, and there is a race between
303 SuspendThread being called (in the child, and the loop below timing out,
304 so the test could fail on a heavily loaded or slow computer.
307 for(i
=0;error
==0 && i
<100;i
++) {
308 error
=SuspendThread(thread
);
309 ResumeThread(thread
);
315 ok(error
==1,"SuspendThread did not work\n");
316 /* check that access restrictions are obeyed */
318 access_thread
=pOpenThread(THREAD_ALL_ACCESS
& (~THREAD_SUSPEND_RESUME
),
320 ok(access_thread
!=NULL
,"OpenThread returned an invalid handle\n");
321 if (access_thread
!=NULL
) {
322 obey_ar(SuspendThread(access_thread
)==~0U);
323 obey_ar(ResumeThread(access_thread
)==~0U);
324 ok(CloseHandle(access_thread
)!=0,"CloseHandle Failed\n");
327 /* Double check that the thread really is suspended */
328 ok((error
=GetExitCodeThread(thread
,&exitCode
))!=0 && exitCode
==STILL_ACTIVE
,
329 "Thread did not really suspend\n");
330 /* Resume the thread, and make sure it actually completes */
331 ok(ResumeThread(thread
)==1,"Resume thread returned an invalid value\n");
332 ok((error
=WaitForSingleObject(thread
,1000))==WAIT_OBJECT_0
,
333 "Thread did not resume\n");
334 if(error
!=WAIT_OBJECT_0
) {
335 TerminateThread(thread
,1);
337 /* Trying to suspend a terminated thread should fail */
338 error
=SuspendThread(thread
);
339 ok(error
==~0U, "wrong return code: %ld\n", error
);
340 ok(GetLastError()==ERROR_ACCESS_DENIED
|| GetLastError()==ERROR_NO_MORE_ITEMS
, "unexpected error code: %ld\n", GetLastError());
342 ok(CloseHandle(thread
)!=0,"CloseHandle Failed\n");
345 /* Check that TerminateThread works properly
347 static VOID
test_TerminateThread(void)
349 HANDLE thread
,access_thread
,event
;
350 DWORD threadId
,exitCode
;
351 event
=CreateEventA(NULL
,TRUE
,FALSE
,NULL
);
352 thread
= CreateThread(NULL
,0,threadFunc4
,
353 (LPVOID
)event
, 0,&threadId
);
354 ok(thread
!=NULL
,"Create Thread failed\n");
355 /* TerminateThread has a race condition in Wine. If the thread is terminated
356 before it starts, it leaves a process behind. Therefore, we wait for the
357 thread to signal that it has started. There is no easy way to force the
358 race to occur, so we don't try to find it.
360 ok(WaitForSingleObject(event
,5000)==WAIT_OBJECT_0
,
361 "TerminateThread didn't work\n");
362 /* check that access restrictions are obeyed */
364 access_thread
=pOpenThread(THREAD_ALL_ACCESS
& (~THREAD_TERMINATE
),
366 ok(access_thread
!=NULL
,"OpenThread returned an invalid handle\n");
367 if (access_thread
!=NULL
) {
368 obey_ar(TerminateThread(access_thread
,99)==0);
369 ok(CloseHandle(access_thread
)!=0,"CloseHandle Failed\n");
372 /* terminate a job and make sure it terminates */
373 ok(TerminateThread(thread
,99)!=0,"TerminateThread failed\n");
374 ok(WaitForSingleObject(thread
,5000)==WAIT_OBJECT_0
,
375 "TerminateThread didn't work\n");
376 ok(GetExitCodeThread(thread
,&exitCode
)!=STILL_ACTIVE
,
377 "TerminateThread should not leave the thread 'STILL_ACTIVE'\n");
378 ok(exitCode
==99, "TerminateThread returned invalid exit code\n");
379 ok(CloseHandle(thread
)!=0,"Error Closing thread handle\n");
382 /* Check if CreateThread obeys the specified stack size. This code does
383 not work properly, and is currently disabled
385 static VOID
test_CreateThread_stack(void)
388 /* The only way I know of to test the stack size is to use alloca
389 and __try/__except. However, this is probably not portable,
390 and I couldn't get it to work under Wine anyhow. However, here
391 is the code which should allow for testing that CreateThread
392 respects the stack-size limit
395 DWORD threadId
,exitCode
;
398 sysInfo
.dwPageSize
=0;
399 GetSystemInfo(&sysInfo
);
400 ok(sysInfo
.dwPageSize
>0,"GetSystemInfo should return a valid page size\n");
401 thread
= CreateThread(NULL
,sysInfo
.dwPageSize
,
402 threadFunc5
,&exitCode
,
404 ok(WaitForSingleObject(thread
,5000)==WAIT_OBJECT_0
,
405 "TerminateThread didn't work\n");
406 ok(exitCode
==1,"CreateThread did not obey stack-size-limit\n");
407 ok(CloseHandle(thread
)!=0,"CloseHandle failed\n");
411 /* Check whether setting/retrieving thread priorities works */
412 static VOID
test_thread_priority(void)
414 HANDLE curthread
,access_thread
;
415 DWORD curthreadId
,exitCode
;
416 int min_priority
=-2,max_priority
=2;
420 curthread
=GetCurrentThread();
421 curthreadId
=GetCurrentThreadId();
422 /* Check thread priority */
423 /* NOTE: on Win2k/XP priority can be from -7 to 6. All other platforms it
424 is -2 to 2. However, even on a real Win2k system, using thread
425 priorities beyond the -2 to 2 range does not work. If you want to try
426 anyway, enable USE_EXTENDED_PRIORITIES
428 ok(GetThreadPriority(curthread
)==THREAD_PRIORITY_NORMAL
,
429 "GetThreadPriority Failed\n");
432 /* check that access control is obeyed */
433 access_thread
=pOpenThread(THREAD_ALL_ACCESS
&
434 (~THREAD_QUERY_INFORMATION
) & (~THREAD_SET_INFORMATION
),
436 ok(access_thread
!=NULL
,"OpenThread returned an invalid handle\n");
437 if (access_thread
!=NULL
) {
438 obey_ar(SetThreadPriority(access_thread
,1)==0);
439 obey_ar(GetThreadPriority(access_thread
)==THREAD_PRIORITY_ERROR_RETURN
);
440 obey_ar(GetExitCodeThread(access_thread
,&exitCode
)==0);
441 ok(CloseHandle(access_thread
),"Error Closing thread handle\n");
443 #if USE_EXTENDED_PRIORITIES
444 min_priority
=-7; max_priority
=6;
447 for(i
=min_priority
;i
<=max_priority
;i
++) {
448 ok(SetThreadPriority(curthread
,i
)!=0,
449 "SetThreadPriority Failed for priority: %d\n",i
);
450 ok(GetThreadPriority(curthread
)==i
,
451 "GetThreadPriority Failed for priority: %d\n",i
);
453 ok(SetThreadPriority(curthread
,THREAD_PRIORITY_TIME_CRITICAL
)!=0,
454 "SetThreadPriority Failed\n");
455 ok(GetThreadPriority(curthread
)==THREAD_PRIORITY_TIME_CRITICAL
,
456 "GetThreadPriority Failed\n");
457 ok(SetThreadPriority(curthread
,THREAD_PRIORITY_IDLE
)!=0,
458 "SetThreadPriority Failed\n");
459 ok(GetThreadPriority(curthread
)==THREAD_PRIORITY_IDLE
,
460 "GetThreadPriority Failed\n");
461 ok(SetThreadPriority(curthread
,0)!=0,"SetThreadPriority Failed\n");
463 /* Check thread priority boost */
464 if (!pGetThreadPriorityBoost
|| !pSetThreadPriorityBoost
)
467 SetLastError(0xdeadbeef);
468 rc
=pGetThreadPriorityBoost(curthread
,&disabled
);
469 if (rc
==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED
)
472 /* check that access control is obeyed */
473 access_thread
=pOpenThread(THREAD_ALL_ACCESS
&
474 (~THREAD_QUERY_INFORMATION
) & (~THREAD_SET_INFORMATION
),
476 ok(access_thread
!=NULL
,"OpenThread returned an invalid handle\n");
477 if (access_thread
!=NULL
) {
478 obey_ar(pSetThreadPriorityBoost(access_thread
,1)==0);
479 obey_ar(pGetThreadPriorityBoost(access_thread
,&disabled
)==0);
480 ok(CloseHandle(access_thread
),"Error Closing thread handle\n");
484 ok(rc
!=0,"error=%ld\n",GetLastError());
486 rc
= pSetThreadPriorityBoost(curthread
,1);
487 ok( rc
!= 0, "error=%ld\n",GetLastError());
488 rc
=pGetThreadPriorityBoost(curthread
,&disabled
);
489 ok(rc
!=0 && disabled
==1,
490 "rc=%d error=%ld disabled=%d\n",rc
,GetLastError(),disabled
);
492 rc
= pSetThreadPriorityBoost(curthread
,0);
493 ok( rc
!= 0, "error=%ld\n",GetLastError());
494 rc
=pGetThreadPriorityBoost(curthread
,&disabled
);
495 ok(rc
!=0 && disabled
==0,
496 "rc=%d error=%ld disabled=%d\n",rc
,GetLastError(),disabled
);
500 /* check the GetThreadTimes function */
501 static VOID
test_GetThreadTimes(void)
503 HANDLE thread
,access_thread
=NULL
;
504 FILETIME creationTime
,exitTime
,kernelTime
,userTime
;
508 thread
= CreateThread(NULL
,0,threadFunc2
,NULL
,
509 CREATE_SUSPENDED
,&threadId
);
511 ok(thread
!=NULL
,"Create Thread failed\n");
512 /* check that access control is obeyed */
514 access_thread
=pOpenThread(THREAD_ALL_ACCESS
&
515 (~THREAD_QUERY_INFORMATION
), 0,threadId
);
516 ok(access_thread
!=NULL
,
517 "OpenThread returned an invalid handle\n");
519 ok(ResumeThread(thread
)==1,"Resume thread returned an invalid value\n");
520 ok(WaitForSingleObject(thread
,5000)==WAIT_OBJECT_0
,
521 "ResumeThread didn't work\n");
522 creationTime
.dwLowDateTime
=99; creationTime
.dwHighDateTime
=99;
523 exitTime
.dwLowDateTime
=99; exitTime
.dwHighDateTime
=99;
524 kernelTime
.dwLowDateTime
=99; kernelTime
.dwHighDateTime
=99;
525 userTime
.dwLowDateTime
=99; userTime
.dwHighDateTime
=99;
526 /* GetThreadTimes should set all of the parameters passed to it */
527 error
=GetThreadTimes(thread
,&creationTime
,&exitTime
,
528 &kernelTime
,&userTime
);
529 if (error
!=0 || GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED
) {
530 ok(error
!=0,"GetThreadTimes failed\n");
531 ok(creationTime
.dwLowDateTime
!=99 || creationTime
.dwHighDateTime
!=99,
532 "creationTime was invalid\n");
533 ok(exitTime
.dwLowDateTime
!=99 || exitTime
.dwHighDateTime
!=99,
534 "exitTime was invalid\n");
535 ok(kernelTime
.dwLowDateTime
!=99 || kernelTime
.dwHighDateTime
!=99,
536 "kernelTimewas invalid\n");
537 ok(userTime
.dwLowDateTime
!=99 || userTime
.dwHighDateTime
!=99,
538 "userTime was invalid\n");
539 ok(CloseHandle(thread
)!=0,"CloseHandle failed\n");
540 if(access_thread
!=NULL
)
542 error
=GetThreadTimes(access_thread
,&creationTime
,&exitTime
,
543 &kernelTime
,&userTime
);
547 if(access_thread
!=NULL
) {
548 ok(CloseHandle(access_thread
)!=0,"CloseHandle Failed\n");
552 /* Check the processor affinity functions */
553 /* NOTE: These functions should also be checked that they obey access control
555 static VOID
test_thread_processor(void)
557 HANDLE curthread
,curproc
;
558 DWORD processMask
,systemMask
;
562 sysInfo
.dwNumberOfProcessors
=0;
563 GetSystemInfo(&sysInfo
);
564 ok(sysInfo
.dwNumberOfProcessors
>0,
565 "GetSystemInfo failed to return a valid # of processors\n");
566 /* Use the current Thread/process for all tests */
567 curthread
=GetCurrentThread();
568 ok(curthread
!=NULL
,"GetCurrentThread failed\n");
569 curproc
=GetCurrentProcess();
570 ok(curproc
!=NULL
,"GetCurrentProcess failed\n");
571 /* Check the Affinity Mask functions */
572 ok(GetProcessAffinityMask(curproc
,&processMask
,&systemMask
)!=0,
573 "GetProcessAffinityMask failed\n");
574 ok(SetThreadAffinityMask(curthread
,processMask
)==processMask
,
575 "SetThreadAffinityMask failed\n");
576 ok(SetThreadAffinityMask(curthread
,processMask
+1)==0,
577 "SetThreadAffinityMask passed for an illegal processor\n");
578 /* NOTE: This only works on WinNT/2000/XP) */
579 if (pSetThreadIdealProcessor
) {
582 error
=pSetThreadIdealProcessor(curthread
,0);
583 if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED
) {
584 ok(error
!=-1, "SetThreadIdealProcessor failed\n");
587 if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED
) {
588 error
=pSetThreadIdealProcessor(curthread
,MAXIMUM_PROCESSORS
+1);
590 "SetThreadIdealProcessor succeeded with an illegal processor #\n");
592 error
=pSetThreadIdealProcessor(curthread
,MAXIMUM_PROCESSORS
);
593 ok(error
==0, "SetThreadIdealProcessor returned an incorrect value\n");
599 static VOID
test_GetThreadExitCode(void)
601 DWORD exitCode
, threadid
;
605 ret
= GetExitCodeThread((HANDLE
)0x2bad2bad,&exitCode
);
606 ok(ret
==0, "GetExitCodeThread returned non zero value: %ld\n", ret
);
607 GLE
= GetLastError();
608 ok(GLE
==ERROR_INVALID_HANDLE
, "GetLastError returned %ld (expected 6)\n", GLE
);
610 thread
= CreateThread(NULL
,0,threadFunc2
,NULL
,0,&threadid
);
611 ret
= WaitForSingleObject(thread
,100);
612 ok(ret
==WAIT_OBJECT_0
, "threadFunc2 did not exit during 100 ms\n");
613 ret
= GetExitCodeThread(thread
,&exitCode
);
614 ok(ret
==exitCode
|| ret
==1,
615 "GetExitCodeThread returned %ld (expected 1 or %ld)\n", ret
, exitCode
);
616 ok(exitCode
==99, "threadFunc2 exited with code %ld (expected 99)\n", exitCode
);
617 ok(CloseHandle(thread
)!=0,"Error closing thread handle\n");
622 static int test_value
= 0;
625 static void WINAPI
set_test_val( int val
)
630 static DWORD WINAPI
threadFunc6(LPVOID p
)
634 test_value
*= (int)p
;
638 static void test_SetThreadContext(void)
646 SetLastError(0xdeadbeef);
647 event
= CreateEvent( NULL
, TRUE
, FALSE
, NULL
);
648 thread
= CreateThread( NULL
, 0, threadFunc6
, (void *)2, 0, &threadid
);
649 ok( thread
!= NULL
, "CreateThread failed : (%ld)\n", GetLastError() );
652 trace("Thread creation failed, skipping rest of test\n");
655 WaitForSingleObject( event
, INFINITE
);
656 SuspendThread( thread
);
657 CloseHandle( event
);
659 ctx
.ContextFlags
= CONTEXT_FULL
;
660 SetLastError(0xdeadbeef);
661 ok( GetThreadContext( thread
, &ctx
), "GetThreadContext failed : (%ld)\n", GetLastError() );
663 /* simulate a call to set_test_val(10) */
664 stack
= (int *)ctx
.Esp
;
667 ctx
.Esp
-= 2 * sizeof(int *);
668 ctx
.Eip
= (DWORD
)set_test_val
;
669 SetLastError(0xdeadbeef);
670 ok( SetThreadContext( thread
, &ctx
), "SetThreadContext failed : (%ld)\n", GetLastError() );
672 SetLastError(0xdeadbeef);
673 prevcount
= ResumeThread( thread
);
674 ok ( prevcount
== 1, "Previous suspend count (%ld) instead of 1, last error : (%ld)\n",
675 prevcount
, GetLastError() );
677 WaitForSingleObject( thread
, INFINITE
);
678 ok( test_value
== 20, "test_value %d instead of 20\n", test_value
);
681 #endif /* __i386__ */
683 static HANDLE finish_event
;
684 static LONG times_executed
;
686 static DWORD CALLBACK
work_function(void *p
)
688 LONG executed
= InterlockedIncrement(×_executed
);
691 SetEvent(finish_event
);
695 static void test_QueueUserWorkItem(void)
701 /* QueueUserWorkItem not present on win9x */
702 if (!pQueueUserWorkItem
) return;
704 finish_event
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
706 before
= GetTickCount();
708 for (i
= 0; i
< 100; i
++)
710 BOOL ret
= pQueueUserWorkItem(work_function
, (void *)i
, WT_EXECUTEDEFAULT
);
711 ok(ret
, "QueueUserWorkItem failed with error %ld\n", GetLastError());
714 wait_result
= WaitForSingleObject(finish_event
, 10000);
716 after
= GetTickCount();
717 trace("100 QueueUserWorkItem calls took %ldms\n", after
- before
);
718 ok(wait_result
== WAIT_OBJECT_0
, "wait failed with error 0x%lx\n", wait_result
);
720 ok(times_executed
== 100, "didn't execute all of the work items\n");
726 /* Neither Cygwin nor mingW export OpenThread, so do a dynamic check
727 so that the compile passes
729 lib
=GetModuleHandleA("kernel32.dll");
730 ok(lib
!=NULL
,"Couldn't get a handle for kernel32.dll\n");
731 pGetThreadPriorityBoost
=(GetThreadPriorityBoost_t
)GetProcAddress(lib
,"GetThreadPriorityBoost");
732 pOpenThread
=(OpenThread_t
)GetProcAddress(lib
,"OpenThread");
733 pQueueUserWorkItem
=(QueueUserWorkItem_t
)GetProcAddress(lib
,"QueueUserWorkItem");
734 pSetThreadIdealProcessor
=(SetThreadIdealProcessor_t
)GetProcAddress(lib
,"SetThreadIdealProcessor");
735 pSetThreadPriorityBoost
=(SetThreadPriorityBoost_t
)GetProcAddress(lib
,"SetThreadPriorityBoost");
736 test_CreateThread_basic();
737 test_CreateThread_suspended();
738 test_SuspendThread();
739 test_TerminateThread();
740 test_CreateThread_stack();
741 test_thread_priority();
742 test_GetThreadTimes();
743 test_thread_processor();
744 test_GetThreadExitCode();
746 test_SetThreadContext();
748 test_QueueUserWorkItem();