summaryrefslogtreecommitdiffstats
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
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.
-rw-r--r--Source/kwsys/Process.h.in28
-rw-r--r--Source/kwsys/ProcessUNIX.c162
-rw-r--r--Source/kwsys/ProcessWin32.c7
3 files changed, 175 insertions, 22 deletions
diff --git a/Source/kwsys/Process.h.in b/Source/kwsys/Process.h.in
index 9f2485f..380d1b4 100644
--- a/Source/kwsys/Process.h.in
+++ b/Source/kwsys/Process.h.in
@@ -32,6 +32,7 @@
#define kwsysProcess_SetWorkingDirectory kwsys_ns(Process_SetWorkingDirectory)
#define kwsysProcess_SetPipeFile kwsys_ns(Process_SetPipeFile)
#define kwsysProcess_SetPipeShared kwsys_ns(Process_SetPipeShared)
+#define kwsysProcess_Option_Detach kwsys_ns(Process_Option_Detach)
#define kwsysProcess_Option_HideWindow kwsys_ns(Process_Option_HideWindow)
#define kwsysProcess_GetOption kwsys_ns(Process_GetOption)
#define kwsysProcess_SetOption kwsys_ns(Process_SetOption)
@@ -43,6 +44,7 @@
#define kwsysProcess_State_Exited kwsys_ns(Process_State_Exited)
#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)
@@ -58,6 +60,7 @@
#define kwsysProcess_GetErrorString kwsys_ns(Process_GetErrorString)
#define kwsysProcess_GetExceptionString kwsys_ns(Process_GetExceptionString)
#define kwsysProcess_Execute kwsys_ns(Process_Execute)
+#define kwsysProcess_Disown kwsys_ns(Process_Disown)
#define kwsysProcess_WaitForData kwsys_ns(Process_WaitForData)
#define kwsysProcess_Pipes_e kwsys_ns(Process_Pipes_e)
#define kwsysProcess_Pipe_None kwsys_ns(Process_Pipe_None)
@@ -140,7 +143,11 @@ kwsysEXPORT void kwsysProcess_SetPipeShared(kwsysProcess* cp, int pipe,
int shared);
/**
- * Get/Set a platform-specific option. Possible options are:
+ * Get/Set a possibly platform-specific option. Possible options are:
+ *
+ * kwsysProcess_Option_Detach = Whether to detach the process.
+ * 0 = No (default)
+ * 1 = Yes
*
* kwsysProcess_Option_HideWindow = Whether to hide window on Windows.
* 0 = No (default)
@@ -151,7 +158,8 @@ kwsysEXPORT void kwsysProcess_SetOption(kwsysProcess* cp, int optionId,
int value);
enum kwsysProcess_Option_e
{
- kwsysProcess_Option_HideWindow
+ kwsysProcess_Option_HideWindow,
+ kwsysProcess_Option_Detach
};
/**
@@ -164,6 +172,7 @@ enum kwsysProcess_Option_e
* kwsysProcess_State_Exited = Child process exited normally.
* kwsysProcess_State_Expired = Child process's timeout expired.
* kwsysProcess_State_Killed = Child process terminated by Kill method.
+ * kwsysProcess_State_Disowned = Child is no longer managed by this object.
*/
kwsysEXPORT int kwsysProcess_GetState(kwsysProcess* cp);
enum kwsysProcess_State_e
@@ -174,7 +183,8 @@ enum kwsysProcess_State_e
kwsysProcess_State_Executing,
kwsysProcess_State_Exited,
kwsysProcess_State_Expired,
- kwsysProcess_State_Killed
+ kwsysProcess_State_Killed,
+ kwsysProcess_State_Disowned
};
/**
@@ -237,6 +247,15 @@ kwsysEXPORT const char* kwsysProcess_GetExceptionString(kwsysProcess* cp);
kwsysEXPORT void kwsysProcess_Execute(kwsysProcess* cp);
/**
+ * Stop management of a detached child process. This closes any pipes
+ * being read. If the child was not created with the
+ * kwsysProcess_Option_Detach option, this method does nothing. This
+ * is because disowning a non-detached process will cause the child
+ * exit signal to be left unhandled until this process exits.
+ */
+kwsysEXPORT void kwsysProcess_Disown(kwsysProcess* cp);
+
+/**
* Block until data are available on a pipe, a timeout expires, or the
* child process terminates. Arguments are as follows:
*
@@ -318,6 +337,7 @@ kwsysEXPORT void kwsysProcess_Kill(kwsysProcess* cp);
# undef kwsysProcess_SetWorkingDirectory
# undef kwsysProcess_SetPipeFile
# undef kwsysProcess_SetPipeShared
+# undef kwsysProcess_Option_Detach
# undef kwsysProcess_Option_HideWindow
# undef kwsysProcess_GetOption
# undef kwsysProcess_SetOption
@@ -329,6 +349,7 @@ kwsysEXPORT void kwsysProcess_Kill(kwsysProcess* cp);
# undef kwsysProcess_State_Exited
# undef kwsysProcess_State_Expired
# undef kwsysProcess_State_Killed
+# undef kwsysProcess_State_Disowned
# undef kwsysProcess_GetState
# undef kwsysProcess_State_e
# undef kwsysProcess_Exception_None
@@ -344,6 +365,7 @@ kwsysEXPORT void kwsysProcess_Kill(kwsysProcess* cp);
# undef kwsysProcess_GetErrorString
# undef kwsysProcess_GetExceptionString
# undef kwsysProcess_Execute
+# undef kwsysProcess_Disown
# undef kwsysProcess_WaitForData
# undef kwsysProcess_Pipes_e
# undef kwsysProcess_Pipe_None
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;
diff --git a/Source/kwsys/ProcessWin32.c b/Source/kwsys/ProcessWin32.c
index 9e42e05..ad02951 100644
--- a/Source/kwsys/ProcessWin32.c
+++ b/Source/kwsys/ProcessWin32.c
@@ -1137,6 +1137,13 @@ void kwsysProcess_Execute(kwsysProcess* cp)
}
/*--------------------------------------------------------------------------*/
+void kwsysProcess_Disown(kwsysProcess* cp)
+{
+ /* TODO: Implement windows version. */
+ (void)cp;
+}
+
+/*--------------------------------------------------------------------------*/
int kwsysProcess_WaitForData(kwsysProcess* cp, char** data, int* length,
double* userTimeout)