diff options
author | Brad King <brad.king@kitware.com> | 2003-06-18 21:06:21 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2003-06-18 21:06:21 (GMT) |
commit | 7e80f2f8746ab1a98879d37b1ece42a7f3ba6b01 (patch) | |
tree | 41141b9412b4a1583c73441f9f3caf688b9cecf8 /Source | |
parent | 5394a7534010660b0ad15ddb44c58ff293bdf41e (diff) | |
download | CMake-7e80f2f8746ab1a98879d37b1ece42a7f3ba6b01.zip CMake-7e80f2f8746ab1a98879d37b1ece42a7f3ba6b01.tar.gz CMake-7e80f2f8746ab1a98879d37b1ece42a7f3ba6b01.tar.bz2 |
ENH: Added documentation to interface. Finished process exit code interpretation implementation prototype.
Diffstat (limited to 'Source')
-rw-r--r-- | Source/kwsys/Process.h.in | 305 | ||||
-rw-r--r-- | Source/kwsys/ProcessUNIX.c | 93 | ||||
-rw-r--r-- | Source/kwsys/ProcessWin32.c | 111 | ||||
-rw-r--r-- | Source/kwsys/test1.cxx | 3 |
4 files changed, 367 insertions, 145 deletions
diff --git a/Source/kwsys/Process.h.in b/Source/kwsys/Process.h.in index 11c63ff..0fdf5d2 100644 --- a/Source/kwsys/Process.h.in +++ b/Source/kwsys/Process.h.in @@ -17,119 +17,223 @@ #ifndef @KWSYS_NAMESPACE@_Process_h #define @KWSYS_NAMESPACE@_Process_h +/* Redefine all public interface symbol names to be in the proper + namespace. These macros are used internally to kwsys only, and are + not visible to user code. Use kwsysHeaderDump.pl to reproduce + these macros after making changes to the interface. */ #define kwsys(x) @KWSYS_NAMESPACE@##x -#define kwsysProcess_STDOUT kwsys(Process_STDOUT) -#define kwsysProcess_STDERR kwsys(Process_STDERR) -#define kwsysProcess_Timeout kwsys(Process_Timeout) -#define kwsysProcess_Starting kwsys(Process_Starting) -#define kwsysProcess_Executing kwsys(Process_Executing) -#define kwsysProcess_Expired kwsys(Process_Expired) -#define kwsysProcess_Exited kwsys(Process_Exited) -#define kwsysProcess_Killed kwsys(Process_Killed) -#define kwsysProcess_Signalled kwsys(Process_Signalled) -#define kwsysProcess_Error kwsys(Process_Error) -#define kwsysProcess_State kwsys(Process_State) -#define kwsysProcess_Pipes_e kwsys(Process_Pipes_e) -#define kwsysProcess_State_e kwsys(Process_State_e) -#define kwsysProcess_s kwsys(Process_s) -#define kwsysProcess kwsys(Process) -#define kwsysProcess_New kwsys(Process_New) -#define kwsysProcess_Delete kwsys(Process_Delete) -#define kwsysProcess_SetCommand kwsys(Process_SetCommand) -#define kwsysProcess_SetTimeout kwsys(Process_SetTimeout) -#define kwsysProcess_GetState kwsys(Process_GetState) -#define kwsysProcess_GetExitCode kwsys(Process_GetExitCode) -#define kwsysProcess_GetErrorString kwsys(Process_GetErrorString) -#define kwsysProcess_Execute kwsys(Process_Execute) -#define kwsysProcess_WaitForData kwsys(Process_WaitForData) -#define kwsysProcess_WaitForExit kwsys(Process_WaitForExit) -#define kwsysProcess_Kill kwsys(Process_Kill) +#define kwsysProcess kwsys(Process) +#define kwsysProcess_s kwsys(Process_s) +#define kwsysProcess_New kwsys(Process_New) +#define kwsysProcess_Delete kwsys(Process_Delete) +#define kwsysProcess_SetCommand kwsys(Process_SetCommand) +#define kwsysProcess_SetTimeout kwsys(Process_SetTimeout) +#define kwsysProcess_State_Starting kwsys(Process_State_Starting) +#define kwsysProcess_State_Error kwsys(Process_State_Error) +#define kwsysProcess_State_Exception kwsys(Process_State_Exception) +#define kwsysProcess_State_Executing kwsys(Process_State_Executing) +#define kwsysProcess_State_Exited kwsys(Process_State_Exited) +#define kwsysProcess_State_Expired kwsys(Process_State_Expired) +#define kwsysProcess_State_Killed kwsys(Process_State_Killed) +#define kwsysProcess_GetState kwsys(Process_GetState) +#define kwsysProcess_State_e kwsys(Process_State_e) +#define kwsysProcess_Exception_None kwsys(Process_Exception_None) +#define kwsysProcess_Exception_Abort kwsys(Process_Exception_Abort) +#define kwsysProcess_Exception_Fault kwsys(Process_Exception_Fault) +#define kwsysProcess_Exception_Illegal kwsys(Process_Exception_Illegal) +#define kwsysProcess_Exception_Interrupt kwsys(Process_Exception_Interrupt) +#define kwsysProcess_Exception_Numerical kwsys(Process_Exception_Numerical) +#define kwsysProcess_Exception_Other kwsys(Process_Exception_Other) +#define kwsysProcess_GetExitException kwsys(Process_GetExitException) +#define kwsysProcess_Exception_e kwsys(Process_Exception_e) +#define kwsysProcess_GetExitCode kwsys(Process_GetExitCode) +#define kwsysProcess_GetExitValue kwsys(Process_GetExitValue) +#define kwsysProcess_GetErrorString kwsys(Process_GetErrorString) +#define kwsysProcess_Execute kwsys(Process_Execute) +#define kwsysProcess_WaitForData kwsys(Process_WaitForData) +#define kwsysProcess_Pipes_e kwsys(Process_Pipes_e) +#define kwsysProcess_Pipe_STDOUT kwsys(Process_Pipe_STDOUT) +#define kwsysProcess_Pipe_STDERR kwsys(Process_Pipe_STDERR) +#define kwsysProcess_Pipe_Timeout kwsys(Process_Pipe_Timeout) +#define kwsysProcess_WaitForExit kwsys(Process_WaitForExit) +#define kwsysProcess_Kill kwsys(Process_Kill) #if defined(__cplusplus) extern "C" { #endif -typedef enum kwsysProcess_Pipes_e -{ - kwsysProcess_STDOUT=1, - kwsysProcess_STDERR=2, - kwsysProcess_Timeout=255 -} kwsysProcess_Pipes; - -typedef enum kwsysProcess_State_e -{ - kwsysProcess_Starting, /* Between New and Execute; No process run yet */ - kwsysProcess_Executing, /* Process is running */ - kwsysProcess_Expired, /* Process timeout expired and was killed */ - kwsysProcess_Exited, /* Process exited */ - kwsysProcess_Killed, /* Process was killed by Kill */ - kwsysProcess_Signalled, /* Process was terminated by a signal (crash / ctrl-C) */ - kwsysProcess_Error /* Internal error of Process */ -} kwsysProcess_State; - +/** + * Process control data structure. + */ typedef struct kwsysProcess_s kwsysProcess; +/** + * Create a new Process instance. + */ kwsysProcess* kwsysProcess_New(); +/** + * Delete an existing Process instance. If the instance is currently + * executing a process, this blocks until the process terminates. + */ void kwsysProcess_Delete(kwsysProcess* cp); +/** + * Set the command line to be executed. Argument is an array of + * pointers to the command and each argument. Ths array must end with + * a NULL pointer. + */ void kwsysProcess_SetCommand(kwsysProcess* cp, char const* const* command); +/** + * Set the timeout for the child process. The timeout period begins + * when the child is executed. If the child has not terminated when + * the timeout expires, it will be killed. A non-positive (<= 0) + * value will disable the timeout. + */ void kwsysProcess_SetTimeout(kwsysProcess* cp, double timeout); -/* - * Get the current internal state of the kwsysProcess instance +/** + * Get the current state of the Process instance. Possible states are: + * + * kwsysProcess_State_Starting = Execute has not yet been called. + * kwsysProcess_State_Error = Error administrating the child process. + * kwsysProcess_State_Exception = Child process exited abnormally. + * kwsysProcess_State_Executing = Child process is currently running. + * kwsysProcess_State_Exited = Child process exited normally. + * kwsysProcess_State_Expired = Child process's timeout expired. + * kwsysProcess_State_Killed = Child process terminated by Kill method. */ int kwsysProcess_GetState(kwsysProcess* cp); +typedef enum kwsysProcess_State_e +{ + kwsysProcess_State_Starting, + kwsysProcess_State_Error, + kwsysProcess_State_Exception, + kwsysProcess_State_Executing, + kwsysProcess_State_Exited, + kwsysProcess_State_Expired, + kwsysProcess_State_Killed +}; + +/** + * When GetState returns "Exception", this method returns a + * platform-independent description of the exceptional behavior that + * caused the child to terminate abnormally. Possible exceptions are: + * + * kwsysProcess_Exception_None = No exceptional behavior occurred. + * kwsysProcess_Exception_Abort = Child exited with abort call. + * kwsysProcess_Exception_Fault = Child crashed with a memory fault. + * kwsysProcess_Exception_Illegal = Child crashed with an illegal instruction. + * kwsysProcess_Exception_Interrupt = Child was interrupted by user (Cntl-C/Break). + * kwsysProcess_Exception_Numerical = Child crashed with a numerical exception. + * kwsysProcess_Exception_Other = Child terminated for another reason. + */ +int kwsysProcess_GetExitException(kwsysProcess* cp); +typedef enum kwsysProcess_Exception_e +{ + kwsysProcess_Exception_None, + kwsysProcess_Exception_Abort, + kwsysProcess_Exception_Fault, + kwsysProcess_Exception_Illegal, + kwsysProcess_Exception_Interrupt, + kwsysProcess_Exception_Numerical, + kwsysProcess_Exception_Other +}; -/* - * Get process return code or when signalled, get the signal code +/** + * When GetState returns "Exited" or "Exception", this method returns + * the platform-specific raw exit code of the process. UNIX platforms + * should use WIFEXITED/WEXITSTATUS and WIFSIGNALED/WTERMSIG to access + * this value. Windows users should compare the value to the various + * EXCEPTION_* values. + * + * If GetState returns "Exited", use GetExitValue to get the + * platform-independent child return value. */ int kwsysProcess_GetExitCode(kwsysProcess* cp); -/* - * On kwsysProcess_Error get the error message +/** + * When GetState returns "Exited", this method returns the child's + * platform-independent exit code (such as the value returned by the + * child's main). + */ +int kwsysProcess_GetExitValue(kwsysProcess* cp); + +/** + * When GetState returns "Error", this method returns a string + * describing the problem. Otherwise, it returns NULL. */ const char* kwsysProcess_GetErrorString(kwsysProcess* cp); +/** + * Start executing the child process. + */ void kwsysProcess_Execute(kwsysProcess* cp); -/* - * Block until data available on requested pipe or one of the timeouts expired, - * or the process exits. If the pipe is not specified, data on that pipe are - * ignored. +/** + * Block until data are available on a requested pipe, a timeout + * expires, or the child process terminates. Arguments are as + * follows: + * + * pipes = Flags for the child output pipes of interest to the caller. + * Possible values are Pipe_STDOUT and Pipe_STDERR. Multiple + * pipes may be specified by using the bitwise OR operator '|'. + * data = If data are read, the pointer to which this points is + * set to point to the data. + * length = If data are read, the integer to which this points is + * set to the length of the data read. + * timeout = Specifies the maximum time this call may block. Upon + * return after reading data, the time elapsed is subtracted + * from the timeout value. If this timeout expires, the + * value is set to 0. A NULL pointer passed for this argument + * indicates no timeout for the call. + * + * Return value will be one of: + * + * 0 = No more data will be available from the child process, + * or no process has been executed. WaitForExit should + * be called to wait for the process to terminate. + * Pipe_STDOUT = Data have been read from the child's stdout pipe. + * Pipe_STDERR = Data have been read from the child's stderr pipe. + * Pipe_Timeout = No data available within timeout specified for the + * call. Time elapsed has been subtracted from timeout + * argument. + */ +int kwsysProcess_WaitForData(kwsysProcess* cp, int pipes, char** data, + int* length, double* timeout); +typedef enum kwsysProcess_Pipes_e +{ + kwsysProcess_Pipe_STDOUT=1, + kwsysProcess_Pipe_STDERR=2, + kwsysProcess_Pipe_Timeout=255 +}; + +/** + * Block until the child process terminates or the given timeout + * expires. If no process is running, returns immediatly. The + * argument is: * - * pipes - a list of interested pipes - kwsysProcess_STDOUT | kwsysProcess_STDERR - * data - returns pointer to data if read, NULL otherwise - * length - length of the returned data - * userTimeout - timeout for the current kwsysProcess_WaitForData call - * the userTimeout will contain the remaining time + * timeout = Specifies the maximum time this call may block. Upon + * returning due to child termination, the elapsed time + * is subtracted from the given value. A NULL pointer + * passed for this argument indicates no timeout for the + * call. * - * Returns: - * 0 - Process exited or killed or process timeout expired with no data - * available, or no process running. - * PIPE id otherwise: - * kwsysProcess_STDOUT - if stdout is returned - * kwsysProcess_STDERR - if stderr is returned - * kwsysProcess_Timeout - if user timeout expired - */ -int kwsysProcess_WaitForData(kwsysProcess* cp, int pipes, char** data, int* length, - double* userTimeout); - -/* - * Block until the process exits or the timeout expires. If no process is - * running, return immediatly. + * Return value will be one of: * - * Returns: - * 0 - When user timeout expires - * 1 - Otherwise + * 0 = Child did not terminate within timeout specified for + * the call. Time elapsed has been subtracted from timeout + * argument. + * 1 = Child has terminated or was not running. */ -int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout); +int kwsysProcess_WaitForExit(kwsysProcess* cp, double* timeout); -/* - * Kills the process. kwsysProcess_WaitForExit should still be called - * after kwsysProcess_Kill. +/** + * Forcefully terminate the child process that is currently running. + * The caller should call WaitForExit after this returns to wait for + * the child to terminate. */ void kwsysProcess_Kill(kwsysProcess* cp); @@ -137,34 +241,43 @@ void kwsysProcess_Kill(kwsysProcess* cp); } /* extern "C" */ #endif - -/* If we are building a kwsysProcess .c file, let it use these macros. */ +/* If we are building a kwsysProcess .c file, let it use these macros. + Otherwise, undefine them to keep the namespace clean. */ #if !defined(KWSYS_IN_PROCESS_C) # undef kwsys -# undef kwsysProcess_STDOUT -# undef kwsysProcess_STDERR -# undef kwsysProcess_Timeout -# undef kwsysProcess_Starting -# undef kwsysProcess_Executing -# undef kwsysProcess_Expired -# undef kwsysProcess_Exited -# undef kwsysProcess_Killed -# undef kwsysProcess_Signalled -# undef kwsysProcess_Error -# undef kwsysProcess_State -# undef kwsysProcess_Pipes_e -# undef kwsysProcess_State_e -# undef kwsysProcess_s # undef kwsysProcess +# undef kwsysProcess_s # undef kwsysProcess_New # undef kwsysProcess_Delete # undef kwsysProcess_SetCommand # undef kwsysProcess_SetTimeout +# undef kwsysProcess_State_Starting +# undef kwsysProcess_State_Error +# undef kwsysProcess_State_Exception +# undef kwsysProcess_State_Executing +# undef kwsysProcess_State_Exited +# undef kwsysProcess_State_Expired +# undef kwsysProcess_State_Killed # undef kwsysProcess_GetState +# undef kwsysProcess_State_e +# undef kwsysProcess_Exception_None +# undef kwsysProcess_Exception_Abort +# undef kwsysProcess_Exception_Fault +# undef kwsysProcess_Exception_Illegal +# undef kwsysProcess_Exception_Interrupt +# undef kwsysProcess_Exception_Numerical +# undef kwsysProcess_Exception_Other +# undef kwsysProcess_GetExitException +# undef kwsysProcess_Exception_e # undef kwsysProcess_GetExitCode +# undef kwsysProcess_GetExitValue # undef kwsysProcess_GetErrorString # undef kwsysProcess_Execute # undef kwsysProcess_WaitForData +# undef kwsysProcess_Pipes_e +# undef kwsysProcess_Pipe_STDOUT +# undef kwsysProcess_Pipe_STDERR +# undef kwsysProcess_Pipe_Timeout # undef kwsysProcess_WaitForExit # undef kwsysProcess_Kill #endif diff --git a/Source/kwsys/ProcessUNIX.c b/Source/kwsys/ProcessUNIX.c index 3afac8d..11ce2f1 100644 --- a/Source/kwsys/ProcessUNIX.c +++ b/Source/kwsys/ProcessUNIX.c @@ -98,7 +98,7 @@ struct kwsysProcess_s int ChildError; /* The timeout length. */ - float Timeout; + double Timeout; /* Time at which the child started. Negative for no timeout. */ kwsysProcessTime StartTime; @@ -120,10 +120,17 @@ struct kwsysProcess_s /* The current status of the child process. */ int State; - - /* The exit code of the child process, if any. */ + + /* The exceptional behavior that terminated the child process, if + * any. */ + int ExitException; + + /* The exit code of the child process. */ int ExitCode; + /* The exit value of the child process, if any. */ + int ExitValue; + /* Whether the process was killed. */ int Killed; @@ -142,7 +149,7 @@ kwsysProcess* kwsysProcess_New() return 0; } memset(cp, 0, sizeof(kwsysProcess)); - cp->State = kwsysProcess_Starting; + cp->State = kwsysProcess_State_Starting; return cp; } @@ -150,7 +157,7 @@ kwsysProcess* kwsysProcess_New() void kwsysProcess_Delete(kwsysProcess* cp) { /* If the process is executing, wait for it to finish. */ - if(cp->State == kwsysProcess_Executing) + if(cp->State == kwsysProcess_State_Executing) { kwsysProcess_WaitForExit(cp, 0); } @@ -206,19 +213,31 @@ int kwsysProcess_GetState(kwsysProcess* cp) } /*--------------------------------------------------------------------------*/ +int kwsysProcess_GetExitException(kwsysProcess* cp) +{ + return cp->ExitException; +} + +/*--------------------------------------------------------------------------*/ int kwsysProcess_GetExitCode(kwsysProcess* cp) { return cp->ExitCode; } /*--------------------------------------------------------------------------*/ +int kwsysProcess_GetExitValue(kwsysProcess* cp) +{ + return cp->ExitValue; +} + +/*--------------------------------------------------------------------------*/ const char* kwsysProcess_GetErrorString(kwsysProcess* cp) { - if(cp->State == kwsysProcess_Error) + if(cp->State == kwsysProcess_State_Error) { return cp->PipeBuffer; } - return ""; + return 0; } /*--------------------------------------------------------------------------*/ @@ -228,7 +247,7 @@ void kwsysProcess_Execute(kwsysProcess* cp) struct sigaction newSigChldAction; /* Do not execute a second copy simultaneously. */ - if(cp->State == kwsysProcess_Executing) + if(cp->State == kwsysProcess_State_Executing) { return; } @@ -317,7 +336,7 @@ void kwsysProcess_Execute(kwsysProcess* cp) cp->PipesLeft = KWSYSPE_PIPE_COUNT; /* The process has now started. */ - cp->State = kwsysProcess_Executing; + cp->State = kwsysProcess_State_Executing; } /*--------------------------------------------------------------------------*/ @@ -503,7 +522,7 @@ int kwsysProcess_WaitForData(kwsysProcess* cp, int pipes, char** data, int* leng if(user) { /* The user timeout has expired. It has no time left. */ - return kwsysProcess_Timeout; + return kwsysProcess_Pipe_Timeout; } else { @@ -530,7 +549,7 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout) int pipe = 0; /* Make sure we are executing a process. */ - if(cp->State != kwsysProcess_Executing) + if(cp->State != kwsysProcess_State_Executing) { return 1; } @@ -538,7 +557,7 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout) /* Wait for all the pipes to close. Ignore all data. */ while((pipe = kwsysProcess_WaitForData(cp, 0, 0, 0, userTimeout)) > 0) { - if(pipe == kwsysProcess_Timeout) + if(pipe == kwsysProcess_Pipe_Timeout) { return 0; } @@ -561,7 +580,7 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout) /* The error message is already in its buffer. Tell kwsysProcessCleanup to not create it. */ kwsysProcessCleanup(cp, 0); - cp->State = kwsysProcess_Error; + cp->State = kwsysProcess_State_Error; return 1; } @@ -569,30 +588,52 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout) if(cp->Killed) { /* We killed the child. */ - cp->State = kwsysProcess_Killed; + cp->State = kwsysProcess_State_Killed; } else if(cp->TimeoutExpired) { /* The timeout expired. */ - cp->State = kwsysProcess_Expired; + cp->State = kwsysProcess_State_Expired; } else if(WIFEXITED(status)) { - /* The child exited. */ - cp->State = kwsysProcess_Exited; - cp->ExitCode = (int)WEXITSTATUS(status); + /* The child exited normally. */ + cp->State = kwsysProcess_State_Exited; + cp->ExitException = kwsysProcess_Exception_None; + cp->ExitCode = status; + cp->ExitValue = (int)WEXITSTATUS(status); } else if(WIFSIGNALED(status)) { /* The child received an unhandled signal. */ - cp->State = kwsysProcess_Signalled; - cp->ExitCode = (int)WTERMSIG(status); + cp->State = kwsysProcess_State_Exception; + switch ((int)WTERMSIG(status)) + { +#ifdef SIGSEGV + case SIGSEGV: 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 +#ifdef SIGABRT + case SIGABRT: cp->ExitException = kwsysProcess_Exception_Abort; break; +#endif + default: cp->ExitException = kwsysProcess_Exception_Other; break; + } + cp->ExitCode = status; + cp->ExitValue = (int)WTERMSIG(status); } else { /* Error getting the child return code. */ strcpy(cp->ErrorMessage, "Error getting child return code."); - cp->State = kwsysProcess_Error; + cp->State = kwsysProcess_State_Error; } /* Normal cleanup. */ @@ -604,7 +645,7 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout) void kwsysProcess_Kill(kwsysProcess* cp) { /* Make sure we are executing a process. */ - if(cp->State != kwsysProcess_Executing) + if(cp->State != kwsysProcess_State_Executing) { return; } @@ -633,9 +674,11 @@ static void kwsysProcessInitialize(kwsysProcess* cp) cp->TimeoutExpired = 0; cp->PipesLeft = 0; FD_ZERO(&cp->PipeSet); - cp->State = kwsysProcess_Starting; + cp->State = kwsysProcess_State_Starting; cp->Killed = 0; - cp->ExitCode = 0; + cp->ExitException = kwsysProcess_Exception_None; + cp->ExitCode = 1; + cp->ExitValue = 1; cp->ErrorMessage[0] = 0; cp->ErrorMessageLength = 0; } @@ -651,7 +694,7 @@ static void kwsysProcessCleanup(kwsysProcess* cp, int error) if(error) { snprintf(cp->ErrorMessage, KWSYSPE_PIPE_BUFFER_SIZE, "%s", strerror(errno)); - cp->State = kwsysProcess_Error; + cp->State = kwsysProcess_State_Error; } /* Restore the SIGCHLD handler. */ diff --git a/Source/kwsys/ProcessWin32.c b/Source/kwsys/ProcessWin32.c index ed50efe..3d1df05 100644 --- a/Source/kwsys/ProcessWin32.c +++ b/Source/kwsys/ProcessWin32.c @@ -152,9 +152,15 @@ struct kwsysProcess_s /* ------------- Data managed per call to Execute ------------- */ - /* The process exit code, if any. */ + /* The exceptional behavior that terminated the process, if any. */ + int ExitException; + + /* The process exit code. */ int ExitCode; + /* The process return code, if any. */ + int ExitValue; + /* Index of last pipe to report data, if any. */ int CurrentIndex; @@ -218,7 +224,7 @@ kwsysProcess* kwsysProcess_New() ZeroMemory(cp, sizeof(*cp)); /* Set initial status. */ - cp->State = kwsysProcess_Starting; + cp->State = kwsysProcess_State_Starting; /* Choose a method of running the child based on version of windows. */ @@ -368,7 +374,7 @@ void kwsysProcess_Delete(kwsysProcess* cp) int i; /* If the process is executing, wait for it to finish. */ - if(cp->State == kwsysProcess_Executing) + if(cp->State == kwsysProcess_State_Executing) { kwsysProcess_WaitForExit(cp, 0); } @@ -563,6 +569,18 @@ int kwsysProcess_GetState(kwsysProcess* cp) } /*--------------------------------------------------------------------------*/ +int kwsysProcess_GetExitException(kwsysProcess* cp) +{ + return cp->ExitException; +} + +/*--------------------------------------------------------------------------*/ +int kwsysProcess_GetExitValue(kwsysProcess* cp) +{ + return cp->ExitValue; +} + +/*--------------------------------------------------------------------------*/ int kwsysProcess_GetExitCode(kwsysProcess* cp) { return cp->ExitCode; @@ -571,7 +589,11 @@ int kwsysProcess_GetExitCode(kwsysProcess* cp) /*--------------------------------------------------------------------------*/ const char* kwsysProcess_GetErrorString(kwsysProcess* cp) { - return cp->ErrorMessage; + if(cp->State == kwsysProcess_State_Error) + { + return cp->ErrorMessage; + } + return 0; } /*--------------------------------------------------------------------------*/ @@ -583,7 +605,7 @@ void kwsysProcess_Execute(kwsysProcess* cp) STARTUPINFO si; /* Do not execute a second time. */ - if(cp->State == kwsysProcess_Executing) + if(cp->State == kwsysProcess_State_Executing) { return; } @@ -596,6 +618,9 @@ void kwsysProcess_Execute(kwsysProcess* cp) cp->TimeoutExpired = 0; cp->Terminated = 0; cp->Killed = 0; + cp->ExitException = kwsysProcess_Exception_None; + cp->ExitCode = 1; + cp->ExitValue = 1; /* Reset error data. */ cp->ErrorMessage[0] = 0; @@ -701,7 +726,7 @@ void kwsysProcess_Execute(kwsysProcess* cp) cp->PipesLeft = cp->PipeCount; /* The process has now started. */ - cp->State = kwsysProcess_Executing; + cp->State = kwsysProcess_State_Executing; } /*--------------------------------------------------------------------------*/ @@ -721,7 +746,8 @@ int kwsysProcess_WaitForData(kwsysProcess* cp, int pipes, char** data, int* leng HANDLE events[2]; /* Make sure we are executing a process. */ - if(cp->State != kwsysProcess_Executing || cp->Killed || cp->TimeoutExpired) + if(cp->State != kwsysProcess_State_Executing || cp->Killed || + cp->TimeoutExpired) { return 0; } @@ -866,7 +892,7 @@ int kwsysProcess_WaitForData(kwsysProcess* cp, int pipes, char** data, int* leng if(user) { /* The user timeout has expired. It has no time left. */ - return kwsysProcess_Timeout; + return kwsysProcess_Pipe_Timeout; } else { @@ -890,11 +916,8 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout) int i; int pipe = 0; - /* Buffer for child's return value. */ - int childReturnValue = 0; - /* Make sure we are executing a process. */ - if(cp->State != kwsysProcess_Executing) + if(cp->State != kwsysProcess_State_Executing) { return 1; } @@ -902,7 +925,7 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout) /* Wait for the process to terminate. Ignore all data. */ while((pipe = kwsysProcess_WaitForData(cp, 0, 0, 0, userTimeout)) > 0) { - if(pipe == kwsysProcess_Timeout) + if(pipe == kwsysProcess_Pipe_Timeout) { /* The user timeout has expired. */ return 0; @@ -936,30 +959,72 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout) if(cp->Killed) { /* We killed the child. */ - cp->State = kwsysProcess_Killed; + cp->State = kwsysProcess_State_Killed; } else if(cp->ErrorMessageLength) { /* Failed to run the process. */ - cp->State = kwsysProcess_Error; + cp->State = kwsysProcess_State_Error; } else if(cp->TimeoutExpired) { /* The timeout expired. */ - cp->State = kwsysProcess_Expired; + cp->State = kwsysProcess_State_Expired; } else if(GetExitCodeProcess(cp->ProcessInformation.hProcess, - &childReturnValue)) + &cp->ExitCode)) { /* The child exited. */ - cp->State = kwsysProcess_Exited; - cp->ExitCode = childReturnValue; + cp->State = kwsysProcess_State_Exited; + if(cp->ExitCode & 0xC0000000) + { + /* Child terminated due to exceptional behavior. */ + 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; + } + else + { + /* Child exited normally. */ + cp->ExitException = kwsysProcess_Exception_None; + cp->ExitValue = cp->ExitCode & 0x000000FF; + } } else { /* Error getting the child return code. */ strcpy(cp->ErrorMessage, "Error getting child return code."); - cp->State = kwsysProcess_Error; + cp->State = kwsysProcess_State_Error; } /* The child process is terminated. */ @@ -974,8 +1039,8 @@ void kwsysProcess_Kill(kwsysProcess* cp) int i; /* Make sure we are executing a process. */ - if(cp->State != kwsysProcess_Executing || cp->TimeoutExpired || cp->Killed || - cp->Terminated) + if(cp->State != kwsysProcess_State_Executing || cp->TimeoutExpired || + cp->Killed || cp->Terminated) { return; } @@ -1105,7 +1170,7 @@ void kwsysProcessCleanup(kwsysProcess* cp, int error) FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), cp->ErrorMessage, CMPE_PIPE_BUFFER_SIZE, 0); - cp->State = kwsysProcess_Error; + cp->State = kwsysProcess_State_Error; } /* Free memory. */ diff --git a/Source/kwsys/test1.cxx b/Source/kwsys/test1.cxx index 0957d3a..7dd61a4 100644 --- a/Source/kwsys/test1.cxx +++ b/Source/kwsys/test1.cxx @@ -11,7 +11,8 @@ int main() kwsysProcess_Execute(kp); char* data = 0; int length = 0; - while(kwsysProcess_WaitForData(kp, kwsysProcess_STDOUT | kwsysProcess_STDERR, + while(kwsysProcess_WaitForData(kp, (kwsysProcess_Pipe_STDOUT | + kwsysProcess_Pipe_STDERR), &data, &length, 0)) { kwsys_std::cout.write(data, length); |