BUG: Fix hang in Process_Kill on OS X caused by an OS bug in which a pipe read end cannot be closed if the pipe write end is open, the pipe is full, and another process is blocking waiting to write. Work around the problem by killing the children before closing the pipes.
This commit is contained in:
parent
f61305e88c
commit
1c2ffbb5bc
|
@ -141,6 +141,7 @@ typedef struct kwsysProcessCreateInformation_s
|
||||||
static int kwsysProcessInitialize(kwsysProcess* cp);
|
static int kwsysProcessInitialize(kwsysProcess* cp);
|
||||||
static void kwsysProcessCleanup(kwsysProcess* cp, int error);
|
static void kwsysProcessCleanup(kwsysProcess* cp, int error);
|
||||||
static void kwsysProcessCleanupDescriptor(int* pfd);
|
static void kwsysProcessCleanupDescriptor(int* pfd);
|
||||||
|
static void kwsysProcessClosePipes(kwsysProcess* cp);
|
||||||
static int kwsysProcessSetNonBlocking(int fd);
|
static int kwsysProcessSetNonBlocking(int fd);
|
||||||
static int kwsysProcessCreate(kwsysProcess* cp, int prIndex,
|
static int kwsysProcessCreate(kwsysProcess* cp, int prIndex,
|
||||||
kwsysProcessCreateInformation* si, int* readEnd);
|
kwsysProcessCreateInformation* si, int* readEnd);
|
||||||
|
@ -893,8 +894,6 @@ void kwsysProcess_Execute(kwsysProcess* cp)
|
||||||
/*--------------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------------*/
|
||||||
kwsysEXPORT void kwsysProcess_Disown(kwsysProcess* cp)
|
kwsysEXPORT void kwsysProcess_Disown(kwsysProcess* cp)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
|
|
||||||
/* Make sure a detached child process is running. */
|
/* Make sure a detached child process is running. */
|
||||||
if(!cp || !cp->Detached || cp->State != kwsysProcess_State_Executing ||
|
if(!cp || !cp->Detached || cp->State != kwsysProcess_State_Executing ||
|
||||||
cp->TimeoutExpired || cp->Killed)
|
cp->TimeoutExpired || cp->Killed)
|
||||||
|
@ -902,33 +901,8 @@ kwsysEXPORT void kwsysProcess_Disown(kwsysProcess* cp)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Close any pipes that are still open. */
|
/* Close all the pipes safely. */
|
||||||
for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
|
kwsysProcessClosePipes(cp);
|
||||||
{
|
|
||||||
if(cp->PipeReadEnds[i] >= 0)
|
|
||||||
{
|
|
||||||
#if KWSYSPE_USE_SELECT
|
|
||||||
/* If the pipe was reported by the last call to select, we must
|
|
||||||
read from it. This is needed to satisfy the suggestions from
|
|
||||||
"man select_tut" and is not needed for the polling
|
|
||||||
implementation. 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));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* We are done reading from this pipe. */
|
|
||||||
kwsysProcessCleanupDescriptor(&cp->PipeReadEnds[i]);
|
|
||||||
--cp->PipesLeft;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We will not wait for exit, so cleanup now. */
|
/* We will not wait for exit, so cleanup now. */
|
||||||
kwsysProcessCleanup(cp, 0);
|
kwsysProcessCleanup(cp, 0);
|
||||||
|
@ -1346,18 +1320,17 @@ void kwsysProcess_Kill(kwsysProcess* cp)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* First close the child exit report pipe write end to avoid causing a
|
||||||
|
SIGPIPE when the child terminates and our signal handler tries to
|
||||||
|
report it after we have already closed the read end. */
|
||||||
|
kwsysProcessCleanupDescriptor(&cp->SignalPipe);
|
||||||
|
|
||||||
|
#if !defined(__APPLE__)
|
||||||
/* Close all the pipe read ends. Do this before killing the
|
/* Close all the pipe read ends. Do this before killing the
|
||||||
children because Cygwin has problems killing processes that are
|
children because Cygwin has problems killing processes that are
|
||||||
blocking to wait for writing to their output pipes. First close
|
blocking to wait for writing to their output pipes. */
|
||||||
the child exit report pipe write end to avoid causing a SIGPIPE
|
kwsysProcessClosePipes(cp);
|
||||||
when the child terminates and our signal handler tries to report
|
#endif
|
||||||
it. */
|
|
||||||
kwsysProcessCleanupDescriptor(&cp->SignalPipe);
|
|
||||||
for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
|
|
||||||
{
|
|
||||||
kwsysProcessCleanupDescriptor(&cp->PipeReadEnds[i]);
|
|
||||||
}
|
|
||||||
cp->PipesLeft = 0;
|
|
||||||
|
|
||||||
/* Kill the children. */
|
/* Kill the children. */
|
||||||
cp->Killed = 1;
|
cp->Killed = 1;
|
||||||
|
@ -1374,6 +1347,14 @@ void kwsysProcess_Kill(kwsysProcess* cp)
|
||||||
while((waitpid(cp->ForkPIDs[i], &status, 0) < 0) && (errno == EINTR));
|
while((waitpid(cp->ForkPIDs[i], &status, 0) < 0) && (errno == EINTR));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
/* Close all the pipe read ends. Do this after killing the
|
||||||
|
children because OS X has problems closing pipe read ends whose
|
||||||
|
pipes are full and still have an open write end. */
|
||||||
|
kwsysProcessClosePipes(cp);
|
||||||
|
#endif
|
||||||
|
|
||||||
cp->CommandsLeft = 0;
|
cp->CommandsLeft = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1533,6 +1514,40 @@ static void kwsysProcessCleanupDescriptor(int* pfd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
static void kwsysProcessClosePipes(kwsysProcess* cp)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Close any pipes that are still open. */
|
||||||
|
for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
|
||||||
|
{
|
||||||
|
if(cp->PipeReadEnds[i] >= 0)
|
||||||
|
{
|
||||||
|
#if KWSYSPE_USE_SELECT
|
||||||
|
/* If the pipe was reported by the last call to select, we must
|
||||||
|
read from it. This is needed to satisfy the suggestions from
|
||||||
|
"man select_tut" and is not needed for the polling
|
||||||
|
implementation. 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));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* We are done reading from this pipe. */
|
||||||
|
kwsysProcessCleanupDescriptor(&cp->PipeReadEnds[i]);
|
||||||
|
--cp->PipesLeft;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------------*/
|
||||||
static int kwsysProcessSetNonBlocking(int fd)
|
static int kwsysProcessSetNonBlocking(int fd)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue