diff --git a/Process.h.in b/Process.h.in index b8349a66a148c0a6172560ec659f0c74450420d1..237001c604d2aaa31a2942ae7756b47d7e3a273c 100644 --- a/Process.h.in +++ b/Process.h.in @@ -42,7 +42,6 @@ #define kwsysProcess_State_Expired kwsys_ns(Process_State_Expired) #define kwsysProcess_State_Killed kwsys_ns(Process_State_Killed) #define kwsysProcess_State_Disowned kwsys_ns(Process_State_Disowned) -#define kwsysProcess_GetState kwsys_ns(Process_GetState) #define kwsysProcess_State_e kwsys_ns(Process_State_e) #define kwsysProcess_Exception_None kwsys_ns(Process_Exception_None) #define kwsysProcess_Exception_Fault kwsys_ns(Process_Exception_Fault) @@ -50,12 +49,21 @@ #define kwsysProcess_Exception_Interrupt kwsys_ns(Process_Exception_Interrupt) #define kwsysProcess_Exception_Numerical kwsys_ns(Process_Exception_Numerical) #define kwsysProcess_Exception_Other kwsys_ns(Process_Exception_Other) -#define kwsysProcess_GetExitException kwsys_ns(Process_GetExitException) #define kwsysProcess_Exception_e kwsys_ns(Process_Exception_e) +#define kwsysProcess_GetState kwsys_ns(Process_GetState) +#define kwsysProcess_GetExitException kwsys_ns(Process_GetExitException) #define kwsysProcess_GetExitCode kwsys_ns(Process_GetExitCode) #define kwsysProcess_GetExitValue kwsys_ns(Process_GetExitValue) #define kwsysProcess_GetErrorString kwsys_ns(Process_GetErrorString) #define kwsysProcess_GetExceptionString kwsys_ns(Process_GetExceptionString) +#define kwsysProcess_GetStateByIndex kwsys_ns(Process_GetStateByIndex) +#define kwsysProcess_GetExitExceptionByIndex \ + kwsys_ns(Process_GetExitExceptionByIndex) +#define kwsysProcess_GetExitCodeByIndex kwsys_ns(Process_GetExitCodeByIndex) +#define kwsysProcess_GetExitValueByIndex kwsys_ns(Process_GetExitValueByIndex) +#define kwsysProcess_GetExceptionStringByIndex \ + kwsys_ns(Process_GetExceptionStringByIndex) +#define kwsysProcess_GetExitCodeByIndex kwsys_ns(Process_GetExitCodeByIndex) #define kwsysProcess_Execute kwsys_ns(Process_Execute) #define kwsysProcess_Disown kwsys_ns(Process_Disown) #define kwsysProcess_WaitForData kwsys_ns(Process_WaitForData) @@ -297,6 +305,67 @@ kwsysEXPORT const char* kwsysProcess_GetErrorString(kwsysProcess* cp); */ kwsysEXPORT const char* kwsysProcess_GetExceptionString(kwsysProcess* cp); +/** +* Get the current state of the Process instance. Possible states are: +* +* kwsysProcess_StateByIndex_Starting = Execute has not yet been called. +* kwsysProcess_StateByIndex_Exception = Child process exited abnormally. +* kwsysProcess_StateByIndex_Exited = Child process exited normally. +* kwsysProcess_StateByIndex_Error = Error getting the child return code. +*/ +kwsysEXPORT int kwsysProcess_GetStateByIndex(kwsysProcess* cp, int idx); +enum kwsysProcess_StateByIndex_e +{ + kwsysProcess_StateByIndex_Starting = kwsysProcess_State_Starting, + kwsysProcess_StateByIndex_Exception = kwsysProcess_State_Exception, + kwsysProcess_StateByIndex_Exited = kwsysProcess_State_Exited, + kwsysProcess_StateByIndex_Error = kwsysProcess_State_Error +}; + +/** +* 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_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. +*/ +kwsysEXPORT int kwsysProcess_GetExitExceptionByIndex(kwsysProcess* cp, + int idx); + +/** +* 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. +*/ +kwsysEXPORT int kwsysProcess_GetExitCodeByIndex(kwsysProcess* cp, int idx); + +/** +* When GetState returns "Exited", this method returns the child's +* platform-independent exit code (such as the value returned by the +* child's main). +*/ +kwsysEXPORT int kwsysProcess_GetExitValueByIndex(kwsysProcess* cp, int idx); + +/** +* When GetState returns "Exception", this method returns a string +* describing the problem. Otherwise, it returns NULL. +*/ +kwsysEXPORT const char* kwsysProcess_GetExceptionStringByIndex( + kwsysProcess* cp, int idx); + /** * Start executing the child process. */ diff --git a/ProcessUNIX.c b/ProcessUNIX.c index 1de81c7beebd426973f4cb0aee0434678b8786a1..9ebcfce592759922ce8fdb5cc02882ea2aae5e10 100644 --- a/ProcessUNIX.c +++ b/ProcessUNIX.c @@ -165,7 +165,8 @@ static kwsysProcessTime kwsysProcessTimeAdd(kwsysProcessTime in1, kwsysProcessTime in2); static kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1, kwsysProcessTime in2); -static void kwsysProcessSetExitException(kwsysProcess* cp, int sig); +static void kwsysProcessSetExitExceptionByIndex(kwsysProcess* cp, int sig, + int idx); static void kwsysProcessChildErrorExit(int errorPipe); static void kwsysProcessRestoreDefaultSignalHandlers(void); static pid_t kwsysProcessFork(kwsysProcess* cp, @@ -183,6 +184,26 @@ static void kwsysProcessesSignalHandler(int signum, siginfo_t* info, static void kwsysProcessesSignalHandler(int signum); #endif +/* A structure containing results data for each process. */ +typedef struct kwsysProcessResults_s kwsysProcessResults; +struct kwsysProcessResults_s +{ + /* The status of the child process. */ + int State; + + /* 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; + + /* Description for the ExitException. */ + char ExitExceptionString[KWSYSPE_PIPE_BUFFER_SIZE + 1]; +}; + /* Structure containing data used to implement the child's execution. */ struct kwsysProcess_s { @@ -253,28 +274,18 @@ struct kwsysProcess_s /* The number of children still executing. */ int CommandsLeft; - /* The current status of the child process. Must be atomic because + /* The status of the process structure. Must be atomic because the signal handler checks this to avoid a race. */ volatile sig_atomic_t State; - /* 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. */ volatile sig_atomic_t Killed; /* 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]; + /* process results. */ + kwsysProcessResults* ProcessResults; /* The exit codes of each child process in the pipeline. */ int* CommandExitCodes; @@ -350,6 +361,7 @@ void kwsysProcess_Delete(kwsysProcess* cp) if (cp->CommandExitCodes) { free(cp->CommandExitCodes); } + free(cp->ProcessResults); free(cp); } @@ -652,17 +664,23 @@ int kwsysProcess_GetState(kwsysProcess* cp) int kwsysProcess_GetExitException(kwsysProcess* cp) { - return cp ? cp->ExitException : kwsysProcess_Exception_Other; + return (cp && cp->ProcessResults && (cp->NumberOfCommands > 0)) + ? cp->ProcessResults[cp->NumberOfCommands - 1].ExitException + : kwsysProcess_Exception_Other; } int kwsysProcess_GetExitCode(kwsysProcess* cp) { - return cp ? cp->ExitCode : 0; + return (cp && cp->ProcessResults && (cp->NumberOfCommands > 0)) + ? cp->ProcessResults[cp->NumberOfCommands - 1].ExitCode + : 0; } int kwsysProcess_GetExitValue(kwsysProcess* cp) { - return cp ? cp->ExitValue : -1; + return (cp && cp->ProcessResults && (cp->NumberOfCommands > 0)) + ? cp->ProcessResults[cp->NumberOfCommands - 1].ExitValue + : -1; } const char* kwsysProcess_GetErrorString(kwsysProcess* cp) @@ -677,14 +695,56 @@ const char* kwsysProcess_GetErrorString(kwsysProcess* cp) const char* kwsysProcess_GetExceptionString(kwsysProcess* cp) { - if (!cp) { + if (!(cp && cp->ProcessResults && (cp->NumberOfCommands > 0))) { return "GetExceptionString called with NULL process management structure"; } else if (cp->State == kwsysProcess_State_Exception) { - return cp->ExitExceptionString; + return cp->ProcessResults[cp->NumberOfCommands - 1].ExitExceptionString; + } + return "No exception"; +} + +/* the index should be in array bound. */ +#define KWSYSPE_IDX_CHK(RET) \ + if (!cp || idx >= cp->NumberOfCommands || idx < 0) { \ + return RET; \ + } + +int kwsysProcess_GetStateByIndex(kwsysProcess* cp, int idx) +{ + KWSYSPE_IDX_CHK(kwsysProcess_State_Error) + return cp->ProcessResults[idx].State; +} + +int kwsysProcess_GetExitExceptionByIndex(kwsysProcess* cp, int idx) +{ + KWSYSPE_IDX_CHK(kwsysProcess_Exception_Other) + return cp->ProcessResults[idx].ExitException; +} + +int kwsysProcess_GetExitValueByIndex(kwsysProcess* cp, int idx) +{ + KWSYSPE_IDX_CHK(-1) + return cp->ProcessResults[idx].ExitValue; +} + +int kwsysProcess_GetExitCodeByIndex(kwsysProcess* cp, int idx) +{ + KWSYSPE_IDX_CHK(-1) + return cp->CommandExitCodes[idx]; +} + +const char* kwsysProcess_GetExceptionStringByIndex(kwsysProcess* cp, int idx) +{ + KWSYSPE_IDX_CHK("GetExceptionString called with NULL process management " + "structure or index out of bound") + if (cp->ProcessResults[idx].State == kwsysProcess_StateByIndex_Exception) { + return cp->ProcessResults[idx].ExitExceptionString; } return "No exception"; } +#undef KWSYSPE_IDX_CHK + void kwsysProcess_Execute(kwsysProcess* cp) { int i; @@ -1263,7 +1323,6 @@ static int kwsysProcessWaitForPipe(kwsysProcess* cp, char** data, int* length, int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout) { - int status = 0; int prPipe = 0; /* Make sure we are executing a process. */ @@ -1294,10 +1353,6 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout) cp->State = kwsysProcess_State_Error; return 1; } - - /* Use the status of the last process in the pipeline. */ - status = cp->CommandExitCodes[cp->NumberOfCommands - 1]; - /* Determine the outcome. */ if (cp->Killed) { /* We killed the child. */ @@ -1305,23 +1360,31 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout) } else if (cp->TimeoutExpired) { /* The timeout expired. */ cp->State = kwsysProcess_State_Expired; - } else if (WIFEXITED(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_State_Exception; - cp->ExitCode = status; - kwsysProcessSetExitException(cp, (int)WTERMSIG(status)); } else { - /* Error getting the child return code. */ - strcpy(cp->ErrorMessage, "Error getting child return code."); - cp->State = kwsysProcess_State_Error; + /* The children exited. Report the outcome of the child processes. */ + for (prPipe = 0; prPipe < cp->NumberOfCommands; ++prPipe) { + cp->ProcessResults[prPipe].ExitCode = cp->CommandExitCodes[prPipe]; + if (WIFEXITED(cp->ProcessResults[prPipe].ExitCode)) { + /* The child exited normally. */ + cp->ProcessResults[prPipe].State = kwsysProcess_StateByIndex_Exited; + cp->ProcessResults[prPipe].ExitException = kwsysProcess_Exception_None; + cp->ProcessResults[prPipe].ExitValue = + (int)WEXITSTATUS(cp->ProcessResults[prPipe].ExitCode); + } else if (WIFSIGNALED(cp->ProcessResults[prPipe].ExitCode)) { + /* The child received an unhandled signal. */ + cp->ProcessResults[prPipe].State = kwsysProcess_State_Exception; + kwsysProcessSetExitExceptionByIndex( + cp, (int)WTERMSIG(cp->ProcessResults[prPipe].ExitCode), prPipe); + } else { + /* Error getting the child return code. */ + strcpy(cp->ProcessResults[prPipe].ExitExceptionString, + "Error getting child return code."); + cp->ProcessResults[prPipe].State = kwsysProcess_StateByIndex_Error; + } + } + /* support legacy state status value */ + cp->State = cp->ProcessResults[cp->NumberOfCommands - 1].State; } - /* Normal cleanup. */ kwsysProcessCleanup(cp, 0); return 1; @@ -1445,11 +1508,7 @@ static int kwsysProcessInitialize(kwsysProcess* cp) #endif cp->State = kwsysProcess_State_Starting; cp->Killed = 0; - cp->ExitException = kwsysProcess_Exception_None; - cp->ExitCode = 1; - cp->ExitValue = 1; cp->ErrorMessage[0] = 0; - strcpy(cp->ExitExceptionString, "No exception"); oldForkPIDs = cp->ForkPIDs; cp->ForkPIDs = (volatile pid_t*)malloc(sizeof(volatile pid_t) * @@ -1475,6 +1534,23 @@ static int kwsysProcessInitialize(kwsysProcess* cp) memset(cp->CommandExitCodes, 0, sizeof(int) * (size_t)(cp->NumberOfCommands)); + /* Allocate process result information for each process. */ + free(cp->ProcessResults); + cp->ProcessResults = (kwsysProcessResults*)malloc( + sizeof(kwsysProcessResults) * (size_t)(cp->NumberOfCommands)); + if (!cp->ProcessResults) { + return 0; + } + memset(cp->ProcessResults, 0, + sizeof(kwsysProcessResults) * (size_t)(cp->NumberOfCommands)); + for (i = 0; i < cp->NumberOfCommands; i++) { + cp->ProcessResults[i].ExitException = kwsysProcess_Exception_None; + cp->ProcessResults[i].State = kwsysProcess_StateByIndex_Starting; + cp->ProcessResults[i].ExitCode = 1; + cp->ProcessResults[i].ExitValue = 1; + strcpy(cp->ProcessResults[i].ExitExceptionString, "No exception"); + } + /* Allocate memory to save the real working directory. */ if (cp->WorkingDirectory) { #if defined(MAXPATHLEN) @@ -2008,9 +2084,10 @@ static kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1, } #define KWSYSPE_CASE(type, str) \ - cp->ExitException = kwsysProcess_Exception_##type; \ - strcpy(cp->ExitExceptionString, str) -static void kwsysProcessSetExitException(kwsysProcess* cp, int sig) + cp->ProcessResults[idx].ExitException = kwsysProcess_Exception_##type; \ + strcpy(cp->ProcessResults[idx].ExitExceptionString, str) +static void kwsysProcessSetExitExceptionByIndex(kwsysProcess* cp, int sig, + int idx) { switch (sig) { #ifdef SIGSEGV @@ -2196,8 +2273,8 @@ static void kwsysProcessSetExitException(kwsysProcess* cp, int sig) #endif #endif default: - cp->ExitException = kwsysProcess_Exception_Other; - sprintf(cp->ExitExceptionString, "Signal %d", sig); + cp->ProcessResults[idx].ExitException = kwsysProcess_Exception_Other; + sprintf(cp->ProcessResults[idx].ExitExceptionString, "Signal %d", sig); break; } } diff --git a/ProcessWin32.c b/ProcessWin32.c index 06d91ae18f5fbd549cdc343aa8a43f3b1e6c16c9..5183e3d2c96ec05345328a98689572b85429cab8 100644 --- a/ProcessWin32.c +++ b/ProcessWin32.c @@ -118,6 +118,8 @@ static kwsysProcessTime kwsysProcessTimeAdd(kwsysProcessTime in1, static kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1, kwsysProcessTime in2); static void kwsysProcessSetExitException(kwsysProcess* cp, int code); +static void kwsysProcessSetExitExceptionByIndex(kwsysProcess* cp, int code, + int idx); static void kwsysProcessKillTree(int pid); static void kwsysProcessDisablePipeThreads(kwsysProcess* cp); static int kwsysProcessesInitialize(void); @@ -180,6 +182,26 @@ struct kwsysProcessPipeData_s HANDLE Write; }; +/* A structure containing results data for each process. */ +typedef struct kwsysProcessResults_s kwsysProcessResults; +struct kwsysProcessResults_s +{ + /* The status of the process. */ + int State; + + /* The exceptional behavior that terminated the process, if any. */ + int ExitException; + + /* The process exit code. */ + DWORD ExitCode; + + /* The process return code, if any. */ + int ExitValue; + + /* Description for the ExitException. */ + char ExitExceptionString[KWSYSPE_PIPE_BUFFER_SIZE + 1]; +}; + /* Structure containing data used to implement the child's execution. */ struct kwsysProcess_s { @@ -245,15 +267,6 @@ struct kwsysProcess_s /* ------------- Data managed per call to Execute ------------- */ - /* The exceptional behavior that terminated the process, if any. */ - int ExitException; - - /* The process exit code. */ - DWORD ExitCode; - - /* The process return code, if any. */ - int ExitValue; - /* Index of last pipe to report data, if any. */ int CurrentIndex; @@ -285,8 +298,8 @@ struct kwsysProcess_s /* Buffer for error messages. */ char ErrorMessage[KWSYSPE_PIPE_BUFFER_SIZE + 1]; - /* Description for the ExitException. */ - char ExitExceptionString[KWSYSPE_PIPE_BUFFER_SIZE + 1]; + /* process results. */ + kwsysProcessResults* ProcessResults; /* Windows process information data. */ PROCESS_INFORMATION* ProcessInformation; @@ -513,6 +526,7 @@ void kwsysProcess_Delete(kwsysProcess* cp) if (cp->CommandExitCodes) { free(cp->CommandExitCodes); } + free(cp->ProcessResults); free(cp); } @@ -839,17 +853,23 @@ int kwsysProcess_GetState(kwsysProcess* cp) int kwsysProcess_GetExitException(kwsysProcess* cp) { - return cp ? cp->ExitException : kwsysProcess_Exception_Other; + return (cp && cp->ProcessResults && (cp->NumberOfCommands > 0)) + ? cp->ProcessResults[cp->NumberOfCommands - 1].ExitException + : kwsysProcess_Exception_Other; } int kwsysProcess_GetExitValue(kwsysProcess* cp) { - return cp ? cp->ExitValue : -1; + return (cp && cp->ProcessResults && (cp->NumberOfCommands > 0)) + ? cp->ProcessResults[cp->NumberOfCommands - 1].ExitValue + : -1; } int kwsysProcess_GetExitCode(kwsysProcess* cp) { - return cp ? cp->ExitCode : 0; + return (cp && cp->ProcessResults && (cp->NumberOfCommands > 0)) + ? cp->ProcessResults[cp->NumberOfCommands - 1].ExitCode + : 0; } const char* kwsysProcess_GetErrorString(kwsysProcess* cp) @@ -864,14 +884,57 @@ const char* kwsysProcess_GetErrorString(kwsysProcess* cp) const char* kwsysProcess_GetExceptionString(kwsysProcess* cp) { - if (!cp) { + if (!(cp && cp->ProcessResults && (cp->NumberOfCommands > 0))) { return "GetExceptionString called with NULL process management structure"; } else if (cp->State == kwsysProcess_State_Exception) { - return cp->ExitExceptionString; + return cp->ProcessResults[cp->NumberOfCommands - 1].ExitExceptionString; } return "No exception"; } +/* the index should be in array bound. */ +#define KWSYSPE_IDX_CHK(RET) \ + if (!cp || idx >= cp->NumberOfCommands || idx < 0) { \ + KWSYSPE_DEBUG((stderr, "array index out of bound\n")); \ + return RET; \ + } + +int kwsysProcess_GetStateByIndex(kwsysProcess* cp, int idx) +{ + KWSYSPE_IDX_CHK(kwsysProcess_State_Error) + return cp->ProcessResults[idx].State; +} + +int kwsysProcess_GetExitExceptionByIndex(kwsysProcess* cp, int idx) +{ + KWSYSPE_IDX_CHK(kwsysProcess_Exception_Other) + return cp->ProcessResults[idx].ExitException; +} + +int kwsysProcess_GetExitValueByIndex(kwsysProcess* cp, int idx) +{ + KWSYSPE_IDX_CHK(-1) + return cp->ProcessResults[idx].ExitValue; +} + +int kwsysProcess_GetExitCodeByIndex(kwsysProcess* cp, int idx) +{ + KWSYSPE_IDX_CHK(-1) + return cp->CommandExitCodes[idx]; +} + +const char* kwsysProcess_GetExceptionStringByIndex(kwsysProcess* cp, int idx) +{ + KWSYSPE_IDX_CHK("GetExceptionString called with NULL process management " + "structure or index out of bound") + if (cp->ProcessResults[idx].State == kwsysProcess_StateByIndex_Exception) { + return cp->ProcessResults[idx].ExitExceptionString; + } + return "No exception"; +} + +#undef KWSYSPE_IDX_CHK + void kwsysProcess_Execute(kwsysProcess* cp) { int i; @@ -1312,19 +1375,24 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout) /* The timeout expired. */ cp->State = kwsysProcess_State_Expired; } else { - /* The children exited. Report the outcome of the last process. */ - cp->ExitCode = cp->CommandExitCodes[cp->NumberOfCommands - 1]; - if ((cp->ExitCode & 0xF0000000) == 0xC0000000) { - /* Child terminated due to exceptional behavior. */ - cp->State = kwsysProcess_State_Exception; - cp->ExitValue = 1; - kwsysProcessSetExitException(cp, cp->ExitCode); - } else { - /* Child exited without exception. */ - cp->State = kwsysProcess_State_Exited; - cp->ExitException = kwsysProcess_Exception_None; - cp->ExitValue = cp->ExitCode; + /* The children exited. Report the outcome of the child processes. */ + for (i = 0; i < cp->NumberOfCommands; ++i) { + cp->ProcessResults[i].ExitCode = cp->CommandExitCodes[i]; + if ((cp->ProcessResults[i].ExitCode & 0xF0000000) == 0xC0000000) { + /* Child terminated due to exceptional behavior. */ + cp->ProcessResults[i].State = kwsysProcess_StateByIndex_Exception; + cp->ProcessResults[i].ExitValue = 1; + kwsysProcessSetExitExceptionByIndex(cp, cp->ProcessResults[i].ExitCode, + i); + } else { + /* Child exited without exception. */ + cp->ProcessResults[i].State = kwsysProcess_StateByIndex_Exited; + cp->ProcessResults[i].ExitException = kwsysProcess_Exception_None; + cp->ProcessResults[i].ExitValue = cp->ProcessResults[i].ExitCode; + } } + /* support legacy state status value */ + cp->State = cp->ProcessResults[cp->NumberOfCommands - 1].State; } return 1; @@ -1507,19 +1575,31 @@ void kwsysProcessPipeThreadWakePipe(kwsysProcess* cp, kwsysProcessPipeData* td) /* Initialize a process control structure for kwsysProcess_Execute. */ int kwsysProcessInitialize(kwsysProcess* cp) { + int i; /* Reset internal status flags. */ 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; - strcpy(cp->ExitExceptionString, "No exception"); + free(cp->ProcessResults); + /* Allocate process result information for each process. */ + cp->ProcessResults = (kwsysProcessResults*)malloc( + sizeof(kwsysProcessResults) * (cp->NumberOfCommands)); + if (!cp->ProcessResults) { + return 0; + } + ZeroMemory(cp->ProcessResults, + sizeof(kwsysProcessResults) * cp->NumberOfCommands); + for (i = 0; i < cp->NumberOfCommands; i++) { + cp->ProcessResults[i].ExitException = kwsysProcess_Exception_None; + cp->ProcessResults[i].State = kwsysProcess_StateByIndex_Starting; + cp->ProcessResults[i].ExitCode = 1; + cp->ProcessResults[i].ExitValue = 1; + strcpy(cp->ProcessResults[i].ExitExceptionString, "No exception"); + } /* Allocate process information for each process. */ + free(cp->ProcessInformation); cp->ProcessInformation = (PROCESS_INFORMATION*)malloc( sizeof(PROCESS_INFORMATION) * cp->NumberOfCommands); if (!cp->ProcessInformation) { @@ -1559,7 +1639,6 @@ int kwsysProcessInitialize(kwsysProcess* cp) } } { - int i; for (i = 0; i < 3; ++i) { cp->PipeChildStd[i] = INVALID_HANDLE_VALUE; } @@ -1981,9 +2060,10 @@ kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1, } #define KWSYSPE_CASE(type, str) \ - cp->ExitException = kwsysProcess_Exception_##type; \ - strcpy(cp->ExitExceptionString, str) -static void kwsysProcessSetExitException(kwsysProcess* cp, int code) + cp->ProcessResults[idx].ExitException = kwsysProcess_Exception_##type; \ + strcpy(cp->ProcessResults[idx].ExitExceptionString, str) +static void kwsysProcessSetExitExceptionByIndex(kwsysProcess* cp, int code, + int idx) { switch (code) { case STATUS_CONTROL_C_EXIT: @@ -2062,9 +2142,9 @@ static void kwsysProcessSetExitException(kwsysProcess* cp, int code) case STATUS_NO_MEMORY: default: - cp->ExitException = kwsysProcess_Exception_Other; - _snprintf(cp->ExitExceptionString, KWSYSPE_PIPE_BUFFER_SIZE, - "Exit code 0x%x\n", code); + cp->ProcessResults[idx].ExitException = kwsysProcess_Exception_Other; + _snprintf(cp->ProcessResults[idx].ExitExceptionString, + KWSYSPE_PIPE_BUFFER_SIZE, "Exit code 0x%x\n", code); break; } }