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 #include "wine/test.h"
26 /* Specify the number of simultaneous threads to test */
28 /* Specify whether to test the extended priorities for Win2k/XP */
29 #define USE_EXTENDED_PRIORITIES 0
30 /* Specify whether to test the stack allocation in CreateThread */
33 /* Set CHECK_STACK to 1 if you want to try to test the stack-limit from
34 CreateThread. So far I have been unable to make this work, and
35 I am in doubt as to how portable it is. Also, according to MSDN,
36 you shouldn't mix C-run-time-libraries (i.e. alloca) with CreateThread.
37 Anyhow, the check is currently commented out
42 #define __EXCEPT __except
45 #include "wine/exception.h"
48 typedef HANDLE WINAPI (*OPENTHREADPTR)(DWORD,BOOL,DWORD);
49 OPENTHREADPTR OpenThreadPtr;
50 HANDLE WINAPI OpenThreadDefault(DWORD dwDesiredAccess,
56 /* define a check for whether we are running in Win2k or XP */
57 #define WIN2K_PLUS(version) (version < 0x80000000 && (version & 0xFF) >= 5)
59 /* Functions not tested yet:
65 In addition there are no checks that the inheritance works properly in
77 /* Basic test that simulatneous threads can access shared memory,
78 that the thread local storage routines work correctly, and that
79 threads actually run concurrently
81 VOID WINAPI threadFunc1(t1Struct *tstruct)
84 /* write our thread # into shared memory */
85 tstruct->threadmem[tstruct->threadnum]=GetCurrentThreadId();
86 ok(TlsSetValue(tlsIndex,(LPVOID)(tstruct->threadnum+1))!=0,
87 "TlsSetValue failed");
88 /* The threads synchronize before terminating. This is done by
89 Signaling an event, and waiting for all events to occur
91 SetEvent(tstruct->event[tstruct->threadnum]);
92 WaitForMultipleObjects(NUM_THREADS,tstruct->event,TRUE,INFINITE);
93 /* Double check that all threads really did run by validating that
94 they have all written to the shared memory. There should be no race
95 here, since all threads were synchronized after the write.*/
96 for(i=0;i<NUM_THREADS;i++) {
97 while(tstruct->threadmem[i]==0) ;
99 /* Check that noone cahnged our tls memory */
100 ok((DWORD)TlsGetValue(tlsIndex)-1==tstruct->threadnum,
101 "TlsGetValue failed");
102 ExitThread(NUM_THREADS+tstruct->threadnum);
105 VOID WINAPI threadFunc2()
110 VOID WINAPI threadFunc3()
113 thread=GetCurrentThread();
114 SuspendThread(thread);
118 VOID WINAPI threadFunc4(HANDLE event)
120 if(event != (HANDLE)NULL) {
128 VOID WINAPI threadFunc5(DWORD *exitCode)
131 sysInfo.dwPageSize=0;
132 GetSystemInfo(&sysInfo);
136 alloca(2*sysInfo.dwPageSize);
146 /* Check basic funcationality of CreateThread and Tls* functions */
147 VOID test_CreateThread_basic(DWORD version)
149 HANDLE thread[NUM_THREADS],event[NUM_THREADS];
150 DWORD threadid[NUM_THREADS],curthreadId;
151 DWORD threadmem[NUM_THREADS];
153 t1Struct tstruct[NUM_THREADS];
156 /* Retrieve current Thread ID for later comparisons */
157 curthreadId=GetCurrentThreadId();
158 /* Allocate some local storage */
159 ok((tlsIndex=TlsAlloc())!=TLS_OUT_OF_INDEXES,"TlsAlloc failed");
160 /* Create events for thread synchronization */
161 for(i=0;i<NUM_THREADS;i++) {
163 /* Note that it doesn't matter what type of event we chose here. This
164 test isn't trying to thoroughly test events
166 event[i]=CreateEventA(NULL,TRUE,FALSE,NULL);
167 tstruct[i].threadnum=i;
168 tstruct[i].threadmem=threadmem;
169 tstruct[i].event=event;
172 /* Test that passing arguments to threads works okay */
173 for(i=0;i<NUM_THREADS;i++) {
174 thread[i] = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)threadFunc1,
175 &tstruct[i],0,&threadid[i]);
176 ok(thread[i]!=(HANDLE)NULL,"Create Thread failed.");
178 /* Test that the threads actually complete */
179 for(i=0;i<NUM_THREADS;i++) {
180 error=WaitForSingleObject(thread[i],5000);
181 ok(error==WAIT_OBJECT_0, "Thread did not complete within timelimit");
182 if(ok!=WAIT_OBJECT_0) {
183 TerminateThread(thread[i],1);
185 ok(GetExitCodeThread(thread[i],&exitCode),"Could not retrieve ext code");
187 ok(exitCode==i+NUM_THREADS,"Thread returned an incorrect exit code");
190 /* Test that each thread executed in its parent's address space
191 (it was able to change threadmem and pass that change back to its parent)
192 and that each thread id was independant). Note that we prove that the
193 threads actually execute concurrently by having them block on each other
196 for(i=0;i<NUM_THREADS;i++) {
198 for(j=i+1;j<NUM_THREADS;j++) {
199 if (threadmem[i]==threadmem[j]) {
203 ok(!error && threadmem[i]==threadid[i] && threadmem[i]!=curthreadId,
204 "Thread did not execute successfully");
205 ok(CloseHandle(thread[i])!=0,"CloseHandle failed");
207 ok(TlsFree(tlsIndex)!=0,"TlsFree failed");
210 /* Check that using the CREATE_SUSPENDED flag works */
211 VOID test_CreateThread_suspended(DWORD version)
217 thread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)threadFunc2,NULL,
218 CREATE_SUSPENDED,&threadId);
219 ok(thread!=(HANDLE)NULL,"Create Thread failed.");
220 /* Check that the thread is suspended */
221 ok(SuspendThread(thread)==1,"Thread did not start suspended");
222 ok(ResumeThread(thread)==2,"Resume thread returned an invalid value");
223 /* Check that resume thread didn't actually start the thread. I can't think
224 of a better way of checking this than just waiting. I am not sure if this
225 will work on slow computers.
227 ok(WaitForSingleObject(thread,1000)==WAIT_TIMEOUT,
228 "ResumeThread should not have actually started the thread");
229 /* Now actually resume the thread and make sure that it actually completes*/
230 ok(ResumeThread(thread)==1,"Resume thread returned an invalid value");
231 ok((error=WaitForSingleObject(thread,1000))==WAIT_OBJECT_0,
232 "Thread did not resume");
233 if(error!=WAIT_OBJECT_0) {
234 TerminateThread(thread,1);
236 ok(CloseHandle(thread)!=0,"CloseHandle failed");
239 /* Check that SuspendThread and ResumeThread work */
240 VOID test_SuspendThread(DWORD version)
242 HANDLE thread,access_thread;
243 DWORD threadId,exitCode;
246 thread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)threadFunc3,NULL,
248 ok(thread!=(HANDLE)NULL,"Create Thread failed.");
249 /* Check that the thread is suspended */
250 /* Note that this is a polling method, and there is a race between
251 SuspendThread being called (in the child, and the loop below timing out,
252 so the test could fail on a heavily loaded or slow computer.
255 for(i=0;error==0 && i<100;i++) {
256 error=SuspendThread(thread);
257 ResumeThread(thread);
263 ok(error==1,"SuspendThread did not work");
264 /* check that access restrictions are obeyed */
265 if(WIN2K_PLUS(version)) {
266 access_thread=OpenThreadPtr(THREAD_ALL_ACCESS & (~THREAD_SUSPEND_RESUME),
268 ok(access_thread!=(HANDLE)NULL,"OpenThread returned an invalid handle");
269 if(access_thread!=(HANDLE)NULL) {
270 ok(SuspendThread(access_thread)==-1,
271 "SuspendThread did not obey access restrictions");
272 ok(ResumeThread(access_thread)==-1,
273 "ResumeThread did not obey access restrictions");
274 ok(CloseHandle(access_thread)!=0,"CloseHandle Failed");
277 /* Double check that the thread really is suspended */
278 ok((error=GetExitCodeThread(thread,&exitCode))!=0 && exitCode==STILL_ACTIVE,
279 "Thread did not really suspend");
280 /* Resume the thread, and make sure it actually completes */
281 ok(ResumeThread(thread)==1,"Resume thread returned an invalid value");
282 ok((error=WaitForSingleObject(thread,1000))==WAIT_OBJECT_0,
283 "Thread did not resume");
284 if(error!=WAIT_OBJECT_0) {
285 TerminateThread(thread,1);
287 ok(CloseHandle(thread)!=0,"CloseHandle Failed");
290 /* Check that TerminateThread works properly
292 VOID test_TerminateThread(DWORD version)
294 HANDLE thread,access_thread,event;
295 DWORD threadId,exitCode;
298 event=CreateEventA(NULL,TRUE,FALSE,NULL);
299 thread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)threadFunc4,
300 (LPVOID)event, 0,&threadId);
301 ok(thread!=(HANDLE)NULL,"Create Thread failed.");
302 /* Terminate thread has a race condition in Wine. If the thread is terminated
303 before it starts, it leaves a process behind. Therefore, we wait for the
304 thread to signal that it has started. There is no easy way to force the
305 race to occur, so we don't try to find it.
307 ok(WaitForSingleObject(event,5000)==WAIT_OBJECT_0,
308 "TerminateThread didn't work");
309 /* check that access restrictions are obeyed */
310 if(WIN2K_PLUS(version)) {
311 access_thread=OpenThreadPtr(THREAD_ALL_ACCESS & (~THREAD_TERMINATE),
313 ok(access_thread!=(HANDLE)NULL,"OpenThread returned an invalid handle");
314 if(access_thread!=(HANDLE)NULL) {
315 ok(TerminateThread(access_thread,99)==0,
316 "TerminateThread did not obey access restrictions");
317 ok(CloseHandle(access_thread)!=0,"CloseHandle Failed");
320 /* terminate a job and make sure it terminates */
321 ok(TerminateThread(thread,99)!=0,"TerminateThread failed");
322 ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
323 "TerminateThread didn't work");
324 ok(GetExitCodeThread(thread,&exitCode)!=STILL_ACTIVE,
325 "TerminateThread should not leave the thread 'STILL_ACTIVE'");
326 if(WIN2K_PLUS(version)) {
327 /*NOTE: In Win2k, GetExitCodeThread does not return the value specified by
328 TerminateThread, even though MSDN says it should. So currently
329 there is no check being done for this.
331 trace("TerminateThread returned: 0x%lx instead of 0x%x\n",exitCode,99);
333 ok(exitCode==99, "TerminateThread returned invalid exit code");
335 ok(CloseHandle(thread)!=0,"Error Closing thread handle");
338 /* Check if CreateThread obeys the specified stack size. This code does
339 not work properly, and is currently disabled
341 VOID test_CreateThread_stack(DWORD version)
344 /* The only way I know of to test the stack size is to use alloca
345 and __try/__except. However, this is probably not portable,
346 and I couldn't get it to work under Wine anyhow. However, here
347 is the code which should allow for testing that CreateThread
348 respects the stack-size limit
351 DWORD threadId,exitCode;
354 sysInfo.dwPageSize=0;
355 GetSystemInfo(&sysInfo);
356 ok(sysInfo.dwPageSize>0,"GetSystemInfo should return a valid page size");
357 thread = CreateThread(NULL,sysInfo.dwPageSize,
358 (LPTHREAD_START_ROUTINE)threadFunc5,&exitCode,
360 ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
361 "TerminateThread didn't work");
362 ok(exitCode==1,"CreateThread did not obey stack-size-limit");
363 ok(CloseHandle(thread)!=0,"CloseHandle failed");
367 /* Check whether setting/retreiving thread priorities works */
368 VOID test_thread_priority(DWORD version)
370 HANDLE curthread,access_thread;
371 DWORD curthreadId,exitCode;
372 int min_priority=-2,max_priority=2;
375 curthread=GetCurrentThread();
376 curthreadId=GetCurrentThreadId();
377 /* Check thread priority */
378 /* NOTE: on Win2k/XP priority can be from -7 to 6. All other platforms it
379 is -2 to 2. However, even on a real Win2k system, using thread
380 priorities beyond the -2 to 2 range does not work. If you want to try
381 anyway, enable USE_EXTENDED_PRIORITIES
383 ok(GetThreadPriority(curthread)==THREAD_PRIORITY_NORMAL,
384 "GetThreadPriority Failed");
386 if(WIN2K_PLUS(version)) {
387 /* check that access control is obeyed */
388 access_thread=OpenThreadPtr(THREAD_ALL_ACCESS &
389 (~THREAD_QUERY_INFORMATION) & (~THREAD_SET_INFORMATION),
391 ok(access_thread!=(HANDLE)NULL,"OpenThread returned an invalid handle");
392 if(access_thread!=(HANDLE)NULL) {
393 ok(SetThreadPriority(access_thread,1)==0,
394 "SetThreadPriority did not obey access restrictions");
395 ok(GetThreadPriority(access_thread)==THREAD_PRIORITY_ERROR_RETURN,
396 "GetThreadPriority did not obey access restrictions");
397 ok(SetThreadPriorityBoost(access_thread,1)==0,
398 "SetThreadPriorityBoost did not obey access restrictions");
399 ok(GetThreadPriorityBoost(access_thread,&error)==0,
400 "GetThreadPriorityBoost did not obey access restrictions");
401 ok(GetExitCodeThread(access_thread,&exitCode)==0,
402 "GetExitCodeThread did not obey access restrictions");
403 ok(CloseHandle(access_thread),"Error Closing thread handle");
405 #if USE_EXTENDED_PRIORITIES
406 min_priority=-7; max_priority=6;
409 for(i=min_priority;i<=max_priority;i++) {
410 ok(SetThreadPriority(curthread,i)!=0,
411 "SetThreadPriority Failed for priority: %d",i);
412 ok(GetThreadPriority(curthread)==i,
413 "GetThreadPriority Failed for priority: %d",i);
415 ok(SetThreadPriority(curthread,THREAD_PRIORITY_TIME_CRITICAL)!=0,
416 "SetThreadPriority Failed");
417 ok(GetThreadPriority(curthread)==THREAD_PRIORITY_TIME_CRITICAL,
418 "GetThreadPriority Failed");
419 ok(SetThreadPriority(curthread,THREAD_PRIORITY_IDLE)!=0,
420 "SetThreadPriority Failed");
421 ok(GetThreadPriority(curthread)==THREAD_PRIORITY_IDLE,
422 "GetThreadPriority Failed");
423 ok(SetThreadPriority(curthread,0)!=0,"SetThreadPriority Failed");
425 /* Check thread priority boost */
426 /* NOTE: This only works on WinNT/2000/XP) */
427 if(version < 0x80000000) {
429 ok(SetThreadPriorityBoost(curthread,1)!=0,
430 "SetThreadPriorityBoost Failed");
431 ok(GetThreadPriorityBoost(curthread,&error)!=0 && error==1,
432 "GetThreadPriorityBoost Failed");
433 ok(SetThreadPriorityBoost(curthread,0)!=0,
434 "SetThreadPriorityBoost Failed");
435 ok(GetThreadPriorityBoost(curthread,&error)!=0 && error==0,
436 "GetThreadPriorityBoost Failed");
441 /* check the GetThreadTimes function */
442 VOID test_GetThreadTimes(DWORD version)
444 HANDLE thread,access_thread=(HANDLE)NULL;
445 FILETIME creationTime,exitTime,kernelTime,userTime;
449 thread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)threadFunc2,NULL,
450 CREATE_SUSPENDED,&threadId);
452 ok(thread!=(HANDLE)NULL,"Create Thread failed.");
453 /* check that access control is obeyed */
454 if(WIN2K_PLUS(version)) {
455 access_thread=OpenThreadPtr(THREAD_ALL_ACCESS &
456 (~THREAD_QUERY_INFORMATION), 0,threadId);
457 ok(access_thread!=(HANDLE)NULL,
458 "OpenThread returned an invalid handle");
460 ok(ResumeThread(thread)==1,"Resume thread returned an invalid value");
461 ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
462 "ResumeThread didn't work");
463 if(WIN2K_PLUS(version)) {
464 if(access_thread!=(HANDLE)NULL) {
465 error=GetThreadTimes(access_thread,&creationTime,&exitTime,
466 &kernelTime,&userTime);
467 ok(error==0, "GetThreadTimes did not obey access restrictions");
468 ok(CloseHandle(access_thread)!=0,"CloseHandle Failed");
471 creationTime.dwLowDateTime=99; creationTime.dwHighDateTime=99;
472 exitTime.dwLowDateTime=99; exitTime.dwHighDateTime=99;
473 kernelTime.dwLowDateTime=99; kernelTime.dwHighDateTime=99;
474 userTime.dwLowDateTime=99; userTime.dwHighDateTime=99;
475 /* GetThreadTimes should set all of the parameters passed to it */
477 error=GetThreadTimes(thread,&creationTime,&exitTime,
478 &kernelTime,&userTime);
479 ok(error!=0,"GetThreadTimes failed");
480 ok(creationTime.dwLowDateTime!=99 || creationTime.dwHighDateTime!=99,
481 "creationTime was invalid");
482 ok(exitTime.dwLowDateTime!=99 || exitTime.dwHighDateTime!=99,
483 "exitTime was invalid");
484 ok(kernelTime.dwLowDateTime!=99 || kernelTime.dwHighDateTime!=99,
485 "kernelTime was invalid");
486 ok(userTime.dwLowDateTime!=99 || userTime.dwHighDateTime!=99,
487 "userTime was invalid");
489 ok(CloseHandle(thread)!=0,"ClosewHandle failed");
492 /* Check the processor affinity functions */
493 /* NOTE: These functions should also be checked that they obey access control
495 VOID test_thread_processor(DWORD version)
497 HANDLE curthread,curproc;
498 DWORD processMask,systemMask;
502 sysInfo.dwNumberOfProcessors=0;
503 GetSystemInfo(&sysInfo);
504 ok(sysInfo.dwNumberOfProcessors>0,
505 "GetSystemInfo failed to return a valid # of processors");
506 /* Use the current Thread/process for all tests */
507 curthread=GetCurrentThread();
508 ok(curthread!=(HANDLE)NULL,"GetCurrentThread failed");
509 curproc=GetCurrentProcess();
510 ok(curproc!=(HANDLE)NULL,"GetCurrentProcess failed");
511 /* Check the Affinity Mask functions */
512 ok(GetProcessAffinityMask(curproc,&processMask,&systemMask)!=0,
513 "GetProcessAffinityMask failed");
514 ok(SetThreadAffinityMask(curthread,processMask)==1,
515 "SetThreadAffinityMask failed");
516 ok(SetThreadAffinityMask(curthread,processMask+1)==0,
517 "SetThreadAffinityMask passed for an illegal processor");
518 /* NOTE: This only works on WinNT/2000/XP) */
519 if(version < 0x80000000) {
521 error=SetThreadIdealProcessor(curthread,0);
522 ok(error!=-1, "SetThreadIdealProcessor failed");
523 error=SetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS+1);
526 "SetThreadIdealProccesor succeded with an illegal processor #");
528 error=SetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS);
529 ok(error==0, "SetThreadIdealProccesor returned an incorrect value");
538 version=GetVersion();
539 /* Neither Cygwin nor mingW export OpenThread, so do a dynamic check
540 so that the compile passes
542 lib=LoadLibraryA("kernel32");
543 ok(lib!=(HANDLE)NULL,"Couldn't load kernel32.dll");
544 OpenThreadPtr=(OPENTHREADPTR)GetProcAddress(lib,"OpenThread");
545 if(OpenThreadPtr==NULL) {
546 OpenThreadPtr=&OpenThreadDefault;
548 test_CreateThread_basic(version);
549 test_CreateThread_suspended(version);
550 test_SuspendThread(version);
551 test_TerminateThread(version);
552 test_CreateThread_stack(version);
553 test_thread_priority(version);
554 test_GetThreadTimes(version);
555 test_thread_processor(version);