Przeglądaj źródła

ENH: Added GetExceptionString method to provide an error description when GetState returns Exception.

Brad King 22 lat temu
rodzic
commit
1c8f885f9d

+ 8 - 0
Source/kwsys/Process.h.in

@@ -56,6 +56,7 @@
 #define kwsysProcess_GetExitCode         kwsys(Process_GetExitCode)
 #define kwsysProcess_GetExitCode         kwsys(Process_GetExitCode)
 #define kwsysProcess_GetExitValue        kwsys(Process_GetExitValue)
 #define kwsysProcess_GetExitValue        kwsys(Process_GetExitValue)
 #define kwsysProcess_GetErrorString      kwsys(Process_GetErrorString)
 #define kwsysProcess_GetErrorString      kwsys(Process_GetErrorString)
+#define kwsysProcess_GetExceptionString  kwsys(Process_GetExceptionString)
 #define kwsysProcess_Execute             kwsys(Process_Execute)
 #define kwsysProcess_Execute             kwsys(Process_Execute)
 #define kwsysProcess_WaitForData         kwsys(Process_WaitForData)
 #define kwsysProcess_WaitForData         kwsys(Process_WaitForData)
 #define kwsysProcess_Pipes_e             kwsys(Process_Pipes_e)
 #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);
 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.
  * Start executing the child process.
  */
  */
@@ -335,6 +342,7 @@ kwsysEXPORT void kwsysProcess_Kill(kwsysProcess* cp);
 # undef kwsysProcess_GetExitCode
 # undef kwsysProcess_GetExitCode
 # undef kwsysProcess_GetExitValue
 # undef kwsysProcess_GetExitValue
 # undef kwsysProcess_GetErrorString
 # undef kwsysProcess_GetErrorString
+# undef kwsysProcess_GetExceptionString
 # undef kwsysProcess_Execute
 # undef kwsysProcess_Execute
 # undef kwsysProcess_WaitForData
 # undef kwsysProcess_WaitForData
 # undef kwsysProcess_Pipes_e
 # undef kwsysProcess_Pipes_e

+ 148 - 21
Source/kwsys/ProcessUNIX.c

@@ -95,6 +95,7 @@ static kwsysProcessTime kwsysProcessTimeFromDouble(double d);
 static int kwsysProcessTimeLess(kwsysProcessTime in1, kwsysProcessTime in2);
 static int kwsysProcessTimeLess(kwsysProcessTime in1, kwsysProcessTime in2);
 static kwsysProcessTime kwsysProcessTimeAdd(kwsysProcessTime in1, kwsysProcessTime in2);
 static kwsysProcessTime kwsysProcessTimeAdd(kwsysProcessTime in1, kwsysProcessTime in2);
 static kwsysProcessTime kwsysProcessTimeSubtract(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 kwsysProcessChildErrorExit(int errorPipe);
 static void kwsysProcessRestoreDefaultSignalHandlers();
 static void kwsysProcessRestoreDefaultSignalHandlers();
 
 
@@ -161,6 +162,9 @@ struct kwsysProcess_s
   /* Buffer for error message in case of failure.  */
   /* Buffer for error message in case of failure.  */
   char ErrorMessage[KWSYSPE_PIPE_BUFFER_SIZE+1];
   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.  */
   /* The exit codes of each child process in the pipeline.  */
   int* CommandExitCodes;
   int* CommandExitCodes;
 
 
@@ -481,13 +485,27 @@ const char* kwsysProcess_GetErrorString(kwsysProcess* cp)
 {
 {
   if(!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)
   else if(cp->State == kwsysProcess_State_Error)
     {
     {
     return cp->ErrorMessage;
     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.  */
     /* The child received an unhandled signal.  */
     cp->State = kwsysProcess_State_Exception;
     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;
     cp->ExitCode = status;
+    kwsysProcessSetExitException(cp, (int)WTERMSIG(status));
     }
     }
   else
   else
     {
     {
@@ -1019,6 +1019,7 @@ static int kwsysProcessInitialize(kwsysProcess* cp)
   cp->ExitCode = 1;
   cp->ExitCode = 1;
   cp->ExitValue = 1;
   cp->ExitValue = 1;
   cp->ErrorMessage[0] = 0;
   cp->ErrorMessage[0] = 0;
+  strcpy(cp->ExitExceptionString, "No exception");
 
 
   if(cp->ForkPIDs)
   if(cp->ForkPIDs)
     {
     {
@@ -1461,6 +1462,132 @@ static kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1, kwsysProc
   return out;
   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
 /* When the child process encounters an error before its program is
    invoked, this is called to report the error to the parent and
    invoked, this is called to report the error to the parent and

+ 92 - 34
Source/kwsys/ProcessWin32.c

@@ -92,6 +92,7 @@ static kwsysProcessTime kwsysProcessTimeFromDouble(double d);
 static int kwsysProcessTimeLess(kwsysProcessTime in1, kwsysProcessTime in2);
 static int kwsysProcessTimeLess(kwsysProcessTime in1, kwsysProcessTime in2);
 static kwsysProcessTime kwsysProcessTimeAdd(kwsysProcessTime in1, kwsysProcessTime in2);
 static kwsysProcessTime kwsysProcessTimeAdd(kwsysProcessTime in1, kwsysProcessTime in2);
 static kwsysProcessTime kwsysProcessTimeSubtract(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);
 extern kwsysEXPORT int kwsysEncodedWriteArrayProcessFwd9x(const char* fname);
 
 
 /*--------------------------------------------------------------------------*/
 /*--------------------------------------------------------------------------*/
@@ -234,6 +235,9 @@ struct kwsysProcess_s
   /* Buffer for error messages (possibly from Win9x child).  */
   /* Buffer for error messages (possibly from Win9x child).  */
   char ErrorMessage[KWSYSPE_PIPE_BUFFER_SIZE+1];
   char ErrorMessage[KWSYSPE_PIPE_BUFFER_SIZE+1];
 
 
+  /* Description for the ExitException.  */
+  char ExitExceptionString[KWSYSPE_PIPE_BUFFER_SIZE+1];
+
   /* Windows process information data.  */
   /* Windows process information data.  */
   PROCESS_INFORMATION* ProcessInformation;
   PROCESS_INFORMATION* ProcessInformation;
 
 
@@ -905,13 +909,27 @@ const char* kwsysProcess_GetErrorString(kwsysProcess* cp)
 {
 {
   if(!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)
   else if(cp->State == kwsysProcess_State_Error)
     {
     {
     return cp->ErrorMessage;
     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.  */
       /* Child terminated due to exceptional behavior.  */
       cp->State = kwsysProcess_State_Exception;
       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;
       cp->ExitValue = 1;
+      kwsysProcessSetExitException(cp, cp->ExitCode);
       }
       }
     else
     else
       {
       {
@@ -1493,6 +1480,7 @@ int kwsysProcessInitialize(kwsysProcess* cp)
 
 
   /* Reset error data.  */
   /* Reset error data.  */
   cp->ErrorMessage[0] = 0;
   cp->ErrorMessage[0] = 0;
+  strcpy(cp->ExitExceptionString, "No exception");
 
 
   /* Allocate process information for each process.  */
   /* Allocate process information for each process.  */
   cp->ProcessInformation =
   cp->ProcessInformation =
@@ -2070,3 +2058,73 @@ kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1, kwsysProcessTime
   out.QuadPart = in1.QuadPart - in2.QuadPart;
   out.QuadPart = in1.QuadPart - in2.QuadPart;
   return out;
   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
+

+ 9 - 0
Source/kwsys/test1.cxx

@@ -28,6 +28,15 @@ int main()
     {
     {
     kwsys_ios::cout.write(data, length);
     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);
   kwsysProcess_Delete(kp);
   kwsys_ios::cout << kwsys_ios::endl;
   kwsys_ios::cout << kwsys_ios::endl;
   return 0;
   return 0;