diff options
-rw-r--r-- | gdb/ChangeLog | 9 | ||||
-rw-r--r-- | gdb/defs.h | 4 | ||||
-rw-r--r-- | gdb/ser-pipe.c | 25 | ||||
-rw-r--r-- | gdb/utils.c | 73 |
4 files changed, 106 insertions, 5 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 0cce947..f9d4391 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,12 @@ +2011-12-14 Doug Evans <dje@google.com> + + * defs.h (wait_to_die_with_timeout): Declare. + * utils.c: #include "gdb_wait.h". + (sigalrm_handler, wait_to_die_with_timeout): New functions. + * ser-pipe.c: Don't #include "gdb_wait.h". + (pipe_close): Give child a chance to die on its own after closing + its stdin before SIGTERM'ing it. + 2011-12-14 Joel Brobecker <brobecker@adacore.com> Tom Tromey <tromey@redhat.com> @@ -440,6 +440,10 @@ extern struct cleanup *make_bpstat_clear_actions_cleanup (void); extern int producer_is_gcc_ge_4 (const char *producer); +#ifdef HAVE_WAITPID +extern pid_t wait_to_die_with_timeout (pid_t pid, int *status, int timeout); +#endif + /* Annotation stuff. */ diff --git a/gdb/ser-pipe.c b/gdb/ser-pipe.c index 9bf0d04..7f71987 100644 --- a/gdb/ser-pipe.c +++ b/gdb/ser-pipe.c @@ -31,7 +31,6 @@ #include <sys/time.h> #include <fcntl.h> #include "gdb_string.h" -#include "gdb_wait.h" #include <signal.h> @@ -163,14 +162,30 @@ pipe_close (struct serial *scb) if (state != NULL) { - int status; - kill (state->pid, SIGTERM); -#ifdef HAVE_WAITPID + int wait_result, status; + + /* Don't kill the task right away, give it a chance to shut down cleanly. + But don't wait forever though. */ +#define PIPE_CLOSE_TIMEOUT 5 + /* Assume the program will exit after SIGTERM. Might be useful to print any remaining stderr output from scb->error_fd while waiting. */ - waitpid (state->pid, &status, 0); +#define SIGTERM_TIMEOUT INT_MAX + + wait_result = -1; +#ifdef HAVE_WAITPID + wait_result = wait_to_die_with_timeout (state->pid, &status, + PIPE_CLOSE_TIMEOUT); #endif + if (wait_result == -1) + { + kill (state->pid, SIGTERM); +#ifdef HAVE_WAITPID + wait_to_die_with_timeout (state->pid, &status, SIGTERM_TIMEOUT); +#endif + } + if (scb->error_fd != -1) close (scb->error_fd); scb->error_fd = -1; diff --git a/gdb/utils.c b/gdb/utils.c index cc93915..16405d1 100644 --- a/gdb/utils.c +++ b/gdb/utils.c @@ -24,6 +24,7 @@ #include "gdb_assert.h" #include <ctype.h> #include "gdb_string.h" +#include "gdb_wait.h" #include "event-top.h" #include "exceptions.h" #include "gdbthread.h" @@ -3784,6 +3785,78 @@ producer_is_gcc_ge_4 (const char *producer) return minor; } +#ifdef HAVE_WAITPID + +#ifdef SIGALRM + +/* SIGALRM handler for waitpid_with_timeout. */ + +static void +sigalrm_handler (int signo) +{ + /* Nothing to do. */ +} + +#endif + +/* Wrapper to wait for child PID to die with TIMEOUT. + TIMEOUT is the time to stop waiting in seconds. + If TIMEOUT is zero, pass WNOHANG to waitpid. + Returns PID if it was successfully waited for, otherwise -1. + + Timeouts are currently implemented with alarm and SIGALRM. + If the host does not support them, this waits "forever". + It would be odd though for a host to have waitpid and not SIGALRM. */ + +pid_t +wait_to_die_with_timeout (pid_t pid, int *status, int timeout) +{ + pid_t waitpid_result; + + gdb_assert (pid > 0); + gdb_assert (timeout >= 0); + + if (timeout > 0) + { +#ifdef SIGALRM +#if defined (HAVE_SIGACTION) && defined (SA_RESTART) + struct sigaction sa, old_sa; + + sa.sa_handler = sigalrm_handler; + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + sigaction (SIGALRM, &sa, &old_sa); +#else + void (*ofunc) (); + + ofunc = (void (*)()) signal (SIGALRM, sigalrm_handler); +#endif + + alarm (timeout); +#endif + + waitpid_result = waitpid (pid, status, 0); + +#ifdef SIGALRM + alarm (0); +#if defined (HAVE_SIGACTION) && defined (SA_RESTART) + sigaction (SIGALRM, &old_sa, NULL); +#else + signal (SIGALRM, ofunc); +#endif +#endif + } + else + waitpid_result = waitpid (pid, status, WNOHANG); + + if (waitpid_result == pid) + return pid; + else + return -1; +} + +#endif /* HAVE_WAITPID */ + /* Provide a prototype to silence -Wmissing-prototypes. */ extern initialize_file_ftype _initialize_utils; |