|
|
@@ -75,6 +75,36 @@ typedef ssize_t kwsysProcess_ssize_t;
|
|
|
typedef int kwsysProcess_ssize_t;
|
|
|
#endif
|
|
|
|
|
|
+#if defined(__BEOS__) && !defined(__ZETA__)
|
|
|
+/* BeOS 5 doesn't have usleep(), but it has snooze(), which is identical. */
|
|
|
+# include <be/kernel/OS.h>
|
|
|
+static inline void kwsysProcess_usleep(unsigned int msec)
|
|
|
+{
|
|
|
+ snooze(msec);
|
|
|
+}
|
|
|
+#else
|
|
|
+# define kwsysProcess_usleep usleep
|
|
|
+#endif
|
|
|
+
|
|
|
+/*
|
|
|
+ * BeOS's select() works like WinSock: it's for networking only, and
|
|
|
+ * doesn't work with Unix file handles...socket and file handles are
|
|
|
+ * different namespaces (the same descriptor means different things in
|
|
|
+ * each context!)
|
|
|
+ *
|
|
|
+ * So on Unix-like systems where select() is flakey, we'll set the
|
|
|
+ * pipes' file handles to be non-blocking and just poll them directly
|
|
|
+ * without select().
|
|
|
+ */
|
|
|
+#if !defined(__BEOS__)
|
|
|
+# define KWSYSPE_USE_SELECT 1
|
|
|
+#endif
|
|
|
+
|
|
|
+/* BeOS does not have siginfo on its signal handlers. */
|
|
|
+#if !defined(__BEOS__)
|
|
|
+# define KWSYSPE_USE_SIGINFO 1
|
|
|
+#endif
|
|
|
+
|
|
|
/* The number of pipes for the child's output. The standard stdout
|
|
|
and stderr pipes are the first two. One more pipe is used to
|
|
|
detect when the child process has terminated. The third pipe is
|
|
|
@@ -111,6 +141,7 @@ typedef struct kwsysProcessCreateInformation_s
|
|
|
static int kwsysProcessInitialize(kwsysProcess* cp);
|
|
|
static void kwsysProcessCleanup(kwsysProcess* cp, int error);
|
|
|
static void kwsysProcessCleanupDescriptor(int* pfd);
|
|
|
+static int kwsysProcessSetNonBlocking(int fd);
|
|
|
static int kwsysProcessCreate(kwsysProcess* cp, int prIndex,
|
|
|
kwsysProcessCreateInformation* si, int* readEnd);
|
|
|
static void kwsysProcessDestroy(kwsysProcess* cp);
|
|
|
@@ -135,8 +166,12 @@ static pid_t kwsysProcessFork(kwsysProcess* cp,
|
|
|
static void kwsysProcessKill(pid_t process_id);
|
|
|
static int kwsysProcessesAdd(kwsysProcess* cp);
|
|
|
static void kwsysProcessesRemove(kwsysProcess* cp);
|
|
|
+#if KWSYSPE_USE_SIGINFO
|
|
|
static void kwsysProcessesSignalHandler(int signum, siginfo_t* info,
|
|
|
void* ucontext);
|
|
|
+#else
|
|
|
+static void kwsysProcessesSignalHandler(int signum);
|
|
|
+#endif
|
|
|
static char** kwsysProcessParseVerbatimCommand(const char* command);
|
|
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
@@ -190,8 +225,10 @@ struct kwsysProcess_s
|
|
|
/* The number of pipes left open during execution. */
|
|
|
int PipesLeft;
|
|
|
|
|
|
+#if KWSYSPE_USE_SELECT
|
|
|
/* File descriptor set for call to select. */
|
|
|
fd_set PipeSet;
|
|
|
+#endif
|
|
|
|
|
|
/* The number of children still executing. */
|
|
|
int CommandsLeft;
|
|
|
@@ -731,6 +768,15 @@ void kwsysProcess_Execute(kwsysProcess* cp)
|
|
|
kwsysProcessCleanupDescriptor(&si.StdErr);
|
|
|
return;
|
|
|
}
|
|
|
+
|
|
|
+#if !KWSYSPE_USE_SELECT
|
|
|
+ if(!kwsysProcessSetNonBlocking(p[0]))
|
|
|
+ {
|
|
|
+ kwsysProcessCleanup(cp, 1);
|
|
|
+ kwsysProcessCleanupDescriptor(&si.StdErr);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+#endif
|
|
|
}
|
|
|
|
|
|
/* Replace the stderr pipe with a file if requested. In this case
|
|
|
@@ -775,9 +821,24 @@ void kwsysProcess_Execute(kwsysProcess* cp)
|
|
|
/* Create the pipeline of processes. */
|
|
|
{
|
|
|
int readEnd = -1;
|
|
|
+ int failed = 0;
|
|
|
for(i=0; i < cp->NumberOfCommands; ++i)
|
|
|
{
|
|
|
if(!kwsysProcessCreate(cp, i, &si, &readEnd))
|
|
|
+ {
|
|
|
+ failed = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+#if !KWSYSPE_USE_SELECT
|
|
|
+ /* Set the output pipe of the last process to be non-blocking so
|
|
|
+ we can poll it. */
|
|
|
+ if(i == cp->NumberOfCommands-1 && !kwsysProcessSetNonBlocking(readEnd))
|
|
|
+ {
|
|
|
+ failed = 1;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
+ if(failed)
|
|
|
{
|
|
|
kwsysProcessCleanup(cp, 1);
|
|
|
|
|
|
@@ -846,8 +907,11 @@ kwsysEXPORT void kwsysProcess_Disown(kwsysProcess* 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. Ignore the data. */
|
|
|
+ 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. */
|
|
|
@@ -858,6 +922,7 @@ kwsysEXPORT void kwsysProcess_Disown(kwsysProcess* cp)
|
|
|
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]);
|
|
|
@@ -872,20 +937,31 @@ kwsysEXPORT void kwsysProcess_Disown(kwsysProcess* cp)
|
|
|
cp->State = kwsysProcess_State_Disowned;
|
|
|
}
|
|
|
|
|
|
+/*--------------------------------------------------------------------------*/
|
|
|
+typedef struct kwsysProcessWaitData_s
|
|
|
+{
|
|
|
+ int Expired;
|
|
|
+ int PipeId;
|
|
|
+ int User;
|
|
|
+ double* UserTimeout;
|
|
|
+ kwsysProcessTime TimeoutTime;
|
|
|
+} kwsysProcessWaitData;
|
|
|
+static int kwsysProcessWaitForPipe(kwsysProcess* cp, char** data, int* length,
|
|
|
+ kwsysProcessWaitData* wd);
|
|
|
+
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
int kwsysProcess_WaitForData(kwsysProcess* cp, char** data, int* length,
|
|
|
double* userTimeout)
|
|
|
{
|
|
|
- int i;
|
|
|
- int max = -1;
|
|
|
- kwsysProcessTimeNative* timeout = 0;
|
|
|
- kwsysProcessTimeNative timeoutLength;
|
|
|
- kwsysProcessTime timeoutTime;
|
|
|
kwsysProcessTime userStartTime = {0, 0};
|
|
|
- int user = 0;
|
|
|
- int expired = 0;
|
|
|
- int pipeId = kwsysProcess_Pipe_None;
|
|
|
- int numReady = 0;
|
|
|
+ kwsysProcessWaitData wd =
|
|
|
+ {
|
|
|
+ 0,
|
|
|
+ kwsysProcess_Pipe_None,
|
|
|
+ 0,
|
|
|
+ userTimeout,
|
|
|
+ {0, 0}
|
|
|
+ };
|
|
|
|
|
|
/* Make sure we are executing a process. */
|
|
|
if(!cp || cp->State != kwsysProcess_State_Executing || cp->Killed ||
|
|
|
@@ -902,140 +978,20 @@ int kwsysProcess_WaitForData(kwsysProcess* cp, char** data, int* length,
|
|
|
|
|
|
/* Calculate the time at which a timeout will expire, and whether it
|
|
|
is the user or process timeout. */
|
|
|
- user = kwsysProcessGetTimeoutTime(cp, userTimeout, &timeoutTime);
|
|
|
+ wd.User = kwsysProcessGetTimeoutTime(cp, userTimeout,
|
|
|
+ &wd.TimeoutTime);
|
|
|
|
|
|
/* Data can only be available when pipes are open. If the process
|
|
|
is not running, cp->PipesLeft will be 0. */
|
|
|
- while(cp->PipesLeft > 0)
|
|
|
- {
|
|
|
- /* Check for any open pipes with data reported ready by the last
|
|
|
- call to select. According to "man select_tut" we must deal
|
|
|
- with all descriptors reported by a call to select before
|
|
|
- passing them to another select call. */
|
|
|
- for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
|
|
|
- {
|
|
|
- if(cp->PipeReadEnds[i] >= 0 &&
|
|
|
- FD_ISSET(cp->PipeReadEnds[i], &cp->PipeSet))
|
|
|
- {
|
|
|
- kwsysProcess_ssize_t n;
|
|
|
-
|
|
|
- /* 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(((n = read(cp->PipeReadEnds[i], cp->PipeBuffer,
|
|
|
- KWSYSPE_PIPE_BUFFER_SIZE)) < 0) && (errno == EINTR));
|
|
|
- if(n > 0)
|
|
|
- {
|
|
|
- /* We have data on this pipe. */
|
|
|
- if(i == KWSYSPE_PIPE_SIGNAL)
|
|
|
- {
|
|
|
- /* A child process has terminated. */
|
|
|
- kwsysProcessDestroy(cp);
|
|
|
- }
|
|
|
- else if(data && length)
|
|
|
- {
|
|
|
- /* Report this data. */
|
|
|
- *data = cp->PipeBuffer;
|
|
|
- *length = n;
|
|
|
- switch(i)
|
|
|
- {
|
|
|
- case KWSYSPE_PIPE_STDOUT:
|
|
|
- pipeId = kwsysProcess_Pipe_STDOUT; break;
|
|
|
- case KWSYSPE_PIPE_STDERR:
|
|
|
- pipeId = kwsysProcess_Pipe_STDERR; break;
|
|
|
- };
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- /* We are done reading from this pipe. */
|
|
|
- kwsysProcessCleanupDescriptor(&cp->PipeReadEnds[i]);
|
|
|
- --cp->PipesLeft;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /* If we have data, break early. */
|
|
|
- if(pipeId)
|
|
|
- {
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- /* Make sure the set is empty (it should always be empty here
|
|
|
- anyway). */
|
|
|
- FD_ZERO(&cp->PipeSet);
|
|
|
-
|
|
|
- /* Setup a timeout if required. */
|
|
|
- if(timeoutTime.tv_sec < 0)
|
|
|
- {
|
|
|
- timeout = 0;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- timeout = &timeoutLength;
|
|
|
- }
|
|
|
- if(kwsysProcessGetTimeoutLeft(&timeoutTime, user?userTimeout:0, &timeoutLength))
|
|
|
- {
|
|
|
- /* Timeout has already expired. */
|
|
|
- expired = 1;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- /* Add the pipe reading ends that are still open. */
|
|
|
- max = -1;
|
|
|
- for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
|
|
|
- {
|
|
|
- if(cp->PipeReadEnds[i] >= 0)
|
|
|
- {
|
|
|
- FD_SET(cp->PipeReadEnds[i], &cp->PipeSet);
|
|
|
- if(cp->PipeReadEnds[i] > max)
|
|
|
- {
|
|
|
- max = cp->PipeReadEnds[i];
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /* Make sure we have a non-empty set. */
|
|
|
- if(max < 0)
|
|
|
- {
|
|
|
- /* All pipes have closed. Child has terminated. */
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- /* Run select to block until data are available. Repeat call
|
|
|
- until it is not interrupted. */
|
|
|
- while(((numReady = select(max+1, &cp->PipeSet, 0, 0, timeout)) < 0) &&
|
|
|
- (errno == EINTR));
|
|
|
-
|
|
|
- /* Check result of select. */
|
|
|
- if(numReady == 0)
|
|
|
- {
|
|
|
- /* Select's timeout expired. */
|
|
|
- expired = 1;
|
|
|
- break;
|
|
|
- }
|
|
|
- else if(numReady < 0)
|
|
|
- {
|
|
|
- /* Select returned an error. Leave the error description in the
|
|
|
- pipe buffer. */
|
|
|
- strncpy(cp->ErrorMessage, strerror(errno), KWSYSPE_PIPE_BUFFER_SIZE);
|
|
|
-
|
|
|
- /* Kill the children now. */
|
|
|
- kwsysProcess_Kill(cp);
|
|
|
- cp->Killed = 0;
|
|
|
- cp->SelectError = 1;
|
|
|
- }
|
|
|
- }
|
|
|
+ while(cp->PipesLeft > 0 &&
|
|
|
+ !kwsysProcessWaitForPipe(cp, data, length, &wd)) {}
|
|
|
|
|
|
/* Update the user timeout. */
|
|
|
if(userTimeout)
|
|
|
{
|
|
|
kwsysProcessTime userEndTime = kwsysProcessTimeGetCurrent();
|
|
|
kwsysProcessTime difference = kwsysProcessTimeSubtract(userEndTime,
|
|
|
- userStartTime);
|
|
|
+ userStartTime);
|
|
|
double d = kwsysProcessTimeToDouble(difference);
|
|
|
*userTimeout -= d;
|
|
|
if(*userTimeout < 0)
|
|
|
@@ -1045,15 +1001,15 @@ int kwsysProcess_WaitForData(kwsysProcess* cp, char** data, int* length,
|
|
|
}
|
|
|
|
|
|
/* Check what happened. */
|
|
|
- if(pipeId)
|
|
|
+ if(wd.PipeId)
|
|
|
{
|
|
|
/* Data are ready on a pipe. */
|
|
|
- return pipeId;
|
|
|
+ return wd.PipeId;
|
|
|
}
|
|
|
- else if(expired)
|
|
|
+ else if(wd.Expired)
|
|
|
{
|
|
|
/* A timeout has expired. */
|
|
|
- if(user)
|
|
|
+ if(wd.User)
|
|
|
{
|
|
|
/* The user timeout has expired. It has no time left. */
|
|
|
return kwsysProcess_Pipe_Timeout;
|
|
|
@@ -1074,6 +1030,230 @@ int kwsysProcess_WaitForData(kwsysProcess* cp, char** data, int* length,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/*--------------------------------------------------------------------------*/
|
|
|
+static int kwsysProcessWaitForPipe(kwsysProcess* cp, char** data, int* length,
|
|
|
+ kwsysProcessWaitData* wd)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ kwsysProcessTimeNative timeoutLength;
|
|
|
+
|
|
|
+#if KWSYSPE_USE_SELECT
|
|
|
+ int numReady = 0;
|
|
|
+ int max = -1;
|
|
|
+ kwsysProcessTimeNative* timeout = 0;
|
|
|
+
|
|
|
+ /* Check for any open pipes with data reported ready by the last
|
|
|
+ call to select. According to "man select_tut" we must deal
|
|
|
+ with all descriptors reported by a call to select before
|
|
|
+ passing them to another select call. */
|
|
|
+ for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
|
|
|
+ {
|
|
|
+ if(cp->PipeReadEnds[i] >= 0 &&
|
|
|
+ FD_ISSET(cp->PipeReadEnds[i], &cp->PipeSet))
|
|
|
+ {
|
|
|
+ kwsysProcess_ssize_t n;
|
|
|
+
|
|
|
+ /* 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(((n = read(cp->PipeReadEnds[i], cp->PipeBuffer,
|
|
|
+ KWSYSPE_PIPE_BUFFER_SIZE)) < 0) && (errno == EINTR));
|
|
|
+ if(n > 0)
|
|
|
+ {
|
|
|
+ /* We have data on this pipe. */
|
|
|
+ if(i == KWSYSPE_PIPE_SIGNAL)
|
|
|
+ {
|
|
|
+ /* A child process has terminated. */
|
|
|
+ kwsysProcessDestroy(cp);
|
|
|
+ }
|
|
|
+ else if(data && length)
|
|
|
+ {
|
|
|
+ /* Report this data. */
|
|
|
+ *data = cp->PipeBuffer;
|
|
|
+ *length = n;
|
|
|
+ switch(i)
|
|
|
+ {
|
|
|
+ case KWSYSPE_PIPE_STDOUT:
|
|
|
+ wd->PipeId = kwsysProcess_Pipe_STDOUT; break;
|
|
|
+ case KWSYSPE_PIPE_STDERR:
|
|
|
+ wd->PipeId = kwsysProcess_Pipe_STDERR; break;
|
|
|
+ };
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ /* We are done reading from this pipe. */
|
|
|
+ kwsysProcessCleanupDescriptor(&cp->PipeReadEnds[i]);
|
|
|
+ --cp->PipesLeft;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* If we have data, break early. */
|
|
|
+ if(wd->PipeId)
|
|
|
+ {
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Make sure the set is empty (it should always be empty here
|
|
|
+ anyway). */
|
|
|
+ FD_ZERO(&cp->PipeSet);
|
|
|
+
|
|
|
+ /* Setup a timeout if required. */
|
|
|
+ if(wd->TimeoutTime.tv_sec < 0)
|
|
|
+ {
|
|
|
+ timeout = 0;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ timeout = &timeoutLength;
|
|
|
+ }
|
|
|
+ if(kwsysProcessGetTimeoutLeft(&wd->TimeoutTime,
|
|
|
+ wd->User?wd->UserTimeout:0,
|
|
|
+ &timeoutLength))
|
|
|
+ {
|
|
|
+ /* Timeout has already expired. */
|
|
|
+ wd->Expired = 1;
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Add the pipe reading ends that are still open. */
|
|
|
+ max = -1;
|
|
|
+ for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
|
|
|
+ {
|
|
|
+ if(cp->PipeReadEnds[i] >= 0)
|
|
|
+ {
|
|
|
+ FD_SET(cp->PipeReadEnds[i], &cp->PipeSet);
|
|
|
+ if(cp->PipeReadEnds[i] > max)
|
|
|
+ {
|
|
|
+ max = cp->PipeReadEnds[i];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Make sure we have a non-empty set. */
|
|
|
+ if(max < 0)
|
|
|
+ {
|
|
|
+ /* All pipes have closed. Child has terminated. */
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Run select to block until data are available. Repeat call
|
|
|
+ until it is not interrupted. */
|
|
|
+ while(((numReady = select(max+1, &cp->PipeSet, 0, 0, timeout)) < 0) &&
|
|
|
+ (errno == EINTR));
|
|
|
+
|
|
|
+ /* Check result of select. */
|
|
|
+ if(numReady == 0)
|
|
|
+ {
|
|
|
+ /* Select's timeout expired. */
|
|
|
+ wd->Expired = 1;
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ else if(numReady < 0)
|
|
|
+ {
|
|
|
+ /* Select returned an error. Leave the error description in the
|
|
|
+ pipe buffer. */
|
|
|
+ strncpy(cp->ErrorMessage, strerror(errno), KWSYSPE_PIPE_BUFFER_SIZE);
|
|
|
+
|
|
|
+ /* Kill the children now. */
|
|
|
+ kwsysProcess_Kill(cp);
|
|
|
+ cp->Killed = 0;
|
|
|
+ cp->SelectError = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+#else
|
|
|
+ /* Poll pipes for data since we do not have select. */
|
|
|
+ for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
|
|
|
+ {
|
|
|
+ if(cp->PipeReadEnds[i] >= 0)
|
|
|
+ {
|
|
|
+ const int fd = cp->PipeReadEnds[i];
|
|
|
+ int n = read(fd, cp->PipeBuffer, KWSYSPE_PIPE_BUFFER_SIZE);
|
|
|
+ if(n > 0)
|
|
|
+ {
|
|
|
+ /* We have data on this pipe. */
|
|
|
+ if(i == KWSYSPE_PIPE_SIGNAL)
|
|
|
+ {
|
|
|
+ /* A child process has terminated. */
|
|
|
+ kwsysProcessDestroy(cp);
|
|
|
+ }
|
|
|
+ else if(data && length)
|
|
|
+ {
|
|
|
+ /* Report this data. */
|
|
|
+ *data = cp->PipeBuffer;
|
|
|
+ *length = n;
|
|
|
+ switch(i)
|
|
|
+ {
|
|
|
+ case KWSYSPE_PIPE_STDOUT:
|
|
|
+ wd->PipeId = kwsysProcess_Pipe_STDOUT; break;
|
|
|
+ case KWSYSPE_PIPE_STDERR:
|
|
|
+ wd->PipeId = kwsysProcess_Pipe_STDERR; break;
|
|
|
+ };
|
|
|
+ }
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ else if (n == 0) /* EOF */
|
|
|
+ {
|
|
|
+ /* We are done reading from this pipe. */
|
|
|
+ kwsysProcessCleanupDescriptor(&cp->PipeReadEnds[i]);
|
|
|
+ --cp->PipesLeft;
|
|
|
+ }
|
|
|
+ else if (n < 0) /* error */
|
|
|
+ {
|
|
|
+ if((errno != EINTR) && (errno != EAGAIN))
|
|
|
+ {
|
|
|
+ strncpy(cp->ErrorMessage,strerror(errno),
|
|
|
+ KWSYSPE_PIPE_BUFFER_SIZE);
|
|
|
+ /* Kill the children now. */
|
|
|
+ kwsysProcess_Kill(cp);
|
|
|
+ cp->Killed = 0;
|
|
|
+ cp->SelectError = 1;
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* If we have data, break early. */
|
|
|
+ if(wd->PipeId)
|
|
|
+ {
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(kwsysProcessGetTimeoutLeft(&wd->TimeoutTime, wd->User?wd->UserTimeout:0,
|
|
|
+ &timeoutLength))
|
|
|
+ {
|
|
|
+ /* Timeout has already expired. */
|
|
|
+ wd->Expired = 1;
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if((timeoutLength.tv_sec == 0) && (timeoutLength.tv_usec == 0))
|
|
|
+ {
|
|
|
+ /* Timeout has already expired. */
|
|
|
+ wd->Expired = 1;
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Sleep a little, try again. */
|
|
|
+ {
|
|
|
+ unsigned int msec = ((timeoutLength.tv_sec * 1000) +
|
|
|
+ (timeoutLength.tv_usec / 1000));
|
|
|
+ if (msec > 100000)
|
|
|
+ {
|
|
|
+ msec = 100000; /* do not sleep more than 100 milliseconds at a time */
|
|
|
+ }
|
|
|
+ kwsysProcess_usleep(msec);
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout)
|
|
|
{
|
|
|
@@ -1215,7 +1395,9 @@ static int kwsysProcessInitialize(kwsysProcess* cp)
|
|
|
cp->TimeoutExpired = 0;
|
|
|
cp->PipesLeft = 0;
|
|
|
cp->CommandsLeft = 0;
|
|
|
+#if KWSYSPE_USE_SELECT
|
|
|
FD_ZERO(&cp->PipeSet);
|
|
|
+#endif
|
|
|
cp->State = kwsysProcess_State_Starting;
|
|
|
cp->Killed = 0;
|
|
|
cp->ExitException = kwsysProcess_Exception_None;
|
|
|
@@ -1351,6 +1533,17 @@ static void kwsysProcessCleanupDescriptor(int* pfd)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/*--------------------------------------------------------------------------*/
|
|
|
+static int kwsysProcessSetNonBlocking(int fd)
|
|
|
+{
|
|
|
+ int flags = fcntl(fd, F_GETFL);
|
|
|
+ if(flags >= 0)
|
|
|
+ {
|
|
|
+ flags = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
|
|
+ }
|
|
|
+ return flags >= 0;
|
|
|
+}
|
|
|
+
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
static int kwsysProcessCreate(kwsysProcess* cp, int prIndex,
|
|
|
kwsysProcessCreateInformation* si, int* readEnd)
|
|
|
@@ -2260,10 +2453,8 @@ static int kwsysProcessesAdd(kwsysProcess* cp)
|
|
|
|
|
|
/* Switch the pipe to non-blocking mode so that reading a byte can
|
|
|
be an atomic test-and-set. */
|
|
|
- if((oldfl[0] = fcntl(p[0], F_GETFL) < 0) ||
|
|
|
- (oldfl[1] = fcntl(p[1], F_GETFL) < 0) ||
|
|
|
- (fcntl(p[0], F_SETFL, oldfl[0] | O_NONBLOCK) < 0) ||
|
|
|
- (fcntl(p[1], F_SETFL, oldfl[1] | O_NONBLOCK) < 0))
|
|
|
+ if(!kwsysProcessSetNonBlocking(p[0]) ||
|
|
|
+ !kwsysProcessSetNonBlocking(p[1]))
|
|
|
{
|
|
|
return 0;
|
|
|
}
|
|
|
@@ -2327,10 +2518,15 @@ static int kwsysProcessesAdd(kwsysProcess* cp)
|
|
|
interrupted. */
|
|
|
struct sigaction newSigChldAction;
|
|
|
memset(&newSigChldAction, 0, sizeof(struct sigaction));
|
|
|
+#if KWSYSPE_USE_SIGINFO
|
|
|
newSigChldAction.sa_sigaction = kwsysProcessesSignalHandler;
|
|
|
newSigChldAction.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
|
|
|
-#ifdef SA_RESTART
|
|
|
+# ifdef SA_RESTART
|
|
|
newSigChldAction.sa_flags |= SA_RESTART;
|
|
|
+# endif
|
|
|
+#else
|
|
|
+ newSigChldAction.sa_handler = kwsysProcessesSignalHandler;
|
|
|
+ newSigChldAction.sa_flags = SA_NOCLDSTOP;
|
|
|
#endif
|
|
|
while((sigaction(SIGCHLD, &newSigChldAction,
|
|
|
&kwsysProcessesOldSigChldAction) < 0) &&
|
|
|
@@ -2391,14 +2587,21 @@ static void kwsysProcessesRemove(kwsysProcess* cp)
|
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
-static void kwsysProcessesSignalHandler(int signum, siginfo_t* info,
|
|
|
- void* ucontext)
|
|
|
+static void kwsysProcessesSignalHandler(int signum
|
|
|
+#if KWSYSPE_USE_SIGINFO
|
|
|
+ , siginfo_t* info, void* ucontext
|
|
|
+#endif
|
|
|
+ )
|
|
|
{
|
|
|
- /* Signal all process objects that a child has terminated. */
|
|
|
- int i;
|
|
|
(void)signum;
|
|
|
+#if KWSYSPE_USE_SIGINFO
|
|
|
(void)info;
|
|
|
(void)ucontext;
|
|
|
+#endif
|
|
|
+
|
|
|
+ /* Signal all process objects that a child has terminated. */
|
|
|
+ {
|
|
|
+ int i;
|
|
|
for(i=0; i < kwsysProcesses.Count; ++i)
|
|
|
{
|
|
|
/* Set the pipe in a signalled state. */
|
|
|
@@ -2407,6 +2610,21 @@ static void kwsysProcessesSignalHandler(int signum, siginfo_t* info,
|
|
|
read(cp->PipeReadEnds[KWSYSPE_PIPE_SIGNAL], &buf, 1);
|
|
|
write(cp->SignalPipe, &buf, 1);
|
|
|
}
|
|
|
+ }
|
|
|
+
|
|
|
+#if !KWSYSPE_USE_SIGINFO
|
|
|
+ /* Re-Install our handler for SIGCHLD. Repeat call until it is not
|
|
|
+ interrupted. */
|
|
|
+ {
|
|
|
+ struct sigaction newSigChldAction;
|
|
|
+ memset(&newSigChldAction, 0, sizeof(struct sigaction));
|
|
|
+ newSigChldAction.sa_handler = kwsysProcessesSignalHandler;
|
|
|
+ newSigChldAction.sa_flags = SA_NOCLDSTOP;
|
|
|
+ while((sigaction(SIGCHLD, &newSigChldAction,
|
|
|
+ &kwsysProcessesOldSigChldAction) < 0) &&
|
|
|
+ (errno == EINTR));
|
|
|
+ }
|
|
|
+#endif
|
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
@@ -2661,3 +2879,4 @@ static char** kwsysProcessParseVerbatimCommand(const char* command)
|
|
|
/* Return the final command buffer. */
|
|
|
return newCommand;
|
|
|
}
|
|
|
+
|