aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPedro Alves <palves@redhat.com>2011-10-12 12:11:26 +0000
committerPedro Alves <palves@redhat.com>2011-10-12 12:11:26 +0000
commit12d9289a51b52361abaeb31f1fce8ce38c22afd2 (patch)
treec295e0ab756dd617dbbd1f6caab2316f420d7793
parent9ec72168368110c0ca99f41aacb30a7744379ab5 (diff)
downloadgdb-12d9289a51b52361abaeb31f1fce8ce38c22afd2.zip
gdb-12d9289a51b52361abaeb31f1fce8ce38c22afd2.tar.gz
gdb-12d9289a51b52361abaeb31f1fce8ce38c22afd2.tar.bz2
2011-10-12 Pedro Alves <pedro@codesourcery.com>
gdb/ * linux-nat.c (stop_and_resume_callback): Don't re-resume LWPs if the core wanted them stopped, or if they now have a pending event to report.
-rw-r--r--gdb/ChangeLog6
-rw-r--r--gdb/linux-nat.c74
2 files changed, 67 insertions, 13 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 3ce02ce..fb5aded 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,9 @@
+2011-10-12 Pedro Alves <pedro@codesourcery.com>
+
+ * linux-nat.c (stop_and_resume_callback): Don't re-resume LWPs if
+ the core wanted them stopped, or if they now have a pending event
+ to report.
+
2011-10-11 Sterling Augustine <saugustine@google.com>
* dwarf2read.c: Undo inadvertent changes in previous commit.
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index 9a0d9e6..f8a15c9 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -3109,14 +3109,17 @@ resumed_callback (struct lwp_info *lp, void *data)
return lp->resumed;
}
-/* Stop an active thread, verify it still exists, then resume it. */
+/* Stop an active thread, verify it still exists, then resume it. If
+ the thread ends up with a pending status, then it is not resumed,
+ and *DATA (really a pointer to int), is set. */
static int
stop_and_resume_callback (struct lwp_info *lp, void *data)
{
+ int *new_pending_p = data;
+
if (!lp->stopped)
{
- enum resume_kind last_resume_kind = lp->last_resume_kind;
ptid_t ptid = lp->ptid;
stop_callback (lp, NULL);
@@ -3124,23 +3127,57 @@ stop_and_resume_callback (struct lwp_info *lp, void *data)
/* Resume if the lwp still exists, and the core wanted it
running. */
- if (last_resume_kind != resume_stop)
+ lp = find_lwp_pid (ptid);
+ if (lp != NULL)
{
- lp = find_lwp_pid (ptid);
- if (lp)
- resume_lwp (lp, lp->step);
+ if (lp->last_resume_kind == resume_stop
+ && lp->status == 0)
+ {
+ /* The core wanted the LWP to stop. Even if it stopped
+ cleanly (with SIGSTOP), leave the event pending. */
+ if (debug_linux_nat)
+ fprintf_unfiltered (gdb_stdlog,
+ "SARC: core wanted LWP %ld stopped "
+ "(leaving SIGSTOP pending)\n",
+ GET_LWP (lp->ptid));
+ lp->status = W_STOPCODE (SIGSTOP);
+ }
+
+ if (lp->status == 0)
+ {
+ if (debug_linux_nat)
+ fprintf_unfiltered (gdb_stdlog,
+ "SARC: re-resuming LWP %ld\n",
+ GET_LWP (lp->ptid));
+ resume_lwp (lp, lp->step);
+ }
+ else
+ {
+ if (debug_linux_nat)
+ fprintf_unfiltered (gdb_stdlog,
+ "SARC: not re-resuming LWP %ld "
+ "(has pending)\n",
+ GET_LWP (lp->ptid));
+ if (new_pending_p)
+ *new_pending_p = 1;
+ }
}
}
return 0;
}
/* Check if we should go on and pass this event to common code.
- Return the affected lwp if we are, or NULL otherwise. */
+ Return the affected lwp if we are, or NULL otherwise. If we stop
+ all lwps temporarily, we may end up with new pending events in some
+ other lwp. In that case set *NEW_PENDING_P to true. */
+
static struct lwp_info *
-linux_nat_filter_event (int lwpid, int status, int options)
+linux_nat_filter_event (int lwpid, int status, int options, int *new_pending_p)
{
struct lwp_info *lp;
+ *new_pending_p = 0;
+
lp = find_lwp_pid (pid_to_ptid (lwpid));
/* Check for stop events reported by a process we didn't already
@@ -3240,7 +3277,7 @@ linux_nat_filter_event (int lwpid, int status, int options)
{
lp->stopped = 1;
iterate_over_lwps (pid_to_ptid (GET_PID (lp->ptid)),
- stop_and_resume_callback, NULL);
+ stop_and_resume_callback, new_pending_p);
}
if (debug_linux_nat)
@@ -3358,9 +3395,9 @@ linux_nat_wait_1 (struct target_ops *ops,
{
static sigset_t prev_mask;
enum resume_kind last_resume_kind;
- struct lwp_info *lp = NULL;
- int options = 0;
- int status = 0;
+ struct lwp_info *lp;
+ int options;
+ int status;
pid_t pid;
if (debug_linux_nat)
@@ -3397,6 +3434,7 @@ linux_nat_wait_1 (struct target_ops *ops,
retry:
lp = NULL;
status = 0;
+ options = 0;
/* Make sure that of those LWPs we want to get an event from, there
is at least one LWP that has been resumed. If there's none, just
@@ -3527,6 +3565,10 @@ retry:
if (lwpid > 0)
{
+ /* If this is true, then we paused LWPs momentarily, and may
+ now have pending events to handle. */
+ int new_pending;
+
gdb_assert (pid == -1 || lwpid == pid);
if (debug_linux_nat)
@@ -3536,7 +3578,7 @@ retry:
(long) lwpid, status_to_str (status));
}
- lp = linux_nat_filter_event (lwpid, status, options);
+ lp = linux_nat_filter_event (lwpid, status, options, &new_pending);
/* STATUS is now no longer valid, use LP->STATUS instead. */
status = 0;
@@ -3616,6 +3658,9 @@ retry:
store_waitstatus (&lp->waitstatus, lp->status);
}
+ if (new_pending)
+ goto retry;
+
/* Keep looking. */
lp = NULL;
continue;
@@ -3625,6 +3670,9 @@ retry:
break;
else
{
+ if (new_pending)
+ goto retry;
+
if (pid == -1)
{
/* waitpid did return something. Restart over. */