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
27 #include "wine/test.h"
33 /* Specify the number of simultaneous threads to test */
35 /* Specify whether to test the extended priorities for Win2k/XP */
36 #define USE_EXTENDED_PRIORITIES 0
37 /* Specify whether to test the stack allocation in CreateThread */
40 /* Set CHECK_STACK to 1 if you want to try to test the stack-limit from
41 CreateThread. So far I have been unable to make this work, and
42 I am in doubt as to how portable it is. Also, according to MSDN,
43 you shouldn't mix C-run-time-libraries (i.e. alloca) with CreateThread.
44 Anyhow, the check is currently commented out
49 # define __EXCEPT __except
52 # include "wine/exception.h"
56 typedef BOOL (WINAPI
*GetThreadPriorityBoost_t
)(HANDLE
,PBOOL
);
57 static GetThreadPriorityBoost_t pGetThreadPriorityBoost
=NULL
;
59 typedef HANDLE (WINAPI
*OpenThread_t
)(DWORD
,BOOL
,DWORD
);
60 static OpenThread_t pOpenThread
=NULL
;
62 typedef BOOL (WINAPI
*QueueUserWorkItem_t
)(LPTHREAD_START_ROUTINE
,PVOID
,ULONG
);
63 static QueueUserWorkItem_t pQueueUserWorkItem
=NULL
;
65 typedef DWORD (WINAPI
*SetThreadIdealProcessor_t
)(HANDLE
,DWORD
);
66 static SetThreadIdealProcessor_t pSetThreadIdealProcessor
=NULL
;
68 typedef BOOL (WINAPI
*SetThreadPriorityBoost_t
)(HANDLE
,BOOL
);
69 static SetThreadPriorityBoost_t pSetThreadPriorityBoost
=NULL
;
71 static HANDLE
create_target_process(const char *arg
)
74 char cmdline
[MAX_PATH
];
75 PROCESS_INFORMATION pi
;
76 STARTUPINFO si
= { 0 };
79 winetest_get_mainargs( &argv
);
80 sprintf(cmdline
, "%s %s %s", argv
[0], argv
[1], arg
);
81 ok(CreateProcess(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
,
82 &si
, &pi
) != 0, "error: %u\n", GetLastError());
83 ok(CloseHandle(pi
.hThread
) != 0, "error %u\n", GetLastError());
87 /* Functions not tested yet:
92 In addition there are no checks that the inheritance works properly in
104 /* WinME supports OpenThread but doesn't know about access restrictions so
105 we require them to be either completely ignored or always obeyed.
107 INT obeying_ars
= 0; /* -1 == no, 0 == dunno yet, 1 == yes */
111 ? (obeying_ars = +1) \
112 : ((obeying_ars = -1), \
113 trace("not restricted, assuming consistent behaviour\n"))) \
114 : (obeying_ars < 0) \
115 ? ok(!(x), "access restrictions obeyed\n") \
116 : ok( (x), "access restrictions not obeyed\n"))
118 /* Basic test that simultaneous threads can access shared memory,
119 that the thread local storage routines work correctly, and that
120 threads actually run concurrently
122 static DWORD WINAPI
threadFunc1(LPVOID p
)
124 t1Struct
*tstruct
= (t1Struct
*)p
;
126 /* write our thread # into shared memory */
127 tstruct
->threadmem
[tstruct
->threadnum
]=GetCurrentThreadId();
128 ok(TlsSetValue(tlsIndex
,(LPVOID
)(tstruct
->threadnum
+1))!=0,
129 "TlsSetValue failed\n");
130 /* The threads synchronize before terminating. This is done by
131 Signaling an event, and waiting for all events to occur
133 SetEvent(tstruct
->event
[tstruct
->threadnum
]);
134 WaitForMultipleObjects(NUM_THREADS
,tstruct
->event
,TRUE
,INFINITE
);
135 /* Double check that all threads really did run by validating that
136 they have all written to the shared memory. There should be no race
137 here, since all threads were synchronized after the write.*/
138 for(i
=0;i
<NUM_THREADS
;i
++) {
139 while(tstruct
->threadmem
[i
]==0) ;
142 /* lstrlenA contains an exception handler so this makes sure exceptions work in threads */
143 ok( lstrlenA( (char *)0xdeadbeef ) == 0, "lstrlenA: unexpected success\n" );
145 /* Check that no one changed our tls memory */
146 ok((int)TlsGetValue(tlsIndex
)-1==tstruct
->threadnum
,
147 "TlsGetValue failed\n");
148 return NUM_THREADS
+tstruct
->threadnum
;
151 static DWORD WINAPI
threadFunc2(LPVOID p
)
156 static DWORD WINAPI
threadFunc3(LPVOID p
)
159 thread
=GetCurrentThread();
160 SuspendThread(thread
);
164 static DWORD WINAPI
threadFunc4(LPVOID p
)
166 HANDLE event
= (HANDLE
)p
;
175 static DWORD WINAPI
threadFunc5(LPVOID p
)
177 DWORD
*exitCode
= (DWORD
*)p
;
179 sysInfo
.dwPageSize
=0;
180 GetSystemInfo(&sysInfo
);
184 alloca(2*sysInfo
.dwPageSize
);
194 static DWORD WINAPI
threadFunc_SetEvent(LPVOID p
)
196 SetEvent((HANDLE
) p
);
200 static DWORD WINAPI
threadFunc_CloseHandle(LPVOID p
)
202 CloseHandle((HANDLE
) p
);
206 static void create_function_addr_events(HANDLE events
[2])
210 sprintf(buffer
, "threadFunc_SetEvent %p", threadFunc_SetEvent
);
211 events
[0] = CreateEvent(NULL
, FALSE
, FALSE
, buffer
);
213 sprintf(buffer
, "threadFunc_CloseHandle %p", threadFunc_CloseHandle
);
214 events
[1] = CreateEvent(NULL
, FALSE
, FALSE
, buffer
);
217 /* check CreateRemoteThread */
218 static VOID
test_CreateRemoteThread(void)
220 HANDLE hProcess
, hThread
, hEvent
, hRemoteEvent
;
221 DWORD tid
, ret
, exitcode
;
222 HANDLE hAddrEvents
[2];
224 hProcess
= create_target_process("sleep");
225 ok(hProcess
!= NULL
, "Can't start process\n");
227 /* ensure threadFunc_SetEvent & threadFunc_CloseHandle are the same
228 * address as in the child process */
229 create_function_addr_events(hAddrEvents
);
230 ret
= WaitForMultipleObjects(2, hAddrEvents
, TRUE
, 5000);
231 if (ret
== WAIT_TIMEOUT
)
233 skip("child process wasn't mapped at same address, so can't do CreateRemoteThread tests.\n");
237 hEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
238 ok(hEvent
!= NULL
, "Can't create event, err=%u\n", GetLastError());
239 ret
= DuplicateHandle(GetCurrentProcess(), hEvent
, hProcess
, &hRemoteEvent
,
240 0, FALSE
, DUPLICATE_SAME_ACCESS
);
241 ok(ret
!= 0, "DuplicateHandle failed, err=%u\n", GetLastError());
243 /* create suspended remote thread with entry point SetEvent() */
244 SetLastError(0xdeadbeef);
245 hThread
= CreateRemoteThread(hProcess
, NULL
, 0, threadFunc_SetEvent
,
246 hRemoteEvent
, CREATE_SUSPENDED
, &tid
);
247 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
249 skip("CreateRemoteThread is not implemented\n");
252 ok(hThread
!= NULL
, "CreateRemoteThread failed, err=%u\n", GetLastError());
253 ok(tid
!= 0, "null tid\n");
254 ret
= SuspendThread(hThread
);
255 ok(ret
== 1, "ret=%u, err=%u\n", ret
, GetLastError());
256 ret
= ResumeThread(hThread
);
257 ok(ret
== 2, "ret=%u, err=%u\n", ret
, GetLastError());
259 /* thread still suspended, so wait times out */
260 ret
= WaitForSingleObject(hEvent
, 100);
261 ok(ret
== WAIT_TIMEOUT
, "wait did not time out, ret=%u\n", ret
);
263 ret
= ResumeThread(hThread
);
264 ok(ret
== 1, "ret=%u, err=%u\n", ret
, GetLastError());
266 /* wait that doesn't time out */
267 ret
= WaitForSingleObject(hEvent
, 100);
268 ok(ret
== WAIT_OBJECT_0
, "object not signaled, ret=%u\n", ret
);
270 /* wait for thread end */
271 ret
= WaitForSingleObject(hThread
, 100);
272 ok(ret
== WAIT_OBJECT_0
, "waiting for thread failed, ret=%u\n", ret
);
273 CloseHandle(hThread
);
275 /* create and wait for remote thread with entry point CloseHandle() */
276 hThread
= CreateRemoteThread(hProcess
, NULL
, 0,
277 threadFunc_CloseHandle
,
278 hRemoteEvent
, 0, &tid
);
279 ok(hThread
!= NULL
, "CreateRemoteThread failed, err=%u\n", GetLastError());
280 ret
= WaitForSingleObject(hThread
, 100);
281 ok(ret
== WAIT_OBJECT_0
, "waiting for thread failed, ret=%u\n", ret
);
282 CloseHandle(hThread
);
284 /* create remote thread with entry point SetEvent() */
285 hThread
= CreateRemoteThread(hProcess
, NULL
, 0,
287 hRemoteEvent
, 0, &tid
);
288 ok(hThread
!= NULL
, "CreateRemoteThread failed, err=%u\n", GetLastError());
290 /* closed handle, so wait times out */
291 ret
= WaitForSingleObject(hEvent
, 100);
292 ok(ret
== WAIT_TIMEOUT
, "wait did not time out, ret=%u\n", ret
);
294 /* check that remote SetEvent() failed */
295 ret
= GetExitCodeThread(hThread
, &exitcode
);
296 ok(ret
!= 0, "GetExitCodeThread failed, err=%u\n", GetLastError());
297 if (ret
) ok(exitcode
== 0, "SetEvent succeeded, expected to fail\n");
298 CloseHandle(hThread
);
301 TerminateProcess(hProcess
, 0);
303 CloseHandle(hProcess
);
306 /* Check basic funcationality of CreateThread and Tls* functions */
307 static VOID
test_CreateThread_basic(void)
309 HANDLE thread
[NUM_THREADS
],event
[NUM_THREADS
];
310 DWORD threadid
[NUM_THREADS
],curthreadId
;
311 DWORD threadmem
[NUM_THREADS
];
313 t1Struct tstruct
[NUM_THREADS
];
318 /* lstrlenA contains an exception handler so this makes sure exceptions work in the main thread */
319 ok( lstrlenA( (char *)0xdeadbeef ) == 0, "lstrlenA: unexpected success\n" );
321 /* Retrieve current Thread ID for later comparisons */
322 curthreadId
=GetCurrentThreadId();
323 /* Allocate some local storage */
324 ok((tlsIndex
=TlsAlloc())!=TLS_OUT_OF_INDEXES
,"TlsAlloc failed\n");
325 /* Create events for thread synchronization */
326 for(i
=0;i
<NUM_THREADS
;i
++) {
328 /* Note that it doesn't matter what type of event we chose here. This
329 test isn't trying to thoroughly test events
331 event
[i
]=CreateEventA(NULL
,TRUE
,FALSE
,NULL
);
332 tstruct
[i
].threadnum
=i
;
333 tstruct
[i
].threadmem
=threadmem
;
334 tstruct
[i
].event
=event
;
337 /* Test that passing arguments to threads works okay */
338 for(i
=0;i
<NUM_THREADS
;i
++) {
339 thread
[i
] = CreateThread(NULL
,0,threadFunc1
,
340 &tstruct
[i
],0,&threadid
[i
]);
341 ok(thread
[i
]!=NULL
,"Create Thread failed\n");
343 /* Test that the threads actually complete */
344 for(i
=0;i
<NUM_THREADS
;i
++) {
345 error
=WaitForSingleObject(thread
[i
],5000);
346 ok(error
==WAIT_OBJECT_0
, "Thread did not complete within timelimit\n");
347 if(error
!=WAIT_OBJECT_0
) {
348 TerminateThread(thread
[i
],i
+NUM_THREADS
);
350 ok(GetExitCodeThread(thread
[i
],&exitCode
),"Could not retrieve ext code\n");
351 ok(exitCode
==i
+NUM_THREADS
,"Thread returned an incorrect exit code\n");
353 /* Test that each thread executed in its parent's address space
354 (it was able to change threadmem and pass that change back to its parent)
355 and that each thread id was independent). Note that we prove that the
356 threads actually execute concurrently by having them block on each other
359 for(i
=0;i
<NUM_THREADS
;i
++) {
361 for(j
=i
+1;j
<NUM_THREADS
;j
++) {
362 if (threadmem
[i
]==threadmem
[j
]) {
366 ok(!error
&& threadmem
[i
]==threadid
[i
] && threadmem
[i
]!=curthreadId
,
367 "Thread did not execute successfully\n");
368 ok(CloseHandle(thread
[i
])!=0,"CloseHandle failed\n");
370 ok(TlsFree(tlsIndex
)!=0,"TlsFree failed\n");
372 /* Test how passing NULL as a pointer to threadid works */
373 SetLastError(0xFACEaBAD);
374 thread
[0] = CreateThread(NULL
,0,threadFunc2
,NULL
,0,NULL
);
375 GLE
= GetLastError();
376 if (thread
[0]) { /* NT */
377 ok(GLE
==0xFACEaBAD, "CreateThread set last error to %d, expected 4207848365\n", GLE
);
378 ret
= WaitForSingleObject(thread
[0],100);
379 ok(ret
==WAIT_OBJECT_0
, "threadFunc2 did not exit during 100 ms\n");
380 ret
= GetExitCodeThread(thread
[0],&exitCode
);
381 ok(ret
!=0, "GetExitCodeThread returned %d (expected nonzero)\n", ret
);
382 ok(exitCode
==99, "threadFunc2 exited with code: %d (expected 99)\n", exitCode
);
383 ok(CloseHandle(thread
[0])!=0,"Error closing thread handle\n");
386 ok(GLE
==ERROR_INVALID_PARAMETER
, "CreateThread set last error to %d, expected 87\n", GLE
);
390 /* Check that using the CREATE_SUSPENDED flag works */
391 static VOID
test_CreateThread_suspended(void)
397 thread
= CreateThread(NULL
,0,threadFunc2
,NULL
,
398 CREATE_SUSPENDED
,&threadId
);
399 ok(thread
!=NULL
,"Create Thread failed\n");
400 /* Check that the thread is suspended */
401 ok(SuspendThread(thread
)==1,"Thread did not start suspended\n");
402 ok(ResumeThread(thread
)==2,"Resume thread returned an invalid value\n");
403 /* Check that resume thread didn't actually start the thread. I can't think
404 of a better way of checking this than just waiting. I am not sure if this
405 will work on slow computers.
407 ok(WaitForSingleObject(thread
,1000)==WAIT_TIMEOUT
,
408 "ResumeThread should not have actually started the thread\n");
409 /* Now actually resume the thread and make sure that it actually completes*/
410 ok(ResumeThread(thread
)==1,"Resume thread returned an invalid value\n");
411 ok((error
=WaitForSingleObject(thread
,1000))==WAIT_OBJECT_0
,
412 "Thread did not resume\n");
413 if(error
!=WAIT_OBJECT_0
) {
414 TerminateThread(thread
,1);
416 ok(CloseHandle(thread
)!=0,"CloseHandle failed\n");
419 /* Check that SuspendThread and ResumeThread work */
420 static VOID
test_SuspendThread(void)
422 HANDLE thread
,access_thread
;
423 DWORD threadId
,exitCode
,error
;
426 thread
= CreateThread(NULL
,0,threadFunc3
,NULL
,
428 ok(thread
!=NULL
,"Create Thread failed\n");
429 /* Check that the thread is suspended */
430 /* Note that this is a polling method, and there is a race between
431 SuspendThread being called (in the child, and the loop below timing out,
432 so the test could fail on a heavily loaded or slow computer.
435 for(i
=0;error
==0 && i
<100;i
++) {
436 error
=SuspendThread(thread
);
437 ResumeThread(thread
);
443 ok(error
==1,"SuspendThread did not work\n");
444 /* check that access restrictions are obeyed */
446 access_thread
=pOpenThread(THREAD_ALL_ACCESS
& (~THREAD_SUSPEND_RESUME
),
448 ok(access_thread
!=NULL
,"OpenThread returned an invalid handle\n");
449 if (access_thread
!=NULL
) {
450 obey_ar(SuspendThread(access_thread
)==~0U);
451 obey_ar(ResumeThread(access_thread
)==~0U);
452 ok(CloseHandle(access_thread
)!=0,"CloseHandle Failed\n");
455 /* Double check that the thread really is suspended */
456 ok((error
=GetExitCodeThread(thread
,&exitCode
))!=0 && exitCode
==STILL_ACTIVE
,
457 "Thread did not really suspend\n");
458 /* Resume the thread, and make sure it actually completes */
459 ok(ResumeThread(thread
)==1,"Resume thread returned an invalid value\n");
460 ok((error
=WaitForSingleObject(thread
,1000))==WAIT_OBJECT_0
,
461 "Thread did not resume\n");
462 if(error
!=WAIT_OBJECT_0
) {
463 TerminateThread(thread
,1);
465 /* Trying to suspend a terminated thread should fail */
466 error
=SuspendThread(thread
);
467 ok(error
==~0U, "wrong return code: %d\n", error
);
468 ok(GetLastError()==ERROR_ACCESS_DENIED
|| GetLastError()==ERROR_NO_MORE_ITEMS
, "unexpected error code: %d\n", GetLastError());
470 ok(CloseHandle(thread
)!=0,"CloseHandle Failed\n");
473 /* Check that TerminateThread works properly
475 static VOID
test_TerminateThread(void)
477 HANDLE thread
,access_thread
,event
;
478 DWORD threadId
,exitCode
;
479 event
=CreateEventA(NULL
,TRUE
,FALSE
,NULL
);
480 thread
= CreateThread(NULL
,0,threadFunc4
,
481 (LPVOID
)event
, 0,&threadId
);
482 ok(thread
!=NULL
,"Create Thread failed\n");
483 /* TerminateThread has a race condition in Wine. If the thread is terminated
484 before it starts, it leaves a process behind. Therefore, we wait for the
485 thread to signal that it has started. There is no easy way to force the
486 race to occur, so we don't try to find it.
488 ok(WaitForSingleObject(event
,5000)==WAIT_OBJECT_0
,
489 "TerminateThread didn't work\n");
490 /* check that access restrictions are obeyed */
492 access_thread
=pOpenThread(THREAD_ALL_ACCESS
& (~THREAD_TERMINATE
),
494 ok(access_thread
!=NULL
,"OpenThread returned an invalid handle\n");
495 if (access_thread
!=NULL
) {
496 obey_ar(TerminateThread(access_thread
,99)==0);
497 ok(CloseHandle(access_thread
)!=0,"CloseHandle Failed\n");
500 /* terminate a job and make sure it terminates */
501 ok(TerminateThread(thread
,99)!=0,"TerminateThread failed\n");
502 ok(WaitForSingleObject(thread
,5000)==WAIT_OBJECT_0
,
503 "TerminateThread didn't work\n");
504 ok(GetExitCodeThread(thread
,&exitCode
)!=STILL_ACTIVE
,
505 "TerminateThread should not leave the thread 'STILL_ACTIVE'\n");
506 ok(exitCode
==99, "TerminateThread returned invalid exit code\n");
507 ok(CloseHandle(thread
)!=0,"Error Closing thread handle\n");
510 /* Check if CreateThread obeys the specified stack size. This code does
511 not work properly, and is currently disabled
513 static VOID
test_CreateThread_stack(void)
516 /* The only way I know of to test the stack size is to use alloca
517 and __try/__except. However, this is probably not portable,
518 and I couldn't get it to work under Wine anyhow. However, here
519 is the code which should allow for testing that CreateThread
520 respects the stack-size limit
523 DWORD threadId
,exitCode
;
526 sysInfo
.dwPageSize
=0;
527 GetSystemInfo(&sysInfo
);
528 ok(sysInfo
.dwPageSize
>0,"GetSystemInfo should return a valid page size\n");
529 thread
= CreateThread(NULL
,sysInfo
.dwPageSize
,
530 threadFunc5
,&exitCode
,
532 ok(WaitForSingleObject(thread
,5000)==WAIT_OBJECT_0
,
533 "TerminateThread didn't work\n");
534 ok(exitCode
==1,"CreateThread did not obey stack-size-limit\n");
535 ok(CloseHandle(thread
)!=0,"CloseHandle failed\n");
539 /* Check whether setting/retrieving thread priorities works */
540 static VOID
test_thread_priority(void)
542 HANDLE curthread
,access_thread
;
543 DWORD curthreadId
,exitCode
;
544 int min_priority
=-2,max_priority
=2;
548 curthread
=GetCurrentThread();
549 curthreadId
=GetCurrentThreadId();
550 /* Check thread priority */
551 /* NOTE: on Win2k/XP priority can be from -7 to 6. All other platforms it
552 is -2 to 2. However, even on a real Win2k system, using thread
553 priorities beyond the -2 to 2 range does not work. If you want to try
554 anyway, enable USE_EXTENDED_PRIORITIES
556 ok(GetThreadPriority(curthread
)==THREAD_PRIORITY_NORMAL
,
557 "GetThreadPriority Failed\n");
560 /* check that access control is obeyed */
561 access_thread
=pOpenThread(THREAD_ALL_ACCESS
&
562 (~THREAD_QUERY_INFORMATION
) & (~THREAD_SET_INFORMATION
),
564 ok(access_thread
!=NULL
,"OpenThread returned an invalid handle\n");
565 if (access_thread
!=NULL
) {
566 obey_ar(SetThreadPriority(access_thread
,1)==0);
567 obey_ar(GetThreadPriority(access_thread
)==THREAD_PRIORITY_ERROR_RETURN
);
568 obey_ar(GetExitCodeThread(access_thread
,&exitCode
)==0);
569 ok(CloseHandle(access_thread
),"Error Closing thread handle\n");
572 #if USE_EXTENDED_PRIORITIES
573 min_priority
=-7; max_priority
=6;
575 for(i
=min_priority
;i
<=max_priority
;i
++) {
576 ok(SetThreadPriority(curthread
,i
)!=0,
577 "SetThreadPriority Failed for priority: %d\n",i
);
578 ok(GetThreadPriority(curthread
)==i
,
579 "GetThreadPriority Failed for priority: %d\n",i
);
581 ok(SetThreadPriority(curthread
,THREAD_PRIORITY_TIME_CRITICAL
)!=0,
582 "SetThreadPriority Failed\n");
583 ok(GetThreadPriority(curthread
)==THREAD_PRIORITY_TIME_CRITICAL
,
584 "GetThreadPriority Failed\n");
585 ok(SetThreadPriority(curthread
,THREAD_PRIORITY_IDLE
)!=0,
586 "SetThreadPriority Failed\n");
587 ok(GetThreadPriority(curthread
)==THREAD_PRIORITY_IDLE
,
588 "GetThreadPriority Failed\n");
589 ok(SetThreadPriority(curthread
,0)!=0,"SetThreadPriority Failed\n");
591 /* Check thread priority boost */
592 if (!pGetThreadPriorityBoost
|| !pSetThreadPriorityBoost
)
595 SetLastError(0xdeadbeef);
596 rc
=pGetThreadPriorityBoost(curthread
,&disabled
);
597 if (rc
==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED
)
601 ok(rc
!=0,"error=%d\n",GetLastError());
604 /* check that access control is obeyed */
605 access_thread
=pOpenThread(THREAD_ALL_ACCESS
&
606 (~THREAD_QUERY_INFORMATION
) & (~THREAD_SET_INFORMATION
),
608 ok(access_thread
!=NULL
,"OpenThread returned an invalid handle\n");
609 if (access_thread
!=NULL
) {
610 obey_ar(pSetThreadPriorityBoost(access_thread
,1)==0);
611 obey_ar(pGetThreadPriorityBoost(access_thread
,&disabled
)==0);
612 ok(CloseHandle(access_thread
),"Error Closing thread handle\n");
617 rc
= pSetThreadPriorityBoost(curthread
,1);
618 ok( rc
!= 0, "error=%d\n",GetLastError());
619 rc
=pGetThreadPriorityBoost(curthread
,&disabled
);
620 ok(rc
!=0 && disabled
==1,
621 "rc=%d error=%d disabled=%d\n",rc
,GetLastError(),disabled
);
623 rc
= pSetThreadPriorityBoost(curthread
,0);
624 ok( rc
!= 0, "error=%d\n",GetLastError());
625 rc
=pGetThreadPriorityBoost(curthread
,&disabled
);
626 ok(rc
!=0 && disabled
==0,
627 "rc=%d error=%d disabled=%d\n",rc
,GetLastError(),disabled
);
631 /* check the GetThreadTimes function */
632 static VOID
test_GetThreadTimes(void)
634 HANDLE thread
,access_thread
=NULL
;
635 FILETIME creationTime
,exitTime
,kernelTime
,userTime
;
639 thread
= CreateThread(NULL
,0,threadFunc2
,NULL
,
640 CREATE_SUSPENDED
,&threadId
);
642 ok(thread
!=NULL
,"Create Thread failed\n");
643 /* check that access control is obeyed */
645 access_thread
=pOpenThread(THREAD_ALL_ACCESS
&
646 (~THREAD_QUERY_INFORMATION
), 0,threadId
);
647 ok(access_thread
!=NULL
,
648 "OpenThread returned an invalid handle\n");
650 ok(ResumeThread(thread
)==1,"Resume thread returned an invalid value\n");
651 ok(WaitForSingleObject(thread
,5000)==WAIT_OBJECT_0
,
652 "ResumeThread didn't work\n");
653 creationTime
.dwLowDateTime
=99; creationTime
.dwHighDateTime
=99;
654 exitTime
.dwLowDateTime
=99; exitTime
.dwHighDateTime
=99;
655 kernelTime
.dwLowDateTime
=99; kernelTime
.dwHighDateTime
=99;
656 userTime
.dwLowDateTime
=99; userTime
.dwHighDateTime
=99;
657 /* GetThreadTimes should set all of the parameters passed to it */
658 error
=GetThreadTimes(thread
,&creationTime
,&exitTime
,
659 &kernelTime
,&userTime
);
660 if (error
!=0 || GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED
) {
661 ok(error
!=0,"GetThreadTimes failed\n");
662 ok(creationTime
.dwLowDateTime
!=99 || creationTime
.dwHighDateTime
!=99,
663 "creationTime was invalid\n");
664 ok(exitTime
.dwLowDateTime
!=99 || exitTime
.dwHighDateTime
!=99,
665 "exitTime was invalid\n");
666 ok(kernelTime
.dwLowDateTime
!=99 || kernelTime
.dwHighDateTime
!=99,
667 "kernelTimewas invalid\n");
668 ok(userTime
.dwLowDateTime
!=99 || userTime
.dwHighDateTime
!=99,
669 "userTime was invalid\n");
670 ok(CloseHandle(thread
)!=0,"CloseHandle failed\n");
671 if(access_thread
!=NULL
)
673 error
=GetThreadTimes(access_thread
,&creationTime
,&exitTime
,
674 &kernelTime
,&userTime
);
678 if(access_thread
!=NULL
) {
679 ok(CloseHandle(access_thread
)!=0,"CloseHandle Failed\n");
683 /* Check the processor affinity functions */
684 /* NOTE: These functions should also be checked that they obey access control
686 static VOID
test_thread_processor(void)
688 HANDLE curthread
,curproc
;
689 DWORD_PTR processMask
,systemMask
;
693 sysInfo
.dwNumberOfProcessors
=0;
694 GetSystemInfo(&sysInfo
);
695 ok(sysInfo
.dwNumberOfProcessors
>0,
696 "GetSystemInfo failed to return a valid # of processors\n");
697 /* Use the current Thread/process for all tests */
698 curthread
=GetCurrentThread();
699 ok(curthread
!=NULL
,"GetCurrentThread failed\n");
700 curproc
=GetCurrentProcess();
701 ok(curproc
!=NULL
,"GetCurrentProcess failed\n");
702 /* Check the Affinity Mask functions */
703 ok(GetProcessAffinityMask(curproc
,&processMask
,&systemMask
)!=0,
704 "GetProcessAffinityMask failed\n");
705 ok(SetThreadAffinityMask(curthread
,processMask
)==processMask
,
706 "SetThreadAffinityMask failed\n");
707 ok(SetThreadAffinityMask(curthread
,processMask
+1)==0,
708 "SetThreadAffinityMask passed for an illegal processor\n");
709 /* NOTE: This only works on WinNT/2000/XP) */
710 if (pSetThreadIdealProcessor
) {
713 error
=pSetThreadIdealProcessor(curthread
,0);
714 if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED
) {
715 ok(error
!=-1, "SetThreadIdealProcessor failed\n");
718 if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED
) {
719 error
=pSetThreadIdealProcessor(curthread
,MAXIMUM_PROCESSORS
+1);
721 "SetThreadIdealProcessor succeeded with an illegal processor #\n");
723 error
=pSetThreadIdealProcessor(curthread
,MAXIMUM_PROCESSORS
);
724 ok(error
==0, "SetThreadIdealProcessor returned an incorrect value\n");
730 static VOID
test_GetThreadExitCode(void)
732 DWORD exitCode
, threadid
;
736 ret
= GetExitCodeThread((HANDLE
)0x2bad2bad,&exitCode
);
737 ok(ret
==0, "GetExitCodeThread returned non zero value: %d\n", ret
);
738 GLE
= GetLastError();
739 ok(GLE
==ERROR_INVALID_HANDLE
, "GetLastError returned %d (expected 6)\n", GLE
);
741 thread
= CreateThread(NULL
,0,threadFunc2
,NULL
,0,&threadid
);
742 ret
= WaitForSingleObject(thread
,100);
743 ok(ret
==WAIT_OBJECT_0
, "threadFunc2 did not exit during 100 ms\n");
744 ret
= GetExitCodeThread(thread
,&exitCode
);
745 ok(ret
==exitCode
|| ret
==1,
746 "GetExitCodeThread returned %d (expected 1 or %d)\n", ret
, exitCode
);
747 ok(exitCode
==99, "threadFunc2 exited with code %d (expected 99)\n", exitCode
);
748 ok(CloseHandle(thread
)!=0,"Error closing thread handle\n");
753 static int test_value
= 0;
756 static void WINAPI
set_test_val( int val
)
761 static DWORD WINAPI
threadFunc6(LPVOID p
)
765 test_value
*= (int)p
;
769 static void test_SetThreadContext(void)
777 SetLastError(0xdeadbeef);
778 event
= CreateEvent( NULL
, TRUE
, FALSE
, NULL
);
779 thread
= CreateThread( NULL
, 0, threadFunc6
, (void *)2, 0, &threadid
);
780 ok( thread
!= NULL
, "CreateThread failed : (%d)\n", GetLastError() );
783 trace("Thread creation failed, skipping rest of test\n");
786 WaitForSingleObject( event
, INFINITE
);
787 SuspendThread( thread
);
788 CloseHandle( event
);
790 ctx
.ContextFlags
= CONTEXT_FULL
;
791 SetLastError(0xdeadbeef);
792 ok( GetThreadContext( thread
, &ctx
), "GetThreadContext failed : (%d)\n", GetLastError() );
794 /* simulate a call to set_test_val(10) */
795 stack
= (int *)ctx
.Esp
;
798 ctx
.Esp
-= 2 * sizeof(int *);
799 ctx
.Eip
= (DWORD
)set_test_val
;
800 SetLastError(0xdeadbeef);
801 ok( SetThreadContext( thread
, &ctx
), "SetThreadContext failed : (%d)\n", GetLastError() );
803 SetLastError(0xdeadbeef);
804 prevcount
= ResumeThread( thread
);
805 ok ( prevcount
== 1, "Previous suspend count (%d) instead of 1, last error : (%d)\n",
806 prevcount
, GetLastError() );
808 WaitForSingleObject( thread
, INFINITE
);
809 ok( test_value
== 20, "test_value %d instead of 20\n", test_value
);
812 #endif /* __i386__ */
814 static HANDLE finish_event
;
815 static LONG times_executed
;
817 static DWORD CALLBACK
work_function(void *p
)
819 LONG executed
= InterlockedIncrement(×_executed
);
822 SetEvent(finish_event
);
826 static void test_QueueUserWorkItem(void)
832 /* QueueUserWorkItem not present on win9x */
833 if (!pQueueUserWorkItem
) return;
835 finish_event
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
837 before
= GetTickCount();
839 for (i
= 0; i
< 100; i
++)
841 BOOL ret
= pQueueUserWorkItem(work_function
, (void *)i
, WT_EXECUTEDEFAULT
);
842 ok(ret
, "QueueUserWorkItem failed with error %d\n", GetLastError());
845 wait_result
= WaitForSingleObject(finish_event
, 10000);
847 after
= GetTickCount();
848 trace("100 QueueUserWorkItem calls took %dms\n", after
- before
);
849 ok(wait_result
== WAIT_OBJECT_0
, "wait failed with error 0x%x\n", wait_result
);
851 ok(times_executed
== 100, "didn't execute all of the work items\n");
859 argc
= winetest_get_mainargs( &argv
);
860 /* Neither Cygwin nor mingW export OpenThread, so do a dynamic check
861 so that the compile passes
863 lib
=GetModuleHandleA("kernel32.dll");
864 ok(lib
!=NULL
,"Couldn't get a handle for kernel32.dll\n");
865 pGetThreadPriorityBoost
=(GetThreadPriorityBoost_t
)GetProcAddress(lib
,"GetThreadPriorityBoost");
866 pOpenThread
=(OpenThread_t
)GetProcAddress(lib
,"OpenThread");
867 pQueueUserWorkItem
=(QueueUserWorkItem_t
)GetProcAddress(lib
,"QueueUserWorkItem");
868 pSetThreadIdealProcessor
=(SetThreadIdealProcessor_t
)GetProcAddress(lib
,"SetThreadIdealProcessor");
869 pSetThreadPriorityBoost
=(SetThreadPriorityBoost_t
)GetProcAddress(lib
,"SetThreadPriorityBoost");
873 if (!strcmp(argv
[2], "sleep"))
875 HANDLE hAddrEvents
[2];
876 create_function_addr_events(hAddrEvents
);
877 SetEvent(hAddrEvents
[0]);
878 SetEvent(hAddrEvents
[1]);
879 Sleep(5000); /* spawned process runs for at most 5 seconds */
885 hThread
= CreateThread(NULL
, 0, threadFunc2
, NULL
, 0, NULL
);
886 ok(hThread
!= NULL
, "CreateThread failed, error %u\n",
888 ok(WaitForSingleObject(hThread
, 200) == WAIT_OBJECT_0
,
889 "Thread did not exit in time\n");
890 if (hThread
== NULL
) break;
891 CloseHandle(hThread
);
896 test_CreateRemoteThread();
897 test_CreateThread_basic();
898 test_CreateThread_suspended();
899 test_SuspendThread();
900 test_TerminateThread();
901 test_CreateThread_stack();
902 test_thread_priority();
903 test_GetThreadTimes();
904 test_thread_processor();
905 test_GetThreadExitCode();
907 test_SetThreadContext();
909 test_QueueUserWorkItem();