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
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 DWORD (WINAPI *SetThreadIdealProcessor_t)(HANDLE,DWORD);
62 static SetThreadIdealProcessor_t pSetThreadIdealProcessor=NULL;
64 typedef BOOL (WINAPI *SetThreadPriorityBoost_t)(HANDLE,BOOL);
65 static SetThreadPriorityBoost_t pSetThreadPriorityBoost=NULL;
67 /* Functions not tested yet:
73 In addition there are no checks that the inheritance works properly in
85 /* WinME supports OpenThread but doesn't know about access restrictions so
86 we require them to be either completely ignored or always obeyed.
88 INT obeying_ars = 0; /* -1 == no, 0 == dunno yet, 1 == yes */
92 ? (obeying_ars = +1) \
93 : ((obeying_ars = -1), \
94 trace("not restricted, assuming consistent behaviour\n"))) \
96 ? ok(!(x), "access restrictions obeyed\n") \
97 : ok( (x), "access restrictions not obeyed\n"))
99 /* Basic test that simultaneous threads can access shared memory,
100 that the thread local storage routines work correctly, and that
101 threads actually run concurrently
103 static DWORD WINAPI threadFunc1(LPVOID p)
105 t1Struct *tstruct = (t1Struct *)p;
107 /* write our thread # into shared memory */
108 tstruct->threadmem[tstruct->threadnum]=GetCurrentThreadId();
109 ok(TlsSetValue(tlsIndex,(LPVOID)(tstruct->threadnum+1))!=0,
110 "TlsSetValue failed\n");
111 /* The threads synchronize before terminating. This is done by
112 Signaling an event, and waiting for all events to occur
114 SetEvent(tstruct->event[tstruct->threadnum]);
115 WaitForMultipleObjects(NUM_THREADS,tstruct->event,TRUE,INFINITE);
116 /* Double check that all threads really did run by validating that
117 they have all written to the shared memory. There should be no race
118 here, since all threads were synchronized after the write.*/
119 for(i=0;i<NUM_THREADS;i++) {
120 while(tstruct->threadmem[i]==0) ;
122 /* Check that noone changed our tls memory */
123 ok((int)TlsGetValue(tlsIndex)-1==tstruct->threadnum,
124 "TlsGetValue failed\n");
125 return NUM_THREADS+tstruct->threadnum;
128 static DWORD WINAPI threadFunc2(LPVOID p)
133 static DWORD WINAPI threadFunc3(LPVOID p)
136 thread=GetCurrentThread();
137 SuspendThread(thread);
141 static DWORD WINAPI threadFunc4(LPVOID p)
143 HANDLE event = (HANDLE)p;
152 static DWORD WINAPI threadFunc5(LPVOID p)
154 DWORD *exitCode = (DWORD *)p;
156 sysInfo.dwPageSize=0;
157 GetSystemInfo(&sysInfo);
161 alloca(2*sysInfo.dwPageSize);
171 /* Check basic funcationality of CreateThread and Tls* functions */
172 static VOID test_CreateThread_basic(void)
174 HANDLE thread[NUM_THREADS],event[NUM_THREADS];
175 DWORD threadid[NUM_THREADS],curthreadId;
176 DWORD threadmem[NUM_THREADS];
178 t1Struct tstruct[NUM_THREADS];
181 /* Retrieve current Thread ID for later comparisons */
182 curthreadId=GetCurrentThreadId();
183 /* Allocate some local storage */
184 ok((tlsIndex=TlsAlloc())!=TLS_OUT_OF_INDEXES,"TlsAlloc failed\n");
185 /* Create events for thread synchronization */
186 for(i=0;i<NUM_THREADS;i++) {
188 /* Note that it doesn't matter what type of event we chose here. This
189 test isn't trying to thoroughly test events
191 event[i]=CreateEventA(NULL,TRUE,FALSE,NULL);
192 tstruct[i].threadnum=i;
193 tstruct[i].threadmem=threadmem;
194 tstruct[i].event=event;
197 /* Test that passing arguments to threads works okay */
198 for(i=0;i<NUM_THREADS;i++) {
199 thread[i] = CreateThread(NULL,0,threadFunc1,
200 &tstruct[i],0,&threadid[i]);
201 ok(thread[i]!=NULL,"Create Thread failed\n");
203 /* Test that the threads actually complete */
204 for(i=0;i<NUM_THREADS;i++) {
205 error=WaitForSingleObject(thread[i],5000);
206 ok(error==WAIT_OBJECT_0, "Thread did not complete within timelimit\n");
207 if(error!=WAIT_OBJECT_0) {
208 TerminateThread(thread[i],i+NUM_THREADS);
210 ok(GetExitCodeThread(thread[i],&exitCode),"Could not retrieve ext code\n");
211 ok(exitCode==i+NUM_THREADS,"Thread returned an incorrect exit code\n");
213 /* Test that each thread executed in its parent's address space
214 (it was able to change threadmem and pass that change back to its parent)
215 and that each thread id was independant). Note that we prove that the
216 threads actually execute concurrently by having them block on each other
219 for(i=0;i<NUM_THREADS;i++) {
221 for(j=i+1;j<NUM_THREADS;j++) {
222 if (threadmem[i]==threadmem[j]) {
226 ok(!error && threadmem[i]==threadid[i] && threadmem[i]!=curthreadId,
227 "Thread did not execute successfully\n");
228 ok(CloseHandle(thread[i])!=0,"CloseHandle failed\n");
230 ok(TlsFree(tlsIndex)!=0,"TlsFree failed\n");
233 /* Check that using the CREATE_SUSPENDED flag works */
234 static VOID test_CreateThread_suspended(void)
240 thread = CreateThread(NULL,0,threadFunc2,NULL,
241 CREATE_SUSPENDED,&threadId);
242 ok(thread!=NULL,"Create Thread failed\n");
243 /* Check that the thread is suspended */
244 ok(SuspendThread(thread)==1,"Thread did not start suspended\n");
245 ok(ResumeThread(thread)==2,"Resume thread returned an invalid value\n");
246 /* Check that resume thread didn't actually start the thread. I can't think
247 of a better way of checking this than just waiting. I am not sure if this
248 will work on slow computers.
250 ok(WaitForSingleObject(thread,1000)==WAIT_TIMEOUT,
251 "ResumeThread should not have actually started the thread\n");
252 /* Now actually resume the thread and make sure that it actually completes*/
253 ok(ResumeThread(thread)==1,"Resume thread returned an invalid value\n");
254 ok((error=WaitForSingleObject(thread,1000))==WAIT_OBJECT_0,
255 "Thread did not resume\n");
256 if(error!=WAIT_OBJECT_0) {
257 TerminateThread(thread,1);
259 ok(CloseHandle(thread)!=0,"CloseHandle failed\n");
262 /* Check that SuspendThread and ResumeThread work */
263 static VOID test_SuspendThread(void)
265 HANDLE thread,access_thread;
266 DWORD threadId,exitCode,error;
269 thread = CreateThread(NULL,0,threadFunc3,NULL,
271 ok(thread!=NULL,"Create Thread failed\n");
272 /* Check that the thread is suspended */
273 /* Note that this is a polling method, and there is a race between
274 SuspendThread being called (in the child, and the loop below timing out,
275 so the test could fail on a heavily loaded or slow computer.
278 for(i=0;error==0 && i<100;i++) {
279 error=SuspendThread(thread);
280 ResumeThread(thread);
286 ok(error==1,"SuspendThread did not work\n");
287 /* check that access restrictions are obeyed */
289 access_thread=pOpenThread(THREAD_ALL_ACCESS & (~THREAD_SUSPEND_RESUME),
291 ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
292 if (access_thread!=NULL) {
293 obey_ar(SuspendThread(access_thread)==~0UL);
294 obey_ar(ResumeThread(access_thread)==~0UL);
295 ok(CloseHandle(access_thread)!=0,"CloseHandle Failed\n");
298 /* Double check that the thread really is suspended */
299 ok((error=GetExitCodeThread(thread,&exitCode))!=0 && exitCode==STILL_ACTIVE,
300 "Thread did not really suspend\n");
301 /* Resume the thread, and make sure it actually completes */
302 ok(ResumeThread(thread)==1,"Resume thread returned an invalid value\n");
303 ok((error=WaitForSingleObject(thread,1000))==WAIT_OBJECT_0,
304 "Thread did not resume\n");
305 if(error!=WAIT_OBJECT_0) {
306 TerminateThread(thread,1);
308 /* Trying to suspend a terminated thread should fail */
309 error=SuspendThread(thread);
310 ok(error==~0UL, "wrong return code: %ld\n", error);
311 ok(GetLastError()==ERROR_ACCESS_DENIED || GetLastError()==ERROR_NO_MORE_ITEMS, "unexpected error code: %ld\n", GetLastError());
313 ok(CloseHandle(thread)!=0,"CloseHandle Failed\n");
316 /* Check that TerminateThread works properly
318 static VOID test_TerminateThread(void)
320 HANDLE thread,access_thread,event;
321 DWORD threadId,exitCode;
322 event=CreateEventA(NULL,TRUE,FALSE,NULL);
323 thread = CreateThread(NULL,0,threadFunc4,
324 (LPVOID)event, 0,&threadId);
325 ok(thread!=NULL,"Create Thread failed\n");
326 /* TerminateThread has a race condition in Wine. If the thread is terminated
327 before it starts, it leaves a process behind. Therefore, we wait for the
328 thread to signal that it has started. There is no easy way to force the
329 race to occur, so we don't try to find it.
331 ok(WaitForSingleObject(event,5000)==WAIT_OBJECT_0,
332 "TerminateThread didn't work\n");
333 /* check that access restrictions are obeyed */
335 access_thread=pOpenThread(THREAD_ALL_ACCESS & (~THREAD_TERMINATE),
337 ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
338 if (access_thread!=NULL) {
339 obey_ar(TerminateThread(access_thread,99)==0);
340 ok(CloseHandle(access_thread)!=0,"CloseHandle Failed\n");
343 /* terminate a job and make sure it terminates */
344 ok(TerminateThread(thread,99)!=0,"TerminateThread failed\n");
345 ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
346 "TerminateThread didn't work\n");
347 ok(GetExitCodeThread(thread,&exitCode)!=STILL_ACTIVE,
348 "TerminateThread should not leave the thread 'STILL_ACTIVE'\n");
349 ok(exitCode==99, "TerminateThread returned invalid exit code\n");
350 ok(CloseHandle(thread)!=0,"Error Closing thread handle\n");
353 /* Check if CreateThread obeys the specified stack size. This code does
354 not work properly, and is currently disabled
356 static VOID test_CreateThread_stack(void)
359 /* The only way I know of to test the stack size is to use alloca
360 and __try/__except. However, this is probably not portable,
361 and I couldn't get it to work under Wine anyhow. However, here
362 is the code which should allow for testing that CreateThread
363 respects the stack-size limit
366 DWORD threadId,exitCode;
369 sysInfo.dwPageSize=0;
370 GetSystemInfo(&sysInfo);
371 ok(sysInfo.dwPageSize>0,"GetSystemInfo should return a valid page size\n");
372 thread = CreateThread(NULL,sysInfo.dwPageSize,
373 threadFunc5,&exitCode,
375 ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
376 "TerminateThread didn't work\n");
377 ok(exitCode==1,"CreateThread did not obey stack-size-limit\n");
378 ok(CloseHandle(thread)!=0,"CloseHandle failed\n");
382 /* Check whether setting/retrieving thread priorities works */
383 static VOID test_thread_priority(void)
385 HANDLE curthread,access_thread;
386 DWORD curthreadId,exitCode;
387 int min_priority=-2,max_priority=2;
391 curthread=GetCurrentThread();
392 curthreadId=GetCurrentThreadId();
393 /* Check thread priority */
394 /* NOTE: on Win2k/XP priority can be from -7 to 6. All other platforms it
395 is -2 to 2. However, even on a real Win2k system, using thread
396 priorities beyond the -2 to 2 range does not work. If you want to try
397 anyway, enable USE_EXTENDED_PRIORITIES
399 ok(GetThreadPriority(curthread)==THREAD_PRIORITY_NORMAL,
400 "GetThreadPriority Failed\n");
403 /* check that access control is obeyed */
404 access_thread=pOpenThread(THREAD_ALL_ACCESS &
405 (~THREAD_QUERY_INFORMATION) & (~THREAD_SET_INFORMATION),
407 ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
408 if (access_thread!=NULL) {
409 obey_ar(SetThreadPriority(access_thread,1)==0);
410 obey_ar(GetThreadPriority(access_thread)==THREAD_PRIORITY_ERROR_RETURN);
411 obey_ar(GetExitCodeThread(access_thread,&exitCode)==0);
412 ok(CloseHandle(access_thread),"Error Closing thread handle\n");
414 #if USE_EXTENDED_PRIORITIES
415 min_priority=-7; max_priority=6;
418 for(i=min_priority;i<=max_priority;i++) {
419 ok(SetThreadPriority(curthread,i)!=0,
420 "SetThreadPriority Failed for priority: %d\n",i);
421 ok(GetThreadPriority(curthread)==i,
422 "GetThreadPriority Failed for priority: %d\n",i);
424 ok(SetThreadPriority(curthread,THREAD_PRIORITY_TIME_CRITICAL)!=0,
425 "SetThreadPriority Failed\n");
426 ok(GetThreadPriority(curthread)==THREAD_PRIORITY_TIME_CRITICAL,
427 "GetThreadPriority Failed\n");
428 ok(SetThreadPriority(curthread,THREAD_PRIORITY_IDLE)!=0,
429 "SetThreadPriority Failed\n");
430 ok(GetThreadPriority(curthread)==THREAD_PRIORITY_IDLE,
431 "GetThreadPriority Failed\n");
432 ok(SetThreadPriority(curthread,0)!=0,"SetThreadPriority Failed\n");
434 /* Check thread priority boost */
435 if (!pGetThreadPriorityBoost || !pSetThreadPriorityBoost)
438 SetLastError(0xdeadbeef);
439 rc=pGetThreadPriorityBoost(curthread,&disabled);
440 if (rc==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
443 /* check that access control is obeyed */
444 access_thread=pOpenThread(THREAD_ALL_ACCESS &
445 (~THREAD_QUERY_INFORMATION) & (~THREAD_SET_INFORMATION),
447 ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
448 if (access_thread!=NULL) {
449 obey_ar(pSetThreadPriorityBoost(access_thread,1)==0);
450 obey_ar(pGetThreadPriorityBoost(access_thread,&disabled)==0);
451 ok(CloseHandle(access_thread),"Error Closing thread handle\n");
455 ok(rc!=0,"error=%ld\n",GetLastError());
457 rc = pSetThreadPriorityBoost(curthread,1);
458 ok( rc != 0, "error=%ld\n",GetLastError());
459 rc=pGetThreadPriorityBoost(curthread,&disabled);
460 ok(rc!=0 && disabled==1,
461 "rc=%d error=%ld disabled=%d\n",rc,GetLastError(),disabled);
463 rc = pSetThreadPriorityBoost(curthread,0);
464 ok( rc != 0, "error=%ld\n",GetLastError());
465 rc=pGetThreadPriorityBoost(curthread,&disabled);
466 ok(rc!=0 && disabled==0,
467 "rc=%d error=%ld disabled=%d\n",rc,GetLastError(),disabled);
471 /* check the GetThreadTimes function */
472 static VOID test_GetThreadTimes(void)
474 HANDLE thread,access_thread=NULL;
475 FILETIME creationTime,exitTime,kernelTime,userTime;
479 thread = CreateThread(NULL,0,threadFunc2,NULL,
480 CREATE_SUSPENDED,&threadId);
482 ok(thread!=NULL,"Create Thread failed\n");
483 /* check that access control is obeyed */
485 access_thread=pOpenThread(THREAD_ALL_ACCESS &
486 (~THREAD_QUERY_INFORMATION), 0,threadId);
487 ok(access_thread!=NULL,
488 "OpenThread returned an invalid handle\n");
490 ok(ResumeThread(thread)==1,"Resume thread returned an invalid value\n");
491 ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
492 "ResumeThread didn't work\n");
493 creationTime.dwLowDateTime=99; creationTime.dwHighDateTime=99;
494 exitTime.dwLowDateTime=99; exitTime.dwHighDateTime=99;
495 kernelTime.dwLowDateTime=99; kernelTime.dwHighDateTime=99;
496 userTime.dwLowDateTime=99; userTime.dwHighDateTime=99;
497 /* GetThreadTimes should set all of the parameters passed to it */
498 error=GetThreadTimes(thread,&creationTime,&exitTime,
499 &kernelTime,&userTime);
500 if (error!=0 || GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
501 ok(error!=0,"GetThreadTimes failed\n");
502 ok(creationTime.dwLowDateTime!=99 || creationTime.dwHighDateTime!=99,
503 "creationTime was invalid\n");
504 ok(exitTime.dwLowDateTime!=99 || exitTime.dwHighDateTime!=99,
505 "exitTime was invalid\n");
506 ok(kernelTime.dwLowDateTime!=99 || kernelTime.dwHighDateTime!=99,
507 "kernelTimewas invalid\n");
508 ok(userTime.dwLowDateTime!=99 || userTime.dwHighDateTime!=99,
509 "userTime was invalid\n");
510 ok(CloseHandle(thread)!=0,"CloseHandle failed\n");
511 if(access_thread!=NULL)
513 error=GetThreadTimes(access_thread,&creationTime,&exitTime,
514 &kernelTime,&userTime);
518 if(access_thread!=NULL) {
519 ok(CloseHandle(access_thread)!=0,"CloseHandle Failed\n");
523 /* Check the processor affinity functions */
524 /* NOTE: These functions should also be checked that they obey access control
526 static VOID test_thread_processor(void)
528 HANDLE curthread,curproc;
529 DWORD processMask,systemMask;
533 sysInfo.dwNumberOfProcessors=0;
534 GetSystemInfo(&sysInfo);
535 ok(sysInfo.dwNumberOfProcessors>0,
536 "GetSystemInfo failed to return a valid # of processors\n");
537 /* Use the current Thread/process for all tests */
538 curthread=GetCurrentThread();
539 ok(curthread!=NULL,"GetCurrentThread failed\n");
540 curproc=GetCurrentProcess();
541 ok(curproc!=NULL,"GetCurrentProcess failed\n");
542 /* Check the Affinity Mask functions */
543 ok(GetProcessAffinityMask(curproc,&processMask,&systemMask)!=0,
544 "GetProcessAffinityMask failed\n");
545 ok(SetThreadAffinityMask(curthread,processMask)==processMask,
546 "SetThreadAffinityMask failed\n");
547 ok(SetThreadAffinityMask(curthread,processMask+1)==0,
548 "SetThreadAffinityMask passed for an illegal processor\n");
549 /* NOTE: This only works on WinNT/2000/XP) */
550 if (pSetThreadIdealProcessor) {
553 error=pSetThreadIdealProcessor(curthread,0);
554 if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
555 ok(error!=-1, "SetThreadIdealProcessor failed\n");
558 if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
559 error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS+1);
561 "SetThreadIdealProcessor succeeded with an illegal processor #\n");
563 error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS);
564 ok(error==0, "SetThreadIdealProcessor returned an incorrect value\n");
573 /* Neither Cygwin nor mingW export OpenThread, so do a dynamic check
574 so that the compile passes
576 lib=LoadLibraryA("kernel32");
577 ok(lib!=NULL,"Couldn't load kernel32.dll\n");
578 pGetThreadPriorityBoost=(GetThreadPriorityBoost_t)GetProcAddress(lib,"GetThreadPriorityBoost");
579 pOpenThread=(OpenThread_t)GetProcAddress(lib,"OpenThread");
580 pSetThreadIdealProcessor=(SetThreadIdealProcessor_t)GetProcAddress(lib,"SetThreadIdealProcessor");
581 pSetThreadPriorityBoost=(SetThreadPriorityBoost_t)GetProcAddress(lib,"SetThreadPriorityBoost");
582 test_CreateThread_basic();
583 test_CreateThread_suspended();
584 test_SuspendThread();
585 test_TerminateThread();
586 test_CreateThread_stack();
587 test_thread_priority();
588 test_GetThreadTimes();
589 test_thread_processor();