This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
linux-nat.c:stop_and_resume_callback - handle ending up with pending events
- From: Pedro Alves <pedro at codesourcery dot com>
- To: gdb-patches at sourceware dot org
- Date: Wed, 12 Oct 2011 13:19:37 +0100
- Subject: linux-nat.c:stop_and_resume_callback - handle ending up with pending events
stop_and_resume_callback is resuming the lwp even if after
stopping it momentarily the lwp ended up with a pending event, which
is obviously bad. This stops it doing so. A little extra cared if
needed -- if we do have new pending events to handle after
linux_nat_filter_event, then we need to break from the loop and restart
over (as pending events aren't handled within the loop, but before.
Tested on x86_64-linux and applied.
--
Pedro Alves
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.
(linux_nat_filter_event): New parameter `new_pending_p'. Pass it
down to stop_and_resume_callback.
(linux_nat_wait_1): Always clear `options' when retrying. Handle
having new pending events after calling linux_nat_filter_event.
---
gdb/linux-nat.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++----------
1 file changed, 61 insertions(+), 13 deletions(-)
Index: src/gdb/linux-nat.c
===================================================================
--- src.orig/gdb/linux-nat.c 2011-10-12 12:53:26.238592563 +0100
+++ src/gdb/linux-nat.c 2011-10-12 12:57:11.058592522 +0100
@@ -3109,14 +3109,17 @@ resumed_callback (struct lwp_info *lp, v
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_inf
/* 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 s
{
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. */