From 383304c2848b47c81936ce77cd769dd47ca34d5b Mon Sep 17 00:00:00 2001 From: Gregor Anich Date: Wed, 1 Dec 2004 23:23:47 +0000 Subject: [PATCH] Catch hang-up regtests, added _DispatcherTimeout macros for tests to specify timeout (default is 5000ms) svn path=/trunk/; revision=11896 --- reactos/regtests/regtests/regtests.c | 22 +++++ reactos/regtests/regtests/regtests.def | 4 + reactos/regtests/shared/regtests.c | 123 +++++++++++++++++++------ reactos/regtests/shared/regtests.h | 20 +++- 4 files changed, 139 insertions(+), 30 deletions(-) diff --git a/reactos/regtests/regtests/regtests.c b/reactos/regtests/regtests/regtests.c index db0170b00d0..b59807a1702 100755 --- a/reactos/regtests/regtests/regtests.c +++ b/reactos/regtests/regtests/regtests.c @@ -32,3 +32,25 @@ _ExitProcess(UINT uExitCode) { ExitProcess(uExitCode); } + +HANDLE STDCALL +_CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize, + LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, + DWORD dwCreationFlags, LPDWORD lpThreadId) +{ + return CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress, + lpParameter, dwCreationFlags, lpThreadId); +} + +WINBOOL STDCALL +_TerminateThread(HANDLE hThread, DWORD dwExitCode) +{ + return TerminateThread(hThread, dwExitCode); +} + +DWORD STDCALL +_WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) +{ + return WaitForSingleObject(hHandle, dwMilliseconds); +} + diff --git a/reactos/regtests/regtests/regtests.def b/reactos/regtests/regtests/regtests.def index a6f552ac314..652c3d3423b 100644 --- a/reactos/regtests/regtests/regtests.def +++ b/reactos/regtests/regtests/regtests.def @@ -4,3 +4,7 @@ _ExitProcess@4 _GetModuleHandleA@4 _GetProcAddress@8 _LoadLibraryA@4 +_CreateThread@24 +_TerminateThread@8 +_WaitForSingleObject@8 + diff --git a/reactos/regtests/shared/regtests.c b/reactos/regtests/shared/regtests.c index 7c41412fb22..24528575db2 100755 --- a/reactos/regtests/shared/regtests.c +++ b/reactos/regtests/shared/regtests.c @@ -19,6 +19,13 @@ #define NDEBUG #include +typedef struct _PERFORM_TEST_ARGS +{ + TestOutputRoutine OutputRoutine; + PROS_TEST Test; + LPSTR TestName; +} PERFORM_TEST_ARGS; + int _Result; char *_Buffer; @@ -30,35 +37,17 @@ InitializeTests() InitializeListHead(&AllTests); } -VOID -PerformTest(TestOutputRoutine OutputRoutine, PROS_TEST Test, LPSTR TestName) +DWORD WINAPI +PerformTest(PVOID _arg) { + PERFORM_TEST_ARGS *Args = (PERFORM_TEST_ARGS *)_arg; + TestOutputRoutine OutputRoutine = Args->OutputRoutine; + PROS_TEST Test = Args->Test; + LPSTR TestName = Args->TestName; char OutputBuffer[5000]; char Buffer[5000]; - char Name[200]; memset(Buffer, 0, sizeof(Buffer)); - memset(Name, 0, sizeof(Name)); - - _Result = TS_OK; - _Buffer = Name; - (Test->Routine)(TESTCMD_TESTNAME); - if (_Result != TS_OK) - { - if (TestName != NULL) - { - return; - } - strcpy(Name, "Unnamed"); - } - - if (TestName != NULL) - { - if (_stricmp(Name, TestName) != 0) - { - return; - } - } _SEH_TRY { _Result = TS_OK; @@ -71,11 +60,11 @@ PerformTest(TestOutputRoutine OutputRoutine, PROS_TEST Test, LPSTR TestName) if (_Result != TS_OK) { - sprintf(OutputBuffer, "ROSREGTEST: |%s| Status: Failed (%s)\n", Name, Buffer); + sprintf(OutputBuffer, "ROSREGTEST: |%s| Status: Failed (%s)\n", TestName, Buffer); } else { - sprintf(OutputBuffer, "ROSREGTEST: |%s| Status: Success\n", Name); + sprintf(OutputBuffer, "ROSREGTEST: |%s| Status: Success\n", TestName); } if (OutputRoutine != NULL) { @@ -85,6 +74,7 @@ PerformTest(TestOutputRoutine OutputRoutine, PROS_TEST Test, LPSTR TestName) { DbgPrint(OutputBuffer); } + return 1; } VOID @@ -93,14 +83,89 @@ PerformTests(TestOutputRoutine OutputRoutine, LPSTR TestName) PLIST_ENTRY CurrentEntry; PLIST_ENTRY NextEntry; PROS_TEST Current; + PERFORM_TEST_ARGS Args; + HANDLE hThread; + char OutputBuffer[1024]; + char Name[200]; + DWORD TimeOut; + Args.OutputRoutine = OutputRoutine; + Args.TestName = Name; + CurrentEntry = AllTests.Flink; - while (CurrentEntry != &AllTests) + for (; CurrentEntry != &AllTests; CurrentEntry = NextEntry) { NextEntry = CurrentEntry->Flink; Current = CONTAINING_RECORD(CurrentEntry, ROS_TEST, ListEntry); - PerformTest(OutputRoutine, Current, TestName); - CurrentEntry = NextEntry; + Args.Test = Current; + + /* Get name of test */ + memset(Name, 0, sizeof(Name)); + + _Result = TS_OK; + _Buffer = Name; + (Current->Routine)(TESTCMD_TESTNAME); + if (_Result != TS_OK) + { + if (TestName != NULL) + { + continue; + } + strcpy(Name, "Unnamed"); + } + + if (TestName != NULL) + { + if (_stricmp(Name, TestName) != 0) + { + continue; + } + } + + /* Get timeout for test */ + TimeOut = 0; + _Result = TS_OK; + _Buffer = (char *)&TimeOut; + (Current->Routine)(TESTCMD_TIMEOUT); + if (_Result != TS_OK || TimeOut == INFINITE) + { + TimeOut = 5000; + } + + /* Run test in thread */ + hThread = _CreateThread(NULL, 0, PerformTest, (PVOID)&Args, 0, NULL); + if (hThread == NULL) + { + sprintf(OutputBuffer, + "ROSREGTEST: |%s| Status: Failed (CreateThread failed: 0x%x)\n", + Name, (unsigned int)GetLastError()); + } + else if (_WaitForSingleObject(hThread, TimeOut) == WAIT_TIMEOUT) + { + if (!_TerminateThread(hThread, 0)) + { + sprintf(OutputBuffer, + "ROSREGTEST: |%s| Status: Failed (Test timed out - %d ms, TerminateThread failed: 0x%x)\n", + Name, (int)TimeOut, (unsigned int)GetLastError()); + } + else + { + sprintf(OutputBuffer, "ROSREGTEST: |%s| Status: Failed (Test timed out - %d ms)\n", Name, (int)TimeOut); + } + } + else + { + continue; + } + + if (OutputRoutine != NULL) + { + (*OutputRoutine)(OutputBuffer); + } + else + { + DbgPrint(OutputBuffer); + } } } diff --git a/reactos/regtests/shared/regtests.h b/reactos/regtests/shared/regtests.h index eea2aa8285e..f5dfc320fa5 100755 --- a/reactos/regtests/shared/regtests.h +++ b/reactos/regtests/shared/regtests.h @@ -17,6 +17,7 @@ void SetupOnce() /* Valid values for Command parameter of TestRoutine */ #define TESTCMD_RUN 0 /* Buffer contains information about what failed */ #define TESTCMD_TESTNAME 1 /* Buffer contains description of test */ +#define TESTCMD_TIMEOUT 2 /* Buffer contains timeout for test (DWORD, default is 5000 ms) */ /* Valid values for return values of TestRoutine */ #define TS_EXCEPTION -1 @@ -27,7 +28,7 @@ extern int _Result; extern char *_Buffer; /* Macros to simplify tests */ -#define _Dispatcher(FunctionName, TestName) \ +#define _DispatcherTimeout(FunctionName, TestName, TimeOut) \ void \ FunctionName(int Command) \ { \ @@ -39,12 +40,17 @@ FunctionName(int Command) \ case TESTCMD_TESTNAME: \ strcpy(_Buffer, TestName); \ break; \ + case TESTCMD_TIMEOUT: \ + *(PDWORD)_Buffer = (DWORD)TimeOut; \ + break; \ default: \ _Result = TS_FAILED; \ break; \ } \ } +#define _Dispatcher(FunctionName, TestName) _DispatcherTimeout(FunctionName, TestName, 5000) + static inline void AppendAssertion(char *message) { @@ -173,6 +179,18 @@ _LoadLibraryA(LPCSTR lpLibFileName); VOID STDCALL _ExitProcess(UINT uExitCode); +HANDLE STDCALL +_CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize, + LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, + DWORD dwCreationFlags, LPDWORD lpThreadId); + +WINBOOL STDCALL +_TerminateThread(HANDLE hThread, DWORD dwExitCode); + +DWORD STDCALL +_WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds); + + static inline PCHAR FrameworkGetExportedFunctionNameInternal(PAPI_DESCRIPTION ApiDescription) {