2008-10-23  Pedro Alves  <pedro@codesourcery.com>

	* defs.h: Mention ptid_is_pid.
	* inferior.h (ptid_is_pid): Declare.
	* gdbthread.h (struct thread_info) <stop_requested>: New field.
	(set_stop_requested): Declare.
	* infcmd.c (interrupt_target_1): Call set_stop_requested.
	* infrun.c (clear_proceed_status): Clear stop_requested.
	(infrun_thread_stop_requested_callback,
	infrun_thread_stop_requested): New.
	(handle_inferior_event): If a TARGET_SIGNAL_TRAP is reported on a
	thread that had an explicit stop request, pretend we got a
	TARGET_SIGNAL_0.  Always stop if the thread had an explicit stop
	request.
	(print_stop_reason): In the SIGNAL_RECEIVED case, if we're not
	outputting to MI, and we got a TARGET_SIGNAL_0, print "# Stopped",
	instead of mentioning signal 0.
	(ptid_is_pid): New.
	* thread.c (set_stop_requested): New.

	* linux-nat.c (queued_waitpid): Rename to ...
	(queued_waitpid_1): ... this.  Add `peek' argument.  Handle it.
	(queued_waitpid): New, as wrapper to queued_waitpid_1.
	(push_waitpid): Push the SIGTRAP to the local event queue, to the
	kernel's.
	(send_sigint_callback): Delete.
	(linux_nat_stop_lwp): New.
	(linux_nat_stop): Use it.

gdb/doc/
2008-10-23  Pedro Alves  <pedro@codesourcery.com>

	* observer.texi (thread_stop_requested): New.

gdb/testsuite/
2008-10-23  Pedro Alves  <pedro@codesourcery.com>

	* lib/mi-support.exp (mi_expect_interrupt): Expect signal 0
	instead of SIGINT.
This commit is contained in:
Pedro Alves 2008-10-23 23:11:21 +00:00
parent 3c0ed2996e
commit 252fbfc86a
12 changed files with 351 additions and 50 deletions

View file

@ -1,3 +1,32 @@
2008-10-23 Pedro Alves <pedro@codesourcery.com>
* defs.h: Mention ptid_is_pid.
* inferior.h (ptid_is_pid): Declare.
* gdbthread.h (struct thread_info) <stop_requested>: New field.
(set_stop_requested): Declare.
* infcmd.c (interrupt_target_1): Call set_stop_requested.
* infrun.c (clear_proceed_status): Clear stop_requested.
(infrun_thread_stop_requested_callback,
infrun_thread_stop_requested): New.
(handle_inferior_event): If a TARGET_SIGNAL_TRAP is reported on a
thread that had an explicit stop request, pretend we got a
TARGET_SIGNAL_0. Always stop if the thread had an explicit stop
request.
(print_stop_reason): In the SIGNAL_RECEIVED case, if we're not
outputting to MI, and we got a TARGET_SIGNAL_0, print "# Stopped",
instead of mentioning signal 0.
(ptid_is_pid): New.
* thread.c (set_stop_requested): New.
* linux-nat.c (queued_waitpid): Rename to ...
(queued_waitpid_1): ... this. Add `peek' argument. Handle it.
(queued_waitpid): New, as wrapper to queued_waitpid_1.
(push_waitpid): Push the SIGTRAP to the local event queue, to the
kernel's.
(send_sigint_callback): Delete.
(linux_nat_stop_lwp): New.
(linux_nat_stop): Use it.
2008-10-23 Paul Pluzhnikov <ppluzhnikov@google.com>
* python/python-value (valpy_getitem): Fix heap corruption.

View file

@ -752,6 +752,7 @@ enum val_prettyprint
ptid_get_lwp - Fetch the lwp component of a ptid.
ptid_get_tid - Fetch the tid component of a ptid.
ptid_equal - Test to see if two ptids are equal.
ptid_is_pid - Test to see if this ptid represents a process id.
Please do NOT access the struct ptid members directly (except, of
course, in the implementation of the above ptid manipulation

View file

@ -1,3 +1,7 @@
2008-10-23 Pedro Alves <pedro@codesourcery.com>
* observer.texi (thread_stop_requested): New.
2008-10-22 Joel Brobecker <brobecker@adacore.com>
* gdb.texinfo (Ada Tasks, Ada Tasks and Core Files): New nodes.

View file

@ -135,6 +135,14 @@ The thread specified by @var{t} has been created.
The thread specified by @var{t} has exited.
@end deftypefun
@deftypefun void thread_stop_requested (ptid_t @var{ptid})
An explicit stop request was issued to @var{ptid}. If @var{ptid}
equals @var{minus_one_ptid}, the request applied to all threads. If
@code{ptid_is_pid(ptid)} returns true, the request applied to all
threads of the process pointed at by @var{ptid}. Otherwise, the
request applied to the single thread pointed at by @var{ptid}.
@end deftypefun
@deftypefun void target_resumed (ptid_t @var{ptid})
The target was resumed. The @var{ptid} parameter specifies which
thread was resume, and may be RESUME_ALL if all threads are resumed.

View file

@ -168,6 +168,9 @@ struct thread_info
at. */
bpstat stop_bpstat;
/* True if this thread has been explicitly requested to stop. */
int stop_requested;
/* Private data used by the target vector implementation. */
struct private_thread_info *private;
};
@ -239,6 +242,13 @@ extern void switch_to_thread (ptid_t ptid);
If PIDGET (PTID) is -1, marks all threads. */
extern void set_running (ptid_t ptid, int running);
/* Marks or clears thread(s) PTID as having been requested to stop.
If PTID is MINUS_ONE_PTID, applies to all threads. If
ptid_is_pid(PTID) is true, applies to all threads of the process
pointed at by PTID. If STOP, then the THREAD_STOP_REQUESTED
observer is called with PTID as argument. */
extern void set_stop_requested (ptid_t ptid, int stop);
/* NOTE: Since the thread state is not a boolean, most times, you do
not want to check it with negation. If you really want to check if
the thread is stopped,

View file

@ -2245,6 +2245,15 @@ interrupt_target_1 (int all_threads)
else
ptid = inferior_ptid;
target_stop (ptid);
/* Tag the thread as having been explicitly requested to stop, so
other parts of gdb know not to resume this thread automatically,
if it was stopped due to an internal event. Limit this to
non-stop mode, as when debugging a multi-threaded application in
all-stop mode, we will only get one stop event --- it's undefined
which thread will report the event. */
if (non_stop)
set_stop_requested (ptid, 1);
}
/* Stop the execution of the target while running in async mode, in

View file

@ -89,6 +89,9 @@ long ptid_get_tid (ptid_t ptid);
/* Compare two ptids to see if they are equal */
extern int ptid_equal (ptid_t p1, ptid_t p2);
/* Return true if PTID represents a process id. */
extern int ptid_is_pid (ptid_t ptid);
/* Save value of inferior_ptid so that it may be restored by
a later call to do_cleanups(). Returns the struct cleanup
pointer needed for later doing the cleanup. */

View file

@ -1147,6 +1147,7 @@ clear_proceed_status (void)
tp->step_range_end = 0;
tp->step_frame_id = null_frame_id;
tp->step_over_calls = STEP_OVER_UNDEBUGGABLE;
tp->stop_requested = 0;
tp->stop_step = 0;
@ -1528,6 +1529,100 @@ static void keep_going (struct execution_control_state *ecs);
static void print_stop_reason (enum inferior_stop_reason stop_reason,
int stop_info);
/* Callback for iterate over threads. If the thread is stopped, but
the user/frontend doesn't know about that yet, go through
normal_stop, as if the thread had just stopped now. ARG points at
a ptid. If PTID is MINUS_ONE_PTID, applies to all threads. If
ptid_is_pid(PTID) is true, applies to all threads of the process
pointed at by PTID. Otherwise, apply only to the thread pointed by
PTID. */
static int
infrun_thread_stop_requested_callback (struct thread_info *info, void *arg)
{
ptid_t ptid = * (ptid_t *) arg;
if ((ptid_equal (info->ptid, ptid)
|| ptid_equal (minus_one_ptid, ptid)
|| (ptid_is_pid (ptid)
&& ptid_get_pid (ptid) == ptid_get_pid (info->ptid)))
&& is_running (info->ptid)
&& !is_executing (info->ptid))
{
struct cleanup *old_chain;
struct execution_control_state ecss;
struct execution_control_state *ecs = &ecss;
memset (ecs, 0, sizeof (*ecs));
old_chain = make_cleanup_restore_current_thread ();
switch_to_thread (info->ptid);
/* Go through handle_inferior_event/normal_stop, so we always
have consistent output as if the stop event had been
reported. */
ecs->ptid = info->ptid;
ecs->event_thread = find_thread_pid (info->ptid);
ecs->ws.kind = TARGET_WAITKIND_STOPPED;
ecs->ws.value.sig = TARGET_SIGNAL_0;
handle_inferior_event (ecs);
if (!ecs->wait_some_more)
{
struct thread_info *tp;
normal_stop ();
/* Finish off the continuations. The continations
themselves are responsible for realising the thread
didn't finish what it was supposed to do. */
tp = inferior_thread ();
do_all_intermediate_continuations_thread (tp);
do_all_continuations_thread (tp);
}
do_cleanups (old_chain);
}
return 0;
}
/* This function is attached as a "thread_stop_requested" observer.
Cleanup local state that assumed the PTID was to be resumed, and
report the stop to the frontend. */
void
infrun_thread_stop_requested (ptid_t ptid)
{
struct displaced_step_request *it, *next, *prev = NULL;
/* PTID was requested to stop. Remove it from the displaced
stepping queue, so we don't try to resume it automatically. */
for (it = displaced_step_request_queue; it; it = next)
{
next = it->next;
if (ptid_equal (it->ptid, ptid)
|| ptid_equal (minus_one_ptid, ptid)
|| (ptid_is_pid (ptid)
&& ptid_get_pid (ptid) == ptid_get_pid (it->ptid)))
{
if (displaced_step_request_queue == it)
displaced_step_request_queue = it->next;
else
prev->next = it->next;
xfree (it);
}
else
prev = it;
}
iterate_over_threads (infrun_thread_stop_requested_callback, &ptid);
}
/* Callback for iterate_over_threads. */
static int
@ -2279,11 +2374,21 @@ targets should add new threads to the thread list themselves in non-stop mode.")
return;
}
/* Do we need to clean up the state of a thread that has completed a
displaced single-step? (Doing so usually affects the PC, so do
it here, before we set stop_pc.) */
if (ecs->ws.kind == TARGET_WAITKIND_STOPPED)
displaced_step_fixup (ecs->ptid, ecs->event_thread->stop_signal);
{
/* Do we need to clean up the state of a thread that has
completed a displaced single-step? (Doing so usually affects
the PC, so do it here, before we set stop_pc.) */
displaced_step_fixup (ecs->ptid, ecs->event_thread->stop_signal);
/* If we either finished a single-step or hit a breakpoint, but
the user wanted this thread to be stopped, pretend we got a
SIG0 (generic unsignaled stop). */
if (ecs->event_thread->stop_requested
&& ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP)
ecs->event_thread->stop_signal = TARGET_SIGNAL_0;
}
stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid));
@ -2779,9 +2884,11 @@ process_event_stop_test:
target_terminal_ours_for_output ();
print_stop_reason (SIGNAL_RECEIVED, ecs->event_thread->stop_signal);
}
/* Always stop on signals if we're just gaining control of the
program. */
/* Always stop on signals if we're either just gaining control
of the program, or the user explicitly requested this thread
to remain stopped. */
if (stop_soon != NO_STOP_QUIETLY
|| ecs->event_thread->stop_requested
|| signal_stop_state (ecs->event_thread->stop_signal))
{
stop_stepping (ecs);
@ -3891,22 +3998,36 @@ print_stop_reason (enum inferior_stop_reason stop_reason, int stop_info)
return_child_result_value = stop_info;
break;
case SIGNAL_RECEIVED:
/* Signal received. The signal table tells us to print about
it. */
/* Signal received. The signal table tells us to print about
it. */
annotate_signal ();
ui_out_text (uiout, "\nProgram received signal ");
annotate_signal_name ();
if (ui_out_is_mi_like_p (uiout))
ui_out_field_string
(uiout, "reason", async_reason_lookup (EXEC_ASYNC_SIGNAL_RECEIVED));
ui_out_field_string (uiout, "signal-name",
target_signal_to_name (stop_info));
annotate_signal_name_end ();
ui_out_text (uiout, ", ");
annotate_signal_string ();
ui_out_field_string (uiout, "signal-meaning",
target_signal_to_string (stop_info));
annotate_signal_string_end ();
if (stop_info == TARGET_SIGNAL_0 && !ui_out_is_mi_like_p (uiout))
{
struct thread_info *t = inferior_thread ();
ui_out_text (uiout, "\n[");
ui_out_field_string (uiout, "thread-name",
target_pid_to_str (t->ptid));
ui_out_field_fmt (uiout, "thread-id", "] #%d", t->num);
ui_out_text (uiout, " stopped");
}
else
{
ui_out_text (uiout, "\nProgram received signal ");
annotate_signal_name ();
if (ui_out_is_mi_like_p (uiout))
ui_out_field_string
(uiout, "reason", async_reason_lookup (EXEC_ASYNC_SIGNAL_RECEIVED));
ui_out_field_string (uiout, "signal-name",
target_signal_to_name (stop_info));
annotate_signal_name_end ();
ui_out_text (uiout, ", ");
annotate_signal_string ();
ui_out_field_string (uiout, "signal-meaning",
target_signal_to_string (stop_info));
annotate_signal_string_end ();
}
ui_out_text (uiout, ".\n");
break;
case NO_HISTORY:
@ -4817,6 +4938,19 @@ ptid_equal (ptid_t ptid1, ptid_t ptid2)
&& ptid1.tid == ptid2.tid);
}
/* Returns true if PTID represents a process. */
int
ptid_is_pid (ptid_t ptid)
{
if (ptid_equal (minus_one_ptid, ptid))
return 0;
if (ptid_equal (null_ptid, ptid))
return 0;
return (ptid_get_lwp (ptid) == 0 && ptid_get_tid (ptid) == 0);
}
/* restore_inferior_ptid() will be used by the cleanup machinery
to restore the inferior_ptid value saved in a call to
save_inferior_ptid(). */
@ -5134,4 +5268,5 @@ Options are 'forward' or 'reverse'."),
displaced_step_ptid = null_ptid;
observer_attach_thread_ptid_changed (infrun_thread_ptid_changed);
observer_attach_thread_stop_requested (infrun_thread_stop_requested);
}

View file

@ -316,7 +316,6 @@ static void linux_nat_async (void (*callback)
static int linux_nat_async_mask (int mask);
static int kill_lwp (int lwpid, int signo);
static int send_sigint_callback (struct lwp_info *lp, void *data);
static int stop_callback (struct lwp_info *lp, void *data);
/* Captures the result of a successful waitpid call, along with the
@ -333,8 +332,12 @@ struct waitpid_result
in the async SIGCHLD handler. */
static struct waitpid_result *waitpid_queue = NULL;
/* Similarly to `waitpid', but check the local event queue instead of
querying the kernel queue. If PEEK, don't remove the event found
from the queue. */
static int
queued_waitpid (int pid, int *status, int flags)
queued_waitpid_1 (int pid, int *status, int flags, int peek)
{
struct waitpid_result *msg = waitpid_queue, *prev = NULL;
@ -370,12 +373,6 @@ QWPID: linux_nat_async_events_state(%d), linux_nat_num_queued_events(%d)\n",
{
int pid;
if (prev)
prev->next = msg->next;
else
waitpid_queue = msg->next;
msg->next = NULL;
if (status)
*status = msg->status;
pid = msg->pid;
@ -383,7 +380,17 @@ QWPID: linux_nat_async_events_state(%d), linux_nat_num_queued_events(%d)\n",
if (debug_linux_nat_async)
fprintf_unfiltered (gdb_stdlog, "QWPID: pid(%d), status(%x)\n",
pid, msg->status);
xfree (msg);
if (!peek)
{
if (prev)
prev->next = msg->next;
else
waitpid_queue = msg->next;
msg->next = NULL;
xfree (msg);
}
return pid;
}
@ -396,6 +403,14 @@ QWPID: linux_nat_async_events_state(%d), linux_nat_num_queued_events(%d)\n",
return -1;
}
/* Similarly to `waitpid', but check the local event queue. */
static int
queued_waitpid (int pid, int *status, int flags)
{
return queued_waitpid_1 (pid, status, flags, 0);
}
static void
push_waitpid (int pid, int status, int options)
{
@ -2200,11 +2215,11 @@ stop_wait_callback (struct lwp_info *lp, void *data)
/* There was no gdb breakpoint set at pc. Put
the event back in the queue. */
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"SWC: kill %s, %s\n",
target_pid_to_str (lp->ptid),
status_to_str ((int) status));
kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (status));
fprintf_unfiltered (gdb_stdlog, "\
SWC: leaving SIGTRAP in local queue of %s\n", target_pid_to_str (lp->ptid));
push_waitpid (GET_LWP (lp->ptid),
W_STOPCODE (SIGTRAP),
lp->cloned ? __WCLONE : 0);
}
}
else
@ -4368,15 +4383,76 @@ linux_nat_async (void (*callback) (enum inferior_event_type event_type,
return;
}
/* Stop an LWP, and push a TARGET_SIGNAL_0 stop status if no other
event came out. */
static int
send_sigint_callback (struct lwp_info *lp, void *data)
linux_nat_stop_lwp (struct lwp_info *lwp, void *data)
{
/* Use is_running instead of !lp->stopped, because the lwp may be
stopped due to an internal event, and we want to interrupt it in
that case too. What we want is to check if the thread is stopped
from the point of view of the user. */
if (is_running (lp->ptid))
kill_lwp (GET_LWP (lp->ptid), SIGINT);
ptid_t ptid = * (ptid_t *) data;
if (ptid_equal (lwp->ptid, ptid)
|| ptid_equal (minus_one_ptid, ptid)
|| (ptid_is_pid (ptid)
&& ptid_get_pid (ptid) == ptid_get_pid (lwp->ptid)))
{
if (!lwp->stopped)
{
int pid, status;
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"LNSL: running -> suspending %s\n",
target_pid_to_str (lwp->ptid));
/* Peek once, to check if we've already waited for this
LWP. */
pid = queued_waitpid_1 (ptid_get_lwp (lwp->ptid), &status,
lwp->cloned ? __WCLONE : 0, 1 /* peek */);
if (pid == -1)
{
ptid_t ptid = lwp->ptid;
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;
pid = queued_waitpid_1 (ptid_get_lwp (lwp->ptid), &status,
lwp->cloned ? __WCLONE : 0,
1 /* peek */);
}
/* 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 (pid == -1)
push_waitpid (ptid_get_lwp (lwp->ptid), W_STOPCODE (0),
lwp->cloned ? __WCLONE : 0);
}
else
{
/* Already known to be stopped; do nothing. */
if (debug_linux_nat)
{
if (find_thread_pid (lwp->ptid)->stop_requested)
fprintf_unfiltered (gdb_stdlog, "\
LNSL: already stopped/stop_requested %s\n",
target_pid_to_str (lwp->ptid));
else
fprintf_unfiltered (gdb_stdlog, "\
LNSL: already stopped/no stop_requested yet %s\n",
target_pid_to_str (lwp->ptid));
}
}
}
return 0;
}
@ -4385,13 +4461,9 @@ linux_nat_stop (ptid_t ptid)
{
if (non_stop)
{
if (ptid_equal (ptid, minus_one_ptid))
iterate_over_lwps (send_sigint_callback, &ptid);
else
{
struct lwp_info *lp = find_lwp_pid (ptid);
send_sigint_callback (lp, NULL);
}
linux_nat_async_events (sigchld_sync);
iterate_over_lwps (linux_nat_stop_lwp, &ptid);
target_async (inferior_event_handler, 0);
}
else
linux_ops->to_stop (ptid);

View file

@ -1,3 +1,8 @@
2008-10-23 Pedro Alves <pedro@codesourcery.com>
* lib/mi-support.exp (mi_expect_interrupt): Expect signal 0
instead of SIGINT.
2008-10-22 Joel Brobecker <brobecker@adacore.com>
* gdb.base/completion.exp: Update expected output following

View file

@ -1050,7 +1050,7 @@ proc mi_expect_interrupt { test } {
set prompt_re "$mi_gdb_prompt$"
}
set r "reason=\"signal-received\",signal-name=\"SIGINT\",signal-meaning=\"Interrupt\""
set r "reason=\"signal-received\",signal-name=\"0\",signal-meaning=\"Signal 0\""
set any "\[^\n\]*"

View file

@ -606,6 +606,31 @@ set_executing (ptid_t ptid, int executing)
}
}
void
set_stop_requested (ptid_t ptid, int stop)
{
struct thread_info *tp;
int all = ptid_equal (ptid, minus_one_ptid);
if (all || ptid_is_pid (ptid))
{
for (tp = thread_list; tp; tp = tp->next)
if (all || ptid_get_pid (tp->ptid) == ptid_get_pid (ptid))
tp->stop_requested = stop;
}
else
{
tp = find_thread_pid (ptid);
gdb_assert (tp);
tp->stop_requested = stop;
}
/* Call the stop requested observer so other components of GDB can
react to this request. */
if (stop)
observer_notify_thread_stop_requested (ptid);
}
/* Prints the list of threads and their details on UIOUT.
This is a version of 'info_thread_command' suitable for
use from MI.