Per-thread commands.

* gdbthread.h: Remove unneeded forward declarations.
	Include "inferior.h".
	(struct thread_info): Add continuations,
	intermediate_continuations, proceed_to_finish, step_over_calls,
	stop_step, step_multi and stop_signal members.
	(save_infrun_state): Add continuations,
	intermediate_continuations, proceed_to_finish, step_over_calls,
	stop_step, step_multi, stop_signal and stop_bpstat parameters.
	(load_infrun_state): Add continuations,
	intermediate_continuations, proceed_to_finish, step_over_calls,
	stop_step, step_multi, stop_signal and stop_bpstat parameters.

	* thread.c (load_infrun_state): In non-stop mode, load
	continuations, intermediate_continuations, proceed_to_finish,
	step_over_calls, stop_step, step_multi and stop_signal.
	(save_infrun_state): Store continuations,
	intermediate_continuations, proceed_to_finish, step_over_calls,
	stop_step, step_multi, stop_signal and stop_bpstat.
	(save_infrun_state): Store continuations,
	intermediate_continuations, proceed_to_finish, step_over_calls,
	stop_step, step_multi, stop_signal and stop_bpstat.
	(free_thread): Clear The thread's stop_bpstat.

	* inferior.h (context_switch_to): Declare.

	* infrun.c (ecss): New global.
	(context_switch): Context switch continuations,
	intermediate_continuations, proceed_to_finish, step_over_calls,
	stop_step, step_multi, stop_signal and stop_bpstat.
	(wait_for_inferior): Use global ecss.
	(async_ecss, async_ecs): Delete.
	(fetch_inferior_event): Use global ecss.
	(context_switch_to): New.

	* top.c (execute_command): In non-stop, only check if the current
	thread is running, in all-stop, check if there's any thread
	running.

	* breakpoint.c (bpstat_remove_breakpoint): New.
	(bpstat_remove_breakpoint_callback): New.
	(delete_breakpoint): Clear the stop_bpstats of all threads.

	* mi/mi-main.c (mi_cmd_execute): In non-stop, only check if the
	current thread is running, in all-stop, check if there's any
	thread running.

	* Makefile.in (gdbthread_h): Depend on $(inferior_h).
This commit is contained in:
Pedro Alves
2008-07-09 22:30:46 +00:00
parent ad52ddc6a4
commit a474d7c2a3
9 changed files with 221 additions and 44 deletions

View File

@ -1,3 +1,56 @@
2008-07-09 Pedro Alves <pedro@codesourcery.com>
Vladimir Prus <vladimir@codesourcery.com>
Per-thread commands.
* gdbthread.h: Remove unneeded forward declarations.
Include "inferior.h".
(struct thread_info): Add continuations,
intermediate_continuations, proceed_to_finish, step_over_calls,
stop_step, step_multi and stop_signal members.
(save_infrun_state): Add continuations,
intermediate_continuations, proceed_to_finish, step_over_calls,
stop_step, step_multi, stop_signal and stop_bpstat parameters.
(load_infrun_state): Add continuations,
intermediate_continuations, proceed_to_finish, step_over_calls,
stop_step, step_multi, stop_signal and stop_bpstat parameters.
* thread.c (load_infrun_state): In non-stop mode, load
continuations, intermediate_continuations, proceed_to_finish,
step_over_calls, stop_step, step_multi and stop_signal.
(save_infrun_state): Store continuations,
intermediate_continuations, proceed_to_finish, step_over_calls,
stop_step, step_multi, stop_signal and stop_bpstat.
(save_infrun_state): Store continuations,
intermediate_continuations, proceed_to_finish, step_over_calls,
stop_step, step_multi, stop_signal and stop_bpstat.
(free_thread): Clear The thread's stop_bpstat.
* inferior.h (context_switch_to): Declare.
* infrun.c (ecss): New global.
(context_switch): Context switch continuations,
intermediate_continuations, proceed_to_finish, step_over_calls,
stop_step, step_multi, stop_signal and stop_bpstat.
(wait_for_inferior): Use global ecss.
(async_ecss, async_ecs): Delete.
(fetch_inferior_event): Use global ecss.
(context_switch_to): New.
* top.c (execute_command): In non-stop, only check if the current
thread is running, in all-stop, check if there's any thread
running.
* breakpoint.c (bpstat_remove_breakpoint): New.
(bpstat_remove_breakpoint_callback): New.
(delete_breakpoint): Clear the stop_bpstats of all threads.
* mi/mi-main.c (mi_cmd_execute): In non-stop, only check if the
current thread is running, in all-stop, check if there's any
thread running.
* Makefile.in (gdbthread_h): Depend on $(inferior_h).
2008-07-09 Pedro Alves <pedro@codesourcery.com> 2008-07-09 Pedro Alves <pedro@codesourcery.com>
Add non_stop global. Add non_stop global.

View File

@ -800,7 +800,7 @@ gdb_stabs_h = gdb-stabs.h
gdb_stat_h = gdb_stat.h gdb_stat_h = gdb_stat.h
gdb_string_h = gdb_string.h gdb_string_h = gdb_string.h
gdb_thread_db_h = gdb_thread_db.h gdb_thread_db_h = gdb_thread_db.h
gdbthread_h = gdbthread.h $(breakpoint_h) $(frame_h) $(ui_out_h) gdbthread_h = gdbthread.h $(breakpoint_h) $(frame_h) $(ui_out_h) $(inferior_h)
gdbtypes_h = gdbtypes.h $(hashtab_h) gdbtypes_h = gdbtypes.h $(hashtab_h)
gdb_vfork_h = gdb_vfork.h gdb_vfork_h = gdb_vfork.h
gdb_wait_h = gdb_wait.h gdb_wait_h = gdb_wait.h

View File

@ -7168,6 +7168,29 @@ update_global_location_list_nothrow (int inserting)
update_global_location_list (inserting); update_global_location_list (inserting);
} }
/* Clear BPT from a BPS. */
static void
bpstat_remove_breakpoint (bpstat bps, struct breakpoint *bpt)
{
bpstat bs;
for (bs = bps; bs; bs = bs->next)
if (bs->breakpoint_at && bs->breakpoint_at->owner == bpt)
{
bs->breakpoint_at = NULL;
bs->old_val = NULL;
/* bs->commands will be freed later. */
}
}
/* Callback for iterate_over_threads. */
static int
bpstat_remove_breakpoint_callback (struct thread_info *th, void *data)
{
struct breakpoint *bpt = data;
bpstat_remove_breakpoint (th->stop_bpstat, bpt);
return 0;
}
/* Delete a breakpoint and clean up all traces of it in the data /* Delete a breakpoint and clean up all traces of it in the data
structures. */ structures. */
@ -7175,7 +7198,6 @@ void
delete_breakpoint (struct breakpoint *bpt) delete_breakpoint (struct breakpoint *bpt)
{ {
struct breakpoint *b; struct breakpoint *b;
bpstat bs;
struct bp_location *loc, *next; struct bp_location *loc, *next;
gdb_assert (bpt != NULL); gdb_assert (bpt != NULL);
@ -7239,13 +7261,11 @@ delete_breakpoint (struct breakpoint *bpt)
bpstat_do_actions (&stop_bpstat); bpstat_do_actions (&stop_bpstat);
in event-top.c won't do anything, and temporary breakpoints in event-top.c won't do anything, and temporary breakpoints
with commands won't work. */ with commands won't work. */
for (bs = stop_bpstat; bs; bs = bs->next)
if (bs->breakpoint_at && bs->breakpoint_at->owner == bpt) /* Clear the current context. */
{ bpstat_remove_breakpoint (stop_bpstat, bpt);
bs->breakpoint_at = NULL; /* And from all threads. */
bs->old_val = NULL; iterate_over_threads (bpstat_remove_breakpoint_callback, bpt);
/* bs->commands will be freed later. */
}
/* Now that breakpoint is removed from breakpoint /* Now that breakpoint is removed from breakpoint
list, update the global location list. This list, update the global location list. This

View File

@ -22,17 +22,12 @@
#ifndef GDBTHREAD_H #ifndef GDBTHREAD_H
#define GDBTHREAD_H #define GDBTHREAD_H
struct breakpoint;
struct frame_id;
struct symtab; struct symtab;
/* For bpstat */
#include "breakpoint.h" #include "breakpoint.h"
/* For struct frame_id. */
#include "frame.h" #include "frame.h"
#include "ui-out.h" #include "ui-out.h"
#include "inferior.h"
struct thread_info struct thread_info
{ {
@ -82,6 +77,20 @@ struct thread_info
when we finally do stop stepping. */ when we finally do stop stepping. */
bpstat stepping_through_solib_catchpoints; bpstat stepping_through_solib_catchpoints;
/* The below are only per-thread in non-stop mode. */
/* Per-thread command support. */
struct continuation *continuations;
struct continuation *intermediate_continuations;
int proceed_to_finish;
enum step_over_calls_kind step_over_calls;
int stop_step;
int step_multi;
enum target_signal stop_signal;
/* Used in continue_command to set the proceed count of the
breakpoint the thread stopped at. */
bpstat stop_bpstat;
/* Private data used by the target vector implementation. */ /* Private data used by the target vector implementation. */
struct private_thread_info *private; struct private_thread_info *private;
}; };
@ -152,7 +161,15 @@ extern void save_infrun_state (ptid_t ptid,
int stepping_through_solib_after_catch, int stepping_through_solib_after_catch,
bpstat stepping_through_solib_catchpoints, bpstat stepping_through_solib_catchpoints,
int current_line, int current_line,
struct symtab *current_symtab); struct symtab *current_symtab,
struct continuation *continuations,
struct continuation *intermediate_continuations,
int proceed_to_finish,
enum step_over_calls_kind step_over_calls,
int stop_step,
int step_multi,
enum target_signal stop_signal,
bpstat stop_bpstat);
/* infrun context switch: load the debugger state previously saved /* infrun context switch: load the debugger state previously saved
for the given thread. */ for the given thread. */
@ -164,10 +181,18 @@ extern void load_infrun_state (ptid_t ptid,
CORE_ADDR *step_range_end, CORE_ADDR *step_range_end,
struct frame_id *step_frame_id, struct frame_id *step_frame_id,
int *another_trap, int *another_trap,
int *stepping_through_solib_affter_catch, int *stepping_through_solib_after_catch,
bpstat *stepping_through_solib_catchpoints, bpstat *stepping_through_solib_catchpoints,
int *current_line, int *current_line,
struct symtab **current_symtab); struct symtab **current_symtab,
struct continuation **continuations,
struct continuation **intermediate_continuations,
int *proceed_to_finish,
enum step_over_calls_kind *step_over_calls,
int *stop_step,
int *step_multi,
enum target_signal *stop_signal,
bpstat *stop_bpstat);
/* Switch from one thread to another. */ /* Switch from one thread to another. */
extern void switch_to_thread (ptid_t ptid); extern void switch_to_thread (ptid_t ptid);

View File

@ -132,6 +132,8 @@ extern void clear_proceed_status (void);
extern void proceed (CORE_ADDR, enum target_signal, int); extern void proceed (CORE_ADDR, enum target_signal, int);
extern ptid_t context_switch_to (ptid_t ptid);
/* When set, stop the 'step' command if we enter a function which has /* When set, stop the 'step' command if we enter a function which has
no line number information. The normal behavior is that we step no line number information. The normal behavior is that we step
over such function. */ over such function. */

View File

@ -288,6 +288,8 @@ static struct breakpoint *step_resume_breakpoint = NULL;
static ptid_t target_last_wait_ptid; static ptid_t target_last_wait_ptid;
static struct target_waitstatus target_last_waitstatus; static struct target_waitstatus target_last_waitstatus;
struct execution_control_state ecss;
/* This is used to remember when a fork, vfork or exec event /* This is used to remember when a fork, vfork or exec event
was caught by a catchpoint, and thus the event is to be was caught by a catchpoint, and thus the event is to be
followed at the next resume of the inferior, and not followed at the next resume of the inferior, and not
@ -1429,7 +1431,6 @@ void
wait_for_inferior (int treat_exec_as_sigtrap) wait_for_inferior (int treat_exec_as_sigtrap)
{ {
struct cleanup *old_cleanups; struct cleanup *old_cleanups;
struct execution_control_state ecss;
struct execution_control_state *ecs; struct execution_control_state *ecs;
if (debug_infrun) if (debug_infrun)
@ -1440,8 +1441,6 @@ wait_for_inferior (int treat_exec_as_sigtrap)
old_cleanups = make_cleanup (delete_step_resume_breakpoint, old_cleanups = make_cleanup (delete_step_resume_breakpoint,
&step_resume_breakpoint); &step_resume_breakpoint);
/* wfi still stays in a loop, so it's OK just to take the address of
a local to get the ecs pointer. */
ecs = &ecss; ecs = &ecss;
/* Fill in with reasonable starting values. */ /* Fill in with reasonable starting values. */
@ -1487,25 +1486,20 @@ wait_for_inferior (int treat_exec_as_sigtrap)
event loop whenever a change of state is detected on the file event loop whenever a change of state is detected on the file
descriptor corresponding to the target. It can be called more than descriptor corresponding to the target. It can be called more than
once to complete a single execution command. In such cases we need once to complete a single execution command. In such cases we need
to keep the state in a global variable ASYNC_ECSS. If it is the to keep the state in a global variable ECSS. If it is the last time
last time that this function is called for a single execution that this function is called for a single execution command, then
command, then report to the user that the inferior has stopped, and report to the user that the inferior has stopped, and do the
do the necessary cleanups. */ necessary cleanups. */
struct execution_control_state async_ecss;
struct execution_control_state *async_ecs;
void void
fetch_inferior_event (void *client_data) fetch_inferior_event (void *client_data)
{ {
static struct cleanup *old_cleanups; struct execution_control_state *ecs = &ecss;
async_ecs = &async_ecss; if (!ecs->wait_some_more)
if (!async_ecs->wait_some_more)
{ {
/* Fill in with reasonable starting values. */ /* Fill in with reasonable starting values. */
init_execution_control_state (async_ecs); init_execution_control_state (ecs);
/* We'll update this if & when we switch to a new thread. */ /* We'll update this if & when we switch to a new thread. */
previous_inferior_ptid = inferior_ptid; previous_inferior_ptid = inferior_ptid;
@ -1522,15 +1516,15 @@ fetch_inferior_event (void *client_data)
} }
if (deprecated_target_wait_hook) if (deprecated_target_wait_hook)
async_ecs->ptid = ecs->ptid =
deprecated_target_wait_hook (async_ecs->waiton_ptid, async_ecs->wp); deprecated_target_wait_hook (ecs->waiton_ptid, ecs->wp);
else else
async_ecs->ptid = target_wait (async_ecs->waiton_ptid, async_ecs->wp); ecs->ptid = target_wait (ecs->waiton_ptid, ecs->wp);
/* Now figure out what to do with the result of the result. */ /* Now figure out what to do with the result of the result. */
handle_inferior_event (async_ecs); handle_inferior_event (ecs);
if (!async_ecs->wait_some_more) if (!ecs->wait_some_more)
{ {
delete_step_resume_breakpoint (&step_resume_breakpoint); delete_step_resume_breakpoint (&step_resume_breakpoint);
@ -1608,7 +1602,14 @@ context_switch (struct execution_control_state *ecs)
ecs->stepping_over_breakpoint, ecs->stepping_over_breakpoint,
ecs->stepping_through_solib_after_catch, ecs->stepping_through_solib_after_catch,
ecs->stepping_through_solib_catchpoints, ecs->stepping_through_solib_catchpoints,
ecs->current_line, ecs->current_symtab); ecs->current_line, ecs->current_symtab,
cmd_continuation, intermediate_continuation,
proceed_to_finish,
step_over_calls,
stop_step,
step_multi,
stop_signal,
stop_bpstat);
/* Load infrun state for the new thread. */ /* Load infrun state for the new thread. */
load_infrun_state (ecs->ptid, &prev_pc, load_infrun_state (ecs->ptid, &prev_pc,
@ -1618,12 +1619,34 @@ context_switch (struct execution_control_state *ecs)
&ecs->stepping_over_breakpoint, &ecs->stepping_over_breakpoint,
&ecs->stepping_through_solib_after_catch, &ecs->stepping_through_solib_after_catch,
&ecs->stepping_through_solib_catchpoints, &ecs->stepping_through_solib_catchpoints,
&ecs->current_line, &ecs->current_symtab); &ecs->current_line, &ecs->current_symtab,
&cmd_continuation, &intermediate_continuation,
&proceed_to_finish,
&step_over_calls,
&stop_step,
&step_multi,
&stop_signal,
&stop_bpstat);
} }
switch_to_thread (ecs->ptid); switch_to_thread (ecs->ptid);
} }
/* Context switch to thread PTID. */
ptid_t
context_switch_to (ptid_t ptid)
{
ptid_t current_ptid = inferior_ptid;
/* Context switch to the new thread. */
if (!ptid_equal (ptid, inferior_ptid))
{
ecss.ptid = ptid;
context_switch (&ecss);
}
return current_ptid;
}
static void static void
adjust_pc_after_break (struct execution_control_state *ecs) adjust_pc_after_break (struct execution_control_state *ecs)
{ {

View File

@ -1059,7 +1059,8 @@ mi_cmd_execute (struct mi_parse *parse)
if (parse->cmd->argv_func != NULL) if (parse->cmd->argv_func != NULL)
{ {
if (is_running (inferior_ptid)) if ((!non_stop && any_running ())
|| (non_stop && is_running (inferior_ptid)))
{ {
if (strcmp (parse->command, "exec-interrupt")) if (strcmp (parse->command, "exec-interrupt"))
{ {

View File

@ -93,6 +93,8 @@ free_thread (struct thread_info *tp)
if (tp->step_resume_breakpoint) if (tp->step_resume_breakpoint)
tp->step_resume_breakpoint->disposition = disp_del_at_next_stop; tp->step_resume_breakpoint->disposition = disp_del_at_next_stop;
bpstat_clear (&tp->stop_bpstat);
/* FIXME: do I ever need to call the back-end to give it a /* FIXME: do I ever need to call the back-end to give it a
chance at this private data before deleting the thread? */ chance at this private data before deleting the thread? */
if (tp->private) if (tp->private)
@ -358,7 +360,15 @@ load_infrun_state (ptid_t ptid,
int *stepping_through_solib_after_catch, int *stepping_through_solib_after_catch,
bpstat *stepping_through_solib_catchpoints, bpstat *stepping_through_solib_catchpoints,
int *current_line, int *current_line,
struct symtab **current_symtab) struct symtab **current_symtab,
struct continuation **continuations,
struct continuation **intermediate_continuations,
int *proceed_to_finish,
enum step_over_calls_kind *step_over_calls,
int *stop_step,
int *step_multi,
enum target_signal *stop_signal,
bpstat *stop_bpstat)
{ {
struct thread_info *tp; struct thread_info *tp;
@ -381,6 +391,26 @@ load_infrun_state (ptid_t ptid,
tp->stepping_through_solib_catchpoints; tp->stepping_through_solib_catchpoints;
*current_line = tp->current_line; *current_line = tp->current_line;
*current_symtab = tp->current_symtab; *current_symtab = tp->current_symtab;
/* In all-stop mode, these are global state, while in non-stop mode,
they are per thread. */
if (non_stop)
{
*continuations = tp->continuations;
tp->continuations = NULL;
*intermediate_continuations = tp->intermediate_continuations;
tp->intermediate_continuations = NULL;
*proceed_to_finish = tp->proceed_to_finish;
*step_over_calls = tp->step_over_calls;
*stop_step = tp->stop_step;
*step_multi = tp->step_multi;
*stop_signal = tp->stop_signal;
/* Swap instead of copy, so we only have to update one of
them. */
*stop_bpstat = tp->stop_bpstat;
tp->stop_bpstat = 0;
}
} }
/* Save infrun state for the thread PID. */ /* Save infrun state for the thread PID. */
@ -397,7 +427,15 @@ save_infrun_state (ptid_t ptid,
int stepping_through_solib_after_catch, int stepping_through_solib_after_catch,
bpstat stepping_through_solib_catchpoints, bpstat stepping_through_solib_catchpoints,
int current_line, int current_line,
struct symtab *current_symtab) struct symtab *current_symtab,
struct continuation *continuations,
struct continuation *intermediate_continuations,
int proceed_to_finish,
enum step_over_calls_kind step_over_calls,
int stop_step,
int step_multi,
enum target_signal stop_signal,
bpstat stop_bpstat)
{ {
struct thread_info *tp; struct thread_info *tp;
@ -418,6 +456,20 @@ save_infrun_state (ptid_t ptid,
tp->stepping_through_solib_catchpoints = stepping_through_solib_catchpoints; tp->stepping_through_solib_catchpoints = stepping_through_solib_catchpoints;
tp->current_line = current_line; tp->current_line = current_line;
tp->current_symtab = current_symtab; tp->current_symtab = current_symtab;
/* In all-stop mode, these are global state, while in non-stop mode,
they are per thread. */
if (non_stop)
{
tp->continuations = continuations;
tp->intermediate_continuations = intermediate_continuations;
tp->proceed_to_finish = proceed_to_finish;
tp->step_over_calls = step_over_calls;
tp->stop_step = stop_step;
tp->step_multi = step_multi;
tp->stop_signal = stop_signal;
tp->stop_bpstat = stop_bpstat;
}
} }
/* Return true if TP is an active thread. */ /* Return true if TP is an active thread. */

View File

@ -418,7 +418,8 @@ execute_command (char *p, int from_tty)
/* If the target is running, we allow only a limited set of /* If the target is running, we allow only a limited set of
commands. */ commands. */
if (target_can_async_p () if (target_can_async_p ()
&& any_running () && ((!non_stop && any_running ())
|| (non_stop && is_running (inferior_ptid)))
&& !get_cmd_async_ok (c)) && !get_cmd_async_ok (c))
error (_("Cannot execute this command while the target is running.")); error (_("Cannot execute this command while the target is running."));