Skip to content
Snippets Groups Projects
Commit 7d56ef24 authored by Adam Weisi's avatar Adam Weisi Committed by Brad King
Browse files

Process: Save results from all children internally

parent 8a799e36
No related branches found
No related tags found
No related merge requests found
......@@ -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;
}
}
......
......@@ -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;
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment