summaryrefslogtreecommitdiffstats
path: root/Source/kwsys/ProcessUNIX.c
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2004-07-07 21:27:50 (GMT)
committerBrad King <brad.king@kitware.com>2004-07-07 21:27:50 (GMT)
commitae28d93a72850d5d48bc8e941af5e99c4f8f2202 (patch)
tree0c5b7a136f08acfdef6c16faa52f164ea848cbe0 /Source/kwsys/ProcessUNIX.c
parent52eff235d853a3eceadb17d886d797e91b1c6b57 (diff)
downloadCMake-ae28d93a72850d5d48bc8e941af5e99c4f8f2202.zip
CMake-ae28d93a72850d5d48bc8e941af5e99c4f8f2202.tar.gz
CMake-ae28d93a72850d5d48bc8e941af5e99c4f8f2202.tar.bz2
ENH: Added kwsysProcess_Disown an kwsysProcess_Option_Detach to allow detached processes to be created. Currently implemented only on UNIX.
Diffstat (limited to 'Source/kwsys/ProcessUNIX.c')
-rw-r--r--Source/kwsys/ProcessUNIX.c162
1 files changed, 143 insertions, 19 deletions
diff --git a/Source/kwsys/ProcessUNIX.c b/Source/kwsys/ProcessUNIX.c
index d24f515..c91afb2 100644
--- a/Source/kwsys/ProcessUNIX.c
+++ b/Source/kwsys/ProcessUNIX.c
@@ -99,6 +99,8 @@ static kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1, kwsysProc
static void kwsysProcessSetExitException(kwsysProcess* cp, int sig);
static void kwsysProcessChildErrorExit(int errorPipe);
static void kwsysProcessRestoreDefaultSignalHandlers(void);
+static pid_t kwsysProcessFork(kwsysProcess* cp,
+ kwsysProcessCreateInformation* si);
static void kwsysProcessKill(pid_t process_id);
/*--------------------------------------------------------------------------*/
@@ -127,6 +129,12 @@ struct kwsysProcess_s
/* The working directory for the process. */
char* WorkingDirectory;
+ /* Whether to create the child as a detached process. */
+ int OptionDetach;
+
+ /* Whether the child was created as a detached process. */
+ int Detached;
+
/* Time at which the child started. Negative for no timeout. */
kwsysProcessTime StartTime;
@@ -217,7 +225,14 @@ void kwsysProcess_Delete(kwsysProcess* cp)
/* If the process is executing, wait for it to finish. */
if(cp->State == kwsysProcess_State_Executing)
{
- kwsysProcess_WaitForExit(cp, 0);
+ if(cp->Detached)
+ {
+ kwsysProcess_Disown(cp);
+ }
+ else
+ {
+ kwsysProcess_WaitForExit(cp, 0);
+ }
}
/* Free memory. */
@@ -445,17 +460,31 @@ void kwsysProcess_SetPipeShared(kwsysProcess* cp, int pipe, int shared)
/*--------------------------------------------------------------------------*/
int kwsysProcess_GetOption(kwsysProcess* cp, int optionId)
{
- (void)cp;
- (void)optionId;
- return 0;
+ if(!cp)
+ {
+ return 0;
+ }
+
+ switch(optionId)
+ {
+ case kwsysProcess_Option_Detach: return cp->OptionDetach;
+ default: return 0;
+ }
}
/*--------------------------------------------------------------------------*/
void kwsysProcess_SetOption(kwsysProcess* cp, int optionId, int value)
{
- (void)cp;
- (void)optionId;
- (void)value;
+ if(!cp)
+ {
+ return;
+ }
+
+ switch(optionId)
+ {
+ case kwsysProcess_Option_Detach: cp->OptionDetach = value; break;
+ default: break;
+ }
}
/*--------------------------------------------------------------------------*/
@@ -673,6 +702,45 @@ void kwsysProcess_Execute(kwsysProcess* cp)
/* The process has now started. */
cp->State = kwsysProcess_State_Executing;
+ cp->Detached = cp->OptionDetach;
+}
+
+/*--------------------------------------------------------------------------*/
+kwsysEXPORT void kwsysProcess_Disown(kwsysProcess* cp)
+{
+ int i;
+
+ /* Make sure a detached child process is running. */
+ if(!cp || !cp->Detached || cp->State != kwsysProcess_State_Executing)
+ {
+ return;
+ }
+
+ /* Close any pipes that are still open. */
+ for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
+ {
+ if(cp->PipeReadEnds[i] >= 0)
+ {
+ /* If the pipe was reported by the last call to select, we must
+ read from it. Ignore the data. */
+ if(FD_ISSET(cp->PipeReadEnds[i], &cp->PipeSet))
+ {
+ /* We are handling this pipe now. Remove it from the set. */
+ FD_CLR(cp->PipeReadEnds[i], &cp->PipeSet);
+
+ /* The pipe is ready to read without blocking. Keep trying to
+ read until the operation is not interrupted. */
+ while((read(cp->PipeReadEnds[i], cp->PipeBuffer,
+ KWSYSPE_PIPE_BUFFER_SIZE) < 0) && (errno == EINTR));
+ }
+
+ /* We are done reading from this pipe. */
+ kwsysProcessCleanupDescriptor(&cp->PipeReadEnds[i]);
+ --cp->PipesLeft;
+ }
+ }
+
+ cp->State = kwsysProcess_State_Disowned;
}
/*--------------------------------------------------------------------------*/
@@ -901,21 +969,22 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout)
/* 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)
+ if(!cp->Detached)
{
- while(((result = waitpid(cp->ForkPIDs[i],
- &cp->CommandExitCodes[i], 0)) < 0) &&
- (errno == EINTR));
- if(result <= 0 && cp->State != kwsysProcess_State_Error)
+ int i;
+ for(i=0; i < cp->NumberOfCommands; ++i)
{
- /* Unexpected error. Report the first time this happens. */
- strncpy(cp->ErrorMessage, strerror(errno), KWSYSPE_PIPE_BUFFER_SIZE);
- cp->State = kwsysProcess_State_Error;
+ 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)
@@ -1225,7 +1294,7 @@ static int kwsysProcessCreate(kwsysProcess* cp, int index,
}
/* Fork off a child process. */
- cp->ForkPIDs[index] = fork();
+ cp->ForkPIDs[index] = kwsysProcessFork(cp, si);
if(cp->ForkPIDs[index] < 0)
{
return 0;
@@ -1720,6 +1789,61 @@ static void kwsysProcessRestoreDefaultSignalHandlers(void)
}
/*--------------------------------------------------------------------------*/
+static pid_t kwsysProcessFork(kwsysProcess* cp,
+ kwsysProcessCreateInformation* si)
+{
+ /* Create a detached process if requested. */
+ if(cp->OptionDetach)
+ {
+ /* Create an intermediate process. */
+ pid_t middle_pid = fork();
+ if(middle_pid < 0)
+ {
+ /* Fork failed. Return as if we were not detaching. */
+ return middle_pid;
+ }
+ else if(middle_pid == 0)
+ {
+ /* This is the intermediate process. Create the real child. */
+ pid_t child_pid = fork();
+ if(child_pid == 0)
+ {
+ /* This is the real child process. There is nothing to do here. */
+ return 0;
+ }
+ else
+ {
+ /* Use the error pipe to report the pid to the real parent. */
+ while((write(si->ErrorPipe[1], &child_pid, sizeof(child_pid)) < 0) &&
+ (errno == EINTR));
+
+ /* Exit without cleanup. The parent holds all resources. */
+ _exit(0);
+ }
+ }
+ else
+ {
+ /* This is the original parent process. The intermediate
+ process will use the error pipe to report the pid of the
+ detached child. */
+ pid_t child_pid;
+ int status;
+ while((read(si->ErrorPipe[0], &child_pid, sizeof(child_pid)) < 0) &&
+ (errno == EINTR));
+
+ /* Wait for the intermediate process to exit and clean it up. */
+ while((waitpid(middle_pid, &status, 0) < 0) && (errno == EINTR));
+ return child_pid;
+ }
+ }
+ else
+ {
+ /* Not creating a detached process. Use normal fork. */
+ return fork();
+ }
+}
+
+/*--------------------------------------------------------------------------*/
static void kwsysProcessKill(pid_t process_id)
{
DIR* procdir;