summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2006-10-03 13:10:03 (GMT)
committerBrad King <brad.king@kitware.com>2006-10-03 13:10:03 (GMT)
commit6eef6638a5ca1c76b7d51e9d71bc5ef9c96875e0 (patch)
tree06047abad6d96cf164aaf9266257b5098cc9cc18
parent9d566ee8bd6e1c93aa083aac496e2335891cccec (diff)
downloadCMake-6eef6638a5ca1c76b7d51e9d71bc5ef9c96875e0.zip
CMake-6eef6638a5ca1c76b7d51e9d71bc5ef9c96875e0.tar.gz
CMake-6eef6638a5ca1c76b7d51e9d71bc5ef9c96875e0.tar.bz2
ENH: Added Process_SetPipeNative method to allow user code to override the pipes connected to the child pipeline.
-rw-r--r--Source/kwsys/Process.h.in32
-rw-r--r--Source/kwsys/ProcessUNIX.c110
-rw-r--r--Source/kwsys/ProcessWin32.c109
3 files changed, 247 insertions, 4 deletions
diff --git a/Source/kwsys/Process.h.in b/Source/kwsys/Process.h.in
index 3d2db7b..26ff75e 100644
--- a/Source/kwsys/Process.h.in
+++ b/Source/kwsys/Process.h.in
@@ -33,6 +33,7 @@
#define kwsysProcess_SetTimeout kwsys_ns(Process_SetTimeout)
#define kwsysProcess_SetWorkingDirectory kwsys_ns(Process_SetWorkingDirectory)
#define kwsysProcess_SetPipeFile kwsys_ns(Process_SetPipeFile)
+#define kwsysProcess_SetPipeNative kwsys_ns(Process_SetPipeNative)
#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)
@@ -71,6 +72,7 @@
#define kwsysProcess_Pipe_STDOUT kwsys_ns(Process_Pipe_STDOUT)
#define kwsysProcess_Pipe_STDERR kwsys_ns(Process_Pipe_STDERR)
#define kwsysProcess_Pipe_Timeout kwsys_ns(Process_Pipe_Timeout)
+#define kwsysProcess_Pipe_Handle kwsys_ns(Process_Pipe_Handle)
#define kwsysProcess_WaitForExit kwsys_ns(Process_WaitForExit)
#define kwsysProcess_Kill kwsys_ns(Process_Kill)
@@ -84,6 +86,13 @@ extern "C"
*/
typedef struct kwsysProcess_s kwsysProcess;
+/* Platform-specific pipe handle type. */
+#if defined(_WIN32) && !defined(__CYGWIN__)
+typedef void* kwsysProcess_Pipe_Handle;
+#else
+typedef int kwsysProcess_Pipe_Handle;
+#endif
+
/**
* Create a new Process instance.
*/
@@ -146,6 +155,27 @@ kwsysEXPORT void kwsysProcess_SetPipeShared(kwsysProcess* cp, int pipe,
int shared);
/**
+ * Specify a platform-specific native pipe for use as one of the child
+ * interface pipes. The native pipe is specified by an array of two
+ * descriptors or handles. The first entry in the array (index 0)
+ * should be the read end of the pipe. The second entry in the array
+ * (index 1) should be the write end of the pipe. If a null pointer
+ * is given the option will be disabled.
+ *
+ * For Pipe_STDIN the native pipe is connected to the first child in
+ * the pipeline as its stdin. After the children are created the
+ * write end of the pipe will be closed in the child process and the
+ * read end will be closed in the parent process.
+ *
+ * For Pipe_STDOUT and Pipe_STDERR the pipe is connected to the last
+ * child as its stdout or stderr. After the children are created the
+ * write end of the pipe will be closed in the parent process and the
+ * read end will be closed in the child process.
+ */
+kwsysEXPORT void kwsysProcess_SetPipeNative(kwsysProcess* cp, int pipe,
+ kwsysProcess_Pipe_Handle p[2]);
+
+/**
* Get/Set a possibly platform-specific option. Possible options are:
*
* kwsysProcess_Option_Detach = Whether to detach the process.
@@ -349,6 +379,7 @@ kwsysEXPORT void kwsysProcess_Kill(kwsysProcess* cp);
# undef kwsysProcess_SetTimeout
# undef kwsysProcess_SetWorkingDirectory
# undef kwsysProcess_SetPipeFile
+# undef kwsysProcess_SetPipeNative
# undef kwsysProcess_SetPipeShared
# undef kwsysProcess_Option_Detach
# undef kwsysProcess_Option_HideWindow
@@ -387,6 +418,7 @@ kwsysEXPORT void kwsysProcess_Kill(kwsysProcess* cp);
# undef kwsysProcess_Pipe_STDOUT
# undef kwsysProcess_Pipe_STDERR
# undef kwsysProcess_Pipe_Timeout
+# undef kwsysProcess_Pipe_Handle
# undef kwsysProcess_WaitForExit
# undef kwsysProcess_Kill
#endif
diff --git a/Source/kwsys/ProcessUNIX.c b/Source/kwsys/ProcessUNIX.c
index fadc5f6..e4b4219 100644
--- a/Source/kwsys/ProcessUNIX.c
+++ b/Source/kwsys/ProcessUNIX.c
@@ -102,6 +102,7 @@ static int kwsysProcessCreate(kwsysProcess* cp, int prIndex,
kwsysProcessCreateInformation* si, int* readEnd);
static void kwsysProcessDestroy(kwsysProcess* cp);
static int kwsysProcessSetupOutputPipeFile(int* p, const char* name);
+static int kwsysProcessSetupOutputPipeNative(int* p, int des[2]);
static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout,
kwsysProcessTime* timeoutTime);
static int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime,
@@ -217,6 +218,11 @@ struct kwsysProcess_s
int PipeSharedSTDOUT;
int PipeSharedSTDERR;
+ /* Native pipes provided by the user. */
+ int PipeNativeSTDIN[2];
+ int PipeNativeSTDOUT[2];
+ int PipeNativeSTDERR[2];
+
/* The real working directory of this process. */
int RealWorkingDirectoryLength;
char* RealWorkingDirectory;
@@ -470,9 +476,11 @@ int kwsysProcess_SetPipeFile(kwsysProcess* cp, int prPipe, const char* file)
strcpy(*pfile, file);
}
- /* If we are redirecting the pipe, do not share it. */
+ /* If we are redirecting the pipe, do not share it or use a native
+ pipe. */
if(*pfile)
{
+ kwsysProcess_SetPipeNative(cp, prPipe, 0);
kwsysProcess_SetPipeShared(cp, prPipe, 0);
}
return 1;
@@ -494,10 +502,51 @@ void kwsysProcess_SetPipeShared(kwsysProcess* cp, int prPipe, int shared)
default: return;
}
- /* If we are sharing the pipe, do not redirect it to a file. */
+ /* If we are sharing the pipe, do not redirect it to a file or use a
+ native pipe. */
if(shared)
{
kwsysProcess_SetPipeFile(cp, prPipe, 0);
+ kwsysProcess_SetPipeNative(cp, prPipe, 0);
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_SetPipeNative(kwsysProcess* cp, int prPipe, int p[2])
+{
+ int* pPipeNative = 0;
+
+ if(!cp)
+ {
+ return;
+ }
+
+ switch(prPipe)
+ {
+ case kwsysProcess_Pipe_STDIN: pPipeNative = cp->PipeNativeSTDIN; break;
+ case kwsysProcess_Pipe_STDOUT: pPipeNative = cp->PipeNativeSTDOUT; break;
+ case kwsysProcess_Pipe_STDERR: pPipeNative = cp->PipeNativeSTDERR; break;
+ default: return;
+ }
+
+ /* Copy the native pipe descriptors provided. */
+ if(p)
+ {
+ pPipeNative[0] = p[0];
+ pPipeNative[1] = p[1];
+ }
+ else
+ {
+ pPipeNative[0] = -1;
+ pPipeNative[1] = -1;
+ }
+
+ /* If we are using a native pipe, do not share it or redirect it to
+ a file. */
+ if(p)
+ {
+ kwsysProcess_SetPipeFile(cp, prPipe, 0);
+ kwsysProcess_SetPipeShared(cp, prPipe, 0);
}
}
@@ -684,6 +733,19 @@ void kwsysProcess_Execute(kwsysProcess* cp)
si.StdErr = 2;
}
+ /* Replace the stderr pipe with the native pipe provided if any. In
+ this case the select call will report that stderr is closed
+ immediately. */
+ if(cp->PipeNativeSTDERR[1] >= 0)
+ {
+ if(!kwsysProcessSetupOutputPipeNative(&si.StdErr, cp->PipeNativeSTDERR))
+ {
+ kwsysProcessCleanup(cp, 1);
+ kwsysProcessCleanupDescriptor(&si.StdErr);
+ return;
+ }
+ }
+
/* The timeout period starts now. */
cp->StartTime = kwsysProcessTimeGetCurrent();
cp->TimeoutTime.tv_sec = -1;
@@ -1297,6 +1359,19 @@ static int kwsysProcessCreate(kwsysProcess* cp, int prIndex,
{
si->StdIn = 0;
}
+ else if(cp->PipeNativeSTDIN[0] >= 0)
+ {
+ si->StdIn = cp->PipeNativeSTDIN[0];
+
+ /* Set close-on-exec flag on the pipe's ends. The read end will
+ be dup2-ed into the stdin descriptor after the fork but before
+ the exec. */
+ if((fcntl(cp->PipeNativeSTDIN[0], F_SETFD, FD_CLOEXEC) < 0) ||
+ (fcntl(cp->PipeNativeSTDIN[1], F_SETFD, FD_CLOEXEC) < 0))
+ {
+ return 0;
+ }
+ }
else
{
si->StdIn = -1;
@@ -1340,6 +1415,17 @@ static int kwsysProcessCreate(kwsysProcess* cp, int prIndex,
si->StdOut = 1;
}
+ /* Replace the stdout pipe with the native pipe provided if any. In
+ this case the select call will report that stdout is closed
+ immediately. */
+ if(prIndex == cp->NumberOfCommands-1 && cp->PipeNativeSTDOUT[1] >= 0)
+ {
+ if(!kwsysProcessSetupOutputPipeNative(&si->StdOut, cp->PipeNativeSTDOUT))
+ {
+ return 0;
+ }
+ }
+
/* Create the error reporting pipe. */
if(pipe(si->ErrorPipe) < 0)
{
@@ -1520,6 +1606,26 @@ static int kwsysProcessSetupOutputPipeFile(int* p, const char* name)
}
/*--------------------------------------------------------------------------*/
+static int kwsysProcessSetupOutputPipeNative(int* p, int des[2])
+{
+ /* Close the existing descriptor. */
+ kwsysProcessCleanupDescriptor(p);
+
+ /* Set close-on-exec flag on the pipe's ends. The proper end will
+ be dup2-ed into the standard descriptor number after fork but
+ before exec. */
+ if((fcntl(des[0], F_SETFD, FD_CLOEXEC) < 0) ||
+ (fcntl(des[1], F_SETFD, FD_CLOEXEC) < 0))
+ {
+ return 0;
+ }
+
+ /* Assign the replacement descriptor. */
+ *p = des[1];
+ 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,
diff --git a/Source/kwsys/ProcessWin32.c b/Source/kwsys/ProcessWin32.c
index 4f50d36..8f8aca6 100644
--- a/Source/kwsys/ProcessWin32.c
+++ b/Source/kwsys/ProcessWin32.c
@@ -105,6 +105,8 @@ static int kwsysProcessCreate(kwsysProcess* cp, int index,
static void kwsysProcessDestroy(kwsysProcess* cp, int event);
static int kwsysProcessSetupOutputPipeFile(PHANDLE handle, const char* name);
static int kwsysProcessSetupSharedPipe(DWORD nStdHandle, PHANDLE handle);
+static int kwsysProcessSetupPipeNative(PHANDLE handle, HANDLE p[2],
+ int isWrite);
static void kwsysProcessCleanupHandle(PHANDLE h);
static void kwsysProcessCleanupHandleSafe(PHANDLE h, DWORD nStdHandle);
static void kwsysProcessCleanup(kwsysProcess* cp, int error);
@@ -247,6 +249,11 @@ struct kwsysProcess_s
int PipeSharedSTDOUT;
int PipeSharedSTDERR;
+ /* Native pipes provided by the user. */
+ HANDLE PipeNativeSTDIN[2];
+ HANDLE PipeNativeSTDOUT[2];
+ HANDLE PipeNativeSTDERR[2];
+
/* Handle to automatically delete the Win9x forwarding executable. */
HANDLE Win9xHandle;
@@ -790,9 +797,11 @@ int kwsysProcess_SetPipeFile(kwsysProcess* cp, int pipe, const char* file)
strcpy(*pfile, file);
}
- /* If we are redirecting the pipe, do not share it. */
+ /* If we are redirecting the pipe, do not share it or use a native
+ pipe. */
if(*pfile)
{
+ kwsysProcess_SetPipeNative(cp, pipe, 0);
kwsysProcess_SetPipeShared(cp, pipe, 0);
}
@@ -815,10 +824,51 @@ void kwsysProcess_SetPipeShared(kwsysProcess* cp, int pipe, int shared)
default: return;
}
- /* If we are sharing the pipe, do not redirect it to a file. */
+ /* If we are sharing the pipe, do not redirect it to a file or use a
+ native pipe. */
if(shared)
{
kwsysProcess_SetPipeFile(cp, pipe, 0);
+ kwsysProcess_SetPipeNative(cp, pipe, 0);
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_SetPipeNative(kwsysProcess* cp, int pipe, HANDLE p[2])
+{
+ HANDLE* pPipeNative = 0;
+
+ if(!cp)
+ {
+ return;
+ }
+
+ switch(pipe)
+ {
+ case kwsysProcess_Pipe_STDIN: pPipeNative = cp->PipeNativeSTDIN; break;
+ case kwsysProcess_Pipe_STDOUT: pPipeNative = cp->PipeNativeSTDOUT; break;
+ case kwsysProcess_Pipe_STDERR: pPipeNative = cp->PipeNativeSTDERR; break;
+ default: return;
+ }
+
+ /* Copy the native pipe handles provided. */
+ if(p)
+ {
+ pPipeNative[0] = p[0];
+ pPipeNative[1] = p[1];
+ }
+ else
+ {
+ pPipeNative[0] = 0;
+ pPipeNative[1] = 0;
+ }
+
+ /* If we are using a native pipe, do not share it or redirect it to
+ a file. */
+ if(p)
+ {
+ kwsysProcess_SetPipeFile(cp, pipe, 0);
+ kwsysProcess_SetPipeShared(cp, pipe, 0);
}
}
@@ -1020,6 +1070,21 @@ void kwsysProcess_Execute(kwsysProcess* cp)
}
}
+ /* Replace the stderr pipe with the native pipe provided if any. In
+ this case the pipe thread will still run but never report
+ data. */
+ if(cp->PipeNativeSTDERR[1])
+ {
+ if(!kwsysProcessSetupPipeNative(&si.StartupInfo.hStdError,
+ cp->PipeNativeSTDERR, 1))
+ {
+ kwsysProcessCleanup(cp, 1);
+ kwsysProcessCleanupHandleSafe(&si.StartupInfo.hStdError,
+ STD_ERROR_HANDLE);
+ return;
+ }
+ }
+
/* Create the pipeline of processes. */
{
HANDLE readEnd = 0;
@@ -1622,6 +1687,15 @@ int kwsysProcessCreate(kwsysProcess* cp, int index,
return 0;
}
}
+ else if(cp->PipeNativeSTDIN[0])
+ {
+ /* Use the provided native pipe. */
+ if(!kwsysProcessSetupPipeNative(&si->StartupInfo.hStdInput,
+ cp->PipeNativeSTDIN, 0))
+ {
+ return 0;
+ }
+ }
else
{
/* Explicitly give the child no stdin. */
@@ -1680,6 +1754,18 @@ int kwsysProcessCreate(kwsysProcess* cp, int index,
}
}
+ /* Replace the stdout pipe with the native pipe provided if any. In
+ this case the pipe thread will still run but never report
+ data. */
+ if(index == cp->NumberOfCommands-1 && cp->PipeNativeSTDOUT[1])
+ {
+ if(!kwsysProcessSetupPipeNative(&si->StartupInfo.hStdOutput,
+ cp->PipeNativeSTDOUT, 1))
+ {
+ return 0;
+ }
+ }
+
/* Create the child process. */
{
BOOL r;
@@ -1929,6 +2015,25 @@ int kwsysProcessSetupSharedPipe(DWORD nStdHandle, PHANDLE handle)
}
/*--------------------------------------------------------------------------*/
+int kwsysProcessSetupPipeNative(PHANDLE handle, HANDLE p[2], int isWrite)
+{
+ /* Close the existing inherited handle. */
+ kwsysProcessCleanupHandle(handle);
+
+ /* Create an inherited duplicate of the handle. This also closes
+ the non-inherited version. */
+ if(!DuplicateHandle(GetCurrentProcess(), p[isWrite? 1:0],
+ GetCurrentProcess(), handle,
+ 0, TRUE, (DUPLICATE_CLOSE_SOURCE |
+ DUPLICATE_SAME_ACCESS)))
+ {
+ return 0;
+ }
+
+ return 1;
+}
+
+/*--------------------------------------------------------------------------*/
/* Close the given handle if it is open. Reset its value to 0. */
void kwsysProcessCleanupHandle(PHANDLE h)