diff options
-rw-r--r-- | gdb/ChangeLog | 6 | ||||
-rw-r--r-- | gdb/linux-nat.c | 68 |
2 files changed, 50 insertions, 24 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index e451cb6..ec2ef4e 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,11 @@ 2011-10-10 Pedro Alves <pedro@codesourcery.com> + * linux-nat.c (linux_handle_extended_wait): Don't resume the new + new clone lwp if the core asked it to stop. Don't pass on + unexpected signals to the new clone; leave them pending instead. + +2011-10-10 Pedro Alves <pedro@codesourcery.com> + * linux-nat.c (resume_lwp): Remove redundant debug output. 2011-10-10 Pedro Alves <pedro@codesourcery.com> diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c index 099f8ed..0cb4096 100644 --- a/gdb/linux-nat.c +++ b/gdb/linux-nat.c @@ -2237,7 +2237,29 @@ linux_handle_extended_wait (struct lwp_info *lp, int status, new_lp->signalled = 1; } else - status = 0; + { + struct thread_info *tp; + + /* When we stop for an event in some other thread, and + pull the thread list just as this thread has cloned, + we'll have seen the new thread in the thread_db list + before handling the CLONE event (glibc's + pthread_create adds the new thread to the thread list + before clone'ing, and has the kernel fill in the + thread's tid on the clone call with + CLONE_PARENT_SETTID). If that happened, and the core + had requested the new thread to stop, we'll have + killed it with SIGSTOP. But since SIGSTOP is not an + RT signal, it can only be queued once. We need to be + careful to not resume the LWP if we wanted it to + stop. In that case, we'll leave the SIGSTOP pending. + It will later be reported as TARGET_SIGNAL_0. */ + tp = find_thread_ptid (new_lp->ptid); + if (tp != NULL && tp->stop_requested) + new_lp->last_resume_kind = resume_stop; + else + status = 0; + } if (non_stop) { @@ -2266,39 +2288,37 @@ linux_handle_extended_wait (struct lwp_info *lp, int status, } } + if (status != 0) + { + /* We created NEW_LP so it cannot yet contain STATUS. */ + gdb_assert (new_lp->status == 0); + + /* Save the wait status to report later. */ + if (debug_linux_nat) + fprintf_unfiltered (gdb_stdlog, + "LHEW: waitpid of new LWP %ld, " + "saving status %s\n", + (long) GET_LWP (new_lp->ptid), + status_to_str (status)); + new_lp->status = status; + } + /* Note the need to use the low target ops to resume, to handle resuming with PT_SYSCALL if we have syscall catchpoints. */ if (!stopping) { - enum target_signal signo; - - new_lp->stopped = 0; new_lp->resumed = 1; - new_lp->last_resume_kind = resume_continue; - signo = (status - ? target_signal_from_host (WSTOPSIG (status)) - : TARGET_SIGNAL_0); - - linux_ops->to_resume (linux_ops, pid_to_ptid (new_pid), - 0, signo); - } - else - { - if (status != 0) + if (status == 0) { - /* We created NEW_LP so it cannot yet contain STATUS. */ - gdb_assert (new_lp->status == 0); - - /* Save the wait status to report later. */ if (debug_linux_nat) fprintf_unfiltered (gdb_stdlog, - "LHEW: waitpid of new LWP %ld, " - "saving status %s\n", - (long) GET_LWP (new_lp->ptid), - status_to_str (status)); - new_lp->status = status; + "LHEW: resuming new LWP %ld\n", + GET_LWP (new_lp->ptid)); + linux_ops->to_resume (linux_ops, pid_to_ptid (new_pid), + 0, TARGET_SIGNAL_0); + new_lp->stopped = 0; } } |