And persistent_waitpid() to recover the information from the last run. Signed-off-by: Felipe Contreras <felipe.contreras@xxxxxxxxx> --- run-command.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++------ run-command.h | 5 +++++ 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/run-command.c b/run-command.c index 07e27ff..b900c6e 100644 --- a/run-command.c +++ b/run-command.c @@ -226,14 +226,27 @@ static inline void set_cloexec(int fd) fcntl(fd, F_SETFD, flags | FD_CLOEXEC); } -static int wait_or_whine(pid_t pid, const char *argv0) +static pid_t persistent_waitpid(struct child_process *cmd, pid_t pid, int *status) +{ + pid_t waiting; + + if (cmd->last_status.valid) { + *status = cmd->last_status.status; + return pid; + } + + while ((waiting = waitpid(pid, status, 0)) < 0 && errno == EINTR) + ; /* nothing */ + return waiting; +} + +static int wait_or_whine(struct child_process *cmd, pid_t pid, const char *argv0) { int status, code = -1; pid_t waiting; int failed_errno = 0; - while ((waiting = waitpid(pid, &status, 0)) < 0 && errno == EINTR) - ; /* nothing */ + waiting = persistent_waitpid(cmd, pid, &status); if (waiting < 0) { failed_errno = errno; @@ -276,6 +289,8 @@ int start_command(struct child_process *cmd) int failed_errno = failed_errno; char *str; + cmd->last_status.valid = 0; + /* * In case of errors we must keep the promise to close FDs * that have been passed in via ->in and ->out. @@ -437,7 +452,7 @@ fail_pipe: * At this point we know that fork() succeeded, but execvp() * failed. Errors have been reported to our stderr. */ - wait_or_whine(cmd->pid, cmd->argv[0]); + wait_or_whine(cmd, cmd->pid, cmd->argv[0]); failed_errno = errno; cmd->pid = -1; } @@ -542,7 +557,7 @@ fail_pipe: int finish_command(struct child_process *cmd) { - return wait_or_whine(cmd->pid, cmd->argv[0]); + return wait_or_whine(cmd, cmd->pid, cmd->argv[0]); } int run_command(struct child_process *cmd) @@ -553,6 +568,32 @@ int run_command(struct child_process *cmd) return finish_command(cmd); } +int check_command(struct child_process *cmd) +{ + int status; + pid_t waiting; + + if (cmd->last_status.valid) + return 0; + + while ((waiting = waitpid(cmd->pid, &status, WNOHANG)) < 0 && errno == EINTR) + ; /* nothing */ + + if (!waiting) + return 1; + + if (waiting == cmd->pid) { + cmd->last_status.valid = 1; + cmd->last_status.status = status; + return 0; + } + + if (waiting > 0) + die("BUG: waitpid reported a random pid?"); + + return 0; +} + static void prepare_run_command_v_opt(struct child_process *cmd, const char **argv, int opt) @@ -729,7 +770,7 @@ error: int finish_async(struct async *async) { #ifdef NO_PTHREADS - return wait_or_whine(async->pid, "child process"); + return wait_or_whine(cmd, async->pid, "child process"); #else void *ret = (void *)(intptr_t)(-1); diff --git a/run-command.h b/run-command.h index 221ce33..74a733d 100644 --- a/run-command.h +++ b/run-command.h @@ -39,11 +39,16 @@ struct child_process { unsigned stdout_to_stderr:1; unsigned use_shell:1; unsigned clean_on_exit:1; + struct last_status { + unsigned valid:1; + int status; + } last_status; }; int start_command(struct child_process *); int finish_command(struct child_process *); int run_command(struct child_process *); +int check_command(struct child_process *); extern char *find_hook(const char *name); extern int run_hook(const char *index_file, const char *name, ...); -- 1.8.2 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html