* 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>
+ 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>
Add non_stop global.
gdb_stat_h = gdb_stat.h
gdb_string_h = gdb_string.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)
gdb_vfork_h = gdb_vfork.h
gdb_wait_h = gdb_wait.h
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
structures. */
delete_breakpoint (struct breakpoint *bpt)
{
struct breakpoint *b;
- bpstat bs;
struct bp_location *loc, *next;
gdb_assert (bpt != NULL);
bpstat_do_actions (&stop_bpstat);
in event-top.c won't do anything, and temporary breakpoints
with commands won't work. */
- for (bs = stop_bpstat; 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. */
- }
+
+ /* Clear the current context. */
+ bpstat_remove_breakpoint (stop_bpstat, bpt);
+ /* And from all threads. */
+ iterate_over_threads (bpstat_remove_breakpoint_callback, bpt);
/* Now that breakpoint is removed from breakpoint
list, update the global location list. This
#ifndef GDBTHREAD_H
#define GDBTHREAD_H
-struct breakpoint;
-struct frame_id;
struct symtab;
-/* For bpstat */
#include "breakpoint.h"
-
-/* For struct frame_id. */
#include "frame.h"
-
#include "ui-out.h"
+#include "inferior.h"
struct thread_info
{
when we finally do stop stepping. */
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. */
struct private_thread_info *private;
};
int stepping_through_solib_after_catch,
bpstat stepping_through_solib_catchpoints,
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
for the given thread. */
CORE_ADDR *step_range_end,
struct frame_id *step_frame_id,
int *another_trap,
- int *stepping_through_solib_affter_catch,
+ int *stepping_through_solib_after_catch,
bpstat *stepping_through_solib_catchpoints,
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. */
extern void switch_to_thread (ptid_t ptid);
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
no line number information. The normal behavior is that we step
over such function. */
static ptid_t target_last_wait_ptid;
static struct target_waitstatus target_last_waitstatus;
+struct execution_control_state ecss;
+
/* This is used to remember when a fork, vfork or exec event
was caught by a catchpoint, and thus the event is to be
followed at the next resume of the inferior, and not
wait_for_inferior (int treat_exec_as_sigtrap)
{
struct cleanup *old_cleanups;
- struct execution_control_state ecss;
struct execution_control_state *ecs;
if (debug_infrun)
old_cleanups = make_cleanup (delete_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;
/* Fill in with reasonable starting values. */
event loop whenever a change of state is detected on the file
descriptor corresponding to the target. It can be called more than
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
- last time that this function is called for a single execution
- command, then report to the user that the inferior has stopped, and
- do the necessary cleanups. */
-
-struct execution_control_state async_ecss;
-struct execution_control_state *async_ecs;
+ to keep the state in a global variable ECSS. If it is the last time
+ that this function is called for a single execution command, then
+ report to the user that the inferior has stopped, and do the
+ necessary cleanups. */
void
fetch_inferior_event (void *client_data)
{
- static struct cleanup *old_cleanups;
-
- async_ecs = &async_ecss;
+ struct execution_control_state *ecs = &ecss;
- if (!async_ecs->wait_some_more)
+ if (!ecs->wait_some_more)
{
/* 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. */
previous_inferior_ptid = inferior_ptid;
}
if (deprecated_target_wait_hook)
- async_ecs->ptid =
- deprecated_target_wait_hook (async_ecs->waiton_ptid, async_ecs->wp);
+ ecs->ptid =
+ deprecated_target_wait_hook (ecs->waiton_ptid, ecs->wp);
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. */
- 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);
ecs->stepping_over_breakpoint,
ecs->stepping_through_solib_after_catch,
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 (ecs->ptid, &prev_pc,
&ecs->stepping_over_breakpoint,
&ecs->stepping_through_solib_after_catch,
&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);
}
+/* 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
adjust_pc_after_break (struct execution_control_state *ecs)
{
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 (tp->step_resume_breakpoint)
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
chance at this private data before deleting the thread? */
if (tp->private)
int *stepping_through_solib_after_catch,
bpstat *stepping_through_solib_catchpoints,
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;
tp->stepping_through_solib_catchpoints;
*current_line = tp->current_line;
*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. */
int stepping_through_solib_after_catch,
bpstat stepping_through_solib_catchpoints,
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;
tp->stepping_through_solib_catchpoints = stepping_through_solib_catchpoints;
tp->current_line = current_line;
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. */
/* If the target is running, we allow only a limited set of
commands. */
if (target_can_async_p ()
- && any_running ()
+ && ((!non_stop && any_running ())
+ || (non_stop && is_running (inferior_ptid)))
&& !get_cmd_async_ok (c))
error (_("Cannot execute this command while the target is running."));