Checked on Win95, Win98, NT4, and XP. Changelog: * dlls/kernel/tests/thread.c {Get,Set}ThreadPriorityBoost and SetThreadIdealProcessor are missing on Win95 -> use GetProcAddress Cleanup the handling of OpenThread Check SuspendThread after a thread terminates (needed by Ipix) Remove unnecessary version checks (check for ERROR_CALL_NOT_IMPLEMENTED and similar instead) Cleanup casts, signed/unsigned comparisons Index: dlls/kernel/tests/thread.c =================================================================== RCS file: /home/wine/wine/dlls/kernel/tests/thread.c,v retrieving revision 1.7 diff -u -r1.7 thread.c --- dlls/kernel/tests/thread.c 30 Nov 2002 01:56:57 -0000 1.7 +++ dlls/kernel/tests/thread.c 30 Nov 2002 04:46:13 -0000 @@ -48,16 +48,18 @@ #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) + +typedef BOOL (WINAPI *GetThreadPriorityBoost_t)(HANDLE,PBOOL); +static GetThreadPriorityBoost_t pGetThreadPriorityBoost=NULL; + +typedef HANDLE (WINAPI *OpenThread_t)(DWORD,BOOL,DWORD); +static OpenThread_t pOpenThread=NULL; + +typedef DWORD (WINAPI *SetThreadIdealProcessor_t)(HANDLE,DWORD); +static SetThreadIdealProcessor_t pSetThreadIdealProcessor=NULL; + +typedef BOOL (WINAPI *SetThreadPriorityBoost_t)(HANDLE,BOOL); +static SetThreadPriorityBoost_t pSetThreadPriorityBoost=NULL; /* Functions not tested yet: AttachThreadInput @@ -100,7 +102,7 @@ while(tstruct->threadmem[i]==0) ; } /* Check that noone cahnged our tls memory */ - ok((DWORD)TlsGetValue(tlsIndex)-1==tstruct->threadnum, + ok((int)TlsGetValue(tlsIndex)-1==tstruct->threadnum, "TlsGetValue failed"); ExitThread(NUM_THREADS+tstruct->threadnum); } @@ -120,7 +122,7 @@ VOID WINAPI threadFunc4(HANDLE event) { - if(event != (HANDLE)NULL) { + if(event != NULL) { SetEvent(event); } Sleep(99000); @@ -147,7 +149,7 @@ #endif /* Check basic funcationality of CreateThread and Tls* functions */ -VOID test_CreateThread_basic(DWORD version) +VOID test_CreateThread_basic() { HANDLE thread[NUM_THREADS],event[NUM_THREADS]; DWORD threadid[NUM_THREADS],curthreadId; @@ -155,7 +157,7 @@ DWORD exitCode; t1Struct tstruct[NUM_THREADS]; int error; - int i,j; + DWORD i,j; /* Retrieve current Thread ID for later comparisons */ curthreadId=GetCurrentThreadId(); /* Allocate some local storage */ @@ -176,7 +178,7 @@ for(i=0;i<NUM_THREADS;i++) { thread[i] = Cr`eateThread(NULL,0,(LPTHREAD_START_ROUTINE)threadFunc1, &tstruct[i],0,&threadid[i]); - ok(thread[i]!=(HANDLE)NULL,"Create Thread failed."); + ok(thread[i]!=NULL,"Create Thread failed."); } /* Test that the threads actually complete */ for(i=0;i<NUM_THREADS;i++) { @@ -209,7 +211,7 @@ } /* Check that using the CREATE_SUSPENDED flag works */ -VOID test_CreateThread_suspended(DWORD version) +VOID test_CreateThread_suspended() { HANDLE thread; DWORD threadId; @@ -217,7 +219,7 @@ thread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)threadFunc2,NULL, CREATE_SUSPENDED,&threadId); - ok(thread!=(HANDLE)NULL,"Create Thread failed."); + ok(thread!=NULL,"Create Thread failed."); /* Check that the thread is suspended */ ok(SuspendThread(thread)==1,"Thread did not start suspended"); ok(ResumeThread(thread)==2,"Resume thread returned an invalid value"); @@ -238,7 +240,7 @@ } /* Check that SuspendThread and ResumeThread work */ -VOID test_SuspendThread(DWORD version) +VOID test_SuspendThread() { HANDLE thread,access_thread; DWORD threadId,exitCode; @@ -246,7 +248,7 @@ thread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)threadFunc3,NULL, 0,&threadId); - ok(thread!=(HANDLE)NULL,"Create Thread failed."); + ok(thread!=NULL,"Create Thread failed."); /* Check that the thread is suspended */ /* Note that this is a polling method, and there is a race between SuspendThread being called (in the child, and the loop below timing out, @@ -263,11 +265,11 @@ } ok(error==1,"SuspendThread did not work"); /* check that access restrictions are obeyed */ - if(WIN2K_PLUS(version)) { - access_thread=OpenThreadPtr(THREAD_ALL_ACCESS & (~THREAD_SUSPEND_RESUME), + if (pOpenThread) { + access_thread=pOpenThread(THREAD_ALL_ACCESS & (~THREAD_SUSPEND_RESUME), 0,threadId); - ok(access_thread!=(HANDLE)NULL,"OpenThread returned an invalid handle"); - if(access_thread!=(HANDLE)NULL) { + ok(access_thread!=NULL,"OpenThread returned an invalid handle"); + if (access_thread!=NULL) { ok(SuspendThread(access_thread)==-1, "SuspendThread did not obey access restrictions"); ok(ResumeThread(access_thread)==-1, @@ -285,12 +287,17 @@ if(error!=WAIT_OBJECT_0) { TerminateThread(thread,1); } + /* Trying to suspend a terminated thread should fail */ + error=SuspendThread(thread); + ok(error==0xffffffff, "wrong return code: %d", error); + ok(GetLastError()==ERROR_ACCESS_DENIED || GetLastError()==ERROR_NO_MORE_ITEMS, "unexpected error code: %ld", GetLastError()); + ok(CloseHandle(thread)!=0,"CloseHandle Failed"); } /* Check that TerminateThread works properly */ -VOID test_TerminateThread(DWORD version) +VOID test_TerminateThread() { HANDLE thread,access_thread,event; DWORD threadId,exitCode; @@ -299,7 +307,7 @@ event=CreateEventA(NULL,TRUE,FALSE,NULL); thread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)threadFunc4, (LPVOID)event, 0,&threadId); - ok(thread!=(HANDLE)NULL,"Create Thread failed."); + ok(thread!=NULL,"Create Thread failed."); /* Terminate thread has a race condition in Wine. If the thread is terminated before it starts, it leaves a process behind. Therefore, we wait for the thread to signal that it has started. There is no easy way to force the @@ -308,11 +316,11 @@ ok(WaitForSingleObject(event,5000)==WAIT_OBJECT_0, "TerminateThread didn't work"); /* check that access restrictions are obeyed */ - if(WIN2K_PLUS(version)) { - access_thread=OpenThreadPtr(THREAD_ALL_ACCESS & (~THREAD_TERMINATE), + if (pOpenThread) { + access_thread=pOpenThread(THREAD_ALL_ACCESS & (~THREAD_TERMINATE), 0,threadId); - ok(access_thread!=(HANDLE)NULL,"OpenThread returned an invalid handle"); - if(access_thread!=(HANDLE)NULL) { + ok(access_thread!=NULL,"OpenThread returned an invalid handle"); + if (access_thread!=NULL) { ok(TerminateThread(access_thread,99)==0, "TerminateThread did not obey access restrictions"); ok(CloseHandle(access_thread)!=0,"CloseHandle Failed"); @@ -324,22 +332,14 @@ "TerminateThread didn't work"); ok(GetExitCodeThread(thread,&exitCode)!=STILL_ACTIVE, "TerminateThread should not leave the thread 'STILL_ACTIVE'"); - if(WIN2K_PLUS(version)) { -/*NOTE: In Win2k, GetExitCodeThread does not return the value specified by - TerminateThread, even though MSDN says it should. So currently - there is no check being done for this. -*/ - trace("TerminateThread returned: 0x%lx instead of 0x%x\n",exitCode,99); - } else { - ok(exitCode==99, "TerminateThread returned invalid exit code"); - } + ok(exitCode==99, "TerminateThread returned invalid exit code"); ok(CloseHandle(thread)!=0,"Error Closing thread handle"); } /* Check if CreateThread obeys the specified stack size. This code does not work properly, and is currently disabled */ -VOID test_CreateThread_stack(DWORD version) +VOID test_CreateThread_stack() { #if CHECK_STACK /* The only way I know of to test the stack size is to use alloca @@ -366,7 +366,7 @@ } /* Check whether setting/retreiving thread priorities works */ -VOID test_thread_priority(DWORD version) +VOID test_thread_priority() { HANDLE curthread,access_thread; DWORD curthreadId,exitCode; @@ -384,21 +384,23 @@ ok(GetThreadPriority(curthread)==THREAD_PRIORITY_NORMAL, "GetThreadPriority Failed"); - if(WIN2K_PLUS(version)) { + if (pOpenThread) { /* check that access control is obeyed */ - access_thread=OpenThreadPtr(THREAD_ALL_ACCESS & + access_thread=pOpenThread(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(access_thread!=NULL,"OpenThread returned an invalid handle"); + if (access_thread!=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"); + if (pSetThreadPriorityBoost) + ok(pSetThreadPriorityBoost(access_thread,1)==0, + "SetThreadPriorityBoost did not obey access restrictions"); + if (pGetThreadPriorityBoost) + ok(pGetThreadPriorityBoost(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"); @@ -424,25 +426,24 @@ ok(SetThreadPriority(curthread,0)!=0,"SetThreadPriority Failed"); /* Check thread priority boost */ -/* NOTE: This only works on WinNT/2000/XP) */ - if(version < 0x80000000) { + if (pGetThreadPriorityBoost && pSetThreadPriorityBoost) { todo_wine { - ok(SetThreadPriorityBoost(curthread,1)!=0, + ok(pSetThreadPriorityBoost(curthread,1)!=0, "SetThreadPriorityBoost Failed"); - ok(GetThreadPriorityBoost(curthread,&error)!=0 && error==1, + ok(pGetThreadPriorityBoost(curthread,&error)!=0 && error==1, "GetThreadPriorityBoost Failed"); - ok(SetThreadPriorityBoost(curthread,0)!=0, + ok(pSetThreadPriorityBoost(curthread,0)!=0, "SetThreadPriorityBoost Failed"); - ok(GetThreadPriorityBoost(curthread,&error)!=0 && error==0, + ok(pGetThreadPriorityBoost(curthread,&error)!=0 && error==0, "GetThreadPriorityBoost Failed"); } } } /* check the GetThreadTimes function */ -VOID test_GetThreadTimes(DWORD version) +VOID test_GetThreadTimes() { - HANDLE thread,access_thread=(HANDLE)NULL; + HANDLE thread,access_thread=NULL; FILETIME creationTime,exitTime,kernelTime,userTime; DWORD threadId; int error; @@ -450,24 +451,22 @@ thread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)threadFunc2,NULL, CREATE_SUSPENDED,&threadId); - ok(thread!=(HANDLE)NULL,"Create Thread failed."); + ok(thread!=NULL,"Create Thread failed."); /* check that access control is obeyed */ - if(WIN2K_PLUS(version)) { - access_thread=OpenThreadPtr(THREAD_ALL_ACCESS & + if (pOpenThread) { + access_thread=pOpenThread(THREAD_ALL_ACCESS & (~THREAD_QUERY_INFORMATION), 0,threadId); - ok(access_thread!=(HANDLE)NULL, + ok(access_thread!=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"); - } + if(access_thread!=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; @@ -476,22 +475,24 @@ /* GetThreadTimes should set all of the parameters passed to it */ 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,"CloseHandle failed"); + if (error!=0 || GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) { + 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, + "kernelTimewas invalid"); + ok(userTime.dwLowDateTime!=99 || userTime.dwHighDateTime!=99, + "userTime was invalid"); + ok(CloseHandle(thread)!=0,"CloseHandle failed"); + } } /* Check the processor affinity functions */ /* NOTE: These functions should also be checked that they obey access control */ -VOID test_thread_processor(DWORD version) +VOID test_thread_processor() { HANDLE curthread,curproc; DWORD processMask,systemMask; @@ -504,9 +505,9 @@ "GetSystemInfo failed to return a valid # of processors"); /* Use the current Thread/process for all tests */ curthread=GetCurrentThread(); - ok(curthread!=(HANDLE)NULL,"GetCurrentThread failed"); + ok(curthread!=NULL,"GetCurrentThread failed"); curproc=GetCurrentProcess(); - ok(curproc!=(HANDLE)NULL,"GetCurrentProcess failed"); + ok(curproc!=NULL,"GetCurrentProcess failed"); /* Check the Affinity Mask functions */ ok(GetProcessAffinityMask(curproc,&processMask,&systemMask)!=0, "GetProcessAffinityMask failed"); @@ -515,41 +516,44 @@ ok(SetThreadAffinityMask(curthread,processMask+1)==0, "SetThreadAffinityMask passed for an illegal processor"); /* NOTE: This only works on WinNT/2000/XP) */ - if(version < 0x80000000) { + if (pSetThreadIdealProcessor) { todo_wine { - error=SetThreadIdealProcessor(curthread,0); - ok(error!=-1, "SetThreadIdealProcessor failed"); - error=SetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS+1); + SetLastError(0); + error=pSetThreadIdealProcessor(curthread,0); + if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) { + ok(error!=-1, "SetThreadIdealProcessor failed"); + } } + if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) { + error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS+1); ok(error==-1, "SetThreadIdealProccesor succeeded with an illegal processor #"); - todo_wine { - error=SetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS); - ok(error==0, "SetThreadIdealProccesor returned an incorrect value"); + todo_wine { + error=pSetThreadIdealProcessor(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); + ok(lib!=NULL,"Couldn't load kernel32.dll"); + pGetThreadPriorityBoost=(GetThreadPriorityBoost_t)GetProcAddress(lib,"GetThreadPriorityBoost"); + pOpenThread=(OpenThread_t)GetProcAddress(lib,"OpenThread"); + pSetThreadIdealProcessor=(SetThreadIdealProcessor_t)GetProcAddress(lib,"SetThreadIdealProcessor"); + pSetThreadPriorityBoost=(SetThreadPriorityBoost_t)GetProcAddress(lib,"SetThreadPriorityBoost"); + test_CreateThread_basic(); + test_CreateThread_suspended(); + test_SuspendThread(); + test_TerminateThread(); + test_CreateThread_stack(); + test_thread_priority(); + test_GetThreadTimes(); + test_thread_processor(); } -- Francois Gouget fgouget@free.fr http://fgouget.free.fr/ If it stinks, it's chemistry. If it moves, it's biology. If it does not work, It's computer science.