ENH: Added Process_SetPipeNative method to allow user code to override the pipes connected to the child pipeline.
This commit is contained in:
parent
9d566ee8bd
commit
6eef6638a5
|
@ -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.
|
||||
*/
|
||||
|
@ -145,6 +154,27 @@ kwsysEXPORT int kwsysProcess_SetPipeFile(kwsysProcess* cp, int pipe,
|
|||
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:
|
||||
*
|
||||
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
@ -1519,6 +1605,26 @@ static int kwsysProcessSetupOutputPipeFile(int* p, const char* name)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
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. */
|
||||
|
|
|
@ -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;
|
||||
|
@ -1928,6 +2014,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. */
|
||||
|
|
Loading…
Reference in New Issue