ENH: Added documentation to interface. Finished process exit code interpretation implementation prototype.

This commit is contained in:
Brad King 2003-06-18 17:06:21 -04:00
parent 5394a75340
commit 7e80f2f874
4 changed files with 367 additions and 145 deletions

View File

@ -17,31 +17,44 @@
#ifndef @KWSYS_NAMESPACE@_Process_h #ifndef @KWSYS_NAMESPACE@_Process_h
#define @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 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 kwsys(Process)
#define kwsysProcess_s kwsys(Process_s)
#define kwsysProcess_New kwsys(Process_New) #define kwsysProcess_New kwsys(Process_New)
#define kwsysProcess_Delete kwsys(Process_Delete) #define kwsysProcess_Delete kwsys(Process_Delete)
#define kwsysProcess_SetCommand kwsys(Process_SetCommand) #define kwsysProcess_SetCommand kwsys(Process_SetCommand)
#define kwsysProcess_SetTimeout kwsys(Process_SetTimeout) #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_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_GetExitCode kwsys(Process_GetExitCode)
#define kwsysProcess_GetExitValue kwsys(Process_GetExitValue)
#define kwsysProcess_GetErrorString kwsys(Process_GetErrorString) #define kwsysProcess_GetErrorString kwsys(Process_GetErrorString)
#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_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_WaitForExit kwsys(Process_WaitForExit)
#define kwsysProcess_Kill kwsys(Process_Kill) #define kwsysProcess_Kill kwsys(Process_Kill)
@ -50,86 +63,177 @@ extern "C"
{ {
#endif #endif
typedef enum kwsysProcess_Pipes_e /**
{ * Process control data structure.
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;
typedef struct kwsysProcess_s kwsysProcess; typedef struct kwsysProcess_s kwsysProcess;
/**
* Create a new Process instance.
*/
kwsysProcess* kwsysProcess_New(); 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); 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); 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); 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); 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
};
/* /**
* Get process return code or when signalled, get the signal code * 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
};
/**
* 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); 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); const char* kwsysProcess_GetErrorString(kwsysProcess* cp);
/**
* Start executing the child process.
*/
void kwsysProcess_Execute(kwsysProcess* cp); void kwsysProcess_Execute(kwsysProcess* cp);
/* /**
* Block until data available on requested pipe or one of the timeouts expired, * Block until data are available on a requested pipe, a timeout
* or the process exits. If the pipe is not specified, data on that pipe are * expires, or the child process terminates. Arguments are as
* ignored. * follows:
* *
* pipes - a list of interested pipes - kwsysProcess_STDOUT | kwsysProcess_STDERR * pipes = Flags for the child output pipes of interest to the caller.
* data - returns pointer to data if read, NULL otherwise * Possible values are Pipe_STDOUT and Pipe_STDERR. Multiple
* length - length of the returned data * pipes may be specified by using the bitwise OR operator '|'.
* userTimeout - timeout for the current kwsysProcess_WaitForData call * data = If data are read, the pointer to which this points is
* the userTimeout will contain the remaining time * 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.
* *
* Returns: * Return value will be one of:
* 0 - Process exited or killed or process timeout expired with no data *
* available, or no process running. * 0 = No more data will be available from the child process,
* PIPE id otherwise: * or no process has been executed. WaitForExit should
* kwsysProcess_STDOUT - if stdout is returned * be called to wait for the process to terminate.
* kwsysProcess_STDERR - if stderr is returned * Pipe_STDOUT = Data have been read from the child's stdout pipe.
* kwsysProcess_Timeout - if user timeout expired * 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, int kwsysProcess_WaitForData(kwsysProcess* cp, int pipes, char** data,
double* userTimeout); int* length, double* timeout);
typedef enum kwsysProcess_Pipes_e
{
kwsysProcess_Pipe_STDOUT=1,
kwsysProcess_Pipe_STDERR=2,
kwsysProcess_Pipe_Timeout=255
};
/* /**
* Block until the process exits or the timeout expires. If no process is * Block until the child process terminates or the given timeout
* running, return immediatly. * expires. If no process is running, returns immediatly. The
* argument is:
* *
* Returns: * timeout = Specifies the maximum time this call may block. Upon
* 0 - When user timeout expires * returning due to child termination, the elapsed time
* 1 - Otherwise * is subtracted from the given value. A NULL pointer
* passed for this argument indicates no timeout for the
* call.
*
* Return value will be one of:
*
* 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 * Forcefully terminate the child process that is currently running.
* after kwsysProcess_Kill. * The caller should call WaitForExit after this returns to wait for
* the child to terminate.
*/ */
void kwsysProcess_Kill(kwsysProcess* cp); void kwsysProcess_Kill(kwsysProcess* cp);
@ -137,34 +241,43 @@ void kwsysProcess_Kill(kwsysProcess* cp);
} /* extern "C" */ } /* extern "C" */
#endif #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) #if !defined(KWSYS_IN_PROCESS_C)
# undef kwsys # 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
# undef kwsysProcess_s
# undef kwsysProcess_New # undef kwsysProcess_New
# undef kwsysProcess_Delete # undef kwsysProcess_Delete
# undef kwsysProcess_SetCommand # undef kwsysProcess_SetCommand
# undef kwsysProcess_SetTimeout # 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_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_GetExitCode
# undef kwsysProcess_GetExitValue
# undef kwsysProcess_GetErrorString # undef kwsysProcess_GetErrorString
# undef kwsysProcess_Execute # undef kwsysProcess_Execute
# undef kwsysProcess_WaitForData # undef kwsysProcess_WaitForData
# undef kwsysProcess_Pipes_e
# undef kwsysProcess_Pipe_STDOUT
# undef kwsysProcess_Pipe_STDERR
# undef kwsysProcess_Pipe_Timeout
# undef kwsysProcess_WaitForExit # undef kwsysProcess_WaitForExit
# undef kwsysProcess_Kill # undef kwsysProcess_Kill
#endif #endif

View File

@ -98,7 +98,7 @@ struct kwsysProcess_s
int ChildError; int ChildError;
/* The timeout length. */ /* The timeout length. */
float Timeout; double Timeout;
/* Time at which the child started. Negative for no timeout. */ /* Time at which the child started. Negative for no timeout. */
kwsysProcessTime StartTime; kwsysProcessTime StartTime;
@ -121,9 +121,16 @@ struct kwsysProcess_s
/* The current status of the child process. */ /* The current status of the child process. */
int State; 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; int ExitCode;
/* The exit value of the child process, if any. */
int ExitValue;
/* Whether the process was killed. */ /* Whether the process was killed. */
int Killed; int Killed;
@ -142,7 +149,7 @@ kwsysProcess* kwsysProcess_New()
return 0; return 0;
} }
memset(cp, 0, sizeof(kwsysProcess)); memset(cp, 0, sizeof(kwsysProcess));
cp->State = kwsysProcess_Starting; cp->State = kwsysProcess_State_Starting;
return cp; return cp;
} }
@ -150,7 +157,7 @@ kwsysProcess* kwsysProcess_New()
void kwsysProcess_Delete(kwsysProcess* cp) void kwsysProcess_Delete(kwsysProcess* cp)
{ {
/* If the process is executing, wait for it to finish. */ /* 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); kwsysProcess_WaitForExit(cp, 0);
} }
@ -205,20 +212,32 @@ int kwsysProcess_GetState(kwsysProcess* cp)
return cp->State; return cp->State;
} }
/*--------------------------------------------------------------------------*/
int kwsysProcess_GetExitException(kwsysProcess* cp)
{
return cp->ExitException;
}
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
int kwsysProcess_GetExitCode(kwsysProcess* cp) int kwsysProcess_GetExitCode(kwsysProcess* cp)
{ {
return cp->ExitCode; return cp->ExitCode;
} }
/*--------------------------------------------------------------------------*/
int kwsysProcess_GetExitValue(kwsysProcess* cp)
{
return cp->ExitValue;
}
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
const char* kwsysProcess_GetErrorString(kwsysProcess* cp) const char* kwsysProcess_GetErrorString(kwsysProcess* cp)
{ {
if(cp->State == kwsysProcess_Error) if(cp->State == kwsysProcess_State_Error)
{ {
return cp->PipeBuffer; return cp->PipeBuffer;
} }
return ""; return 0;
} }
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
@ -228,7 +247,7 @@ void kwsysProcess_Execute(kwsysProcess* cp)
struct sigaction newSigChldAction; struct sigaction newSigChldAction;
/* Do not execute a second copy simultaneously. */ /* Do not execute a second copy simultaneously. */
if(cp->State == kwsysProcess_Executing) if(cp->State == kwsysProcess_State_Executing)
{ {
return; return;
} }
@ -317,7 +336,7 @@ void kwsysProcess_Execute(kwsysProcess* cp)
cp->PipesLeft = KWSYSPE_PIPE_COUNT; cp->PipesLeft = KWSYSPE_PIPE_COUNT;
/* The process has now started. */ /* 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) if(user)
{ {
/* The user timeout has expired. It has no time left. */ /* The user timeout has expired. It has no time left. */
return kwsysProcess_Timeout; return kwsysProcess_Pipe_Timeout;
} }
else else
{ {
@ -530,7 +549,7 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout)
int pipe = 0; int pipe = 0;
/* Make sure we are executing a process. */ /* Make sure we are executing a process. */
if(cp->State != kwsysProcess_Executing) if(cp->State != kwsysProcess_State_Executing)
{ {
return 1; return 1;
} }
@ -538,7 +557,7 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout)
/* Wait for all the pipes to close. Ignore all data. */ /* Wait for all the pipes to close. Ignore all data. */
while((pipe = kwsysProcess_WaitForData(cp, 0, 0, 0, userTimeout)) > 0) while((pipe = kwsysProcess_WaitForData(cp, 0, 0, 0, userTimeout)) > 0)
{ {
if(pipe == kwsysProcess_Timeout) if(pipe == kwsysProcess_Pipe_Timeout)
{ {
return 0; return 0;
} }
@ -561,7 +580,7 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout)
/* The error message is already in its buffer. Tell /* The error message is already in its buffer. Tell
kwsysProcessCleanup to not create it. */ kwsysProcessCleanup to not create it. */
kwsysProcessCleanup(cp, 0); kwsysProcessCleanup(cp, 0);
cp->State = kwsysProcess_Error; cp->State = kwsysProcess_State_Error;
return 1; return 1;
} }
@ -569,30 +588,52 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout)
if(cp->Killed) if(cp->Killed)
{ {
/* We killed the child. */ /* We killed the child. */
cp->State = kwsysProcess_Killed; cp->State = kwsysProcess_State_Killed;
} }
else if(cp->TimeoutExpired) else if(cp->TimeoutExpired)
{ {
/* The timeout expired. */ /* The timeout expired. */
cp->State = kwsysProcess_Expired; cp->State = kwsysProcess_State_Expired;
} }
else if(WIFEXITED(status)) else if(WIFEXITED(status))
{ {
/* The child exited. */ /* The child exited normally. */
cp->State = kwsysProcess_Exited; cp->State = kwsysProcess_State_Exited;
cp->ExitCode = (int)WEXITSTATUS(status); cp->ExitException = kwsysProcess_Exception_None;
cp->ExitCode = status;
cp->ExitValue = (int)WEXITSTATUS(status);
} }
else if(WIFSIGNALED(status)) else if(WIFSIGNALED(status))
{ {
/* The child received an unhandled signal. */ /* The child received an unhandled signal. */
cp->State = kwsysProcess_Signalled; cp->State = kwsysProcess_State_Exception;
cp->ExitCode = (int)WTERMSIG(status); 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 else
{ {
/* Error getting the child return code. */ /* Error getting the child return code. */
strcpy(cp->ErrorMessage, "Error getting child return code."); strcpy(cp->ErrorMessage, "Error getting child return code.");
cp->State = kwsysProcess_Error; cp->State = kwsysProcess_State_Error;
} }
/* Normal cleanup. */ /* Normal cleanup. */
@ -604,7 +645,7 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout)
void kwsysProcess_Kill(kwsysProcess* cp) void kwsysProcess_Kill(kwsysProcess* cp)
{ {
/* Make sure we are executing a process. */ /* Make sure we are executing a process. */
if(cp->State != kwsysProcess_Executing) if(cp->State != kwsysProcess_State_Executing)
{ {
return; return;
} }
@ -633,9 +674,11 @@ static void kwsysProcessInitialize(kwsysProcess* cp)
cp->TimeoutExpired = 0; cp->TimeoutExpired = 0;
cp->PipesLeft = 0; cp->PipesLeft = 0;
FD_ZERO(&cp->PipeSet); FD_ZERO(&cp->PipeSet);
cp->State = kwsysProcess_Starting; cp->State = kwsysProcess_State_Starting;
cp->Killed = 0; cp->Killed = 0;
cp->ExitCode = 0; cp->ExitException = kwsysProcess_Exception_None;
cp->ExitCode = 1;
cp->ExitValue = 1;
cp->ErrorMessage[0] = 0; cp->ErrorMessage[0] = 0;
cp->ErrorMessageLength = 0; cp->ErrorMessageLength = 0;
} }
@ -651,7 +694,7 @@ static void kwsysProcessCleanup(kwsysProcess* cp, int error)
if(error) if(error)
{ {
snprintf(cp->ErrorMessage, KWSYSPE_PIPE_BUFFER_SIZE, "%s", strerror(errno)); snprintf(cp->ErrorMessage, KWSYSPE_PIPE_BUFFER_SIZE, "%s", strerror(errno));
cp->State = kwsysProcess_Error; cp->State = kwsysProcess_State_Error;
} }
/* Restore the SIGCHLD handler. */ /* Restore the SIGCHLD handler. */

View File

@ -152,9 +152,15 @@ struct kwsysProcess_s
/* ------------- Data managed per call to Execute ------------- */ /* ------------- 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; int ExitCode;
/* The process return code, if any. */
int ExitValue;
/* Index of last pipe to report data, if any. */ /* Index of last pipe to report data, if any. */
int CurrentIndex; int CurrentIndex;
@ -218,7 +224,7 @@ kwsysProcess* kwsysProcess_New()
ZeroMemory(cp, sizeof(*cp)); ZeroMemory(cp, sizeof(*cp));
/* Set initial status. */ /* Set initial status. */
cp->State = kwsysProcess_Starting; cp->State = kwsysProcess_State_Starting;
/* Choose a method of running the child based on version of /* Choose a method of running the child based on version of
windows. */ windows. */
@ -368,7 +374,7 @@ void kwsysProcess_Delete(kwsysProcess* cp)
int i; int i;
/* If the process is executing, wait for it to finish. */ /* 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); kwsysProcess_WaitForExit(cp, 0);
} }
@ -562,6 +568,18 @@ int kwsysProcess_GetState(kwsysProcess* cp)
return cp->State; return cp->State;
} }
/*--------------------------------------------------------------------------*/
int kwsysProcess_GetExitException(kwsysProcess* cp)
{
return cp->ExitException;
}
/*--------------------------------------------------------------------------*/
int kwsysProcess_GetExitValue(kwsysProcess* cp)
{
return cp->ExitValue;
}
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
int kwsysProcess_GetExitCode(kwsysProcess* cp) int kwsysProcess_GetExitCode(kwsysProcess* cp)
{ {
@ -571,7 +589,11 @@ int kwsysProcess_GetExitCode(kwsysProcess* cp)
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
const char* kwsysProcess_GetErrorString(kwsysProcess* cp) const char* kwsysProcess_GetErrorString(kwsysProcess* cp)
{ {
if(cp->State == kwsysProcess_State_Error)
{
return cp->ErrorMessage; return cp->ErrorMessage;
}
return 0;
} }
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
@ -583,7 +605,7 @@ void kwsysProcess_Execute(kwsysProcess* cp)
STARTUPINFO si; STARTUPINFO si;
/* Do not execute a second time. */ /* Do not execute a second time. */
if(cp->State == kwsysProcess_Executing) if(cp->State == kwsysProcess_State_Executing)
{ {
return; return;
} }
@ -596,6 +618,9 @@ void kwsysProcess_Execute(kwsysProcess* cp)
cp->TimeoutExpired = 0; cp->TimeoutExpired = 0;
cp->Terminated = 0; cp->Terminated = 0;
cp->Killed = 0; cp->Killed = 0;
cp->ExitException = kwsysProcess_Exception_None;
cp->ExitCode = 1;
cp->ExitValue = 1;
/* Reset error data. */ /* Reset error data. */
cp->ErrorMessage[0] = 0; cp->ErrorMessage[0] = 0;
@ -701,7 +726,7 @@ void kwsysProcess_Execute(kwsysProcess* cp)
cp->PipesLeft = cp->PipeCount; cp->PipesLeft = cp->PipeCount;
/* The process has now started. */ /* 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]; HANDLE events[2];
/* Make sure we are executing a process. */ /* 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; return 0;
} }
@ -866,7 +892,7 @@ int kwsysProcess_WaitForData(kwsysProcess* cp, int pipes, char** data, int* leng
if(user) if(user)
{ {
/* The user timeout has expired. It has no time left. */ /* The user timeout has expired. It has no time left. */
return kwsysProcess_Timeout; return kwsysProcess_Pipe_Timeout;
} }
else else
{ {
@ -890,11 +916,8 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout)
int i; int i;
int pipe = 0; int pipe = 0;
/* Buffer for child's return value. */
int childReturnValue = 0;
/* Make sure we are executing a process. */ /* Make sure we are executing a process. */
if(cp->State != kwsysProcess_Executing) if(cp->State != kwsysProcess_State_Executing)
{ {
return 1; return 1;
} }
@ -902,7 +925,7 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout)
/* Wait for the process to terminate. Ignore all data. */ /* Wait for the process to terminate. Ignore all data. */
while((pipe = kwsysProcess_WaitForData(cp, 0, 0, 0, userTimeout)) > 0) while((pipe = kwsysProcess_WaitForData(cp, 0, 0, 0, userTimeout)) > 0)
{ {
if(pipe == kwsysProcess_Timeout) if(pipe == kwsysProcess_Pipe_Timeout)
{ {
/* The user timeout has expired. */ /* The user timeout has expired. */
return 0; return 0;
@ -936,30 +959,72 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout)
if(cp->Killed) if(cp->Killed)
{ {
/* We killed the child. */ /* We killed the child. */
cp->State = kwsysProcess_Killed; cp->State = kwsysProcess_State_Killed;
} }
else if(cp->ErrorMessageLength) else if(cp->ErrorMessageLength)
{ {
/* Failed to run the process. */ /* Failed to run the process. */
cp->State = kwsysProcess_Error; cp->State = kwsysProcess_State_Error;
} }
else if(cp->TimeoutExpired) else if(cp->TimeoutExpired)
{ {
/* The timeout expired. */ /* The timeout expired. */
cp->State = kwsysProcess_Expired; cp->State = kwsysProcess_State_Expired;
} }
else if(GetExitCodeProcess(cp->ProcessInformation.hProcess, else if(GetExitCodeProcess(cp->ProcessInformation.hProcess,
&childReturnValue)) &cp->ExitCode))
{ {
/* The child exited. */ /* The child exited. */
cp->State = kwsysProcess_Exited; cp->State = kwsysProcess_State_Exited;
cp->ExitCode = childReturnValue; 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 else
{ {
/* Error getting the child return code. */ /* Error getting the child return code. */
strcpy(cp->ErrorMessage, "Error getting 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. */ /* The child process is terminated. */
@ -974,8 +1039,8 @@ void kwsysProcess_Kill(kwsysProcess* cp)
int i; int i;
/* Make sure we are executing a process. */ /* Make sure we are executing a process. */
if(cp->State != kwsysProcess_Executing || cp->TimeoutExpired || cp->Killed || if(cp->State != kwsysProcess_State_Executing || cp->TimeoutExpired ||
cp->Terminated) cp->Killed || cp->Terminated)
{ {
return; return;
} }
@ -1105,7 +1170,7 @@ void kwsysProcessCleanup(kwsysProcess* cp, int error)
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
0, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 0, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
cp->ErrorMessage, CMPE_PIPE_BUFFER_SIZE, 0); cp->ErrorMessage, CMPE_PIPE_BUFFER_SIZE, 0);
cp->State = kwsysProcess_Error; cp->State = kwsysProcess_State_Error;
} }
/* Free memory. */ /* Free memory. */

View File

@ -11,7 +11,8 @@ int main()
kwsysProcess_Execute(kp); kwsysProcess_Execute(kp);
char* data = 0; char* data = 0;
int length = 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)) &data, &length, 0))
{ {
kwsys_std::cout.write(data, length); kwsys_std::cout.write(data, length);