diff options
author | Brad King <brad.king@kitware.com> | 2003-12-03 14:20:05 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2003-12-03 14:20:05 (GMT) |
commit | ad8bc4b1a43dd017d361f189ec2b38d97e7de987 (patch) | |
tree | 5133b13c81008845db91c734e9872b66767d7c29 /Source/kwsys/ProcessUNIX.c | |
parent | be15d66e37d000993833a1e5a614ec969c86f7c8 (diff) | |
download | CMake-ad8bc4b1a43dd017d361f189ec2b38d97e7de987.zip CMake-ad8bc4b1a43dd017d361f189ec2b38d97e7de987.tar.gz CMake-ad8bc4b1a43dd017d361f189ec2b38d97e7de987.tar.bz2 |
ENH: Merged changes from KWSys-MultiProcess-bp to KWSys-MultiProcess-b2t-1-mp to main tree. This introduces support for process pipelines.
Diffstat (limited to 'Source/kwsys/ProcessUNIX.c')
-rw-r--r-- | Source/kwsys/ProcessUNIX.c | 543 |
1 files changed, 415 insertions, 128 deletions
diff --git a/Source/kwsys/ProcessUNIX.c b/Source/kwsys/ProcessUNIX.c index b1c40ab..c5bae27 100644 --- a/Source/kwsys/ProcessUNIX.c +++ b/Source/kwsys/ProcessUNIX.c @@ -33,6 +33,17 @@ conjunction with the timeout on the select call to implement a timeout for program even when it closes stdout and stderr. */ +/* + +TODO: + +We cannot create the pipeline of processes in suspended states. How +do we cleanup processes already started when one fails to load? Right +now we are just killing them, which is probably not the right thing to +do. + +*/ + #include <stdio.h> /* snprintf */ #include <stdlib.h> /* malloc, free */ #include <string.h> /* strdup, strerror, memset */ @@ -46,23 +57,35 @@ timeout for program even when it closes stdout and stderr. #include <signal.h> /* sigaction */ /* The number of pipes for the child's output. The standard stdout - and stderr pipes are the first two. One more pipe is used for the - child to report errors to the parent before the real process is - invoked. */ + and stderr pipes are the first two. One more pipe is used to + detect when the child process has terminated. The third pipe is + not given to the child process, so it cannot close it until it + terminates. */ #define KWSYSPE_PIPE_COUNT 3 #define KWSYSPE_PIPE_STDOUT 0 #define KWSYSPE_PIPE_STDERR 1 -#define KWSYSPE_PIPE_ERROR 2 +#define KWSYSPE_PIPE_TERM 2 /* The maximum amount to read from a pipe at a time. */ #define KWSYSPE_PIPE_BUFFER_SIZE 1024 typedef struct timeval kwsysProcessTime; +typedef struct kwsysProcessCreateInformation_s +{ + int stdin; + int stdout; + int stderr; + int term; + int error[2]; +} kwsysProcessCreateInformation; + /*--------------------------------------------------------------------------*/ -static void kwsysProcessInitialize(kwsysProcess* cp); +static int kwsysProcessInitialize(kwsysProcess* cp); static void kwsysProcessCleanup(kwsysProcess* cp, int error); static void kwsysProcessCleanupDescriptor(int* pfd); +static int kwsysProcessCreate(kwsysProcess* cp, int index, + kwsysProcessCreateInformation* si, int* readEnd); static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout, kwsysProcessTime* timeoutTime); static int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime, @@ -73,30 +96,28 @@ static kwsysProcessTime kwsysProcessTimeFromDouble(double d); static int kwsysProcessTimeLess(kwsysProcessTime in1, kwsysProcessTime in2); static kwsysProcessTime kwsysProcessTimeAdd(kwsysProcessTime in1, kwsysProcessTime in2); static kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1, kwsysProcessTime in2); -static void kwsysProcessChildErrorExit(kwsysProcess* cp); +static void kwsysProcessChildErrorExit(int errorPipe); static void kwsysProcessRestoreDefaultSignalHandlers(); /*--------------------------------------------------------------------------*/ /* Structure containing data used to implement the child's execution. */ struct kwsysProcess_s { - /* The command line to execute. */ - char** Command; + /* The command lines to execute. */ + char*** Commands; + int NumberOfCommands; /* Descriptors for the read ends of the child's output pipes. */ int PipeReadEnds[KWSYSPE_PIPE_COUNT]; - /* Descriptors for the write ends of the child's output pipes. */ - int PipeWriteEnds[KWSYSPE_PIPE_COUNT]; - /* Buffer for pipe data. */ char PipeBuffer[KWSYSPE_PIPE_BUFFER_SIZE]; - /* Process ID returned by the fork. */ - pid_t ForkPID; + /* Process IDs returned by the calls to fork. */ + pid_t* ForkPIDs; - /* Flag for whether the child reported an error. */ - int ChildError; + /* Flag for whether the children were terminated by a faild select. */ + int SelectError; /* The timeout length. */ double Timeout; @@ -140,7 +161,9 @@ struct kwsysProcess_s /* Buffer for error message in case of failure. */ char ErrorMessage[KWSYSPE_PIPE_BUFFER_SIZE+1]; - int ErrorMessageLength; + + /* The exit codes of each child process in the pipeline. */ + int* CommandExitCodes; }; /*--------------------------------------------------------------------------*/ @@ -169,36 +192,109 @@ void kwsysProcess_Delete(kwsysProcess* cp) /* Free memory. */ kwsysProcess_SetCommand(cp, 0); kwsysProcess_SetWorkingDirectory(cp, 0); + if(cp->CommandExitCodes) + { + free(cp->CommandExitCodes); + } free(cp); } /*--------------------------------------------------------------------------*/ -void kwsysProcess_SetCommand(kwsysProcess* cp, char const* const* command) +int kwsysProcess_SetCommand(kwsysProcess* cp, char const* const* command) { - if(cp->Command) + int i; + for(i=0; i < cp->NumberOfCommands; ++i) { - char** c = cp->Command; + char** c = cp->Commands[i]; while(*c) { free(*c++); } - free(cp->Command); - cp->Command = 0; + free(cp->Commands[i]); + } + cp->NumberOfCommands = 0; + if(cp->Commands) + { + free(cp->Commands); + cp->Commands = 0; } if(command) { - char const* const* c = command; - int n = 0; - int i = 0; - while(*c++); - n = c - command - 1; - cp->Command = (char**)malloc((n+1)*sizeof(char*)); - for(i=0; i < n; ++i) + return kwsysProcess_AddCommand(cp, command); + } + return 1; +} + +/*--------------------------------------------------------------------------*/ +int kwsysProcess_AddCommand(kwsysProcess* cp, char const* const* command) +{ + int newNumberOfCommands; + char*** newCommands; + + /* Make sure we have a command to add. */ + if(!command) + { + return 0; + } + + /* Allocate a new array for command pointers. */ + newNumberOfCommands = cp->NumberOfCommands + 1; + if(!(newCommands = (char***)malloc(sizeof(char**) * newNumberOfCommands))) + { + /* Out of memory. */ + return 0; + } + + /* Copy any existing commands into the new array. */ + { + int i; + for(i=0; i < cp->NumberOfCommands; ++i) + { + newCommands[i] = cp->Commands[i]; + } + } + + /* Add the new command. */ + { + char const* const* c = command; + int n = 0; + int i = 0; + while(*c++); + n = c - command - 1; + newCommands[cp->NumberOfCommands] = (char**)malloc((n+1)*sizeof(char*)); + if(!newCommands[cp->NumberOfCommands]) + { + /* Out of memory. */ + free(newCommands); + return 0; + } + for(i=0; i < n; ++i) + { + newCommands[cp->NumberOfCommands][i] = strdup(command[i]); + if(!newCommands[cp->NumberOfCommands][i]) + { + break; + } + } + if(i < n) + { + /* Out of memory. */ + for(;i > 0; --i) { - cp->Command[i] = strdup(command[i]); + free(newCommands[cp->NumberOfCommands][i-1]); } - cp->Command[n] = 0; + free(newCommands); + return 0; } + newCommands[cp->NumberOfCommands][n] = 0; + } + + /* Successfully allocated new command array. Free the old array. */ + free(cp->Commands); + cp->Commands = newCommands; + cp->NumberOfCommands = newNumberOfCommands; + + return 1; } /*--------------------------------------------------------------------------*/ @@ -289,6 +385,7 @@ void kwsysProcess_Execute(kwsysProcess* cp) { int i; struct sigaction newSigChldAction; + kwsysProcessCreateInformation si = {-1, -1, -1, -1, {-1, -1}}; /* Do not execute a second copy simultaneously. */ if(cp->State == kwsysProcess_State_Executing) @@ -297,7 +394,12 @@ void kwsysProcess_Execute(kwsysProcess* cp) } /* Initialize the control structure for a new process. */ - kwsysProcessInitialize(cp); + if(!kwsysProcessInitialize(cp)) + { + strcpy(cp->ErrorMessage, "Out of memory"); + cp->State = kwsysProcess_State_Error; + return; + } /* We want no special handling of SIGCHLD. Repeat call until it is not interrupted. */ @@ -306,29 +408,37 @@ void kwsysProcess_Execute(kwsysProcess* cp) while((sigaction(SIGCHLD, &newSigChldAction, &cp->OldSigChldAction) < 0) && (errno == EINTR)); - /* Create pipes for subprocess output. */ - for(i=0; i < KWSYSPE_PIPE_COUNT; ++i) + /* Setup the stderr and termination pipes to be shared by all processes. */ + for(i=KWSYSPE_PIPE_STDERR; i < KWSYSPE_PIPE_COUNT; ++i) { - int p[2]; - /* Create the pipe. */ + int p[2]; if(pipe(p) < 0) { kwsysProcessCleanup(cp, 1); return; } + /* Store the pipe. */ + cp->PipeReadEnds[i] = p[0]; + if(i == KWSYSPE_PIPE_STDERR) + { + si.stderr = p[1]; + } + else + { + si.term = p[1]; + } + /* Set close-on-exec flag on the pipe's ends. */ if((fcntl(p[0], F_SETFD, FD_CLOEXEC) < 0) || (fcntl(p[1], F_SETFD, FD_CLOEXEC) < 0)) { kwsysProcessCleanup(cp, 1); + kwsysProcessCleanupDescriptor(&si.stderr); + kwsysProcessCleanupDescriptor(&si.term); return; } - - /* Store the pipe. */ - cp->PipeReadEnds[i] = p[0]; - cp->PipeWriteEnds[i] = p[1]; } /* The timeout period starts now. */ @@ -336,62 +446,37 @@ void kwsysProcess_Execute(kwsysProcess* cp) cp->TimeoutTime.tv_sec = -1; cp->TimeoutTime.tv_usec = -1; - /* Fork off a child process. */ - cp->ForkPID = fork(); - if(cp->ForkPID < 0) - { - kwsysProcessCleanup(cp, 1); - return; - } - - /* If this is the child process, run the real process. */ - if(cp->ForkPID == 0) + /* Create the pipeline of processes. */ + { + int readEnd = 0; + for(i=0; i < cp->NumberOfCommands; ++i) { - /* We used to close stdin, but some programs do not like being run - without stdin. Just use whatever stdin the parent program is - using. */ - /*close(0);*/ - - /* Setup the stdout/stderr pipes. */ - dup2(cp->PipeWriteEnds[KWSYSPE_PIPE_STDOUT], 1); - dup2(cp->PipeWriteEnds[KWSYSPE_PIPE_STDERR], 2); - - /* Clear the close-on-exec flag for stdout, stderr, and the child - error report pipe. All other pipe handles will be closed when - exec succeeds. */ - fcntl(1, F_SETFD, 0); - fcntl(2, F_SETFD, 0); - fcntl(cp->PipeWriteEnds[KWSYSPE_PIPE_ERROR], F_SETFD, 0); - - /* Restore all default signal handlers. */ - kwsysProcessRestoreDefaultSignalHandlers(); - - /* Change to the working directory specified, if any. */ - if(cp->WorkingDirectory) + if(!kwsysProcessCreate(cp, i, &si, &readEnd)) { - /* Some platforms specify that the chdir call may be - interrupted. Repeat the call until it finishes. */ - int r; - while(((r = chdir(cp->WorkingDirectory)) < 0) && (errno == EINTR)); - if(r < 0) + kwsysProcessCleanup(cp, 1); + + /* Release resources that may have been allocated for this + process before an error occurred. */ + kwsysProcessCleanupDescriptor(&readEnd); + if(i > 0) { - /* Failure. Report error to parent and terminate. */ - kwsysProcessChildErrorExit(cp); + kwsysProcessCleanupDescriptor(&si.stdin); } + kwsysProcessCleanupDescriptor(&si.stdout); + kwsysProcessCleanupDescriptor(&si.stderr); + kwsysProcessCleanupDescriptor(&si.term); + kwsysProcessCleanupDescriptor(&si.error[0]); + kwsysProcessCleanupDescriptor(&si.error[1]); + return; } - - /* Execute the real process. If successful, this does not return. */ - execvp(cp->Command[0], cp->Command); - - /* Failure. Report error to parent and terminate. */ - kwsysProcessChildErrorExit(cp); } + /* Save a handle to the output pipe for the last process. */ + cp->PipeReadEnds[KWSYSPE_PIPE_STDOUT] = readEnd; + } - /* The parent process does not need the pipe write ends. */ - for(i=0; i < KWSYSPE_PIPE_COUNT; ++i) - { - kwsysProcessCleanupDescriptor(&cp->PipeWriteEnds[i]); - } + /* The parent process does not need the output pipe write ends. */ + kwsysProcessCleanupDescriptor(&si.stderr); + kwsysProcessCleanupDescriptor(&si.term); /* All the pipes are now open. */ cp->PipesLeft = KWSYSPE_PIPE_COUNT; @@ -401,8 +486,8 @@ void kwsysProcess_Execute(kwsysProcess* cp) } /*--------------------------------------------------------------------------*/ -int kwsysProcess_WaitForData(kwsysProcess* cp, int pipes, char** data, int* length, - double* userTimeout) +int kwsysProcess_WaitForData(kwsysProcess* cp, int pipes, char** data, + int* length, double* userTimeout) { int i; int max = -1; @@ -448,22 +533,9 @@ int kwsysProcess_WaitForData(kwsysProcess* cp, int pipes, char** data, int* leng if(n > 0) { /* We have data on this pipe. */ - if(i == KWSYSPE_PIPE_ERROR) + if(i == KWSYSPE_PIPE_TERM) { - /* This is data on the special error reporting pipe. The - child process failed to execute the program. */ - cp->ChildError = 1; - if(n > KWSYSPE_PIPE_BUFFER_SIZE - cp->ErrorMessageLength) - { - n = KWSYSPE_PIPE_BUFFER_SIZE - cp->ErrorMessageLength; - } - if(n > 0) - { - memcpy(cp->ErrorMessage+cp->ErrorMessageLength, - cp->PipeBuffer, n); - cp->ErrorMessageLength += n; - cp->ErrorMessage[cp->ErrorMessageLength] = 0; - } + /* This is data on the special termination pipe. Ignore it. */ } else if(pipes & (1 << i)) { @@ -548,10 +620,10 @@ int kwsysProcess_WaitForData(kwsysProcess* cp, int pipes, char** data, int* leng pipe buffer. */ strncpy(cp->ErrorMessage, strerror(errno), KWSYSPE_PIPE_BUFFER_SIZE); - /* Kill the child now. */ + /* Kill the children now. */ kwsysProcess_Kill(cp); cp->Killed = 0; - cp->ChildError = 1; + cp->SelectError = 1; cp->PipesLeft = 0; } } @@ -586,7 +658,7 @@ int kwsysProcess_WaitForData(kwsysProcess* cp, int pipes, char** data, int* leng } else { - /* The process timeout has expired. Kill the child now. */ + /* The process timeout has expired. Kill the children now. */ kwsysProcess_Kill(cp); cp->Killed = 0; cp->TimeoutExpired = 1; @@ -623,19 +695,36 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout) } } - /* Wait for the child to terminate. The process should have already - exited because KWSYSPE_PIPE_ERROR has been closed by this point. - Repeat the call until it is not interrupted. */ - while(((result = waitpid(cp->ForkPID, &status, 0)) < 0) && (errno == EINTR)); - if(result <= 0) + /* Wait for each child to terminate. The process should have + already exited because KWSYSPE_PIPE_TERM has been closed by this + point. Repeat the call until it is not interrupted. */ + { + int i; + for(i=0; i < cp->NumberOfCommands; ++i) { - /* Unexpected error. */ - kwsysProcessCleanup(cp, 1); + while(((result = waitpid(cp->ForkPIDs[i], + &cp->CommandExitCodes[i], 0)) < 0) && + (errno == EINTR)); + if(result <= 0 && cp->State != kwsysProcess_State_Error) + { + /* Unexpected error. Report the first time this happens. */ + strncpy(cp->ErrorMessage, strerror(errno), KWSYSPE_PIPE_BUFFER_SIZE); + cp->State = kwsysProcess_State_Error; + } + } + } + + /* Check if there was an error in one of the waitpid calls. */ + if(cp->State == kwsysProcess_State_Error) + { + /* The error message is already in its buffer. Tell + kwsysProcessCleanup to not create it. */ + kwsysProcessCleanup(cp, 0); return 1; } /* Check whether the child reported an error invoking the process. */ - if(cp->ChildError) + if(cp->SelectError) { /* The error message is already in its buffer. Tell kwsysProcessCleanup to not create it. */ @@ -644,6 +733,9 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout) return 1; } + /* Use the status of the last process in the pipeline. */ + status = cp->CommandExitCodes[cp->NumberOfCommands-1]; + /* Determine the outcome. */ if(cp->Killed) { @@ -703,29 +795,35 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout) /*--------------------------------------------------------------------------*/ void kwsysProcess_Kill(kwsysProcess* cp) { + int i; + /* Make sure we are executing a process. */ if(cp->State != kwsysProcess_State_Executing) { return; } - /* Kill the child. */ + /* Kill the children. */ cp->Killed = 1; - kill(cp->ForkPID, SIGKILL); + for(i=0; i < cp->NumberOfCommands; ++i) + { + if(cp->ForkPIDs[i]) + { + kill(cp->ForkPIDs[i], SIGKILL); + } + } } /*--------------------------------------------------------------------------*/ /* Initialize a process control structure for kwsysProcess_Execute. */ -static void kwsysProcessInitialize(kwsysProcess* cp) +static int kwsysProcessInitialize(kwsysProcess* cp) { int i; for(i=0; i < KWSYSPE_PIPE_COUNT; ++i) { cp->PipeReadEnds[i] = -1; - cp->PipeWriteEnds[i] = -1; } - cp->ForkPID = -1; - cp->ChildError = 0; + cp->SelectError = 0; cp->StartTime.tv_sec = -1; cp->StartTime.tv_usec = -1; cp->TimeoutTime.tv_sec = -1; @@ -739,7 +837,30 @@ static void kwsysProcessInitialize(kwsysProcess* cp) cp->ExitCode = 1; cp->ExitValue = 1; cp->ErrorMessage[0] = 0; - cp->ErrorMessageLength = 0; + + if(cp->ForkPIDs) + { + free(cp->ForkPIDs); + } + cp->ForkPIDs = (pid_t*)malloc(sizeof(pid_t)*cp->NumberOfCommands); + if(!cp->ForkPIDs) + { + return 0; + } + memset(cp->ForkPIDs, 0, sizeof(pid_t)*cp->NumberOfCommands); + + if(cp->CommandExitCodes) + { + free(cp->CommandExitCodes); + } + cp->CommandExitCodes = (int*)malloc(sizeof(int)*cp->NumberOfCommands); + if(!cp->CommandExitCodes) + { + return 0; + } + memset(cp->CommandExitCodes, 0, sizeof(int)*cp->NumberOfCommands); + + return 1; } /*--------------------------------------------------------------------------*/ @@ -749,22 +870,46 @@ static void kwsysProcessCleanup(kwsysProcess* cp, int error) { int i; - /* If cleaning up due to an error, report the error message. */ if(error) { - strncpy(cp->ErrorMessage, strerror(errno), KWSYSPE_PIPE_BUFFER_SIZE); + /* We are cleaning up due to an error. Report the error message + if one has not been provided already. */ + if(cp->ErrorMessage[0] == 0) + { + strncpy(cp->ErrorMessage, strerror(errno), KWSYSPE_PIPE_BUFFER_SIZE); + } + + /* Set the error state. */ cp->State = kwsysProcess_State_Error; + + /* Kill any children already started. */ + if(cp->ForkPIDs) + { + for(i=0; i < cp->NumberOfCommands; ++i) + { + if(cp->ForkPIDs[i]) + { + kill(cp->ForkPIDs[i], SIGKILL); + } + } + } } /* Restore the SIGCHLD handler. */ while((sigaction(SIGCHLD, &cp->OldSigChldAction, 0) < 0) && (errno == EINTR)); + /* Free memory. */ + if(cp->ForkPIDs) + { + free(cp->ForkPIDs); + cp->ForkPIDs = 0; + } + /* Close pipe handles. */ for(i=0; i < KWSYSPE_PIPE_COUNT; ++i) { kwsysProcessCleanupDescriptor(&cp->PipeReadEnds[i]); - kwsysProcessCleanupDescriptor(&cp->PipeWriteEnds[i]); } } @@ -782,6 +927,148 @@ static void kwsysProcessCleanupDescriptor(int* pfd) } /*--------------------------------------------------------------------------*/ +int kwsysProcessCreate(kwsysProcess* cp, int index, + kwsysProcessCreateInformation* si, int* readEnd) +{ + /* Setup the process's stdin. */ + if(index > 0) + { + si->stdin = *readEnd; + *readEnd = 0; + } + else + { + si->stdin = 0; + } + + /* Setup the process's stdout. */ + { + /* Create the pipe. */ + int p[2]; + if(pipe(p) < 0) + { + return 0; + } + *readEnd = p[0]; + si->stdout = p[1]; + + /* Set close-on-exec flag on the pipe's ends. */ + if((fcntl(p[0], F_SETFD, FD_CLOEXEC) < 0) || + (fcntl(p[1], F_SETFD, FD_CLOEXEC) < 0)) + { + return 0; + } + } + + /* Create the error reporting pipe. */ + if(pipe(si->error) < 0) + { + return 0; + } + + /* Set close-on-exec flag on the error pipe's write end. */ + if(fcntl(si->error[1], F_SETFD, FD_CLOEXEC) < 0) + { + return 0; + } + + /* Fork off a child process. */ + cp->ForkPIDs[index] = fork(); + if(cp->ForkPIDs[index] < 0) + { + return 0; + } + + if(cp->ForkPIDs[index] == 0) + { + /* Close the read end of the error reporting pipe. */ + close(si->error[0]); + + /* Setup the stdin, stdout, and stderr pipes. */ + if(index > 0) + { + dup2(si->stdin, 0); + } + dup2(si->stdout, 1); + dup2(si->stderr, 2); + + /* Clear the close-on-exec flag for stdin, stdout, and stderr. + Also clear it for the termination pipe. All other pipe handles + will be closed when exec succeeds. */ + fcntl(0, F_SETFD, 0); + fcntl(1, F_SETFD, 0); + fcntl(2, F_SETFD, 0); + fcntl(si->term, F_SETFD, 0); + + /* Restore all default signal handlers. */ + kwsysProcessRestoreDefaultSignalHandlers(); + + /* Change to the working directory specified, if any. */ + if(cp->WorkingDirectory) + { + /* Some platforms specify that the chdir call may be + interrupted. Repeat the call until it finishes. */ + int r; + while(((r = chdir(cp->WorkingDirectory)) < 0) && (errno == EINTR)); + if(r < 0) + { + /* Failure. Report error to parent and terminate. */ + kwsysProcessChildErrorExit(si->error[1]); + } + } + + /* Execute the real process. If successful, this does not return. */ + execvp(cp->Commands[index][0], cp->Commands[index]); + + /* Failure. Report error to parent and terminate. */ + kwsysProcessChildErrorExit(si->error[1]); + } + + /* We are done with the error reporting pipe write end. */ + kwsysProcessCleanupDescriptor(&si->error[1]); + + /* Block until the child's exec call succeeds and closes the error + pipe or writes data to the pipe to report an error. */ + { + int total = 0; + int n = 1; + /* Read the entire error message up to the length of our buffer. */ + while(total < KWSYSPE_PIPE_BUFFER_SIZE && n > 0) + { + /* Keep trying to read until the operation is not interrupted. */ + while(((n = read(si->error[0], cp->ErrorMessage+total, + KWSYSPE_PIPE_BUFFER_SIZE-total)) < 0) && + (errno == EINTR)); + if(n > 0) + { + total += n; + } + } + + /* We are done with the error reporting pipe read end. */ + kwsysProcessCleanupDescriptor(&si->error[0]); + + if(total > 0) + { + /* The child failed to execute the process. */ + return 0; + } + } + + /* Successfully created this child process. */ + if(index > 0) + { + /* The parent process does not need the input pipe read end. */ + kwsysProcessCleanupDescriptor(&si->stdin); + } + + /* The parent process does not need the output pipe write ends. */ + kwsysProcessCleanupDescriptor(&si->stdout); + + return 1; +} + +/*--------------------------------------------------------------------------*/ /* Get the time at which either the process or user timeout will expire. Returns 1 if the user timeout is first, and 0 otherwise. */ static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout, @@ -905,14 +1192,14 @@ static kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1, kwsysProc /* When the child process encounters an error before its program is invoked, this is called to report the error to the parent and exit. */ -static void kwsysProcessChildErrorExit(kwsysProcess* cp) +static void kwsysProcessChildErrorExit(int errorPipe) { /* Construct the error message. */ char buffer[KWSYSPE_PIPE_BUFFER_SIZE]; strncpy(buffer, strerror(errno), KWSYSPE_PIPE_BUFFER_SIZE); /* Report the error to the parent through the special pipe. */ - write(cp->PipeWriteEnds[KWSYSPE_PIPE_ERROR], buffer, strlen(buffer)); + write(errorPipe, buffer, strlen(buffer)); /* Terminate without cleanup. */ _exit(1); |