/* * Unit test suite for directory functions. * * Copyright 2002 Geoffrey Hausheer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "wine/test.h" #include #include #include /* Specify the number of simultaneous threads to test */ #define NUM_THREADS 4 /* Specify whether to test the extended priorities for Win2k/XP */ #define USE_EXTENDED_PRIORITIES 0 /* Specify whether to test the stack allocation in CreateThread */ #define CHECK_STACK 0 /* Set CHECK_STACK to 1 if you want to try to test the stack-limit from CreateThread. So far I have been unable to make this work, and I am in doubt as to how portable it is. Also, according to MSDN, you shouldn't mix C-run-time-libraries (i.e. alloca) with CreateThread. Anyhow, the check is currently commented out */ #if CHECK_STACK #ifdef __try #define __TRY __try #define __EXCEPT __except #define __ENDTRY #else #include "wine/exception.h" #endif #endif typedef HANDLE WINAPI (*OPENTHREADPTR)(DWORD,BOOL,DWORD); OPENTHREADPTR OpenThreadPtr; HANDLE WINAPI OpenThreadDefault(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId) { return (HANDLE)NULL; } /* define a check for whether we are running in Win2k or XP */ #define WIN2K_PLUS(version) (version < 0x80000000 && (version & 0xFF) >= 5) /* Functions not tested yet: AttachThreadInput CreateRemoteThread SetThreadContext SwitchToThread In addition there are no checks that the inheritance works properly in CreateThread */ DWORD tlsIndex; typedef struct { int threadnum; HANDLE *event; DWORD *threadmem; } t1Struct; /* Basic test that simulatneous threads can access shared memory, that the thread local storage routines work correctly, and that threads actually run concurrently */ VOID WINAPI threadFunc1(t1Struct *tstruct) { int i; /* write our thread # into shared memory */ tstruct->threadmem[tstruct->threadnum]=GetCurrentThreadId(); ok(TlsSetValue(tlsIndex,(LPVOID)(tstruct->threadnum+1))!=0, "TlsSetValue failed"); /* The threads synchronize before terminating. This is done by Signaling an event, and waiting for all events to occur */ SetEvent(tstruct->event[tstruct->threadnum]); WaitForMultipleObjects(NUM_THREADS,tstruct->event,TRUE,INFINITE); /* Double check that all threads really did run by validating that they have all written to the shared memory. There should be no race here, since all threads were synchronized after the write.*/ for(i=0;ithreadmem[i]==0) ; } /* Check that noone cahnged our tls memory */ ok((DWORD)TlsGetValue(tlsIndex)-1==tstruct->threadnum, "TlsGetValue failed"); ExitThread(NUM_THREADS+tstruct->threadnum); } VOID WINAPI threadFunc2() { ExitThread(99); } VOID WINAPI threadFunc3() { HANDLE thread; thread=GetCurrentThread(); SuspendThread(thread); ExitThread(99); } VOID WINAPI threadFunc4(HANDLE event) { if(event != (HANDLE)NULL) { SetEvent(event); } Sleep(99000); ExitThread(0); } #if CHECK_STACK VOID WINAPI threadFunc5(DWORD *exitCode) { SYSTEM_INFO sysInfo; sysInfo.dwPageSize=0; GetSystemInfo(&sysInfo); *exitCode=0; __TRY { alloca(2*sysInfo.dwPageSize); } __EXCEPT(1) { *exitCode=1; } __ENDTRY ExitThread(0); } #endif /* Check basic funcationality of CreateThread and Tls* functions */ VOID test_CreateThread_basic(DWORD version) { HANDLE thread[NUM_THREADS],event[NUM_THREADS]; DWORD threadid[NUM_THREADS],curthreadId; DWORD threadmem[NUM_THREADS]; DWORD exitCode; t1Struct tstruct[NUM_THREADS]; int error; int i,j; /* Retrieve current Thread ID for later comparisons */ curthreadId=GetCurrentThreadId(); /* Allocate some local storage */ ok((tlsIndex=TlsAlloc())!=TLS_OUT_OF_INDEXES,"TlsAlloc failed"); /* Create events for thread synchronization */ for(i=0;i0,"GetSystemInfo should return a valid page size"); thread = CreateThread(NULL,sysInfo.dwPageSize, (LPTHREAD_START_ROUTINE)threadFunc5,&exitCode, 0,&threadId); ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0, "TerminateThread didn't work"); ok(exitCode==1,"CreateThread did not obey stack-size-limit"); ok(CloseHandle(thread)!=0,"CloseHandle failed"); #endif } /* Check whether setting/retreiving thread priorities works */ VOID test_thread_priority(DWORD version) { HANDLE curthread,access_thread; DWORD curthreadId,exitCode; int min_priority=-2,max_priority=2; int i,error; curthread=GetCurrentThread(); curthreadId=GetCurrentThreadId(); /* Check thread priority */ /* NOTE: on Win2k/XP priority can be from -7 to 6. All other platforms it is -2 to 2. However, even on a real Win2k system, using thread priorities beyond the -2 to 2 range does not work. If you want to try anyway, enable USE_EXTENDED_PRIORITIES */ ok(GetThreadPriority(curthread)==THREAD_PRIORITY_NORMAL, "GetThreadPriority Failed"); if(WIN2K_PLUS(version)) { /* check that access control is obeyed */ access_thread=OpenThreadPtr(THREAD_ALL_ACCESS & (~THREAD_QUERY_INFORMATION) & (~THREAD_SET_INFORMATION), 0,curthreadId); ok(access_thread!=(HANDLE)NULL,"OpenThread returned an invalid handle"); if(access_thread!=(HANDLE)NULL) { ok(SetThreadPriority(access_thread,1)==0, "SetThreadPriority did not obey access restrictions"); ok(GetThreadPriority(access_thread)==THREAD_PRIORITY_ERROR_RETURN, "GetThreadPriority did not obey access restrictions"); ok(SetThreadPriorityBoost(access_thread,1)==0, "SetThreadPriorityBoost did not obey access restrictions"); ok(GetThreadPriorityBoost(access_thread,&error)==0, "GetThreadPriorityBoost did not obey access restrictions"); ok(GetExitCodeThread(access_thread,&exitCode)==0, "GetExitCodeThread did not obey access restrictions"); ok(CloseHandle(access_thread),"Error Closing thread handle"); } #if USE_EXTENDED_PRIORITIES min_priority=-7; max_priority=6; #endif } for(i=min_priority;i<=max_priority;i++) { ok(SetThreadPriority(curthread,i)!=0, "SetThreadPriority Failed for priority: %d",i); ok(GetThreadPriority(curthread)==i, "GetThreadPriority Failed for priority: %d",i); } ok(SetThreadPriority(curthread,THREAD_PRIORITY_TIME_CRITICAL)!=0, "SetThreadPriority Failed"); ok(GetThreadPriority(curthread)==THREAD_PRIORITY_TIME_CRITICAL, "GetThreadPriority Failed"); ok(SetThreadPriority(curthread,THREAD_PRIORITY_IDLE)!=0, "SetThreadPriority Failed"); ok(GetThreadPriority(curthread)==THREAD_PRIORITY_IDLE, "GetThreadPriority Failed"); ok(SetThreadPriority(curthread,0)!=0,"SetThreadPriority Failed"); /* Check thread priority boost */ /* NOTE: This only works on WinNT/2000/XP) */ if(version < 0x80000000) { todo_wine { ok(SetThreadPriorityBoost(curthread,1)!=0, "SetThreadPriorityBoost Failed"); ok(GetThreadPriorityBoost(curthread,&error)!=0 && error==1, "GetThreadPriorityBoost Failed"); ok(SetThreadPriorityBoost(curthread,0)!=0, "SetThreadPriorityBoost Failed"); ok(GetThreadPriorityBoost(curthread,&error)!=0 && error==0, "GetThreadPriorityBoost Failed"); } } } /* check the GetThreadTimes function */ VOID test_GetThreadTimes(DWORD version) { HANDLE thread,access_thread=(HANDLE)NULL; FILETIME creationTime,exitTime,kernelTime,userTime; DWORD threadId; int error; thread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)threadFunc2,NULL, CREATE_SUSPENDED,&threadId); ok(thread!=(HANDLE)NULL,"Create Thread failed."); /* check that access control is obeyed */ if(WIN2K_PLUS(version)) { access_thread=OpenThreadPtr(THREAD_ALL_ACCESS & (~THREAD_QUERY_INFORMATION), 0,threadId); ok(access_thread!=(HANDLE)NULL, "OpenThread returned an invalid handle"); } ok(ResumeThread(thread)==1,"Resume thread returned an invalid value"); ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0, "ResumeThread didn't work"); if(WIN2K_PLUS(version)) { if(access_thread!=(HANDLE)NULL) { error=GetThreadTimes(access_thread,&creationTime,&exitTime, &kernelTime,&userTime); ok(error==0, "GetThreadTimes did not obey access restrictions"); ok(CloseHandle(access_thread)!=0,"CloseHandle Failed"); } } creationTime.dwLowDateTime=99; creationTime.dwHighDateTime=99; exitTime.dwLowDateTime=99; exitTime.dwHighDateTime=99; kernelTime.dwLowDateTime=99; kernelTime.dwHighDateTime=99; userTime.dwLowDateTime=99; userTime.dwHighDateTime=99; /* GetThreadTimes should set all of the parameters passed to it */ todo_wine { error=GetThreadTimes(thread,&creationTime,&exitTime, &kernelTime,&userTime); ok(error!=0,"GetThreadTimes failed"); ok(creationTime.dwLowDateTime!=99 || creationTime.dwHighDateTime!=99, "creationTime was invalid"); ok(exitTime.dwLowDateTime!=99 || exitTime.dwHighDateTime!=99, "exitTime was invalid"); ok(kernelTime.dwLowDateTime!=99 || kernelTime.dwHighDateTime!=99, "kernelTime was invalid"); ok(userTime.dwLowDateTime!=99 || userTime.dwHighDateTime!=99, "userTime was invalid"); } ok(CloseHandle(thread)!=0,"ClosewHandle failed"); } /* Check the processor affinity functions */ /* NOTE: These functions should also be checked that they obey access control */ VOID test_thread_processor(DWORD version) { HANDLE curthread,curproc; DWORD processMask,systemMask; SYSTEM_INFO sysInfo; int error=0; sysInfo.dwNumberOfProcessors=0; GetSystemInfo(&sysInfo); ok(sysInfo.dwNumberOfProcessors>0, "GetSystemInfo failed to return a valid # of processors"); /* Use the current Thread/process for all tests */ curthread=GetCurrentThread(); ok(curthread!=(HANDLE)NULL,"GetCurrentThread failed"); curproc=GetCurrentProcess(); ok(curproc!=(HANDLE)NULL,"GetCurrentProcess failed"); /* Check the Affinity Mask functions */ ok(GetProcessAffinityMask(curproc,&processMask,&systemMask)!=0, "GetProcessAffinityMask failed"); ok(SetThreadAffinityMask(curthread,processMask)==1, "SetThreadAffinityMask failed"); ok(SetThreadAffinityMask(curthread,processMask+1)==0, "SetThreadAffinityMask passed for an illegal processor"); /* NOTE: This only works on WinNT/2000/XP) */ if(version < 0x80000000) { todo_wine { error=SetThreadIdealProcessor(curthread,0); ok(error!=-1, "SetThreadIdealProcessor failed"); error=SetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS+1); } ok(error==-1, "SetThreadIdealProccesor succeded with an illegal processor #"); todo_wine { error=SetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS); ok(error==0, "SetThreadIdealProccesor returned an incorrect value"); } } } START_TEST(thread) { DWORD version; HINSTANCE lib; version=GetVersion(); /* Neither Cygwin nor mingW export OpenThread, so do a dynamic check so that the compile passes */ lib=LoadLibraryA("kernel32"); ok(lib!=(HANDLE)NULL,"Couldn't load kernel32.dll"); OpenThreadPtr=(OPENTHREADPTR)GetProcAddress(lib,"OpenThread"); if(OpenThreadPtr==NULL) { OpenThreadPtr=&OpenThreadDefault; } test_CreateThread_basic(version); test_CreateThread_suspended(version); test_SuspendThread(version); test_TerminateThread(version); test_CreateThread_stack(version); test_thread_priority(version); test_GetThreadTimes(version); test_thread_processor(version); }