2011-09-09 Pedro Alves <pedro@codesourcery.com>

* linux-nat.h (enum resume_kind): New.
	(struct lwp_info) <last_resume_kind>: New field.
	(linux_child_follow_fork): Set last_resume_kind to resume_stop on
	the new lwp.
	(add_lwp): Set last_resume_kind as resume_continue by default.
	(lin_lwp_attach_lwp): Set last_resume_kind as resume_stop.
	(resume_lwp): New, factored out from resume_callback.  Also check
	for pending status in lp->waitstatus.
	(resume_callback): Reimplement.
	(resume_clear_callback): Set last_resume_kind as resume_stop.
	(resume_set_callback): Set last_resume_kind as resume_continue.
	(linux_nat_resume, linux_handle_extended_wait): Set
	last_resume_kind.
	(running_callback): Also check lp->waitstatus for pending events.
	(select_singlestep_lwp_callback): Check that lp->last_resume_kind
	is resume_step.
	(stop_and_resume_callback): Don't re-resume if the core wanted the
	lwp stopped.  Use resume_lwp instead of resume_callback.  Avoid
	using an invalidated pointer.
	(linux_nat_filter_event): Don't discard SIGSTOPs as delayed
	SIGSTOPs if the core wanted the LWP to stop.
	(linux_nat_wait_1) Don't consume a pending SIGSTOP if the core
	wanted the lwp to stop.  If the core wanted the lwp to stop, and
	the lwp stopped with a SIGSTOP, report a TARGET_SIGNAL_0 instead
	of TARGET_SIGNAL_STOP.
	(linux_nat_stop_lwp): Don't synchronously wait for the lwp to stop
	here.  Instead, signal the lwp, and set the last_resume_kind to
	resume_stop.
This commit is contained in:
Pedro Alves 2011-09-09 19:27:50 +00:00
parent f687d03564
commit 25289eb274
3 changed files with 170 additions and 79 deletions

View File

@ -1,3 +1,34 @@
2011-09-09 Pedro Alves <pedro@codesourcery.com>
* linux-nat.h (enum resume_kind): New.
(struct lwp_info) <last_resume_kind>: New field.
(linux_child_follow_fork): Set last_resume_kind to resume_stop on
the new lwp.
(add_lwp): Set last_resume_kind as resume_continue by default.
(lin_lwp_attach_lwp): Set last_resume_kind as resume_stop.
(resume_lwp): New, factored out from resume_callback. Also check
for pending status in lp->waitstatus.
(resume_callback): Reimplement.
(resume_clear_callback): Set last_resume_kind as resume_stop.
(resume_set_callback): Set last_resume_kind as resume_continue.
(linux_nat_resume, linux_handle_extended_wait): Set
last_resume_kind.
(running_callback): Also check lp->waitstatus for pending events.
(select_singlestep_lwp_callback): Check that lp->last_resume_kind
is resume_step.
(stop_and_resume_callback): Don't re-resume if the core wanted the
lwp stopped. Use resume_lwp instead of resume_callback. Avoid
using an invalidated pointer.
(linux_nat_filter_event): Don't discard SIGSTOPs as delayed
SIGSTOPs if the core wanted the LWP to stop.
(linux_nat_wait_1) Don't consume a pending SIGSTOP if the core
wanted the lwp to stop. If the core wanted the lwp to stop, and
the lwp stopped with a SIGSTOP, report a TARGET_SIGNAL_0 instead
of TARGET_SIGNAL_STOP.
(linux_nat_stop_lwp): Don't synchronously wait for the lwp to stop
here. Instead, signal the lwp, and set the last_resume_kind to
resume_stop.
2011-09-09 Pedro Alves <pedro@codesourcery.com>
* linux-nat.c (lin_lwp_attach_lwp): Return 1 (ignore) instead of

View File

@ -701,6 +701,7 @@ holding the child stopped. Try \"set detach-on-fork\" or \
add_thread (inferior_ptid);
child_lp = add_lwp (inferior_ptid);
child_lp->stopped = 1;
child_lp->last_resume_kind = resume_stop;
/* If this is a vfork child, then the address-space is
shared with the parent. */
@ -891,6 +892,7 @@ holding the child stopped. Try \"set detach-on-fork\" or \
add_thread (inferior_ptid);
child_lp = add_lwp (inferior_ptid);
child_lp->stopped = 1;
child_lp->last_resume_kind = resume_stop;
/* If this is a vfork child, then the address-space is shared
with the parent. If we detached from the parent, then we can
@ -1158,6 +1160,7 @@ add_lwp (ptid_t ptid)
memset (lp, 0, sizeof (struct lwp_info));
lp->last_resume_kind = resume_continue;
lp->waitstatus.kind = TARGET_WAITKIND_IGNORE;
lp->ptid = ptid;
@ -1515,6 +1518,7 @@ lin_lwp_attach_lwp (ptid_t ptid)
lp->stopped = 1;
}
lp->last_resume_kind = resume_stop;
restore_child_signals_mask (&prev_mask);
return 0;
}
@ -1829,46 +1833,61 @@ linux_nat_detach (struct target_ops *ops, char *args, int from_tty)
/* Resume LP. */
static void
resume_lwp (struct lwp_info *lp, int step)
{
if (lp->stopped)
{
struct inferior *inf = find_inferior_pid (GET_PID (lp->ptid));
if (inf->vfork_child != NULL)
{
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"RC: Not resuming %s (vfork parent)\n",
target_pid_to_str (lp->ptid));
}
else if (lp->status == 0
&& lp->waitstatus.kind == TARGET_WAITKIND_IGNORE)
{
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"RC: PTRACE_CONT %s, 0, 0 (resuming sibling)\n",
target_pid_to_str (lp->ptid));
linux_ops->to_resume (linux_ops,
pid_to_ptid (GET_LWP (lp->ptid)),
step, TARGET_SIGNAL_0);
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"RC: PTRACE_CONT %s, 0, 0 (resume sibling)\n",
target_pid_to_str (lp->ptid));
lp->stopped = 0;
lp->step = step;
memset (&lp->siginfo, 0, sizeof (lp->siginfo));
lp->stopped_by_watchpoint = 0;
}
else
{
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"RC: Not resuming sibling %s (has pending)\n",
target_pid_to_str (lp->ptid));
}
}
else
{
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"RC: Not resuming sibling %s (not stopped)\n",
target_pid_to_str (lp->ptid));
}
}
static int
resume_callback (struct lwp_info *lp, void *data)
{
struct inferior *inf = find_inferior_pid (GET_PID (lp->ptid));
if (lp->stopped && inf->vfork_child != NULL)
{
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"RC: Not resuming %s (vfork parent)\n",
target_pid_to_str (lp->ptid));
}
else if (lp->stopped && lp->status == 0)
{
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"RC: PTRACE_CONT %s, 0, 0 (resuming sibling)\n",
target_pid_to_str (lp->ptid));
linux_ops->to_resume (linux_ops,
pid_to_ptid (GET_LWP (lp->ptid)),
0, TARGET_SIGNAL_0);
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"RC: PTRACE_CONT %s, 0, 0 (resume sibling)\n",
target_pid_to_str (lp->ptid));
lp->stopped = 0;
lp->step = 0;
memset (&lp->siginfo, 0, sizeof (lp->siginfo));
lp->stopped_by_watchpoint = 0;
}
else if (lp->stopped && debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"RC: Not resuming sibling %s (has pending)\n",
target_pid_to_str (lp->ptid));
else if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"RC: Not resuming sibling %s (not stopped)\n",
target_pid_to_str (lp->ptid));
resume_lwp (lp, 0);
return 0;
}
@ -1876,6 +1895,7 @@ static int
resume_clear_callback (struct lwp_info *lp, void *data)
{
lp->resumed = 0;
lp->last_resume_kind = resume_stop;
return 0;
}
@ -1883,6 +1903,7 @@ static int
resume_set_callback (struct lwp_info *lp, void *data)
{
lp->resumed = 1;
lp->last_resume_kind = resume_continue;
return 0;
}
@ -1922,6 +1943,7 @@ linux_nat_resume (struct target_ops *ops,
/* Remember if we're stepping. */
lp->step = step;
lp->last_resume_kind = step ? resume_step : resume_continue;
/* If we have a pending wait status for this thread, there is no
point in resuming the process. But first make sure that
@ -2286,6 +2308,7 @@ linux_handle_extended_wait (struct lwp_info *lp, int status,
new_lp->stopped = 0;
new_lp->resumed = 1;
new_lp->last_resume_kind = resume_continue;
signo = (status
? target_signal_from_host (WSTOPSIG (status))
@ -2918,7 +2941,10 @@ status_callback (struct lwp_info *lp, void *data)
static int
running_callback (struct lwp_info *lp, void *data)
{
return (lp->stopped == 0 || (lp->status != 0 && lp->resumed));
return (!lp->stopped
|| ((lp->status != 0
|| lp->waitstatus.kind != TARGET_WAITKIND_IGNORE)
&& lp->resumed));
}
/* Count the LWP's that have had events. */
@ -2942,7 +2968,8 @@ count_events_callback (struct lwp_info *lp, void *data)
static int
select_singlestep_lwp_callback (struct lwp_info *lp, void *data)
{
if (lp->step && lp->status != 0)
if (lp->last_resume_kind == resume_step
&& lp->status != 0)
return 1;
else
return 0;
@ -3094,19 +3121,22 @@ resumed_callback (struct lwp_info *lp, void *data)
static int
stop_and_resume_callback (struct lwp_info *lp, void *data)
{
struct lwp_info *ptr;
if (!lp->stopped && !lp->signalled)
if (!lp->stopped)
{
enum resume_kind last_resume_kind = lp->last_resume_kind;
ptid_t ptid = lp->ptid;
stop_callback (lp, NULL);
stop_wait_callback (lp, NULL);
/* Resume if the lwp still exists. */
for (ptr = lwp_list; ptr; ptr = ptr->next)
if (lp == ptr)
{
resume_callback (lp, NULL);
resume_set_callback (lp, NULL);
}
/* 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)
resume_lwp (lp, lp->step);
}
}
return 0;
}
@ -3267,25 +3297,29 @@ linux_nat_filter_event (int lwpid, int status, int options)
"LLW: Delayed SIGSTOP caught for %s.\n",
target_pid_to_str (lp->ptid));
/* This is a delayed SIGSTOP. */
lp->signalled = 0;
registers_changed ();
if (lp->last_resume_kind != resume_stop)
{
/* This is a delayed SIGSTOP. */
linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
registers_changed ();
linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
lp->step, TARGET_SIGNAL_0);
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"LLW: %s %s, 0, 0 (discard SIGSTOP)\n",
lp->step ?
"PTRACE_SINGLESTEP" : "PTRACE_CONT",
target_pid_to_str (lp->ptid));
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"LLW: %s %s, 0, 0 (discard SIGSTOP)\n",
lp->step ?
"PTRACE_SINGLESTEP" : "PTRACE_CONT",
target_pid_to_str (lp->ptid));
lp->stopped = 0;
gdb_assert (lp->resumed);
lp->stopped = 0;
gdb_assert (lp->resumed);
/* Discard the event. */
return NULL;
/* Discard the event. */
return NULL;
}
}
/* Make sure we don't report a SIGINT that we have already displayed
@ -3435,7 +3469,7 @@ retry:
lp = NULL;
}
if (lp && lp->signalled)
if (lp && lp->signalled && lp->last_resume_kind != resume_stop)
{
/* A pending SIGSTOP may interfere with the normal stream of
events. In a typical case where interference is a problem,
@ -3747,7 +3781,10 @@ retry:
iterate_over_lwps (minus_one_ptid, resume_clear_callback, NULL);
}
else
lp->resumed = 0;
{
lp->resumed = 0;
lp->last_resume_kind = resume_stop;
}
if (linux_nat_status_is_event (status))
{
@ -3770,6 +3807,16 @@ retry:
restore_child_signals_mask (&prev_mask);
if (lp->last_resume_kind == resume_stop
&& ourstatus->kind == TARGET_WAITKIND_STOPPED
&& WSTOPSIG (status) == SIGSTOP)
{
/* A thread that has been requested to stop by GDB with
target_stop, and it stopped cleanly, so report as SIG0. The
use of SIGSTOP is an implementation detail. */
ourstatus->value.sig = TARGET_SIGNAL_0;
}
if (ourstatus->kind == TARGET_WAITKIND_EXITED
|| ourstatus->kind == TARGET_WAITKIND_SIGNALLED)
lp->core = -1;
@ -5426,22 +5473,18 @@ linux_nat_stop_lwp (struct lwp_info *lwp, void *data)
target_pid_to_str (lwp->ptid));
if (lwp->last_resume_kind == resume_stop)
{
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"linux-nat: already stopping LWP %ld at "
"GDB's request\n",
ptid_get_lwp (lwp->ptid));
return 0;
}
stop_callback (lwp, NULL);
stop_wait_callback (lwp, NULL);
/* If the lwp exits while we try to stop it, there's nothing
else to do. */
lwp = find_lwp_pid (ptid);
if (lwp == NULL)
return 0;
/* If we didn't collect any signal other than SIGSTOP while
stopping the LWP, push a SIGNAL_0 event. In either case, the
event-loop will end up calling target_wait which will collect
these. */
if (lwp->status == 0)
lwp->status = W_STOPCODE (0);
async_file_mark ();
lwp->last_resume_kind = resume_stop;
}
else
{

View File

@ -22,6 +22,20 @@
#include <signal.h>
/* Ways to "resume" a thread. */
enum resume_kind
{
/* Thread should continue. */
resume_continue,
/* Thread should single-step. */
resume_step,
/* Thread should be stopped. */
resume_stop
};
/* Structure describing an LWP. This is public only for the purposes
of ALL_LWPS; target-specific code should generally not access it
directly. */
@ -52,6 +66,9 @@ struct lwp_info
didn't try to let the LWP run. */
int resumed;
/* The last resume GDB requested on this thread. */
enum resume_kind last_resume_kind;
/* If non-zero, a pending wait status. */
int status;