From 1c8f885f9dc2fe73dcc3651eaead86d566030c2b Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 30 Dec 2003 16:23:16 -0500 Subject: [PATCH] ENH: Added GetExceptionString method to provide an error description when GetState returns Exception. --- Source/kwsys/Process.h.in | 8 ++ Source/kwsys/ProcessUNIX.c | 169 +++++++++++++++++++++++++++++++----- Source/kwsys/ProcessWin32.c | 126 +++++++++++++++++++-------- Source/kwsys/test1.cxx | 9 ++ 4 files changed, 257 insertions(+), 55 deletions(-) diff --git a/Source/kwsys/Process.h.in b/Source/kwsys/Process.h.in index 83e3060aa..001b853d8 100644 --- a/Source/kwsys/Process.h.in +++ b/Source/kwsys/Process.h.in @@ -56,6 +56,7 @@ #define kwsysProcess_GetExitCode kwsys(Process_GetExitCode) #define kwsysProcess_GetExitValue kwsys(Process_GetExitValue) #define kwsysProcess_GetErrorString kwsys(Process_GetErrorString) +#define kwsysProcess_GetExceptionString kwsys(Process_GetExceptionString) #define kwsysProcess_Execute kwsys(Process_Execute) #define kwsysProcess_WaitForData kwsys(Process_WaitForData) #define kwsysProcess_Pipes_e kwsys(Process_Pipes_e) @@ -224,6 +225,12 @@ kwsysEXPORT int kwsysProcess_GetExitValue(kwsysProcess* cp); */ kwsysEXPORT const char* kwsysProcess_GetErrorString(kwsysProcess* cp); +/** + * When GetState returns "Exception", this method returns a string + * describing the problem. Otherwise, it returns NULL. + */ +kwsysEXPORT const char* kwsysProcess_GetExceptionString(kwsysProcess* cp); + /** * Start executing the child process. */ @@ -335,6 +342,7 @@ kwsysEXPORT void kwsysProcess_Kill(kwsysProcess* cp); # undef kwsysProcess_GetExitCode # undef kwsysProcess_GetExitValue # undef kwsysProcess_GetErrorString +# undef kwsysProcess_GetExceptionString # undef kwsysProcess_Execute # undef kwsysProcess_WaitForData # undef kwsysProcess_Pipes_e diff --git a/Source/kwsys/ProcessUNIX.c b/Source/kwsys/ProcessUNIX.c index 2abc8e1ef..96d1afbbd 100644 --- a/Source/kwsys/ProcessUNIX.c +++ b/Source/kwsys/ProcessUNIX.c @@ -95,6 +95,7 @@ static kwsysProcessTime kwsysProcessTimeFromDouble(double d); static int kwsysProcessTimeLess(kwsysProcessTime in1, kwsysProcessTime in2); static kwsysProcessTime kwsysProcessTimeAdd(kwsysProcessTime in1, kwsysProcessTime in2); static kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1, kwsysProcessTime in2); +static void kwsysProcessSetExitException(kwsysProcess* cp, int sig); static void kwsysProcessChildErrorExit(int errorPipe); static void kwsysProcessRestoreDefaultSignalHandlers(); @@ -161,6 +162,9 @@ struct kwsysProcess_s /* Buffer for error message in case of failure. */ char ErrorMessage[KWSYSPE_PIPE_BUFFER_SIZE+1]; + /* Description for the ExitException. */ + char ExitExceptionString[KWSYSPE_PIPE_BUFFER_SIZE+1]; + /* The exit codes of each child process in the pipeline. */ int* CommandExitCodes; @@ -481,13 +485,27 @@ const char* kwsysProcess_GetErrorString(kwsysProcess* cp) { if(!cp) { - return "Process management structure could not be allocated."; + return "Process management structure could not be allocated"; } else if(cp->State == kwsysProcess_State_Error) { return cp->ErrorMessage; } - return 0; + return "Success"; +} + +/*--------------------------------------------------------------------------*/ +const char* kwsysProcess_GetExceptionString(kwsysProcess* cp) +{ + if(!cp) + { + return "GetExceptionString called with NULL process management structure"; + } + else if(cp->State == kwsysProcess_State_Exception) + { + return cp->ExitExceptionString; + } + return "No exception"; } /*--------------------------------------------------------------------------*/ @@ -941,26 +959,8 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout) { /* The child received an unhandled signal. */ cp->State = kwsysProcess_State_Exception; - switch ((int)WTERMSIG(status)) - { -#ifdef SIGSEGV - case SIGSEGV: cp->ExitException = kwsysProcess_Exception_Fault; break; -#endif -#ifdef SIGBUS - case SIGBUS: cp->ExitException = kwsysProcess_Exception_Fault; break; -#endif -#ifdef SIGFPE - case SIGFPE: cp->ExitException = kwsysProcess_Exception_Numerical; break; -#endif -#ifdef SIGILL - case SIGILL: cp->ExitException = kwsysProcess_Exception_Illegal; break; -#endif -#ifdef SIGINT - case SIGINT: cp->ExitException = kwsysProcess_Exception_Interrupt; break; -#endif - default: cp->ExitException = kwsysProcess_Exception_Other; break; - } cp->ExitCode = status; + kwsysProcessSetExitException(cp, (int)WTERMSIG(status)); } else { @@ -1019,6 +1019,7 @@ static int kwsysProcessInitialize(kwsysProcess* cp) cp->ExitCode = 1; cp->ExitValue = 1; cp->ErrorMessage[0] = 0; + strcpy(cp->ExitExceptionString, "No exception"); if(cp->ForkPIDs) { @@ -1461,6 +1462,132 @@ static kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1, kwsysProc return out; } +/*--------------------------------------------------------------------------*/ +#define KWSYSPE_CASE(type, str) \ + cp->ExitException = kwsysProcess_Exception_##type; \ + strcpy(cp->ExitExceptionString, str) +static void kwsysProcessSetExitException(kwsysProcess* cp, int sig) +{ + switch (sig) + { +#ifdef SIGSEGV + case SIGSEGV: KWSYSPE_CASE(Fault, "Segmentation fault"); break; +#endif +#ifdef SIGBUS + case SIGBUS: KWSYSPE_CASE(Fault, "Bus error"); break; +#endif +#ifdef SIGFPE + case SIGFPE: KWSYSPE_CASE(Numerical, "Floating-point exception"); break; +#endif +#ifdef SIGILL + case SIGILL: KWSYSPE_CASE(Illegal, "Illegal instruction"); break; +#endif +#ifdef SIGINT + case SIGINT: KWSYSPE_CASE(Interrupt, "User interrupt"); break; +#endif +#ifdef SIGABRT + case SIGABRT: KWSYSPE_CASE(Other, "Child aborted"); break; +#endif +#ifdef SIGKILL + case SIGKILL: KWSYSPE_CASE(Other, "Child killed"); break; +#endif +#ifdef SIGTERM + case SIGTERM: KWSYSPE_CASE(Other, "Child terminated"); break; +#endif +#ifdef SIGHUP + case SIGHUP: KWSYSPE_CASE(Other, "SIGHUP"); break; +#endif +#ifdef SIGQUIT + case SIGQUIT: KWSYSPE_CASE(Other, "SIGQUIT"); break; +#endif +#ifdef SIGTRAP + case SIGTRAP: KWSYSPE_CASE(Other, "SIGTRAP"); break; +#endif +#ifdef SIGIOT +# if !defined(SIGABRT) || SIGIOT != SIGABRT + case SIGIOT: KWSYSPE_CASE(Other, "SIGIOT"); break; +# endif +#endif +#ifdef SIGUSR1 + case SIGUSR1: KWSYSPE_CASE(Other, "SIGUSR1"); break; +#endif +#ifdef SIGUSR2 + case SIGUSR2: KWSYSPE_CASE(Other, "SIGUSR2"); break; +#endif +#ifdef SIGPIPE + case SIGPIPE: KWSYSPE_CASE(Other, "SIGPIPE"); break; +#endif +#ifdef SIGALRM + case SIGALRM: KWSYSPE_CASE(Other, "SIGALRM"); break; +#endif +#ifdef SIGSTKFLT + case SIGSTKFLT: KWSYSPE_CASE(Other, "SIGSTKFLT"); break; +#endif +#ifdef SIGCHLD + case SIGCHLD: KWSYSPE_CASE(Other, "SIGCHLD"); break; +#elif defined(SIGCLD) + case SIGCLD: KWSYSPE_CASE(Other, "SIGCLD"); break; +#endif +#ifdef SIGCONT + case SIGCONT: KWSYSPE_CASE(Other, "SIGCONT"); break; +#endif +#ifdef SIGSTOP + case SIGSTOP: KWSYSPE_CASE(Other, "SIGSTOP"); break; +#endif +#ifdef SIGTSTP + case SIGTSTP: KWSYSPE_CASE(Other, "SIGTSTP"); break; +#endif +#ifdef SIGTTIN + case SIGTTIN: KWSYSPE_CASE(Other, "SIGTTIN"); break; +#endif +#ifdef SIGTTOU + case SIGTTOU: KWSYSPE_CASE(Other, "SIGTTOU"); break; +#endif +#ifdef SIGURG + case SIGURG: KWSYSPE_CASE(Other, "SIGURG"); break; +#endif +#ifdef SIGXCPU + case SIGXCPU: KWSYSPE_CASE(Other, "SIGXCPU"); break; +#endif +#ifdef SIGXFSZ + case SIGXFSZ: KWSYSPE_CASE(Other, "SIGXFSZ"); break; +#endif +#ifdef SIGVTALRM + case SIGVTALRM: KWSYSPE_CASE(Other, "SIGVTALRM"); break; +#endif +#ifdef SIGPROF + case SIGPROF: KWSYSPE_CASE(Other, "SIGPROF"); break; +#endif +#ifdef SIGWINCH + case SIGWINCH: KWSYSPE_CASE(Other, "SIGWINCH"); break; +#endif +#ifdef SIGPOLL + case SIGPOLL: KWSYSPE_CASE(Other, "SIGPOLL"); break; +#endif +#ifdef SIGIO +# if !defined(SIGPOLL) || SIGIO != SIGPOLL + case SIGIO: KWSYSPE_CASE(Other, "SIGIO"); break; +# endif +#endif +#ifdef SIGPWR + case SIGPWR: KWSYSPE_CASE(Other, "SIGPWR"); break; +#endif +#ifdef SIGSYS + case SIGSYS: KWSYSPE_CASE(Other, "SIGSYS"); break; +#endif +#ifdef SIGUNUSED +# if !defined(SIGSYS) || SIGUNUSED != SIGSYS + case SIGUNUSED: KWSYSPE_CASE(Other, "SIGUNUSED"); break; +# endif +#endif + default: + cp->ExitException = kwsysProcess_Exception_Other; + sprintf(cp->ExitExceptionString, "Signal %d", sig); + break; + } +} +#undef KWSYSPE_CASE + /*--------------------------------------------------------------------------*/ /* When the child process encounters an error before its program is invoked, this is called to report the error to the parent and diff --git a/Source/kwsys/ProcessWin32.c b/Source/kwsys/ProcessWin32.c index c710fac64..8556a962a 100644 --- a/Source/kwsys/ProcessWin32.c +++ b/Source/kwsys/ProcessWin32.c @@ -92,6 +92,7 @@ static kwsysProcessTime kwsysProcessTimeFromDouble(double d); static int kwsysProcessTimeLess(kwsysProcessTime in1, kwsysProcessTime in2); static kwsysProcessTime kwsysProcessTimeAdd(kwsysProcessTime in1, kwsysProcessTime in2); static kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1, kwsysProcessTime in2); +static void kwsysProcessSetExitException(kwsysProcess* cp, int code); extern kwsysEXPORT int kwsysEncodedWriteArrayProcessFwd9x(const char* fname); /*--------------------------------------------------------------------------*/ @@ -234,6 +235,9 @@ struct kwsysProcess_s /* Buffer for error messages (possibly from Win9x child). */ char ErrorMessage[KWSYSPE_PIPE_BUFFER_SIZE+1]; + /* Description for the ExitException. */ + char ExitExceptionString[KWSYSPE_PIPE_BUFFER_SIZE+1]; + /* Windows process information data. */ PROCESS_INFORMATION* ProcessInformation; @@ -905,13 +909,27 @@ const char* kwsysProcess_GetErrorString(kwsysProcess* cp) { if(!cp) { - return "Process management structure could not be allocated."; + return "Process management structure could not be allocated"; } else if(cp->State == kwsysProcess_State_Error) { return cp->ErrorMessage; } - return 0; + return "Success"; +} + +/*--------------------------------------------------------------------------*/ +const char* kwsysProcess_GetExceptionString(kwsysProcess* cp) +{ + if(!cp) + { + return "GetExceptionString called with NULL process management structure"; + } + else if(cp->State == kwsysProcess_State_Exception) + { + return cp->ExitExceptionString; + } + return "No exception"; } /*--------------------------------------------------------------------------*/ @@ -1312,39 +1330,8 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout) { /* Child terminated due to exceptional behavior. */ cp->State = kwsysProcess_State_Exception; - switch (cp->ExitCode) - { - case CONTROL_C_EXIT: - cp->ExitException = kwsysProcess_Exception_Interrupt; break; - - case EXCEPTION_FLT_DENORMAL_OPERAND: - case EXCEPTION_FLT_DIVIDE_BY_ZERO: - case EXCEPTION_FLT_INEXACT_RESULT: - case EXCEPTION_FLT_INVALID_OPERATION: - case EXCEPTION_FLT_OVERFLOW: - case EXCEPTION_FLT_STACK_CHECK: - case EXCEPTION_FLT_UNDERFLOW: - case EXCEPTION_INT_DIVIDE_BY_ZERO: - case EXCEPTION_INT_OVERFLOW: - cp->ExitException = kwsysProcess_Exception_Numerical; break; - - case EXCEPTION_ACCESS_VIOLATION: - case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: - case EXCEPTION_DATATYPE_MISALIGNMENT: - case EXCEPTION_INVALID_DISPOSITION: - case EXCEPTION_IN_PAGE_ERROR: - case EXCEPTION_NONCONTINUABLE_EXCEPTION: - case EXCEPTION_STACK_OVERFLOW: - cp->ExitException = kwsysProcess_Exception_Fault; break; - - case EXCEPTION_ILLEGAL_INSTRUCTION: - case EXCEPTION_PRIV_INSTRUCTION: - cp->ExitException = kwsysProcess_Exception_Illegal; break; - - default: - cp->ExitException = kwsysProcess_Exception_Other; break; - } cp->ExitValue = 1; + kwsysProcessSetExitException(cp, cp->ExitCode); } else { @@ -1493,6 +1480,7 @@ int kwsysProcessInitialize(kwsysProcess* cp) /* Reset error data. */ cp->ErrorMessage[0] = 0; + strcpy(cp->ExitExceptionString, "No exception"); /* Allocate process information for each process. */ cp->ProcessInformation = @@ -2070,3 +2058,73 @@ kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1, kwsysProcessTime out.QuadPart = in1.QuadPart - in2.QuadPart; return out; } + +/*--------------------------------------------------------------------------*/ +#define KWSYSPE_CASE(type, str) \ + cp->ExitException = kwsysProcess_Exception_##type; \ + strcpy(cp->ExitExceptionString, str) +static void kwsysProcessSetExitException(kwsysProcess* cp, int code) +{ + switch (code) + { + case STATUS_CONTROL_C_EXIT: + KWSYSPE_CASE(Interrupt, "User interrupt"); break; + + case STATUS_FLOAT_DENORMAL_OPERAND: + KWSYSPE_CASE(Numerical, "Floating-point exception (denormal operand)"); break; + case STATUS_FLOAT_DIVIDE_BY_ZERO: + KWSYSPE_CASE(Numerical, "Divide-by-zero"); break; + case STATUS_FLOAT_INEXACT_RESULT: + KWSYSPE_CASE(Numerical, "Floating-point exception (inexact result)"); break; + case STATUS_FLOAT_INVALID_OPERATION: + KWSYSPE_CASE(Numerical, "Invalid floating-point operation"); break; + case STATUS_FLOAT_OVERFLOW: + KWSYSPE_CASE(Numerical, "Floating-point overflow"); break; + case STATUS_FLOAT_STACK_CHECK: + KWSYSPE_CASE(Numerical, "Floating-point stack check failed"); break; + case STATUS_FLOAT_UNDERFLOW: + KWSYSPE_CASE(Numerical, "Floating-point underflow"); break; +#ifdef STATUS_FLOAT_MULTIPLE_FAULTS + case STATUS_FLOAT_MULTIPLE_FAULTS: + KWSYSPE_CASE(Numerical, "Floating-point exception (multiple faults)"); break; +#endif +#ifdef STATUS_FLOAT_MULTIPLE_TRAPS + case STATUS_FLOAT_MULTIPLE_TRAPS: + KWSYSPE_CASE(Numerical, "Floating-point exception (multiple traps)"); break; +#endif + case STATUS_INTEGER_DIVIDE_BY_ZERO: + KWSYSPE_CASE(Numerical, "Integer divide-by-zero"); break; + case STATUS_INTEGER_OVERFLOW: + KWSYSPE_CASE(Numerical, "Integer overflow"); break; + + case STATUS_DATATYPE_MISALIGNMENT: + KWSYSPE_CASE(Fault, "Datatype misalignment"); break; + case STATUS_ACCESS_VIOLATION: + KWSYSPE_CASE(Fault, "Access violation"); break; + case STATUS_IN_PAGE_ERROR: + KWSYSPE_CASE(Fault, "In-page error"); break; + case STATUS_INVALID_HANDLE: + KWSYSPE_CASE(Fault, "Invalid hanlde"); break; + case STATUS_NONCONTINUABLE_EXCEPTION: + KWSYSPE_CASE(Fault, "Noncontinuable exception"); break; + case STATUS_INVALID_DISPOSITION: + KWSYSPE_CASE(Fault, "Invalid disposition"); break; + case STATUS_ARRAY_BOUNDS_EXCEEDED: + KWSYSPE_CASE(Fault, "Array bounds exceeded"); break; + case STATUS_STACK_OVERFLOW: + KWSYSPE_CASE(Fault, "Stack overflow"); break; + + case STATUS_ILLEGAL_INSTRUCTION: + KWSYSPE_CASE(Illegal, "Illegal instruction"); break; + case STATUS_PRIVILEGED_INSTRUCTION: + KWSYSPE_CASE(Illegal, "Privileged instruction"); break; + + case STATUS_NO_MEMORY: + default: + cp->ExitException = kwsysProcess_Exception_Other; + sprintf(cp->ExitExceptionString, "Exit code 0x%x\n", code); + break; + } +} +#undef KWSYSPE_CASE + diff --git a/Source/kwsys/test1.cxx b/Source/kwsys/test1.cxx index 4c1def5cd..840253fa8 100644 --- a/Source/kwsys/test1.cxx +++ b/Source/kwsys/test1.cxx @@ -28,6 +28,15 @@ int main() { kwsys_ios::cout.write(data, length); } + kwsysProcess_WaitForExit(kp, 0); + if(kwsysProcess_GetState(kp) == kwsysProcess_State_Error) + { + kwsys_ios::cout << kwsysProcess_GetErrorString(kp) << kwsys_ios::endl; + } + else if(kwsysProcess_GetState(kp) == kwsysProcess_State_Exception) + { + kwsys_ios::cout << kwsysProcess_GetExceptionString(kp) << kwsys_ios::endl; + } kwsysProcess_Delete(kp); kwsys_ios::cout << kwsys_ios::endl; return 0;