diff --git a/ProcessUNIX.c b/ProcessUNIX.c index 1de81c7beebd426973f4cb0aee0434678b8786a1..8bcb671219d1444633c56d3db56ae55ea5f267db 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,10 +695,10 @@ 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"; } @@ -1263,7 +1281,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 +1311,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 +1318,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_State_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_State_Error; + } + } + /* support legacy state status value */ + cp->State = cp->ProcessResults[cp->NumberOfCommands - 1].State; } - /* Normal cleanup. */ kwsysProcessCleanup(cp, 0); return 1; @@ -1445,11 +1466,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 +1492,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_State_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 +2042,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 +2231,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..a9f68b35b71321311a53d7f37462c05101244e09 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,10 +884,10 @@ 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"; } @@ -1312,19 +1332,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_State_Exception; + cp->ProcessResults[i].ExitValue = 1; + kwsysProcessSetExitExceptionByIndex(cp, cp->ProcessResults[i].ExitCode, + i); + } else { + /* Child exited without exception. */ + cp->ProcessResults[i].State = kwsysProcess_State_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 +1532,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_State_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 +1596,6 @@ int kwsysProcessInitialize(kwsysProcess* cp) } } { - int i; for (i = 0; i < 3; ++i) { cp->PipeChildStd[i] = INVALID_HANDLE_VALUE; } @@ -1981,9 +2017,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 +2099,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; } }