mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-05 14:46:43 +08:00
Per-inferior thread list, thread ranges/iterators, down with ALL_THREADS, etc.
As preparation for multi-target, this patch makes each inferior have its own thread list. This isn't absolutely necessary for multi-target, but simplifies things. It originally stemmed from the desire to eliminate the init_thread_list calls sprinkled around, plus it makes it more efficient to iterate over threads of a given inferior (no need to always iterate over threads of all inferiors). We still need to iterate over threads of all inferiors in a number of places, which means we'd need adjust the ALL_THREADS / ALL_NON_EXITED_THREADS macros. However, naively tweaking those macros to have an extra for loop, like: #define ALL_THREADS (thr, inf) \ for (inf = inferior_list; inf; inf = inf->next) \ for (thr = inf->thread_list; thr; thr = thr->next) causes problems with code that does "break" or "continue" within the ALL_THREADS loop body. Plus, we need to declare the extra "inf" local variable in order to pass it as temporary variable to ALL_THREADS (etc.) It gets even trickier when we consider extending the macros to filter out threads matching a ptid_t and a target. The macros become tricker to read/write. Been there. An alternative (which was my next attempt), is to replace the ALL_THREADS etc. iteration style with for_each_all_threads, for_each_non_exited_threads, etc. functions which would take a callback as parameter, which would usually be passed a lambda. However, I did not find that satisfactory at all, because the resulting code ends up a little less natural / more noisy to read, write and debug/step-through (due to use of lambdas), and in many places where we use "continue;" to skip to the next thread now need to use "return;". (I ran into hard to debug bugs caused by a continue/return confusion.) I.e., before: ALL_NON_EXITED_THREADS (tp) { if (tp->not_what_I_want) continue; // do something } would turn into: for_each_non_exited_thread ([&] (thread_info *tp) { if (tp->not_what_I_want) return; // do something }); Lastly, the solution I settled with was to replace the ALL_THREADS / ALL_NON_EXITED_THREADS / ALL_INFERIORS macros with (C++20-like) ranges and iterators, such that you can instead naturaly iterate over threads/inferiors using range-for, like e.g,.: // all threads, including THREAD_EXITED threads. for (thread_info *tp : all_threads ()) { .... } // all non-exited threads. for (thread_info *tp : all_non_exited_threads ()) { .... } // all non-exited threads of INF inferior. for (thread_info *tp : inf->non_exited_threads ()) { .... } The all_non_exited_threads() function takes an optional filter ptid_t as parameter, which is quite convenient when we need to iterate over threads matching that filter. See e.g., how the set_executing/set_stop_requested/finish_thread_state etc. functions in thread.c end up being simplified. Most of the patch thus is about adding the infrustructure for allowing the above. Later on when we get to actual multi-target, these functions/ranges/iterators will gain a "target_ops *" parameter so that e.g., we can iterate over all threads of a given target that match a given filter ptid_t. The only entry points users needs to be aware of are the all_threads/all_non_exited_threads etc. functions seen above. Thus, those functions are declared in gdbthread.h/inferior.h. The actual iterators/ranges are mainly "internals" and thus are put out of view in the new thread-iter.h/thread-iter.c/inferior-iter.h files. That keeps the gdbthread.h/inferior.h headers quite a bit more readable. A common/safe-iterator.h header is added which adds a template that can be used to build "safe" iterators, which are forward iterators that can be used to replace the ALL_THREADS_SAFE macro and other instances of the same idiom in future. There's a little bit of shuffling of code between gdbthread.h/thread.c/inferior.h in the patch. That is necessary in order to avoid circular dependencies between the gdbthread.h/inferior.h headers. As for the init_thread_list calls sprinkled around, they're all eliminated by this patch, and a new, central call is added to inferior_appeared. Note how also related to that, there's a call to init_wait_for_inferior in remote.c that is eliminated. init_wait_for_inferior is currently responsible for discarding skipped inline frames, which had to be moved elsewhere. Given that nowadays we always have a thread even for single-threaded processes, the natural place is to delete a frame's inline frame info when we delete the thread. I.e., from clear_thread_inferior_resources. gdb/ChangeLog: 2018-11-22 Pedro Alves <palves@redhat.com> * Makefile.in (COMMON_SFILES): Add thread-iter.c. * breakpoint.c (breakpoints_should_be_inserted_now): Replace ALL_NON_EXITED_THREADS with all_non_exited_threads. (print_one_breakpoint_location): Replace ALL_INFERIORS with all_inferiors. * bsd-kvm.c: Include inferior.h. * btrace.c (btrace_free_objfile): Replace ALL_NON_EXITED_THREADS with all_non_exited_threads. * common/filtered-iterator.h: New. * common/safe-iterator.h: New. * corelow.c (core_target_open): Don't call init_thread_list here. * darwin-nat.c (thread_info_from_private_thread_info): Replace ALL_THREADS with all_threads. * fbsd-nat.c (fbsd_nat_target::resume): Replace ALL_NON_EXITED_THREADS with inf->non_exited_threads. * fbsd-tdep.c (fbsd_make_corefile_notes): Replace ALL_NON_EXITED_THREADS with inf->non_exited_threads. * fork-child.c (postfork_hook): Don't call init_thread_list here. * gdbarch-selftests.c (register_to_value_test): Adjust. * gdbthread.h: Don't include "inferior.h" here. (struct inferior): Forward declare. (enum step_over_calls_kind): Moved here from inferior.h. (thread_info::deletable): Definition moved to thread.c. (find_thread_ptid (inferior *, ptid_t)): Declare. (ALL_THREADS, ALL_THREADS_BY_INFERIOR, ALL_THREADS_SAFE): Delete. Include "thread-iter.h". (all_threads, all_non_exited_threads, all_threads_safe): New. (any_thread_p): Declare. (thread_list): Delete. * infcmd.c (signal_command): Replace ALL_NON_EXITED_THREADS with all_non_exited_threads. (proceed_after_attach_callback): Delete. (proceed_after_attach): Take an inferior pointer instead of an integer PID. Adjust to use range-for. (attach_post_wait): Pass down inferior pointer instead of pid. Use range-for instead of ALL_NON_EXITED_THREADS. (detach_command): Remove init_thread_list call. * inferior-iter.h: New. * inferior.c (struct delete_thread_of_inferior_arg): Delete. (delete_thread_of_inferior): Delete. (delete_inferior, exit_inferior_1): Use range-for with inf->threads_safe() instead of iterate_over_threads. (inferior_appeared): Call init_thread_list here. (discard_all_inferiors): Use all_non_exited_inferiors. (find_inferior_id, find_inferior_pid): Use all_inferiors. (iterate_over_inferiors): Use all_inferiors_safe. (have_inferiors, number_of_live_inferiors): Use all_non_exited_inferiors. (number_of_inferiors): Use all_inferiors and std::distance. (print_inferior): Use all_inferiors. * inferior.h: Include gdbthread.h. (enum step_over_calls_kind): Moved to gdbthread.h. (struct inferior) <thread_list>: New field. <threads, non_exited_threads, threads_safe>: New methods. (ALL_INFERIORS): Delete. Include "inferior-iter.h". (ALL_NON_EXITED_INFERIORS): Delete. (all_inferiors_safe, all_inferiors, all_non_exited_inferiors): New functions. * inflow.c (child_interrupt, child_pass_ctrlc): Replace ALL_NON_EXITED_THREADS with all_non_exited_threads. * infrun.c (follow_exec): Use all_threads_safe. (clear_proceed_status, proceed): Use all_non_exited_threads. (init_wait_for_inferior): Don't clear inline frame state here. (infrun_thread_stop_requested, for_each_just_stopped_thread): Use all_threads instead of ALL_NON_EXITED_THREADS. (random_pending_event_thread): Use all_non_exited_threads instead of ALL_NON_EXITED_THREADS. Use a lambda for repeated code. (clean_up_just_stopped_threads_fsms): Use all_non_exited_threads instead of ALL_NON_EXITED_THREADS. (handle_no_resumed): Use all_non_exited_threads instead of ALL_NON_EXITED_THREADS. Use all_inferiors instead of ALL_INFERIORS. (restart_threads, switch_back_to_stepped_thread): Use all_non_exited_threads instead of ALL_NON_EXITED_THREADS. * linux-nat.c (check_zombie_leaders): Replace ALL_INFERIORS with all_inferiors. (kill_unfollowed_fork_children): Use inf->non_exited_threads instead of ALL_NON_EXITED_THREADS. * linux-tdep.c (linux_make_corefile_notes): Use inf->non_exited_threads instead of ALL_NON_EXITED_THREADS. * linux-thread-db.c (thread_db_target::update_thread_list): Replace ALL_INFERIORS with all_inferiors. (thread_db_target::thread_handle_to_thread_info): Use inf->non_exited_threads instead of ALL_NON_EXITED_THREADS. * mi/mi-interp.c (multiple_inferiors_p): New. (mi_on_resume_1): Simplify using all_non_exited_threads and multiple_inferiors_p. * mi/mi-main.c (mi_cmd_thread_list_ids): Use all_non_exited_threads instead of ALL_NON_EXITED_THREADS. * nto-procfs.c (nto_procfs_target::open): Don't call init_thread_list here. * record-btrace.c (record_btrace_target_open) (record_btrace_target::stop_recording) (record_btrace_target::close) (record_btrace_target::record_is_replaying) (record_btrace_target::resume, record_btrace_target::wait) (record_btrace_target::record_stop_replaying): Use all_non_exited_threads instead of ALL_NON_EXITED_THREADS. * record-full.c (record_full_wait_1): Use all_non_exited_threads instead of ALL_NON_EXITED_THREADS. * regcache.c (cooked_read_test): Remove reference to global thread_list. * remote-sim.c (gdbsim_target::create_inferior): Don't call init_thread_list here. * remote.c (remote_target::update_thread_list): Use all_threads_safe instead of ALL_NON_EXITED_THREADS. (remote_target::process_initial_stop_replies): Replace ALL_INFERIORS with all_non_exited_inferiors and use all_non_exited_threads instead of ALL_NON_EXITED_THREADS. (remote_target::open_1): Don't call init_thread_list here. (remote_target::append_pending_thread_resumptions) (remote_target::remote_resume_with_hc): Use all_non_exited_threads instead of ALL_NON_EXITED_THREADS. (remote_target::commit_resume) (remote_target::remove_new_fork_children): Replace ALL_INFERIORS with all_non_exited_inferiors and use all_non_exited_threads instead of ALL_NON_EXITED_THREADS. (remote_target::kill_new_fork_children): Use all_non_exited_threads instead of ALL_NON_EXITED_THREADS. Remove init_thread_list and init_wait_for_inferior calls. (remote_target::remote_btrace_maybe_reopen) (remote_target::thread_handle_to_thread_info): Use all_non_exited_threads instead of ALL_NON_EXITED_THREADS. * target.c (target_terminal::restore_inferior) (target_terminal_is_ours_kind): Replace ALL_INFERIORS with all_non_exited_inferiors. * thread-iter.c: New file. * thread-iter.h: New file. * thread.c: Include "inline-frame.h". (thread_list): Delete. (clear_thread_inferior_resources): Call clear_inline_frame_state. (init_thread_list): Use all_threads_safe instead of ALL_THREADS_SAFE. Adjust to per-inferior thread lists. (new_thread): Adjust to per-inferior thread lists. (add_thread_silent): Pass inferior to find_thread_ptid. (thread_info::deletable): New, moved from the header. (delete_thread_1): Adjust to per-inferior thread lists. (find_thread_global_id): Use inf->threads(). (find_thread_ptid): Use find_inferior_ptid and pass inferior to find_thread_ptid. (find_thread_ptid(inferior*, ptid_t)): New overload. (iterate_over_threads): Use all_threads_safe. (any_thread_p): New. (thread_count): Use all_threads and std::distance. (live_threads_count): Use all_non_exited_threads and std::distance. (valid_global_thread_id): Use all_threads. (in_thread_list): Use find_thread_ptid. (first_thread_of_inferior): Adjust to per-inferior thread lists. (any_thread_of_inferior, any_live_thread_of_inferior): Use inf->non_exited_threads(). (prune_threads, delete_exited_threads): Use all_threads_safe. (thread_change_ptid): Pass inferior pointer to find_thread_ptid. (set_resumed, set_running): Use all_non_exited_threads. (is_thread_state, is_stopped, is_exited, is_running) (is_executing): Delete. (set_executing, set_stop_requested, finish_thread_state): Use all_non_exited_threads. (print_thread_info_1): Use all_inferiors and all_threads. (thread_apply_all_command): Use all_non_exited_threads. (thread_find_command): Use all_threads. (update_threads_executing): Use all_non_exited_threads. * tid-parse.c (parse_thread_id): Use inf->threads. * x86-bsd-nat.c (x86bsd_dr_set): Use inf->non_exited_threads ().
This commit is contained in:
220
gdb/infrun.c
220
gdb/infrun.c
@ -1082,7 +1082,6 @@ show_follow_exec_mode_string (struct ui_file *file, int from_tty,
|
||||
static void
|
||||
follow_exec (ptid_t ptid, char *exec_file_target)
|
||||
{
|
||||
struct thread_info *th, *tmp;
|
||||
struct inferior *inf = current_inferior ();
|
||||
int pid = ptid.pid ();
|
||||
ptid_t process_ptid;
|
||||
@ -1129,7 +1128,7 @@ follow_exec (ptid_t ptid, char *exec_file_target)
|
||||
them. Deleting them now rather than at the next user-visible
|
||||
stop provides a nicer sequence of events for user and MI
|
||||
notifications. */
|
||||
ALL_THREADS_SAFE (th, tmp)
|
||||
for (thread_info *th : all_threads_safe ())
|
||||
if (th->ptid.pid () == pid && th->ptid != ptid)
|
||||
delete_thread (th);
|
||||
|
||||
@ -1137,7 +1136,7 @@ follow_exec (ptid_t ptid, char *exec_file_target)
|
||||
leader/event thread. E.g., if there was any step-resume
|
||||
breakpoint or similar, it's gone now. We cannot truly
|
||||
step-to-next statement through an exec(). */
|
||||
th = inferior_thread ();
|
||||
thread_info *th = inferior_thread ();
|
||||
th->control.step_resume_breakpoint = NULL;
|
||||
th->control.exception_resume_breakpoint = NULL;
|
||||
th->control.single_step_breakpoints = NULL;
|
||||
@ -2851,21 +2850,14 @@ clear_proceed_status (int step)
|
||||
execution_direction))
|
||||
target_record_stop_replaying ();
|
||||
|
||||
if (!non_stop)
|
||||
if (!non_stop && inferior_ptid != null_ptid)
|
||||
{
|
||||
struct thread_info *tp;
|
||||
ptid_t resume_ptid;
|
||||
|
||||
resume_ptid = user_visible_resume_ptid (step);
|
||||
ptid_t resume_ptid = user_visible_resume_ptid (step);
|
||||
|
||||
/* In all-stop mode, delete the per-thread status of all threads
|
||||
we're about to resume, implicitly and explicitly. */
|
||||
ALL_NON_EXITED_THREADS (tp)
|
||||
{
|
||||
if (!tp->ptid.matches (resume_ptid))
|
||||
continue;
|
||||
clear_proceed_status_thread (tp);
|
||||
}
|
||||
for (thread_info *tp : all_non_exited_threads (resume_ptid))
|
||||
clear_proceed_status_thread (tp);
|
||||
}
|
||||
|
||||
if (inferior_ptid != null_ptid)
|
||||
@ -2954,7 +2946,6 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
|
||||
{
|
||||
struct regcache *regcache;
|
||||
struct gdbarch *gdbarch;
|
||||
struct thread_info *tp;
|
||||
CORE_ADDR pc;
|
||||
ptid_t resume_ptid;
|
||||
struct execution_control_state ecss;
|
||||
@ -2981,16 +2972,16 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
|
||||
const address_space *aspace = regcache->aspace ();
|
||||
|
||||
pc = regcache_read_pc (regcache);
|
||||
tp = inferior_thread ();
|
||||
thread_info *cur_thr = inferior_thread ();
|
||||
|
||||
/* Fill in with reasonable starting values. */
|
||||
init_thread_stepping_state (tp);
|
||||
init_thread_stepping_state (cur_thr);
|
||||
|
||||
gdb_assert (!thread_is_in_step_over_chain (tp));
|
||||
gdb_assert (!thread_is_in_step_over_chain (cur_thr));
|
||||
|
||||
if (addr == (CORE_ADDR) -1)
|
||||
{
|
||||
if (pc == tp->suspend.stop_pc
|
||||
if (pc == cur_thr->suspend.stop_pc
|
||||
&& breakpoint_here_p (aspace, pc) == ordinary_breakpoint_here
|
||||
&& execution_direction != EXEC_REVERSE)
|
||||
/* There is a breakpoint at the address we will resume at,
|
||||
@ -3001,13 +2992,13 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
|
||||
Note, we don't do this in reverse, because we won't
|
||||
actually be executing the breakpoint insn anyway.
|
||||
We'll be (un-)executing the previous instruction. */
|
||||
tp->stepping_over_breakpoint = 1;
|
||||
cur_thr->stepping_over_breakpoint = 1;
|
||||
else if (gdbarch_single_step_through_delay_p (gdbarch)
|
||||
&& gdbarch_single_step_through_delay (gdbarch,
|
||||
get_current_frame ()))
|
||||
/* We stepped onto an instruction that needs to be stepped
|
||||
again before re-inserting the breakpoint, do so. */
|
||||
tp->stepping_over_breakpoint = 1;
|
||||
cur_thr->stepping_over_breakpoint = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -3015,9 +3006,9 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
|
||||
}
|
||||
|
||||
if (siggnal != GDB_SIGNAL_DEFAULT)
|
||||
tp->suspend.stop_signal = siggnal;
|
||||
cur_thr->suspend.stop_signal = siggnal;
|
||||
|
||||
resume_ptid = user_visible_resume_ptid (tp->control.stepping_command);
|
||||
resume_ptid = user_visible_resume_ptid (cur_thr->control.stepping_command);
|
||||
|
||||
/* If an exception is thrown from this point on, make sure to
|
||||
propagate GDB's knowledge of the executing state to the
|
||||
@ -3030,7 +3021,7 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
|
||||
threads in RESUME_PTID are now running. Unless we're calling an
|
||||
inferior function, as in that case we pretend the inferior
|
||||
doesn't run at all. */
|
||||
if (!tp->control.in_infcall)
|
||||
if (!cur_thr->control.in_infcall)
|
||||
set_running (resume_ptid, 1);
|
||||
|
||||
if (debug_infrun)
|
||||
@ -3064,19 +3055,13 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
|
||||
|
||||
/* If scheduler locking applies, we can avoid iterating over all
|
||||
threads. */
|
||||
if (!non_stop && !schedlock_applies (tp))
|
||||
if (!non_stop && !schedlock_applies (cur_thr))
|
||||
{
|
||||
struct thread_info *current = tp;
|
||||
|
||||
ALL_NON_EXITED_THREADS (tp)
|
||||
{
|
||||
for (thread_info *tp : all_non_exited_threads (resume_ptid))
|
||||
{
|
||||
/* Ignore the current thread here. It's handled
|
||||
afterwards. */
|
||||
if (tp == current)
|
||||
continue;
|
||||
|
||||
/* Ignore threads of processes we're not resuming. */
|
||||
if (!tp->ptid.matches (resume_ptid))
|
||||
if (tp == cur_thr)
|
||||
continue;
|
||||
|
||||
if (!thread_still_needs_step_over (tp))
|
||||
@ -3091,21 +3076,19 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
|
||||
|
||||
thread_step_over_chain_enqueue (tp);
|
||||
}
|
||||
|
||||
tp = current;
|
||||
}
|
||||
|
||||
/* Enqueue the current thread last, so that we move all other
|
||||
threads over their breakpoints first. */
|
||||
if (tp->stepping_over_breakpoint)
|
||||
thread_step_over_chain_enqueue (tp);
|
||||
if (cur_thr->stepping_over_breakpoint)
|
||||
thread_step_over_chain_enqueue (cur_thr);
|
||||
|
||||
/* If the thread isn't started, we'll still need to set its prev_pc,
|
||||
so that switch_back_to_stepped_thread knows the thread hasn't
|
||||
advanced. Must do this before resuming any thread, as in
|
||||
all-stop/remote, once we resume we can't send any other packet
|
||||
until the target stops again. */
|
||||
tp->prev_pc = regcache_read_pc (regcache);
|
||||
cur_thr->prev_pc = regcache_read_pc (regcache);
|
||||
|
||||
{
|
||||
scoped_restore save_defer_tc = make_scoped_defer_target_commit_resume ();
|
||||
@ -3127,12 +3110,8 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
|
||||
{
|
||||
/* In all-stop, but the target is always in non-stop mode.
|
||||
Start all other threads that are implicitly resumed too. */
|
||||
ALL_NON_EXITED_THREADS (tp)
|
||||
for (thread_info *tp : all_non_exited_threads (resume_ptid))
|
||||
{
|
||||
/* Ignore threads of processes we're not resuming. */
|
||||
if (!tp->ptid.matches (resume_ptid))
|
||||
continue;
|
||||
|
||||
if (tp->resumed)
|
||||
{
|
||||
if (debug_infrun)
|
||||
@ -3164,11 +3143,11 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
|
||||
error (_("Command aborted."));
|
||||
}
|
||||
}
|
||||
else if (!tp->resumed && !thread_is_in_step_over_chain (tp))
|
||||
else if (!cur_thr->resumed && !thread_is_in_step_over_chain (cur_thr))
|
||||
{
|
||||
/* The thread wasn't started, and isn't queued, run it now. */
|
||||
reset_ecs (ecs, tp);
|
||||
switch_to_thread (tp);
|
||||
reset_ecs (ecs, cur_thr);
|
||||
switch_to_thread (cur_thr);
|
||||
keep_going_pass_signal (ecs);
|
||||
if (!ecs->wait_some_more)
|
||||
error (_("Command aborted."));
|
||||
@ -3235,9 +3214,6 @@ init_wait_for_inferior (void)
|
||||
target_last_wait_ptid = minus_one_ptid;
|
||||
|
||||
previous_inferior_ptid = inferior_ptid;
|
||||
|
||||
/* Discard any skipped inlined frames. */
|
||||
clear_inline_frame_state (minus_one_ptid);
|
||||
}
|
||||
|
||||
|
||||
@ -3265,53 +3241,50 @@ static int switch_back_to_stepped_thread (struct execution_control_state *ecs);
|
||||
static void
|
||||
infrun_thread_stop_requested (ptid_t ptid)
|
||||
{
|
||||
struct thread_info *tp;
|
||||
|
||||
/* PTID was requested to stop. If the thread was already stopped,
|
||||
but the user/frontend doesn't know about that yet (e.g., the
|
||||
thread had been temporarily paused for some step-over), set up
|
||||
for reporting the stop now. */
|
||||
ALL_NON_EXITED_THREADS (tp)
|
||||
if (tp->ptid.matches (ptid))
|
||||
{
|
||||
if (tp->state != THREAD_RUNNING)
|
||||
continue;
|
||||
if (tp->executing)
|
||||
continue;
|
||||
for (thread_info *tp : all_threads (ptid))
|
||||
{
|
||||
if (tp->state != THREAD_RUNNING)
|
||||
continue;
|
||||
if (tp->executing)
|
||||
continue;
|
||||
|
||||
/* Remove matching threads from the step-over queue, so
|
||||
start_step_over doesn't try to resume them
|
||||
automatically. */
|
||||
if (thread_is_in_step_over_chain (tp))
|
||||
thread_step_over_chain_remove (tp);
|
||||
/* Remove matching threads from the step-over queue, so
|
||||
start_step_over doesn't try to resume them
|
||||
automatically. */
|
||||
if (thread_is_in_step_over_chain (tp))
|
||||
thread_step_over_chain_remove (tp);
|
||||
|
||||
/* If the thread is stopped, but the user/frontend doesn't
|
||||
know about that yet, queue a pending event, as if the
|
||||
thread had just stopped now. Unless the thread already had
|
||||
a pending event. */
|
||||
if (!tp->suspend.waitstatus_pending_p)
|
||||
{
|
||||
tp->suspend.waitstatus_pending_p = 1;
|
||||
tp->suspend.waitstatus.kind = TARGET_WAITKIND_STOPPED;
|
||||
tp->suspend.waitstatus.value.sig = GDB_SIGNAL_0;
|
||||
}
|
||||
/* If the thread is stopped, but the user/frontend doesn't
|
||||
know about that yet, queue a pending event, as if the
|
||||
thread had just stopped now. Unless the thread already had
|
||||
a pending event. */
|
||||
if (!tp->suspend.waitstatus_pending_p)
|
||||
{
|
||||
tp->suspend.waitstatus_pending_p = 1;
|
||||
tp->suspend.waitstatus.kind = TARGET_WAITKIND_STOPPED;
|
||||
tp->suspend.waitstatus.value.sig = GDB_SIGNAL_0;
|
||||
}
|
||||
|
||||
/* Clear the inline-frame state, since we're re-processing the
|
||||
stop. */
|
||||
clear_inline_frame_state (tp->ptid);
|
||||
/* Clear the inline-frame state, since we're re-processing the
|
||||
stop. */
|
||||
clear_inline_frame_state (tp->ptid);
|
||||
|
||||
/* If this thread was paused because some other thread was
|
||||
doing an inline-step over, let that finish first. Once
|
||||
that happens, we'll restart all threads and consume pending
|
||||
stop events then. */
|
||||
if (step_over_info_valid_p ())
|
||||
continue;
|
||||
/* If this thread was paused because some other thread was
|
||||
doing an inline-step over, let that finish first. Once
|
||||
that happens, we'll restart all threads and consume pending
|
||||
stop events then. */
|
||||
if (step_over_info_valid_p ())
|
||||
continue;
|
||||
|
||||
/* Otherwise we can process the (new) pending event now. Set
|
||||
it so this pending event is considered by
|
||||
do_target_wait. */
|
||||
tp->resumed = 1;
|
||||
}
|
||||
/* Otherwise we can process the (new) pending event now. Set
|
||||
it so this pending event is considered by
|
||||
do_target_wait. */
|
||||
tp->resumed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@ -3352,13 +3325,9 @@ for_each_just_stopped_thread (for_each_just_stopped_thread_callback_func func)
|
||||
}
|
||||
else
|
||||
{
|
||||
struct thread_info *tp;
|
||||
|
||||
/* In all-stop mode, all threads have stopped. */
|
||||
ALL_NON_EXITED_THREADS (tp)
|
||||
{
|
||||
func (tp);
|
||||
}
|
||||
for (thread_info *tp : all_non_exited_threads ())
|
||||
func (tp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3427,24 +3396,26 @@ print_target_wait_results (ptid_t waiton_ptid, ptid_t result_ptid,
|
||||
static struct thread_info *
|
||||
random_pending_event_thread (ptid_t waiton_ptid)
|
||||
{
|
||||
struct thread_info *event_tp;
|
||||
int num_events = 0;
|
||||
int random_selector;
|
||||
|
||||
auto has_event = [] (thread_info *tp)
|
||||
{
|
||||
return (tp->resumed
|
||||
&& tp->suspend.waitstatus_pending_p);
|
||||
};
|
||||
|
||||
/* First see how many events we have. Count only resumed threads
|
||||
that have an event pending. */
|
||||
ALL_NON_EXITED_THREADS (event_tp)
|
||||
if (event_tp->ptid.matches (waiton_ptid)
|
||||
&& event_tp->resumed
|
||||
&& event_tp->suspend.waitstatus_pending_p)
|
||||
for (thread_info *tp : all_non_exited_threads (waiton_ptid))
|
||||
if (has_event (tp))
|
||||
num_events++;
|
||||
|
||||
if (num_events == 0)
|
||||
return NULL;
|
||||
|
||||
/* Now randomly pick a thread out of those that have had events. */
|
||||
random_selector = (int)
|
||||
((num_events * (double) rand ()) / (RAND_MAX + 1.0));
|
||||
int random_selector = (int) ((num_events * (double) rand ())
|
||||
/ (RAND_MAX + 1.0));
|
||||
|
||||
if (debug_infrun && num_events > 1)
|
||||
fprintf_unfiltered (gdb_stdlog,
|
||||
@ -3452,14 +3423,12 @@ random_pending_event_thread (ptid_t waiton_ptid)
|
||||
num_events, random_selector);
|
||||
|
||||
/* Select the Nth thread that has had an event. */
|
||||
ALL_NON_EXITED_THREADS (event_tp)
|
||||
if (event_tp->ptid.matches (waiton_ptid)
|
||||
&& event_tp->resumed
|
||||
&& event_tp->suspend.waitstatus_pending_p)
|
||||
for (thread_info *tp : all_non_exited_threads (waiton_ptid))
|
||||
if (has_event (tp))
|
||||
if (random_selector-- == 0)
|
||||
break;
|
||||
return tp;
|
||||
|
||||
return event_tp;
|
||||
gdb_assert_not_reached ("event thread not found");
|
||||
}
|
||||
|
||||
/* Wrapper for target_wait that first checks whether threads have
|
||||
@ -3755,14 +3724,14 @@ reinstall_readline_callback_handler_cleanup (void *arg)
|
||||
static void
|
||||
clean_up_just_stopped_threads_fsms (struct execution_control_state *ecs)
|
||||
{
|
||||
struct thread_info *thr = ecs->event_thread;
|
||||
|
||||
if (thr != NULL && thr->thread_fsm != NULL)
|
||||
thread_fsm_clean_up (thr->thread_fsm, thr);
|
||||
if (ecs->event_thread != NULL
|
||||
&& ecs->event_thread->thread_fsm != NULL)
|
||||
thread_fsm_clean_up (ecs->event_thread->thread_fsm,
|
||||
ecs->event_thread);
|
||||
|
||||
if (!non_stop)
|
||||
{
|
||||
ALL_NON_EXITED_THREADS (thr)
|
||||
for (thread_info *thr : all_non_exited_threads ())
|
||||
{
|
||||
if (thr->thread_fsm == NULL)
|
||||
continue;
|
||||
@ -4461,13 +4430,12 @@ stop_all_threads (void)
|
||||
ptid_t event_ptid;
|
||||
struct target_waitstatus ws;
|
||||
int need_wait = 0;
|
||||
struct thread_info *t;
|
||||
|
||||
update_thread_list ();
|
||||
|
||||
/* Go through all threads looking for threads that we need
|
||||
to tell the target to stop. */
|
||||
ALL_NON_EXITED_THREADS (t)
|
||||
for (thread_info *t : all_non_exited_threads ())
|
||||
{
|
||||
if (t->executing)
|
||||
{
|
||||
@ -4539,9 +4507,7 @@ stop_all_threads (void)
|
||||
}
|
||||
else
|
||||
{
|
||||
inferior *inf;
|
||||
|
||||
t = find_thread_ptid (event_ptid);
|
||||
thread_info *t = find_thread_ptid (event_ptid);
|
||||
if (t == NULL)
|
||||
t = add_thread (event_ptid);
|
||||
|
||||
@ -4552,7 +4518,7 @@ stop_all_threads (void)
|
||||
|
||||
/* This may be the first time we see the inferior report
|
||||
a stop. */
|
||||
inf = find_inferior_ptid (event_ptid);
|
||||
inferior *inf = find_inferior_ptid (event_ptid);
|
||||
if (inf->needs_setup)
|
||||
{
|
||||
switch_to_thread_no_regs (t);
|
||||
@ -4642,9 +4608,6 @@ stop_all_threads (void)
|
||||
static int
|
||||
handle_no_resumed (struct execution_control_state *ecs)
|
||||
{
|
||||
struct inferior *inf;
|
||||
struct thread_info *thread;
|
||||
|
||||
if (target_can_async_p ())
|
||||
{
|
||||
struct ui *ui;
|
||||
@ -4707,7 +4670,7 @@ handle_no_resumed (struct execution_control_state *ecs)
|
||||
the synchronous command show "no unwaited-for " to the user. */
|
||||
update_thread_list ();
|
||||
|
||||
ALL_NON_EXITED_THREADS (thread)
|
||||
for (thread_info *thread : all_non_exited_threads ())
|
||||
{
|
||||
if (thread->executing
|
||||
|| thread->suspend.waitstatus_pending_p)
|
||||
@ -4727,12 +4690,12 @@ handle_no_resumed (struct execution_control_state *ecs)
|
||||
process exited meanwhile (thus updating the thread list results
|
||||
in an empty thread list). In this case we know we'll be getting
|
||||
a process exit event shortly. */
|
||||
ALL_INFERIORS (inf)
|
||||
for (inferior *inf : all_inferiors ())
|
||||
{
|
||||
if (inf->pid == 0)
|
||||
continue;
|
||||
|
||||
thread = any_live_thread_of_inferior (inf);
|
||||
thread_info *thread = any_live_thread_of_inferior (inf);
|
||||
if (thread == NULL)
|
||||
{
|
||||
if (debug_infrun)
|
||||
@ -5383,12 +5346,10 @@ handle_inferior_event (struct execution_control_state *ecs)
|
||||
static void
|
||||
restart_threads (struct thread_info *event_thread)
|
||||
{
|
||||
struct thread_info *tp;
|
||||
|
||||
/* In case the instruction just stepped spawned a new thread. */
|
||||
update_thread_list ();
|
||||
|
||||
ALL_NON_EXITED_THREADS (tp)
|
||||
for (thread_info *tp : all_non_exited_threads ())
|
||||
{
|
||||
if (tp == event_thread)
|
||||
{
|
||||
@ -6996,7 +6957,6 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs)
|
||||
{
|
||||
if (!target_is_non_stop_p ())
|
||||
{
|
||||
struct thread_info *tp;
|
||||
struct thread_info *stepping_thread;
|
||||
|
||||
/* If any thread is blocked on some internal breakpoint, and we
|
||||
@ -7083,7 +7043,7 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs)
|
||||
/* Look for the stepping/nexting thread. */
|
||||
stepping_thread = NULL;
|
||||
|
||||
ALL_NON_EXITED_THREADS (tp)
|
||||
for (thread_info *tp : all_non_exited_threads ())
|
||||
{
|
||||
/* Ignore threads of processes the caller is not
|
||||
resuming. */
|
||||
|
Reference in New Issue
Block a user