aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog6
-rw-r--r--gdb/linux-nat.c68
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;
}
}