KWSys 2015-05-05 (8c8b2273)
Extract upstream KWSys using the following shell commands. $ git archive --prefix=upstream-kwsys/ 8c8b2273 | tar x $ git shortlog --no-merges --abbrev=8 --format='%h %s' c2387a4b..8c8b2273 Brad King (1): 8c8b2273 Process: Refactor child pipe creation
This commit is contained in:
parent
0c34ac2f01
commit
71f38d060b
363
ProcessUNIX.c
363
ProcessUNIX.c
|
@ -157,7 +157,7 @@ static void kwsysProcessCleanupDescriptor(int* pfd);
|
|||
static void kwsysProcessClosePipes(kwsysProcess* cp);
|
||||
static int kwsysProcessSetNonBlocking(int fd);
|
||||
static int kwsysProcessCreate(kwsysProcess* cp, int prIndex,
|
||||
kwsysProcessCreateInformation* si, int* readEnd);
|
||||
kwsysProcessCreateInformation* si);
|
||||
static void kwsysProcessDestroy(kwsysProcess* cp);
|
||||
static int kwsysProcessSetupOutputPipeFile(int* p, const char* name);
|
||||
static int kwsysProcessSetupOutputPipeNative(int* p, int des[2]);
|
||||
|
@ -203,6 +203,10 @@ struct kwsysProcess_s
|
|||
the signal pipe. */
|
||||
int PipeReadEnds[KWSYSPE_PIPE_COUNT];
|
||||
|
||||
/* Descriptors for the child's ends of the pipes.
|
||||
Used temporarily during process creation. */
|
||||
int PipeChildStd[3];
|
||||
|
||||
/* Write descriptor for child termination signal pipe. */
|
||||
int SignalPipe;
|
||||
|
||||
|
@ -717,7 +721,6 @@ const char* kwsysProcess_GetExceptionString(kwsysProcess* cp)
|
|||
void kwsysProcess_Execute(kwsysProcess* cp)
|
||||
{
|
||||
int i;
|
||||
kwsysProcessCreateInformation si = {-1, -1, -1, {-1, -1}};
|
||||
|
||||
/* Do not execute a second copy simultaneously. */
|
||||
if(!cp || cp->State == kwsysProcess_State_Executing)
|
||||
|
@ -785,7 +788,110 @@ void kwsysProcess_Execute(kwsysProcess* cp)
|
|||
}
|
||||
}
|
||||
|
||||
/* Setup the stderr pipe to be shared by all processes. */
|
||||
/* Setup the stdin pipe for the first process. */
|
||||
if(cp->PipeFileSTDIN)
|
||||
{
|
||||
/* Open a file for the child's stdin to read. */
|
||||
cp->PipeChildStd[0] = open(cp->PipeFileSTDIN, O_RDONLY);
|
||||
if(cp->PipeChildStd[0] < 0)
|
||||
{
|
||||
kwsysProcessCleanup(cp, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set close-on-exec flag on the pipe's end. */
|
||||
if(fcntl(cp->PipeChildStd[0], F_SETFD, FD_CLOEXEC) < 0)
|
||||
{
|
||||
kwsysProcessCleanup(cp, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if(cp->PipeSharedSTDIN)
|
||||
{
|
||||
cp->PipeChildStd[0] = 0;
|
||||
}
|
||||
else if(cp->PipeNativeSTDIN[0] >= 0)
|
||||
{
|
||||
cp->PipeChildStd[0] = 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))
|
||||
{
|
||||
kwsysProcessCleanup(cp, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cp->PipeChildStd[0] = -1;
|
||||
}
|
||||
|
||||
/* Create the output pipe for the last process.
|
||||
We always create this so the pipe can be passed to select even if
|
||||
it will report closed immediately. */
|
||||
{
|
||||
/* Create the pipe. */
|
||||
int p[2];
|
||||
if(pipe(p KWSYSPE_VMS_NONBLOCK) < 0)
|
||||
{
|
||||
kwsysProcessCleanup(cp, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Store the pipe. */
|
||||
cp->PipeReadEnds[KWSYSPE_PIPE_STDOUT] = p[0];
|
||||
cp->PipeChildStd[1] = 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);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set to non-blocking in case select lies, or for the polling
|
||||
implementation. */
|
||||
if(!kwsysProcessSetNonBlocking(p[0]))
|
||||
{
|
||||
kwsysProcessCleanup(cp, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (cp->PipeFileSTDOUT)
|
||||
{
|
||||
/* Use a file for stdout. */
|
||||
if(!kwsysProcessSetupOutputPipeFile(&cp->PipeChildStd[1],
|
||||
cp->PipeFileSTDOUT))
|
||||
{
|
||||
kwsysProcessCleanup(cp, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (cp->PipeSharedSTDOUT)
|
||||
{
|
||||
/* Use the parent stdout. */
|
||||
kwsysProcessCleanupDescriptor(&cp->PipeChildStd[1]);
|
||||
cp->PipeChildStd[1] = 1;
|
||||
}
|
||||
else if (cp->PipeNativeSTDOUT[1] >= 0)
|
||||
{
|
||||
/* Use the given descriptor for stdout. */
|
||||
if(!kwsysProcessSetupOutputPipeNative(&cp->PipeChildStd[1],
|
||||
cp->PipeNativeSTDOUT))
|
||||
{
|
||||
kwsysProcessCleanup(cp, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create stderr pipe to be shared by all processes in the pipeline.
|
||||
We always create this so the pipe can be passed to select even if
|
||||
it will report closed immediately. */
|
||||
{
|
||||
/* Create the pipe. */
|
||||
int p[2];
|
||||
|
@ -797,14 +903,13 @@ void kwsysProcess_Execute(kwsysProcess* cp)
|
|||
|
||||
/* Store the pipe. */
|
||||
cp->PipeReadEnds[KWSYSPE_PIPE_STDERR] = p[0];
|
||||
si.StdErr = p[1];
|
||||
cp->PipeChildStd[2] = 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);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -813,41 +918,33 @@ void kwsysProcess_Execute(kwsysProcess* cp)
|
|||
if(!kwsysProcessSetNonBlocking(p[0]))
|
||||
{
|
||||
kwsysProcessCleanup(cp, 1);
|
||||
kwsysProcessCleanupDescriptor(&si.StdErr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Replace the stderr pipe with a file if requested. In this case
|
||||
the select call will report that stderr is closed immediately. */
|
||||
if(cp->PipeFileSTDERR)
|
||||
if (cp->PipeFileSTDERR)
|
||||
{
|
||||
if(!kwsysProcessSetupOutputPipeFile(&si.StdErr, cp->PipeFileSTDERR))
|
||||
/* Use a file for stderr. */
|
||||
if(!kwsysProcessSetupOutputPipeFile(&cp->PipeChildStd[2],
|
||||
cp->PipeFileSTDERR))
|
||||
{
|
||||
kwsysProcessCleanup(cp, 1);
|
||||
kwsysProcessCleanupDescriptor(&si.StdErr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Replace the stderr pipe with the parent's if requested. In this
|
||||
case the select call will report that stderr is closed
|
||||
immediately. */
|
||||
if(cp->PipeSharedSTDERR)
|
||||
else if (cp->PipeSharedSTDERR)
|
||||
{
|
||||
kwsysProcessCleanupDescriptor(&si.StdErr);
|
||||
si.StdErr = 2;
|
||||
/* Use the parent stderr. */
|
||||
kwsysProcessCleanupDescriptor(&cp->PipeChildStd[2]);
|
||||
cp->PipeChildStd[2] = 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)
|
||||
else if (cp->PipeNativeSTDERR[1] >= 0)
|
||||
{
|
||||
if(!kwsysProcessSetupOutputPipeNative(&si.StdErr, cp->PipeNativeSTDERR))
|
||||
/* Use the given handle for stderr. */
|
||||
if(!kwsysProcessSetupOutputPipeNative(&cp->PipeChildStd[2],
|
||||
cp->PipeNativeSTDERR))
|
||||
{
|
||||
kwsysProcessCleanup(cp, 1);
|
||||
kwsysProcessCleanupDescriptor(&si.StdErr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -859,54 +956,85 @@ void kwsysProcess_Execute(kwsysProcess* cp)
|
|||
|
||||
/* Create the pipeline of processes. */
|
||||
{
|
||||
int readEnd = -1;
|
||||
int failed = 0;
|
||||
kwsysProcessCreateInformation si = {-1, -1, -1, {-1, -1}};
|
||||
int nextStdIn = cp->PipeChildStd[0];
|
||||
for(i=0; i < cp->NumberOfCommands; ++i)
|
||||
{
|
||||
if(!kwsysProcessCreate(cp, i, &si, &readEnd))
|
||||
/* Setup the process's pipes. */
|
||||
si.StdIn = nextStdIn;
|
||||
if (i == cp->NumberOfCommands-1)
|
||||
{
|
||||
failed = 1;
|
||||
nextStdIn = -1;
|
||||
si.StdOut = cp->PipeChildStd[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Create a pipe to sit between the children. */
|
||||
int p[2] = {-1,-1};
|
||||
if(pipe(p KWSYSPE_VMS_NONBLOCK) < 0)
|
||||
{
|
||||
if (nextStdIn != cp->PipeChildStd[0])
|
||||
{
|
||||
kwsysProcessCleanupDescriptor(&nextStdIn);
|
||||
}
|
||||
kwsysProcessCleanup(cp, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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))
|
||||
{
|
||||
close(p[0]);
|
||||
close(p[1]);
|
||||
if (nextStdIn != cp->PipeChildStd[0])
|
||||
{
|
||||
kwsysProcessCleanupDescriptor(&nextStdIn);
|
||||
}
|
||||
kwsysProcessCleanup(cp, 1);
|
||||
return;
|
||||
}
|
||||
nextStdIn = p[0];
|
||||
si.StdOut = p[1];
|
||||
}
|
||||
si.StdErr = cp->PipeChildStd[2];
|
||||
|
||||
{
|
||||
int res = kwsysProcessCreate(cp, i, &si);
|
||||
|
||||
/* Close our copies of pipes used between children. */
|
||||
if (si.StdIn != cp->PipeChildStd[0])
|
||||
{
|
||||
kwsysProcessCleanupDescriptor(&si.StdIn);
|
||||
}
|
||||
if (si.StdOut != cp->PipeChildStd[1])
|
||||
{
|
||||
kwsysProcessCleanupDescriptor(&si.StdOut);
|
||||
}
|
||||
if (si.StdErr != cp->PipeChildStd[2])
|
||||
{
|
||||
kwsysProcessCleanupDescriptor(&si.StdErr);
|
||||
}
|
||||
|
||||
/* Set the output pipe of the last process to be non-blocking in
|
||||
case select lies, or for the polling implementation. */
|
||||
if(i == (cp->NumberOfCommands-1) && !kwsysProcessSetNonBlocking(readEnd))
|
||||
if(!res)
|
||||
{
|
||||
failed = 1;
|
||||
}
|
||||
|
||||
if(failed)
|
||||
{
|
||||
kwsysProcessCleanup(cp, 1);
|
||||
|
||||
/* Release resources that may have been allocated for this
|
||||
process before an error occurred. */
|
||||
kwsysProcessCleanupDescriptor(&readEnd);
|
||||
if(si.StdIn != 0)
|
||||
{
|
||||
kwsysProcessCleanupDescriptor(&si.StdIn);
|
||||
}
|
||||
if(si.StdOut != 1)
|
||||
{
|
||||
kwsysProcessCleanupDescriptor(&si.StdOut);
|
||||
}
|
||||
if(si.StdErr != 2)
|
||||
{
|
||||
kwsysProcessCleanupDescriptor(&si.StdErr);
|
||||
}
|
||||
kwsysProcessCleanupDescriptor(&si.ErrorPipe[0]);
|
||||
kwsysProcessCleanupDescriptor(&si.ErrorPipe[1]);
|
||||
if (nextStdIn != cp->PipeChildStd[0])
|
||||
{
|
||||
kwsysProcessCleanupDescriptor(&nextStdIn);
|
||||
}
|
||||
kwsysProcessCleanup(cp, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* Save a handle to the output pipe for the last process. */
|
||||
cp->PipeReadEnds[KWSYSPE_PIPE_STDOUT] = readEnd;
|
||||
}
|
||||
}
|
||||
|
||||
/* The parent process does not need the output pipe write ends. */
|
||||
if(si.StdErr != 2)
|
||||
/* The parent process does not need the child's pipe ends. */
|
||||
for (i=0; i < 3; ++i)
|
||||
{
|
||||
kwsysProcessCleanupDescriptor(&si.StdErr);
|
||||
kwsysProcessCleanupDescriptor(&cp->PipeChildStd[i]);
|
||||
}
|
||||
|
||||
/* Restore the working directory. */
|
||||
|
@ -1414,6 +1542,10 @@ static int kwsysProcessInitialize(kwsysProcess* cp)
|
|||
{
|
||||
cp->PipeReadEnds[i] = -1;
|
||||
}
|
||||
for(i=0; i < 3; ++i)
|
||||
{
|
||||
cp->PipeChildStd[i] = -1;
|
||||
}
|
||||
cp->SignalPipe = -1;
|
||||
cp->SelectError = 0;
|
||||
cp->StartTime.tv_sec = -1;
|
||||
|
@ -1548,13 +1680,17 @@ static void kwsysProcessCleanup(kwsysProcess* cp, int error)
|
|||
{
|
||||
kwsysProcessCleanupDescriptor(&cp->PipeReadEnds[i]);
|
||||
}
|
||||
for(i=0; i < 3; ++i)
|
||||
{
|
||||
kwsysProcessCleanupDescriptor(&cp->PipeChildStd[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* Close the given file descriptor if it is open. Reset its value to -1. */
|
||||
static void kwsysProcessCleanupDescriptor(int* pfd)
|
||||
{
|
||||
if(pfd && *pfd >= 0)
|
||||
if(pfd && *pfd > 2)
|
||||
{
|
||||
/* Keep trying to close until it is not interrupted by a
|
||||
* signal. */
|
||||
|
@ -1615,100 +1751,8 @@ int decc$set_child_standard_streams(int fd1, int fd2, int fd3);
|
|||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
static int kwsysProcessCreate(kwsysProcess* cp, int prIndex,
|
||||
kwsysProcessCreateInformation* si, int* readEnd)
|
||||
kwsysProcessCreateInformation* si)
|
||||
{
|
||||
/* Setup the process's stdin. */
|
||||
if(prIndex > 0)
|
||||
{
|
||||
si->StdIn = *readEnd;
|
||||
*readEnd = 0;
|
||||
}
|
||||
else if(cp->PipeFileSTDIN)
|
||||
{
|
||||
/* Open a file for the child's stdin to read. */
|
||||
si->StdIn = open(cp->PipeFileSTDIN, O_RDONLY);
|
||||
if(si->StdIn < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set close-on-exec flag on the pipe's end. */
|
||||
if(fcntl(si->StdIn, F_SETFD, FD_CLOEXEC) < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if(cp->PipeSharedSTDIN)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/* Setup the process's stdout. */
|
||||
{
|
||||
/* Create the pipe. */
|
||||
int p[2];
|
||||
if(pipe(p KWSYSPE_VMS_NONBLOCK) < 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* Replace the stdout pipe with a file if requested. In this case
|
||||
the select call will report that stdout is closed immediately. */
|
||||
if(prIndex == cp->NumberOfCommands-1 && cp->PipeFileSTDOUT)
|
||||
{
|
||||
if(!kwsysProcessSetupOutputPipeFile(&si->StdOut, cp->PipeFileSTDOUT))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Replace the stdout pipe with the parent's if requested. In this
|
||||
case the select call will report that stderr is closed
|
||||
immediately. */
|
||||
if(prIndex == cp->NumberOfCommands-1 && cp->PipeSharedSTDOUT)
|
||||
{
|
||||
kwsysProcessCleanupDescriptor(&si->StdOut);
|
||||
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)
|
||||
{
|
||||
|
@ -1819,19 +1863,6 @@ static int kwsysProcessCreate(kwsysProcess* cp, int prIndex,
|
|||
}
|
||||
}
|
||||
|
||||
/* Successfully created this child process. */
|
||||
if(prIndex > 0 || si->StdIn > 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. */
|
||||
if(si->StdOut != 1)
|
||||
{
|
||||
kwsysProcessCleanupDescriptor(&si->StdOut);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
603
ProcessWin32.c
603
ProcessWin32.c
|
@ -94,6 +94,11 @@ typedef struct kwsysProcessCreateInformation_s
|
|||
{
|
||||
/* Windows child startup control data. */
|
||||
STARTUPINFOW StartupInfo;
|
||||
|
||||
/* Original handles before making inherited duplicates. */
|
||||
HANDLE hStdInput;
|
||||
HANDLE hStdOutput;
|
||||
HANDLE hStdError;
|
||||
} kwsysProcessCreateInformation;
|
||||
|
||||
|
||||
|
@ -107,15 +112,12 @@ static void kwsysProcessPipeThreadWakePipe(kwsysProcess* cp,
|
|||
kwsysProcessPipeData* td);
|
||||
static int kwsysProcessInitialize(kwsysProcess* cp);
|
||||
static int kwsysProcessCreate(kwsysProcess* cp, int index,
|
||||
kwsysProcessCreateInformation* si,
|
||||
PHANDLE readEnd);
|
||||
kwsysProcessCreateInformation* si);
|
||||
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 kwsysProcessSetupSharedPipe(DWORD nStdHandle, PHANDLE handle);
|
||||
static void kwsysProcessSetupPipeNative(HANDLE native, PHANDLE handle);
|
||||
static void kwsysProcessCleanupHandle(PHANDLE h);
|
||||
static void kwsysProcessCleanupHandleSafe(PHANDLE h, DWORD nStdHandle);
|
||||
static void kwsysProcessCleanup(kwsysProcess* cp, int error);
|
||||
static void kwsysProcessCleanErrorMessage(kwsysProcess* cp);
|
||||
static int kwsysProcessComputeCommandLength(kwsysProcess* cp,
|
||||
|
@ -306,6 +308,10 @@ struct kwsysProcess_s
|
|||
/* Real working directory of our own process. */
|
||||
DWORD RealWorkingDirectoryLength;
|
||||
wchar_t* RealWorkingDirectory;
|
||||
|
||||
/* Own handles for the child's ends of the pipes in the parent process.
|
||||
Used temporarily during process creation. */
|
||||
HANDLE PipeChildStd[3];
|
||||
};
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
@ -446,6 +452,10 @@ kwsysProcess* kwsysProcess_New(void)
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
for(i=0; i < 3; ++i)
|
||||
{
|
||||
cp->PipeChildStd[i] = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
return cp;
|
||||
}
|
||||
|
@ -875,9 +885,6 @@ void kwsysProcess_Execute(kwsysProcess* cp)
|
|||
{
|
||||
int i;
|
||||
|
||||
/* Child startup control data. */
|
||||
kwsysProcessCreateInformation si;
|
||||
|
||||
/* Do not execute a second time. */
|
||||
if(!cp || cp->State == kwsysProcess_State_Executing)
|
||||
{
|
||||
|
@ -914,6 +921,133 @@ void kwsysProcess_Execute(kwsysProcess* cp)
|
|||
SetCurrentDirectoryW(cp->WorkingDirectory);
|
||||
}
|
||||
|
||||
|
||||
/* Setup the stdin pipe for the first process. */
|
||||
if(cp->PipeFileSTDIN)
|
||||
{
|
||||
/* Create a handle to read a file for stdin. */
|
||||
wchar_t* wstdin = kwsysEncoding_DupToWide(cp->PipeFileSTDIN);
|
||||
cp->PipeChildStd[0] =
|
||||
CreateFileW(wstdin, GENERIC_READ|GENERIC_WRITE,
|
||||
FILE_SHARE_READ|FILE_SHARE_WRITE,
|
||||
0, OPEN_EXISTING, 0, 0);
|
||||
free(wstdin);
|
||||
if(cp->PipeChildStd[0] == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
kwsysProcessCleanup(cp, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if(cp->PipeSharedSTDIN)
|
||||
{
|
||||
/* Share this process's stdin with the child. */
|
||||
kwsysProcessSetupSharedPipe(STD_INPUT_HANDLE, &cp->PipeChildStd[0]);
|
||||
}
|
||||
else if(cp->PipeNativeSTDIN[0])
|
||||
{
|
||||
/* Use the provided native pipe. */
|
||||
kwsysProcessSetupPipeNative(cp->PipeNativeSTDIN[0], &cp->PipeChildStd[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Explicitly give the child no stdin. */
|
||||
cp->PipeChildStd[0] = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
/* Create the output pipe for the last process.
|
||||
We always create this so the pipe thread can run even if we
|
||||
do not end up giving the write end to the child below. */
|
||||
if(!CreatePipe(&cp->Pipe[KWSYSPE_PIPE_STDOUT].Read,
|
||||
&cp->Pipe[KWSYSPE_PIPE_STDOUT].Write, 0, 0))
|
||||
{
|
||||
kwsysProcessCleanup(cp, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if(cp->PipeFileSTDOUT)
|
||||
{
|
||||
/* Use a file for stdout. */
|
||||
if(!kwsysProcessSetupOutputPipeFile(&cp->PipeChildStd[1],
|
||||
cp->PipeFileSTDOUT))
|
||||
{
|
||||
kwsysProcessCleanup(cp, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if(cp->PipeSharedSTDOUT)
|
||||
{
|
||||
/* Use the parent stdout. */
|
||||
kwsysProcessSetupSharedPipe(STD_OUTPUT_HANDLE, &cp->PipeChildStd[1]);
|
||||
}
|
||||
else if(cp->PipeNativeSTDOUT[1])
|
||||
{
|
||||
/* Use the given handle for stdout. */
|
||||
kwsysProcessSetupPipeNative(cp->PipeNativeSTDOUT[1], &cp->PipeChildStd[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Use our pipe for stdout. Duplicate the handle since our waker
|
||||
thread will use the original. Do not make it inherited yet. */
|
||||
if(!DuplicateHandle(GetCurrentProcess(),
|
||||
cp->Pipe[KWSYSPE_PIPE_STDOUT].Write,
|
||||
GetCurrentProcess(), &cp->PipeChildStd[1],
|
||||
0, FALSE, DUPLICATE_SAME_ACCESS))
|
||||
{
|
||||
kwsysProcessCleanup(cp, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create stderr pipe to be shared by all processes in the pipeline.
|
||||
We always create this so the pipe thread can run even if we do not
|
||||
end up giving the write end to the child below. */
|
||||
if(!CreatePipe(&cp->Pipe[KWSYSPE_PIPE_STDERR].Read,
|
||||
&cp->Pipe[KWSYSPE_PIPE_STDERR].Write, 0, 0))
|
||||
{
|
||||
kwsysProcessCleanup(cp, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if(cp->PipeFileSTDERR)
|
||||
{
|
||||
/* Use a file for stderr. */
|
||||
if(!kwsysProcessSetupOutputPipeFile(&cp->PipeChildStd[2],
|
||||
cp->PipeFileSTDERR))
|
||||
{
|
||||
kwsysProcessCleanup(cp, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if(cp->PipeSharedSTDERR)
|
||||
{
|
||||
/* Use the parent stderr. */
|
||||
kwsysProcessSetupSharedPipe(STD_ERROR_HANDLE, &cp->PipeChildStd[2]);
|
||||
}
|
||||
else if(cp->PipeNativeSTDERR[1])
|
||||
{
|
||||
/* Use the given handle for stderr. */
|
||||
kwsysProcessSetupPipeNative(cp->PipeNativeSTDERR[1], &cp->PipeChildStd[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Use our pipe for stderr. Duplicate the handle since our waker
|
||||
thread will use the original. Do not make it inherited yet. */
|
||||
if(!DuplicateHandle(GetCurrentProcess(),
|
||||
cp->Pipe[KWSYSPE_PIPE_STDERR].Write,
|
||||
GetCurrentProcess(), &cp->PipeChildStd[2],
|
||||
0, FALSE, DUPLICATE_SAME_ACCESS))
|
||||
{
|
||||
kwsysProcessCleanup(cp, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create the pipeline of processes. */
|
||||
{
|
||||
/* Child startup control data. */
|
||||
kwsysProcessCreateInformation si;
|
||||
HANDLE nextStdInput = cp->PipeChildStd[0];
|
||||
|
||||
/* Initialize startup info data. */
|
||||
ZeroMemory(&si, sizeof(si));
|
||||
si.StartupInfo.cb = sizeof(si.StartupInfo);
|
||||
|
@ -926,105 +1060,72 @@ void kwsysProcess_Execute(kwsysProcess* cp)
|
|||
/* Connect the child's output pipes to the threads. */
|
||||
si.StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
|
||||
|
||||
/* Create stderr pipe to be shared by all processes in the pipeline.
|
||||
Neither end is directly inherited. */
|
||||
if(!CreatePipe(&cp->Pipe[KWSYSPE_PIPE_STDERR].Read,
|
||||
&cp->Pipe[KWSYSPE_PIPE_STDERR].Write, 0, 0))
|
||||
{
|
||||
kwsysProcessCleanup(cp, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Create an inherited duplicate of the write end, but do not
|
||||
close the non-inherited version. We need to keep it open
|
||||
to use in waking up the pipe threads. */
|
||||
if(!DuplicateHandle(GetCurrentProcess(), cp->Pipe[KWSYSPE_PIPE_STDERR].Write,
|
||||
GetCurrentProcess(), &si.StartupInfo.hStdError,
|
||||
0, TRUE, DUPLICATE_SAME_ACCESS))
|
||||
{
|
||||
kwsysProcessCleanup(cp, 1);
|
||||
kwsysProcessCleanupHandle(&si.StartupInfo.hStdError);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Replace the stderr pipe with a file if requested. In this case
|
||||
the pipe thread will still run but never report data. */
|
||||
if(cp->PipeFileSTDERR)
|
||||
{
|
||||
if(!kwsysProcessSetupOutputPipeFile(&si.StartupInfo.hStdError,
|
||||
cp->PipeFileSTDERR))
|
||||
{
|
||||
kwsysProcessCleanup(cp, 1);
|
||||
kwsysProcessCleanupHandle(&si.StartupInfo.hStdError);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Replace the stderr pipe with the parent process's if requested.
|
||||
In this case the pipe thread will still run but never report
|
||||
data. */
|
||||
if(cp->PipeSharedSTDERR)
|
||||
{
|
||||
if(!kwsysProcessSetupSharedPipe(STD_ERROR_HANDLE,
|
||||
&si.StartupInfo.hStdError))
|
||||
{
|
||||
kwsysProcessCleanup(cp, 1);
|
||||
kwsysProcessCleanupHandleSafe(&si.StartupInfo.hStdError,
|
||||
STD_ERROR_HANDLE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
for(i=0; i < cp->NumberOfCommands; ++i)
|
||||
{
|
||||
if(kwsysProcessCreate(cp, i, &si, &readEnd))
|
||||
/* Setup the process's pipes. */
|
||||
si.hStdInput = nextStdInput;
|
||||
if (i == cp->NumberOfCommands-1)
|
||||
{
|
||||
/* The last child gets the overall stdout. */
|
||||
nextStdInput = INVALID_HANDLE_VALUE;
|
||||
si.hStdOutput = cp->PipeChildStd[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Create a pipe to sit between the children. */
|
||||
HANDLE p[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
|
||||
if (!CreatePipe(&p[0], &p[1], 0, 0))
|
||||
{
|
||||
if (nextStdInput != cp->PipeChildStd[0])
|
||||
{
|
||||
kwsysProcessCleanupHandle(&nextStdInput);
|
||||
}
|
||||
kwsysProcessCleanup(cp, 1);
|
||||
return;
|
||||
}
|
||||
nextStdInput = p[0];
|
||||
si.hStdOutput = p[1];
|
||||
}
|
||||
si.hStdError = cp->PipeChildStd[2];
|
||||
|
||||
{
|
||||
int res = kwsysProcessCreate(cp, i, &si);
|
||||
|
||||
/* Close our copies of pipes used between children. */
|
||||
if (si.hStdInput != cp->PipeChildStd[0])
|
||||
{
|
||||
kwsysProcessCleanupHandle(&si.hStdInput);
|
||||
}
|
||||
if (si.hStdOutput != cp->PipeChildStd[1])
|
||||
{
|
||||
kwsysProcessCleanupHandle(&si.hStdOutput);
|
||||
}
|
||||
if (si.hStdError != cp->PipeChildStd[2])
|
||||
{
|
||||
kwsysProcessCleanupHandle(&si.hStdError);
|
||||
}
|
||||
if (res)
|
||||
{
|
||||
cp->ProcessEvents[i+1] = cp->ProcessInformation[i].hProcess;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nextStdInput != cp->PipeChildStd[0])
|
||||
{
|
||||
kwsysProcessCleanupHandle(&nextStdInput);
|
||||
}
|
||||
kwsysProcessCleanup(cp, 1);
|
||||
|
||||
/* Release resources that may have been allocated for this
|
||||
process before an error occurred. */
|
||||
kwsysProcessCleanupHandle(&readEnd);
|
||||
kwsysProcessCleanupHandleSafe(&si.StartupInfo.hStdInput,
|
||||
STD_INPUT_HANDLE);
|
||||
kwsysProcessCleanupHandleSafe(&si.StartupInfo.hStdOutput,
|
||||
STD_OUTPUT_HANDLE);
|
||||
kwsysProcessCleanupHandleSafe(&si.StartupInfo.hStdError,
|
||||
STD_ERROR_HANDLE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Save a handle to the output pipe for the last process. */
|
||||
cp->Pipe[KWSYSPE_PIPE_STDOUT].Read = readEnd;
|
||||
}
|
||||
}
|
||||
|
||||
/* Close the inherited handles to the stderr pipe shared by all
|
||||
processes in the pipeline. The stdout and stdin pipes are not
|
||||
shared among all children and are therefore closed by
|
||||
kwsysProcessCreate after each child is created. */
|
||||
kwsysProcessCleanupHandleSafe(&si.StartupInfo.hStdError, STD_ERROR_HANDLE);
|
||||
/* The parent process does not need the child's pipe ends. */
|
||||
for (i=0; i < 3; ++i)
|
||||
{
|
||||
kwsysProcessCleanupHandle(&cp->PipeChildStd[i]);
|
||||
}
|
||||
|
||||
/* Restore the working directory. */
|
||||
if(cp->RealWorkingDirectory)
|
||||
|
@ -1543,162 +1644,90 @@ int kwsysProcessInitialize(kwsysProcess* cp)
|
|||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
int i;
|
||||
for (i=0; i < 3; ++i)
|
||||
{
|
||||
cp->PipeChildStd[i] = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int kwsysProcessCreate(kwsysProcess* cp, int index,
|
||||
kwsysProcessCreateInformation* si,
|
||||
PHANDLE readEnd)
|
||||
static int kwsysProcessCreateChildHandle(PHANDLE out, HANDLE in, int isStdIn)
|
||||
{
|
||||
/* Setup the process's stdin. */
|
||||
if(*readEnd)
|
||||
{
|
||||
/* Create an inherited duplicate of the read end from the output
|
||||
pipe of the previous process. This also closes the
|
||||
non-inherited version. */
|
||||
if(!DuplicateHandle(GetCurrentProcess(), *readEnd,
|
||||
GetCurrentProcess(), readEnd,
|
||||
0, TRUE, (DUPLICATE_CLOSE_SOURCE |
|
||||
DUPLICATE_SAME_ACCESS)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
si->StartupInfo.hStdInput = *readEnd;
|
||||
DWORD flags;
|
||||
|
||||
/* This function is done with this handle. */
|
||||
*readEnd = 0;
|
||||
}
|
||||
else if(cp->PipeFileSTDIN)
|
||||
/* Check whether the handle is valid for this process. */
|
||||
if (in != INVALID_HANDLE_VALUE && GetHandleInformation(in, &flags))
|
||||
{
|
||||
/* Create a handle to read a file for stdin. */
|
||||
wchar_t* wstdin = kwsysEncoding_DupToWide(cp->PipeFileSTDIN);
|
||||
HANDLE fin = CreateFileW(wstdin, GENERIC_READ|GENERIC_WRITE,
|
||||
FILE_SHARE_READ|FILE_SHARE_WRITE,
|
||||
0, OPEN_EXISTING, 0, 0);
|
||||
free(wstdin);
|
||||
if(fin == INVALID_HANDLE_VALUE)
|
||||
/* Use the handle as-is if it is already inherited. */
|
||||
if (flags & HANDLE_FLAG_INHERIT)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
/* Create an inherited duplicate of the handle. This also closes
|
||||
the non-inherited version. */
|
||||
if(!DuplicateHandle(GetCurrentProcess(), fin,
|
||||
GetCurrentProcess(), &fin,
|
||||
0, TRUE, (DUPLICATE_CLOSE_SOURCE |
|
||||
DUPLICATE_SAME_ACCESS)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
si->StartupInfo.hStdInput = fin;
|
||||
}
|
||||
else if(cp->PipeSharedSTDIN)
|
||||
{
|
||||
/* Share this process's stdin with the child. */
|
||||
if(!kwsysProcessSetupSharedPipe(STD_INPUT_HANDLE,
|
||||
&si->StartupInfo.hStdInput))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if(cp->PipeNativeSTDIN[0])
|
||||
{
|
||||
/* Use the provided native pipe. */
|
||||
if(!kwsysProcessSetupPipeNative(&si->StartupInfo.hStdInput,
|
||||
cp->PipeNativeSTDIN, 0))
|
||||
{
|
||||
return 0;
|
||||
*out = in;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Create an inherited copy of this handle. */
|
||||
return DuplicateHandle(GetCurrentProcess(), in,
|
||||
GetCurrentProcess(), out,
|
||||
0, TRUE, DUPLICATE_SAME_ACCESS);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Explicitly give the child no stdin. */
|
||||
si->StartupInfo.hStdInput = INVALID_HANDLE_VALUE;
|
||||
/* The given handle is not valid for this process. Some child
|
||||
processes may break if they do not have a valid standard handle,
|
||||
so open NUL to give to the child. */
|
||||
SECURITY_ATTRIBUTES sa;
|
||||
ZeroMemory(&sa, sizeof(sa));
|
||||
sa.nLength = (DWORD)sizeof(sa);
|
||||
sa.bInheritHandle = 1;
|
||||
*out = CreateFileW(L"NUL",
|
||||
(isStdIn ? GENERIC_READ :
|
||||
(GENERIC_WRITE | FILE_READ_ATTRIBUTES)),
|
||||
FILE_SHARE_READ|FILE_SHARE_WRITE,
|
||||
&sa, OPEN_EXISTING, 0, 0);
|
||||
return *out != INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
/* Setup the process's stdout. */
|
||||
{
|
||||
DWORD maybeClose = DUPLICATE_CLOSE_SOURCE;
|
||||
HANDLE writeEnd;
|
||||
}
|
||||
|
||||
/* Create the output pipe for this process. Neither end is directly
|
||||
inherited. */
|
||||
if(!CreatePipe(readEnd, &writeEnd, 0, 0))
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int kwsysProcessCreate(kwsysProcess* cp, int index,
|
||||
kwsysProcessCreateInformation* si)
|
||||
{
|
||||
int res =
|
||||
|
||||
/* Create inherited copies the handles. */
|
||||
kwsysProcessCreateChildHandle(&si->StartupInfo.hStdInput,
|
||||
si->hStdInput, 1) &&
|
||||
kwsysProcessCreateChildHandle(&si->StartupInfo.hStdOutput,
|
||||
si->hStdOutput, 0) &&
|
||||
kwsysProcessCreateChildHandle(&si->StartupInfo.hStdError,
|
||||
si->hStdError, 0) &&
|
||||
|
||||
/* Create the child in a suspended state so we can wait until all
|
||||
children have been created before running any one. */
|
||||
CreateProcessW(0, cp->Commands[index], 0, 0, TRUE, CREATE_SUSPENDED, 0,
|
||||
0, &si->StartupInfo, &cp->ProcessInformation[index]);
|
||||
|
||||
/* Close the inherited copies of the handles. */
|
||||
if (si->StartupInfo.hStdInput != si->hStdInput)
|
||||
{
|
||||
return 0;
|
||||
kwsysProcessCleanupHandle(&si->StartupInfo.hStdInput);
|
||||
}
|
||||
|
||||
/* Create an inherited duplicate of the write end. Close the
|
||||
non-inherited version unless this is the last process. Save the
|
||||
non-inherited write end of the last process. */
|
||||
if(index == cp->NumberOfCommands-1)
|
||||
if (si->StartupInfo.hStdOutput != si->hStdOutput)
|
||||
{
|
||||
cp->Pipe[KWSYSPE_PIPE_STDOUT].Write = writeEnd;
|
||||
maybeClose = 0;
|
||||
kwsysProcessCleanupHandle(&si->StartupInfo.hStdOutput);
|
||||
}
|
||||
if(!DuplicateHandle(GetCurrentProcess(), writeEnd,
|
||||
GetCurrentProcess(), &writeEnd,
|
||||
0, TRUE, (maybeClose | DUPLICATE_SAME_ACCESS)))
|
||||
if (si->StartupInfo.hStdError != si->hStdError)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
si->StartupInfo.hStdOutput = writeEnd;
|
||||
}
|
||||
|
||||
/* Replace the stdout pipe with a file if requested. In this case
|
||||
the pipe thread will still run but never report data. */
|
||||
if(index == cp->NumberOfCommands-1 && cp->PipeFileSTDOUT)
|
||||
{
|
||||
if(!kwsysProcessSetupOutputPipeFile(&si->StartupInfo.hStdOutput,
|
||||
cp->PipeFileSTDOUT))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
kwsysProcessCleanupHandle(&si->StartupInfo.hStdError);
|
||||
}
|
||||
|
||||
/* Replace the stdout pipe of the last child with the parent
|
||||
process's if requested. In this case the pipe thread will still
|
||||
run but never report data. */
|
||||
if(index == cp->NumberOfCommands-1 && cp->PipeSharedSTDOUT)
|
||||
{
|
||||
if(!kwsysProcessSetupSharedPipe(STD_OUTPUT_HANDLE,
|
||||
&si->StartupInfo.hStdOutput))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 in a suspended state so we can wait until all
|
||||
children have been created before running any one. */
|
||||
if(!CreateProcessW(0, cp->Commands[index], 0, 0, TRUE, CREATE_SUSPENDED, 0,
|
||||
0, &si->StartupInfo, &cp->ProcessInformation[index]))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Successfully created this child process. Close the current
|
||||
process's copies of the inherited stdout and stdin handles. The
|
||||
stderr handle is shared among all children and is closed by
|
||||
kwsysProcess_Execute after all children have been created. */
|
||||
kwsysProcessCleanupHandleSafe(&si->StartupInfo.hStdInput,
|
||||
STD_INPUT_HANDLE);
|
||||
kwsysProcessCleanupHandleSafe(&si->StartupInfo.hStdOutput,
|
||||
STD_OUTPUT_HANDLE);
|
||||
|
||||
return 1;
|
||||
return res;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
@ -1763,7 +1792,7 @@ int kwsysProcessSetupOutputPipeFile(PHANDLE phandle, const char* name)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/* Close the existing inherited handle. */
|
||||
/* Close the existing handle. */
|
||||
kwsysProcessCleanupHandle(phandle);
|
||||
|
||||
/* Create a handle to write a file for the pipe. */
|
||||
|
@ -1776,103 +1805,27 @@ int kwsysProcessSetupOutputPipeFile(PHANDLE phandle, const char* name)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Create an inherited duplicate of the handle. This also closes
|
||||
the non-inherited version. */
|
||||
if(!DuplicateHandle(GetCurrentProcess(), fout,
|
||||
GetCurrentProcess(), &fout,
|
||||
0, TRUE, (DUPLICATE_CLOSE_SOURCE |
|
||||
DUPLICATE_SAME_ACCESS)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Assign the replacement handle. */
|
||||
*phandle = fout;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int kwsysProcessSetupSharedPipe(DWORD nStdHandle, PHANDLE handle)
|
||||
void kwsysProcessSetupSharedPipe(DWORD nStdHandle, PHANDLE handle)
|
||||
{
|
||||
/* Check whether the handle to be shared is already inherited. */
|
||||
DWORD flags;
|
||||
int inherited = 0;
|
||||
if(GetHandleInformation(GetStdHandle(nStdHandle), &flags) &&
|
||||
(flags & HANDLE_FLAG_INHERIT))
|
||||
{
|
||||
inherited = 1;
|
||||
}
|
||||
|
||||
/* Cleanup the previous handle. */
|
||||
/* Close the existing handle. */
|
||||
kwsysProcessCleanupHandle(handle);
|
||||
|
||||
/* If the standard handle is not inherited then duplicate it to
|
||||
create an inherited copy. Do not close the original handle when
|
||||
duplicating! */
|
||||
if(inherited)
|
||||
{
|
||||
*handle = GetStdHandle(nStdHandle);
|
||||
return 1;
|
||||
}
|
||||
else if(DuplicateHandle(GetCurrentProcess(), GetStdHandle(nStdHandle),
|
||||
GetCurrentProcess(), handle,
|
||||
0, TRUE, DUPLICATE_SAME_ACCESS))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The given standard handle is not valid for this process. Some
|
||||
child processes may break if they do not have a valid standard
|
||||
pipe, so give the child an empty pipe. For the stdin pipe we
|
||||
want to close the write end and give the read end to the child.
|
||||
For stdout and stderr we want to close the read end and give
|
||||
the write end to the child. */
|
||||
int child_end = (nStdHandle == STD_INPUT_HANDLE)? 0:1;
|
||||
int parent_end = (nStdHandle == STD_INPUT_HANDLE)? 1:0;
|
||||
HANDLE emptyPipe[2];
|
||||
if(!CreatePipe(&emptyPipe[0], &emptyPipe[1], 0, 0))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Close the non-inherited end so the pipe will be broken
|
||||
immediately. */
|
||||
CloseHandle(emptyPipe[parent_end]);
|
||||
|
||||
/* Create an inherited duplicate of the handle. This also
|
||||
closes the non-inherited version. */
|
||||
if(!DuplicateHandle(GetCurrentProcess(), emptyPipe[child_end],
|
||||
GetCurrentProcess(), &emptyPipe[child_end],
|
||||
0, TRUE, (DUPLICATE_CLOSE_SOURCE |
|
||||
DUPLICATE_SAME_ACCESS)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Give the inherited handle to the child. */
|
||||
*handle = emptyPipe[child_end];
|
||||
return 1;
|
||||
}
|
||||
/* Store the new standard handle. */
|
||||
*handle = GetStdHandle(nStdHandle);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int kwsysProcessSetupPipeNative(PHANDLE handle, HANDLE p[2], int isWrite)
|
||||
void kwsysProcessSetupPipeNative(HANDLE native, PHANDLE handle)
|
||||
{
|
||||
/* Close the existing inherited handle. */
|
||||
/* Close the existing 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;
|
||||
/* Store the new given handle. */
|
||||
*handle = native;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
@ -1880,23 +1833,13 @@ int kwsysProcessSetupPipeNative(PHANDLE handle, HANDLE p[2], int isWrite)
|
|||
/* Close the given handle if it is open. Reset its value to 0. */
|
||||
void kwsysProcessCleanupHandle(PHANDLE h)
|
||||
{
|
||||
if(h && *h)
|
||||
if(h && *h && *h != INVALID_HANDLE_VALUE &&
|
||||
*h != GetStdHandle(STD_INPUT_HANDLE) &&
|
||||
*h != GetStdHandle(STD_OUTPUT_HANDLE) &&
|
||||
*h != GetStdHandle(STD_ERROR_HANDLE))
|
||||
{
|
||||
CloseHandle(*h);
|
||||
*h = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/* Close the given handle if it is open and not a standard handle.
|
||||
Reset its value to 0. */
|
||||
void kwsysProcessCleanupHandleSafe(PHANDLE h, DWORD nStdHandle)
|
||||
{
|
||||
if(h && *h && (*h != GetStdHandle(nStdHandle)))
|
||||
{
|
||||
CloseHandle(*h);
|
||||
*h = 0;
|
||||
*h = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1986,6 +1929,10 @@ void kwsysProcessCleanup(kwsysProcess* cp, int error)
|
|||
kwsysProcessCleanupHandle(&cp->Pipe[i].Read);
|
||||
cp->Pipe[i].Closed = 0;
|
||||
}
|
||||
for(i=0; i < 3; ++i)
|
||||
{
|
||||
kwsysProcessCleanupHandle(&cp->PipeChildStd[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
|
Loading…
Reference in New Issue