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 "wine/test.h"
29 /* Specify the number of simultaneous threads to test */
31 /* Specify whether to test the extended priorities for Win2k/XP */
32 #define USE_EXTENDED_PRIORITIES 0
33 /* Specify whether to test the stack allocation in CreateThread */
36 /* Set CHECK_STACK to 1 if you want to try to test the stack-limit from
37 CreateThread. So far I have been unable to make this work, and
38 I am in doubt as to how portable it is. Also, according to MSDN,
39 you shouldn't mix C-run-time-libraries (i.e. alloca) with CreateThread.
40 Anyhow, the check is currently commented out
45 #define __EXCEPT __except
48 #include "wine/exception.h"
51 typedef HANDLE (WINAPI *OPENTHREADPTR)(DWORD,BOOL,DWORD);
52 OPENTHREADPTR OpenThreadPtr;
53 HANDLE WINAPI OpenThreadDefault(DWORD dwDesiredAccess,
59 /* define a check for whether we are running in Win2k or XP */
60 #define WIN2K_PLUS(version) (version < 0x80000000 && (version & 0xFF) >= 5)
62 /* Functions not tested yet:
68 In addition there are no checks that the inheritance works properly in
80 /* Basic test that simulatneous threads can access shared memory,
81 that the thread local storage routines work correctly, and that
82 threads actually run concurrently
84 VOID WINAPI threadFunc1(t1Struct *tstruct)
87 /* write our thread # into shared memory */
88 tstruct->threadmem[tstruct->threadnum]=GetCurrentThreadId();
89 ok(TlsSetValue(tlsIndex,(LPVOID)(tstruct->threadnum+1))!=0,
90 "TlsSetValue failed");
91 /* The threads synchronize before terminating. This is done by
92 Signaling an event, and waiting for all events to occur
94 SetEvent(tstruct->event[tstruct->threadnum]);
95 WaitForMultipleObjects(NUM_THREADS,tstruct->event,TRUE,INFINITE);
96 /* Double check that all threads really did run by validating that
97 they have all written to the shared memory. There should be no race
98 here, since all threads were synchronized after the write.*/
99 for(i=0;i<NUM_THREADS;i++) {
100 while(tstruct->threadmem[i]==0) ;
102 /* Check that noone cahnged our tls memory */
103 ok((DWORD)TlsGetValue(tlsIndex)-1==tstruct->threadnum,
104 "TlsGetValue failed");
105 ExitThread(NUM_THREADS+tstruct->threadnum);
108 VOID WINAPI threadFunc2()
113 VOID WINAPI threadFunc3()
116 thread=GetCurrentThread();
117 SuspendThread(thread);
121 VOID WINAPI threadFunc4(HANDLE event)
123 if(event != (HANDLE)NULL) {
131 VOID WINAPI threadFunc5(DWORD *exitCode)
134 sysInfo.dwPageSize=0;
135 GetSystemInfo(&sysInfo);
139 alloca(2*sysInfo.dwPageSize);
149 /* Check basic funcationality of CreateThread and Tls* functions */
150 VOID test_CreateThread_basic(DWORD version)
152 HANDLE thread[NUM_THREADS],event[NUM_THREADS];
153 DWORD threadid[NUM_THREADS],curthreadId;
154 DWORD threadmem[NUM_THREADS];
156 t1Struct tstruct[NUM_THREADS];
159 /* Retrieve current Thread ID for later comparisons */
160 curthreadId=GetCurrentThreadId();
161 /* Allocate some local storage */
162 ok((tlsIndex=TlsAlloc())!=TLS_OUT_OF_INDEXES,"TlsAlloc failed");
163 /* Create events for thread synchronization */
164 for(i=0;i<NUM_THREADS;i++) {
166 /* Note that it doesn't matter what type of event we chose here. This
167 test isn't trying to thoroughly test events
169 event[i]=CreateEventA(NULL,TRUE,FALSE,NULL);
170 tstruct[i].threadnum=i;
171 tstruct[i].threadmem=threadmem;
172 tstruct[i].event=event;
175 /* Test that passing arguments to threads works okay */
176 for(i=0;i<NUM_THREADS;i++) {
177 thread[i] = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)threadFunc1,
178 &tstruct[i],0,&threadid[i]);
179 ok(thread[i]!=(HANDLE)NULL,"Create Thread failed.");
181 /* Test that the threads actually complete */
182 for(i=0;i<NUM_THREADS;i++) {
183 error=WaitForSingleObject(thread[i],5000);
184 ok(error==WAIT_OBJECT_0, "Thread did not complete within timelimit");
185 if(error!=WAIT_OBJECT_0) {
186 TerminateThread(thread[i],i+NUM_THREADS);
188 ok(GetExitCodeThread(thread[i],&exitCode),"Could not retrieve ext code");
189 ok(exitCode==i+NUM_THREADS,"Thread returned an incorrect exit code");
191 /* Test that each thread executed in its parent's address space
192 (it was able to change threadmem and pass that change back to its parent)
193 and that each thread id was independant). Note that we prove that the
194 threads actually execute concurrently by having them block on each other
197 for(i=0;i<NUM_THREADS;i++) {
199 for(j=i+1;j<NUM_THREADS;j++) {
200 if (threadmem[i]==threadmem[j]) {
204 ok(!error && threadmem[i]==threadid[i] && threadmem[i]!=curthreadId,
205 "Thread did not execute successfully");
206 ok(CloseHandle(thread[i])!=0,"CloseHandle failed");
208 ok(TlsFree(tlsIndex)!=0,"TlsFree failed");
211 /* Check that using the CREATE_SUSPENDED flag works */
212 VOID test_CreateThread_suspended(DWORD version)
218 thread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)threadFunc2,NULL,
219 CREATE_SUSPENDED,&threadId);
220 ok(thread!=(HANDLE)NULL,"Create Thread failed.");
221 /* Check that the thread is suspended */
222 ok(SuspendThread(thread)==1,"Thread did not start suspended");
223 ok(ResumeThread(thread)==2,"Resume thread returned an invalid value");
224 /* Check that resume thread didn't actually start the thread. I can't think
225 of a better way of checking this than just waiting. I am not sure if this
226 will work on slow computers.
228 ok(WaitForSingleObject(thread,1000)==WAIT_TIMEOUT,
229 "ResumeThread should not have actually started the thread");
230 /* Now actually resume the thread and make sure that it actually completes*/
231 ok(ResumeThread(thread)==1,"Resume thread returned an invalid value");
232 ok((error=WaitForSingleObject(thread,1000))==WAIT_OBJECT_0,
233 "Thread did not resume");
234 if(error!=WAIT_OBJECT_0) {
235 TerminateThread(thread,1);
237 ok(CloseHandle(thread)!=0,"CloseHandle failed");
240 /* Check that SuspendThread and ResumeThread work */
241 VOID test_SuspendThread(DWORD version)
243 HANDLE thread,access_thread;
244 DWORD threadId,exitCode;
247 thread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)threadFunc3,NULL,
249 ok(thread!=(HANDLE)NULL,"Create Thread failed.");
250 /* Check that the thread is suspended */
251 /* Note that this is a polling method, and there is a race between
252 SuspendThread being called (in the child, and the loop below timing out,
253 so the test could fail on a heavily loaded or slow computer.
256 for(i=0;error==0 && i<100;i++) {
257 error=SuspendThread(thread);
258 ResumeThread(thread);
264 ok(error==1,"SuspendThread did not work");
265 /* check that access restrictions are obeyed */
266 if(WIN2K_PLUS(version)) {
267 access_thread=OpenThreadPtr(THREAD_ALL_ACCESS & (~THREAD_SUSPEND_RESUME),
269 ok(access_thread!=(HANDLE)NULL,"OpenThread returned an invalid handle");
270 if(access_thread!=(HANDLE)NULL) {
271 ok(SuspendThread(access_thread)==-1,
272 "SuspendThread did not obey access restrictions");
273 ok(ResumeThread(access_thread)==-1,
274 "ResumeThread did not obey access restrictions");
275 ok(CloseHandle(access_thread)!=0,"CloseHandle Failed");
278 /* Double check that the thread really is suspended */
279 ok((error=GetExitCodeThread(thread,&exitCode))!=0 && exitCode==STILL_ACTIVE,
280 "Thread did not really suspend");
281 /* Resume the thread, and make sure it actually completes */
282 ok(ResumeThread(thread)==1,"Resume thread returned an invalid value");
283 ok((error=WaitForSingleObject(thread,1000))==WAIT_OBJECT_0,
284 "Thread did not resume");
285 if(error!=WAIT_OBJECT_0) {
286 TerminateThread(thread,1);
288 ok(CloseHandle(thread)!=0,"CloseHandle Failed");
291 /* Check that TerminateThread works properly
293 VOID test_TerminateThread(DWORD version)
295 HANDLE thread,access_thread,event;
296 DWORD threadId,exitCode;
299 event=CreateEventA(NULL,TRUE,FALSE,NULL);
300 thread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)threadFunc4,
301 (LPVOID)event, 0,&threadId);
302 ok(thread!=(HANDLE)NULL,"Create Thread failed.");
303 /* Terminate thread has a race condition in Wine. If the thread is terminated
304 before it starts, it leaves a process behind. Therefore, we wait for the
305 thread to signal that it has started. There is no easy way to force the
306 race to occur, so we don't try to find it.
308 ok(WaitForSingleObject(event,5000)==WAIT_OBJECT_0,
309 "TerminateThread didn't work");
310 /* check that access restrictions are obeyed */
311 if(WIN2K_PLUS(version)) {
312 access_thread=OpenThreadPtr(THREAD_ALL_ACCESS & (~THREAD_TERMINATE),
314 ok(access_thread!=(HANDLE)NULL,"OpenThread returned an invalid handle");
315 if(access_thread!=(HANDLE)NULL) {
316 ok(TerminateThread(access_thread,99)==0,
317 "TerminateThread did not obey access restrictions");
318 ok(CloseHandle(access_thread)!=0,"CloseHandle Failed");
321 /* terminate a job and make sure it terminates */
322 ok(TerminateThread(thread,99)!=0,"TerminateThread failed");
323 ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
324 "TerminateThread didn't work");
325 ok(GetExitCodeThread(thread,&exitCode)!=STILL_ACTIVE,
326 "TerminateThread should not leave the thread 'STILL_ACTIVE'");
327 if(WIN2K_PLUS(version)) {
328 /*NOTE: In Win2k, GetExitCodeThread does not return the value specified by
329 TerminateThread, even though MSDN says it should. So currently
330 there is no check being done for this.
332 trace("TerminateThread returned: 0x%lx instead of 0x%x\n",exitCode,99);
334 ok(exitCode==99, "TerminateThread returned invalid exit code");
336 ok(CloseHandle(thread)!=0,"Error Closing thread handle");
339 /* Check if CreateThread obeys the specified stack size. This code does
340 not work properly, and is currently disabled
342 VOID test_CreateThread_stack(DWORD version)
345 /* The only way I know of to test the stack size is to use alloca
346 and __try/__except. However, this is probably not portable,
347 and I couldn't get it to work under Wine anyhow. However, here
348 is the code which should allow for testing that CreateThread
349 respects the stack-size limit
352 DWORD threadId,exitCode;
355 sysInfo.dwPageSize=0;
356 GetSystemInfo(&sysInfo);
357 ok(sysInfo.dwPageSize>0,"GetSystemInfo should return a valid page size");
358 thread = CreateThread(NULL,sysInfo.dwPageSize,
359 (LPTHREAD_START_ROUTINE)threadFunc5,&exitCode,
361 ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
362 "TerminateThread didn't work");
363 ok(exitCode==1,"CreateThread did not obey stack-size-limit");
364 ok(CloseHandle(thread)!=0,"CloseHandle failed");
368 /* Check whether setting/retreiving thread priorities works */
369 VOID test_thread_priority(DWORD version)
371 HANDLE curthread,access_thread;
372 DWORD curthreadId,exitCode;
373 int min_priority=-2,max_priority=2;
376 curthread=GetCurrentThread();
377 curthreadId=GetCurrentThreadId();
378 /* Check thread priority */
379 /* NOTE: on Win2k/XP priority can be from -7 to 6. All other platforms it
380 is -2 to 2. However, even on a real Win2k system, using thread
381 priorities beyond the -2 to 2 range does not work. If you want to try
382 anyway, enable USE_EXTENDED_PRIORITIES
384 ok(GetThreadPriority(curthread)==THREAD_PRIORITY_NORMAL,
385 "GetThreadPriority Failed");
387 if(WIN2K_PLUS(version)) {
388 /* check that access control is obeyed */
389 access_thread=OpenThreadPtr(THREAD_ALL_ACCESS &
390 (~THREAD_QUERY_INFORMATION) & (~THREAD_SET_INFORMATION),
392 ok(access_thread!=(HANDLE)NULL,"OpenThread returned an invalid handle");
393 if(access_thread!=(HANDLE)NULL) {
394 ok(SetThreadPriority(access_thread,1)==0,
395 "SetThreadPriority did not obey access restrictions");
396 ok(GetThreadPriority(access_thread)==THREAD_PRIORITY_ERROR_RETURN,
397 "GetThreadPriority did not obey access restrictions");
398 ok(SetThreadPriorityBoost(access_thread,1)==0,
399 "SetThreadPriorityBoost did not obey access restrictions");
400 ok(GetThreadPriorityBoost(access_thread,&error)==0,
401 "GetThreadPriorityBoost did not obey access restrictions");
402 ok(GetExitCodeThread(access_thread,&exitCode)==0,
403 "GetExitCodeThread did not obey access restrictions");
404 ok(CloseHandle(access_thread),"Error Closing thread handle");
406 #if USE_EXTENDED_PRIORITIES
407 min_priority=-7; max_priority=6;
410 for(i=min_priority;i<=max_priority;i++) {
411 ok(SetThreadPriority(curthread,i)!=0,
412 "SetThreadPriority Failed for priority: %d",i);
413 ok(GetThreadPriority(curthread)==i,
414 "GetThreadPriority Failed for priority: %d",i);
416 ok(SetThreadPriority(curthread,THREAD_PRIORITY_TIME_CRITICAL)!=0,
417 "SetThreadPriority Failed");
418 ok(GetThreadPriority(curthread)==THREAD_PRIORITY_TIME_CRITICAL,
419 "GetThreadPriority Failed");
420 ok(SetThreadPriority(curthread,THREAD_PRIORITY_IDLE)!=0,
421 "SetThreadPriority Failed");
422 ok(GetThreadPriority(curthread)==THREAD_PRIORITY_IDLE,
423 "GetThreadPriority Failed");
424 ok(SetThreadPriority(curthread,0)!=0,"SetThreadPriority Failed");
426 /* Check thread priority boost */
427 /* NOTE: This only works on WinNT/2000/XP) */
428 if(version < 0x80000000) {
430 ok(SetThreadPriorityBoost(curthread,1)!=0,
431 "SetThreadPriorityBoost Failed");
432 ok(GetThreadPriorityBoost(curthread,&error)!=0 && error==1,
433 "GetThreadPriorityBoost Failed");
434 ok(SetThreadPriorityBoost(curthread,0)!=0,
435 "SetThreadPriorityBoost Failed");
436 ok(GetThreadPriorityBoost(curthread,&error)!=0 && error==0,
437 "GetThreadPriorityBoost Failed");
442 /* check the GetThreadTimes function */
443 VOID test_GetThreadTimes(DWORD version)
445 HANDLE thread,access_thread=(HANDLE)NULL;
446 FILETIME creationTime,exitTime,kernelTime,userTime;
450 thread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)threadFunc2,NULL,
451 CREATE_SUSPENDED,&threadId);
453 ok(thread!=(HANDLE)NULL,"Create Thread failed.");
454 /* check that access control is obeyed */
455 if(WIN2K_PLUS(version)) {
456 access_thread=OpenThreadPtr(THREAD_ALL_ACCESS &
457 (~THREAD_QUERY_INFORMATION), 0,threadId);
458 ok(access_thread!=(HANDLE)NULL,
459 "OpenThread returned an invalid handle");
461 ok(ResumeThread(thread)==1,"Resume thread returned an invalid value");
462 ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
463 "ResumeThread didn't work");
464 if(WIN2K_PLUS(version)) {
465 if(access_thread!=(HANDLE)NULL) {
466 error=GetThreadTimes(access_thread,&creationTime,&exitTime,
467 &kernelTime,&userTime);
468 ok(error==0, "GetThreadTimes did not obey access restrictions");
469 ok(CloseHandle(access_thread)!=0,"CloseHandle Failed");
472 creationTime.dwLowDateTime=99; creationTime.dwHighDateTime=99;
473 exitTime.dwLowDateTime=99; exitTime.dwHighDateTime=99;
474 kernelTime.dwLowDateTime=99; kernelTime.dwHighDateTime=99;
475 userTime.dwLowDateTime=99; userTime.dwHighDateTime=99;
476 /* GetThreadTimes should set all of the parameters passed to it */
478 error=GetThreadTimes(thread,&creationTime,&exitTime,
479 &kernelTime,&userTime);
480 ok(error!=0,"GetThreadTimes failed");
481 ok(creationTime.dwLowDateTime!=99 || creationTime.dwHighDateTime!=99,
482 "creationTime was invalid");
483 ok(exitTime.dwLowDateTime!=99 || exitTime.dwHighDateTime!=99,
484 "exitTime was invalid");
485 ok(kernelTime.dwLowDateTime!=99 || kernelTime.dwHighDateTime!=99,
486 "kernelTime was invalid");
487 ok(userTime.dwLowDateTime!=99 || userTime.dwHighDateTime!=99,
488 "userTime was invalid");
490 ok(CloseHandle(thread)!=0,"ClosewHandle failed");
493 /* Check the processor affinity functions */
494 /* NOTE: These functions should also be checked that they obey access control
496 VOID test_thread_processor(DWORD version)
498 HANDLE curthread,curproc;
499 DWORD processMask,systemMask;
503 sysInfo.dwNumberOfProcessors=0;
504 GetSystemInfo(&sysInfo);
505 ok(sysInfo.dwNumberOfProcessors>0,
506 "GetSystemInfo failed to return a valid # of processors");
507 /* Use the current Thread/process for all tests */
508 curthread=GetCurrentThread();
509 ok(curthread!=(HANDLE)NULL,"GetCurrentThread failed");
510 curproc=GetCurrentProcess();
511 ok(curproc!=(HANDLE)NULL,"GetCurrentProcess failed");
512 /* Check the Affinity Mask functions */
513 ok(GetProcessAffinityMask(curproc,&processMask,&systemMask)!=0,
514 "GetProcessAffinityMask failed");
515 ok(SetThreadAffinityMask(curthread,processMask)==1,
516 "SetThreadAffinityMask failed");
517 ok(SetThreadAffinityMask(curthread,processMask+1)==0,
518 "SetThreadAffinityMask passed for an illegal processor");
519 /* NOTE: This only works on WinNT/2000/XP) */
520 if(version < 0x80000000) {
522 error=SetThreadIdealProcessor(curthread,0);
523 ok(error!=-1, "SetThreadIdealProcessor failed");
524 error=SetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS+1);
527 "SetThreadIdealProccesor succeeded with an illegal processor #");
529 error=SetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS);
530 ok(error==0, "SetThreadIdealProccesor returned an incorrect value");
539 version=GetVersion();
540 /* Neither Cygwin nor mingW export OpenThread, so do a dynamic check
541 so that the compile passes
543 lib=LoadLibraryA("kernel32");
544 ok(lib!=(HANDLE)NULL,"Couldn't load kernel32.dll");
545 OpenThreadPtr=(OPENTHREADPTR)GetProcAddress(lib,"OpenThread");
546 if(OpenThreadPtr==NULL) {
547 OpenThreadPtr=&OpenThreadDefault;
549 test_CreateThread_basic(version);
550 test_CreateThread_suspended(version);
551 test_SuspendThread(version);
552 test_TerminateThread(version);
553 test_CreateThread_stack(version);
554 test_thread_priority(version);
555 test_GetThreadTimes(version);
556 test_thread_processor(version);