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"
52 typedef BOOL (WINAPI *GetThreadPriorityBoost_t)(HANDLE,PBOOL);
53 static GetThreadPriorityBoost_t pGetThreadPriorityBoost=NULL;
55 typedef HANDLE (WINAPI *OpenThread_t)(DWORD,BOOL,DWORD);
56 static OpenThread_t pOpenThread=NULL;
58 typedef DWORD (WINAPI *SetThreadIdealProcessor_t)(HANDLE,DWORD);
59 static SetThreadIdealProcessor_t pSetThreadIdealProcessor=NULL;
61 typedef BOOL (WINAPI *SetThreadPriorityBoost_t)(HANDLE,BOOL);
62 static SetThreadPriorityBoost_t pSetThreadPriorityBoost=NULL;
64 /* Functions not tested yet:
70 In addition there are no checks that the inheritance works properly in
82 /* Basic test that simulatneous threads can access shared memory,
83 that the thread local storage routines work correctly, and that
84 threads actually run concurrently
86 VOID WINAPI threadFunc1(t1Struct *tstruct)
89 /* write our thread # into shared memory */
90 tstruct->threadmem[tstruct->threadnum]=GetCurrentThreadId();
91 ok(TlsSetValue(tlsIndex,(LPVOID)(tstruct->threadnum+1))!=0,
92 "TlsSetValue failed");
93 /* The threads synchronize before terminating. This is done by
94 Signaling an event, and waiting for all events to occur
96 SetEvent(tstruct->event[tstruct->threadnum]);
97 WaitForMultipleObjects(NUM_THREADS,tstruct->event,TRUE,INFINITE);
98 /* Double check that all threads really did run by validating that
99 they have all written to the shared memory. There should be no race
100 here, since all threads were synchronized after the write.*/
101 for(i=0;i<NUM_THREADS;i++) {
102 while(tstruct->threadmem[i]==0) ;
104 /* Check that noone cahnged our tls memory */
105 ok((int)TlsGetValue(tlsIndex)-1==tstruct->threadnum,
106 "TlsGetValue failed");
107 ExitThread(NUM_THREADS+tstruct->threadnum);
110 VOID WINAPI threadFunc2()
115 VOID WINAPI threadFunc3()
118 thread=GetCurrentThread();
119 SuspendThread(thread);
123 VOID WINAPI threadFunc4(HANDLE event)
133 VOID WINAPI threadFunc5(DWORD *exitCode)
136 sysInfo.dwPageSize=0;
137 GetSystemInfo(&sysInfo);
141 alloca(2*sysInfo.dwPageSize);
151 /* Check basic funcationality of CreateThread and Tls* functions */
152 VOID test_CreateThread_basic()
154 HANDLE thread[NUM_THREADS],event[NUM_THREADS];
155 DWORD threadid[NUM_THREADS],curthreadId;
156 DWORD threadmem[NUM_THREADS];
158 t1Struct tstruct[NUM_THREADS];
161 /* Retrieve current Thread ID for later comparisons */
162 curthreadId=GetCurrentThreadId();
163 /* Allocate some local storage */
164 ok((tlsIndex=TlsAlloc())!=TLS_OUT_OF_INDEXES,"TlsAlloc failed");
165 /* Create events for thread synchronization */
166 for(i=0;i<NUM_THREADS;i++) {
168 /* Note that it doesn't matter what type of event we chose here. This
169 test isn't trying to thoroughly test events
171 event[i]=CreateEventA(NULL,TRUE,FALSE,NULL);
172 tstruct[i].threadnum=i;
173 tstruct[i].threadmem=threadmem;
174 tstruct[i].event=event;
177 /* Test that passing arguments to threads works okay */
178 for(i=0;i<NUM_THREADS;i++) {
179 thread[i] = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)threadFunc1,
180 &tstruct[i],0,&threadid[i]);
181 ok(thread[i]!=NULL,"Create Thread failed.");
183 /* Test that the threads actually complete */
184 for(i=0;i<NUM_THREADS;i++) {
185 error=WaitForSingleObject(thread[i],5000);
186 ok(error==WAIT_OBJECT_0, "Thread did not complete within timelimit");
187 if(error!=WAIT_OBJECT_0) {
188 TerminateThread(thread[i],i+NUM_THREADS);
190 ok(GetExitCodeThread(thread[i],&exitCode),"Could not retrieve ext code");
191 ok(exitCode==i+NUM_THREADS,"Thread returned an incorrect exit code");
193 /* Test that each thread executed in its parent's address space
194 (it was able to change threadmem and pass that change back to its parent)
195 and that each thread id was independant). Note that we prove that the
196 threads actually execute concurrently by having them block on each other
199 for(i=0;i<NUM_THREADS;i++) {
201 for(j=i+1;j<NUM_THREADS;j++) {
202 if (threadmem[i]==threadmem[j]) {
206 ok(!error && threadmem[i]==threadid[i] && threadmem[i]!=curthreadId,
207 "Thread did not execute successfully");
208 ok(CloseHandle(thread[i])!=0,"CloseHandle failed");
210 ok(TlsFree(tlsIndex)!=0,"TlsFree failed");
213 /* Check that using the CREATE_SUSPENDED flag works */
214 VOID test_CreateThread_suspended()
220 thread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)threadFunc2,NULL,
221 CREATE_SUSPENDED,&threadId);
222 ok(thread!=NULL,"Create Thread failed.");
223 /* Check that the thread is suspended */
224 ok(SuspendThread(thread)==1,"Thread did not start suspended");
225 ok(ResumeThread(thread)==2,"Resume thread returned an invalid value");
226 /* Check that resume thread didn't actually start the thread. I can't think
227 of a better way of checking this than just waiting. I am not sure if this
228 will work on slow computers.
230 ok(WaitForSingleObject(thread,1000)==WAIT_TIMEOUT,
231 "ResumeThread should not have actually started the thread");
232 /* Now actually resume the thread and make sure that it actually completes*/
233 ok(ResumeThread(thread)==1,"Resume thread returned an invalid value");
234 ok((error=WaitForSingleObject(thread,1000))==WAIT_OBJECT_0,
235 "Thread did not resume");
236 if(error!=WAIT_OBJECT_0) {
237 TerminateThread(thread,1);
239 ok(CloseHandle(thread)!=0,"CloseHandle failed");
242 /* Check that SuspendThread and ResumeThread work */
243 VOID test_SuspendThread()
245 HANDLE thread,access_thread;
246 DWORD threadId,exitCode;
249 thread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)threadFunc3,NULL,
251 ok(thread!=NULL,"Create Thread failed.");
252 /* Check that the thread is suspended */
253 /* Note that this is a polling method, and there is a race between
254 SuspendThread being called (in the child, and the loop below timing out,
255 so the test could fail on a heavily loaded or slow computer.
258 for(i=0;error==0 && i<100;i++) {
259 error=SuspendThread(thread);
260 ResumeThread(thread);
266 ok(error==1,"SuspendThread did not work");
267 /* check that access restrictions are obeyed */
269 access_thread=pOpenThread(THREAD_ALL_ACCESS & (~THREAD_SUSPEND_RESUME),
271 ok(access_thread!=NULL,"OpenThread returned an invalid handle");
272 if (access_thread!=NULL) {
273 ok(SuspendThread(access_thread)==-1,
274 "SuspendThread did not obey access restrictions");
275 ok(ResumeThread(access_thread)==-1,
276 "ResumeThread did not obey access restrictions");
277 ok(CloseHandle(access_thread)!=0,"CloseHandle Failed");
280 /* Double check that the thread really is suspended */
281 ok((error=GetExitCodeThread(thread,&exitCode))!=0 && exitCode==STILL_ACTIVE,
282 "Thread did not really suspend");
283 /* Resume the thread, and make sure it actually completes */
284 ok(ResumeThread(thread)==1,"Resume thread returned an invalid value");
285 ok((error=WaitForSingleObject(thread,1000))==WAIT_OBJECT_0,
286 "Thread did not resume");
287 if(error!=WAIT_OBJECT_0) {
288 TerminateThread(thread,1);
290 /* Trying to suspend a terminated thread should fail */
291 error=SuspendThread(thread);
292 ok(error==0xffffffff, "wrong return code: %d", error);
293 ok(GetLastError()==ERROR_ACCESS_DENIED || GetLastError()==ERROR_NO_MORE_ITEMS, "unexpected error code: %ld", GetLastError());
295 ok(CloseHandle(thread)!=0,"CloseHandle Failed");
298 /* Check that TerminateThread works properly
300 VOID test_TerminateThread()
302 HANDLE thread,access_thread,event;
303 DWORD threadId,exitCode;
306 event=CreateEventA(NULL,TRUE,FALSE,NULL);
307 thread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)threadFunc4,
308 (LPVOID)event, 0,&threadId);
309 ok(thread!=NULL,"Create Thread failed.");
310 /* Terminate thread has a race condition in Wine. If the thread is terminated
311 before it starts, it leaves a process behind. Therefore, we wait for the
312 thread to signal that it has started. There is no easy way to force the
313 race to occur, so we don't try to find it.
315 ok(WaitForSingleObject(event,5000)==WAIT_OBJECT_0,
316 "TerminateThread didn't work");
317 /* check that access restrictions are obeyed */
319 access_thread=pOpenThread(THREAD_ALL_ACCESS & (~THREAD_TERMINATE),
321 ok(access_thread!=NULL,"OpenThread returned an invalid handle");
322 if (access_thread!=NULL) {
323 ok(TerminateThread(access_thread,99)==0,
324 "TerminateThread did not obey access restrictions");
325 ok(CloseHandle(access_thread)!=0,"CloseHandle Failed");
328 /* terminate a job and make sure it terminates */
329 ok(TerminateThread(thread,99)!=0,"TerminateThread failed");
330 ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
331 "TerminateThread didn't work");
332 ok(GetExitCodeThread(thread,&exitCode)!=STILL_ACTIVE,
333 "TerminateThread should not leave the thread 'STILL_ACTIVE'");
334 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()
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()
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");
387 /* check that access control is obeyed */
388 access_thread=pOpenThread(THREAD_ALL_ACCESS &
389 (~THREAD_QUERY_INFORMATION) & (~THREAD_SET_INFORMATION),
391 ok(access_thread!=NULL,"OpenThread returned an invalid handle");
392 if (access_thread!=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 if (pSetThreadPriorityBoost)
398 ok(pSetThreadPriorityBoost(access_thread,1)==0,
399 "SetThreadPriorityBoost did not obey access restrictions");
400 if (pGetThreadPriorityBoost)
401 ok(pGetThreadPriorityBoost(access_thread,&error)==0,
402 "GetThreadPriorityBoost did not obey access restrictions");
403 ok(GetExitCodeThread(access_thread,&exitCode)==0,
404 "GetExitCodeThread did not obey access restrictions");
405 ok(CloseHandle(access_thread),"Error Closing thread handle");
407 #if USE_EXTENDED_PRIORITIES
408 min_priority=-7; max_priority=6;
411 for(i=min_priority;i<=max_priority;i++) {
412 ok(SetThreadPriority(curthread,i)!=0,
413 "SetThreadPriority Failed for priority: %d",i);
414 ok(GetThreadPriority(curthread)==i,
415 "GetThreadPriority Failed for priority: %d",i);
417 ok(SetThreadPriority(curthread,THREAD_PRIORITY_TIME_CRITICAL)!=0,
418 "SetThreadPriority Failed");
419 ok(GetThreadPriority(curthread)==THREAD_PRIORITY_TIME_CRITICAL,
420 "GetThreadPriority Failed");
421 ok(SetThreadPriority(curthread,THREAD_PRIORITY_IDLE)!=0,
422 "SetThreadPriority Failed");
423 ok(GetThreadPriority(curthread)==THREAD_PRIORITY_IDLE,
424 "GetThreadPriority Failed");
425 ok(SetThreadPriority(curthread,0)!=0,"SetThreadPriority Failed");
427 /* Check thread priority boost */
428 if (pGetThreadPriorityBoost && pSetThreadPriorityBoost) {
430 ok(pSetThreadPriorityBoost(curthread,1)!=0,
431 "SetThreadPriorityBoost Failed");
432 ok(pGetThreadPriorityBoost(curthread,&error)!=0 && error==1,
433 "GetThreadPriorityBoost Failed");
434 ok(pSetThreadPriorityBoost(curthread,0)!=0,
435 "SetThreadPriorityBoost Failed");
436 ok(pGetThreadPriorityBoost(curthread,&error)!=0 && error==0,
437 "GetThreadPriorityBoost Failed");
442 /* check the GetThreadTimes function */
443 VOID test_GetThreadTimes()
445 HANDLE thread,access_thread=NULL;
446 FILETIME creationTime,exitTime,kernelTime,userTime;
450 thread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)threadFunc2,NULL,
451 CREATE_SUSPENDED,&threadId);
453 ok(thread!=NULL,"Create Thread failed.");
454 /* check that access control is obeyed */
456 access_thread=pOpenThread(THREAD_ALL_ACCESS &
457 (~THREAD_QUERY_INFORMATION), 0,threadId);
458 ok(access_thread!=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(access_thread!=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");
470 creationTime.dwLowDateTime=99; creationTime.dwHighDateTime=99;
471 exitTime.dwLowDateTime=99; exitTime.dwHighDateTime=99;
472 kernelTime.dwLowDateTime=99; kernelTime.dwHighDateTime=99;
473 userTime.dwLowDateTime=99; userTime.dwHighDateTime=99;
474 /* GetThreadTimes should set all of the parameters passed to it */
475 error=GetThreadTimes(thread,&creationTime,&exitTime,
476 &kernelTime,&userTime);
477 if (error!=0 || GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
478 ok(error!=0,"GetThreadTimes failed");
479 ok(creationTime.dwLowDateTime!=99 || creationTime.dwHighDateTime!=99,
480 "creationTime was invalid");
481 ok(exitTime.dwLowDateTime!=99 || exitTime.dwHighDateTime!=99,
482 "exitTime was invalid");
483 ok(kernelTime.dwLowDateTime!=99 || kernelTime.dwHighDateTime!=99,
484 "kernelTimewas invalid");
485 ok(userTime.dwLowDateTime!=99 || userTime.dwHighDateTime!=99,
486 "userTime was invalid");
487 ok(CloseHandle(thread)!=0,"CloseHandle failed");
491 /* Check the processor affinity functions */
492 /* NOTE: These functions should also be checked that they obey access control
494 VOID test_thread_processor()
496 HANDLE curthread,curproc;
497 DWORD processMask,systemMask;
501 sysInfo.dwNumberOfProcessors=0;
502 GetSystemInfo(&sysInfo);
503 ok(sysInfo.dwNumberOfProcessors>0,
504 "GetSystemInfo failed to return a valid # of processors");
505 /* Use the current Thread/process for all tests */
506 curthread=GetCurrentThread();
507 ok(curthread!=NULL,"GetCurrentThread failed");
508 curproc=GetCurrentProcess();
509 ok(curproc!=NULL,"GetCurrentProcess failed");
510 /* Check the Affinity Mask functions */
511 ok(GetProcessAffinityMask(curproc,&processMask,&systemMask)!=0,
512 "GetProcessAffinityMask failed");
513 ok(SetThreadAffinityMask(curthread,processMask)==1,
514 "SetThreadAffinityMask failed");
515 ok(SetThreadAffinityMask(curthread,processMask+1)==0,
516 "SetThreadAffinityMask passed for an illegal processor");
517 /* NOTE: This only works on WinNT/2000/XP) */
518 if (pSetThreadIdealProcessor) {
521 error=pSetThreadIdealProcessor(curthread,0);
522 if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
523 ok(error!=-1, "SetThreadIdealProcessor failed");
526 if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
527 error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS+1);
529 "SetThreadIdealProccesor succeeded with an illegal processor #");
531 error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS);
532 ok(error==0, "SetThreadIdealProccesor returned an incorrect value");
541 /* Neither Cygwin nor mingW export OpenThread, so do a dynamic check
542 so that the compile passes
544 lib=LoadLibraryA("kernel32");
545 ok(lib!=NULL,"Couldn't load kernel32.dll");
546 pGetThreadPriorityBoost=(GetThreadPriorityBoost_t)GetProcAddress(lib,"GetThreadPriorityBoost");
547 pOpenThread=(OpenThread_t)GetProcAddress(lib,"OpenThread");
548 pSetThreadIdealProcessor=(SetThreadIdealProcessor_t)GetProcAddress(lib,"SetThreadIdealProcessor");
549 pSetThreadPriorityBoost=(SetThreadPriorityBoost_t)GetProcAddress(lib,"SetThreadPriorityBoost");
550 test_CreateThread_basic();
551 test_CreateThread_suspended();
552 test_SuspendThread();
553 test_TerminateThread();
554 test_CreateThread_stack();
555 test_thread_priority();
556 test_GetThreadTimes();
557 test_thread_processor();