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:
parent
c4c17fb0f5
commit
0803633106
168
gdb/ChangeLog
168
gdb/ChangeLog
|
@ -1,3 +1,171 @@
|
||||||
|
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 ().
|
||||||
|
|
||||||
2018-11-22 Pedro Alves <palves@redhat.com>
|
2018-11-22 Pedro Alves <palves@redhat.com>
|
||||||
|
|
||||||
* infrun.c (follow_exec) <set follow-exec new>: Add thread and
|
* infrun.c (follow_exec) <set follow-exec new>: Add thread and
|
||||||
|
|
|
@ -1111,6 +1111,7 @@ COMMON_SFILES = \
|
||||||
target-descriptions.c \
|
target-descriptions.c \
|
||||||
target-memory.c \
|
target-memory.c \
|
||||||
thread.c \
|
thread.c \
|
||||||
|
thread-iter.c \
|
||||||
thread-fsm.c \
|
thread-fsm.c \
|
||||||
tid-parse.c \
|
tid-parse.c \
|
||||||
top.c \
|
top.c \
|
||||||
|
|
|
@ -400,8 +400,6 @@ breakpoints_should_be_inserted_now (void)
|
||||||
}
|
}
|
||||||
else if (target_has_execution)
|
else if (target_has_execution)
|
||||||
{
|
{
|
||||||
struct thread_info *tp;
|
|
||||||
|
|
||||||
if (always_inserted_mode)
|
if (always_inserted_mode)
|
||||||
{
|
{
|
||||||
/* The user wants breakpoints inserted even if all threads
|
/* The user wants breakpoints inserted even if all threads
|
||||||
|
@ -414,7 +412,7 @@ breakpoints_should_be_inserted_now (void)
|
||||||
|
|
||||||
/* Don't remove breakpoints yet if, even though all threads are
|
/* Don't remove breakpoints yet if, even though all threads are
|
||||||
stopped, we still have events to process. */
|
stopped, we still have events to process. */
|
||||||
ALL_NON_EXITED_THREADS (tp)
|
for (thread_info *tp : all_non_exited_threads ())
|
||||||
if (tp->resumed
|
if (tp->resumed
|
||||||
&& tp->suspend.waitstatus_pending_p)
|
&& tp->suspend.waitstatus_pending_p)
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -6149,11 +6147,10 @@ print_one_breakpoint_location (struct breakpoint *b,
|
||||||
|
|
||||||
if (loc != NULL && !header_of_multiple)
|
if (loc != NULL && !header_of_multiple)
|
||||||
{
|
{
|
||||||
struct inferior *inf;
|
|
||||||
std::vector<int> inf_nums;
|
std::vector<int> inf_nums;
|
||||||
int mi_only = 1;
|
int mi_only = 1;
|
||||||
|
|
||||||
ALL_INFERIORS (inf)
|
for (inferior *inf : all_inferiors ())
|
||||||
{
|
{
|
||||||
if (inf->pspace == loc->pspace)
|
if (inf->pspace == loc->pspace)
|
||||||
inf_nums.push_back (inf->num);
|
inf_nums.push_back (inf->num);
|
||||||
|
|
|
@ -25,7 +25,8 @@
|
||||||
#include "regcache.h"
|
#include "regcache.h"
|
||||||
#include "target.h"
|
#include "target.h"
|
||||||
#include "value.h"
|
#include "value.h"
|
||||||
#include "gdbcore.h" /* for get_exec_file */
|
#include "gdbcore.h"
|
||||||
|
#include "inferior.h" /* for get_exec_file */
|
||||||
#include "gdbthread.h"
|
#include "gdbthread.h"
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
|
@ -2003,11 +2003,9 @@ btrace_clear (struct thread_info *tp)
|
||||||
void
|
void
|
||||||
btrace_free_objfile (struct objfile *objfile)
|
btrace_free_objfile (struct objfile *objfile)
|
||||||
{
|
{
|
||||||
struct thread_info *tp;
|
|
||||||
|
|
||||||
DEBUG ("free objfile");
|
DEBUG ("free objfile");
|
||||||
|
|
||||||
ALL_NON_EXITED_THREADS (tp)
|
for (thread_info *tp : all_non_exited_threads ())
|
||||||
btrace_clear (tp);
|
btrace_clear (tp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
/* A forward filtered iterator for GDB, the GNU debugger.
|
||||||
|
Copyright (C) 2018 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
This file is part of GDB.
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef FILTERED_ITERATOR_H
|
||||||
|
#define FILTERED_ITERATOR_H
|
||||||
|
|
||||||
|
/* A filtered iterator. This wraps BaseIterator and automatically
|
||||||
|
skips elements that FilterFunc filters out. Requires that
|
||||||
|
default-constructing a BaseIterator creates a valid one-past-end
|
||||||
|
iterator. */
|
||||||
|
|
||||||
|
template<typename BaseIterator, typename FilterFunc>
|
||||||
|
class filtered_iterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef filtered_iterator self_type;
|
||||||
|
typedef typename BaseIterator::value_type value_type;
|
||||||
|
typedef typename BaseIterator::reference reference;
|
||||||
|
typedef typename BaseIterator::pointer pointer;
|
||||||
|
typedef typename BaseIterator::iterator_category iterator_category;
|
||||||
|
typedef typename BaseIterator::difference_type difference_type;
|
||||||
|
|
||||||
|
/* Construct by forwarding all arguments to the underlying
|
||||||
|
iterator. */
|
||||||
|
template<typename... Args>
|
||||||
|
explicit filtered_iterator (Args &&...args)
|
||||||
|
: m_it (std::forward<Args> (args)...)
|
||||||
|
{ skip_filtered (); }
|
||||||
|
|
||||||
|
/* Create a one-past-end iterator. */
|
||||||
|
filtered_iterator () = default;
|
||||||
|
|
||||||
|
/* Need these as the variadic constructor would be a better match
|
||||||
|
otherwise. */
|
||||||
|
filtered_iterator (filtered_iterator &) = default;
|
||||||
|
filtered_iterator (const filtered_iterator &) = default;
|
||||||
|
filtered_iterator (filtered_iterator &&) = default;
|
||||||
|
filtered_iterator (const filtered_iterator &&other)
|
||||||
|
: filtered_iterator (static_cast<const filtered_iterator &> (other))
|
||||||
|
{}
|
||||||
|
|
||||||
|
value_type operator* () const { return *m_it; }
|
||||||
|
|
||||||
|
self_type &operator++ ()
|
||||||
|
{
|
||||||
|
++m_it;
|
||||||
|
skip_filtered ();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator== (const self_type &other) const
|
||||||
|
{ return *m_it == *other.m_it; }
|
||||||
|
|
||||||
|
bool operator!= (const self_type &other) const
|
||||||
|
{ return *m_it != *other.m_it; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void skip_filtered ()
|
||||||
|
{
|
||||||
|
for (; m_it != m_end; ++m_it)
|
||||||
|
if (m_filter (*m_it))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
FilterFunc m_filter {};
|
||||||
|
BaseIterator m_it {};
|
||||||
|
BaseIterator m_end {};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* FILTERED_ITERATOR_H */
|
|
@ -0,0 +1,93 @@
|
||||||
|
/* A safe iterator for GDB, the GNU debugger.
|
||||||
|
Copyright (C) 2018 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
This file is part of GDB.
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef SAFE_ITERATOR_H
|
||||||
|
#define SAFE_ITERATOR_H
|
||||||
|
|
||||||
|
/* A forward iterator that wraps Iterator, such that when iterating
|
||||||
|
with iterator IT, it is possible to delete *IT without invalidating
|
||||||
|
IT. Suitably wrapped in a range type and used with range-for, this
|
||||||
|
allow convenient patterns like this:
|
||||||
|
|
||||||
|
// range_safe() returns a range type whose begin()/end() methods
|
||||||
|
// return safe iterators.
|
||||||
|
for (foo *f : range_safe ())
|
||||||
|
{
|
||||||
|
if (f->should_delete ())
|
||||||
|
{
|
||||||
|
// The ++it operation implicitly done by the range-for is
|
||||||
|
// still OK after this.
|
||||||
|
delete f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
template<typename Iterator>
|
||||||
|
class basic_safe_iterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef basic_safe_iterator self_type;
|
||||||
|
typedef typename Iterator::value_type value_type;
|
||||||
|
typedef typename Iterator::reference reference;
|
||||||
|
typedef typename Iterator::pointer pointer;
|
||||||
|
typedef typename Iterator::iterator_category iterator_category;
|
||||||
|
typedef typename Iterator::difference_type difference_type;
|
||||||
|
|
||||||
|
/* Construct by forwarding all arguments to the underlying
|
||||||
|
iterator. */
|
||||||
|
template<typename... Args>
|
||||||
|
explicit basic_safe_iterator (Args &&...args)
|
||||||
|
: m_it (std::forward<Args> (args)...),
|
||||||
|
m_next (m_it)
|
||||||
|
{
|
||||||
|
if (m_it != m_end)
|
||||||
|
++m_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a one-past-end iterator. */
|
||||||
|
basic_safe_iterator ()
|
||||||
|
{}
|
||||||
|
|
||||||
|
value_type operator* () const { return *m_it; }
|
||||||
|
|
||||||
|
self_type &operator++ ()
|
||||||
|
{
|
||||||
|
m_it = m_next;
|
||||||
|
if (m_it != m_end)
|
||||||
|
++m_next;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator== (const self_type &other) const
|
||||||
|
{ return m_it == other.m_it; }
|
||||||
|
|
||||||
|
bool operator!= (const self_type &other) const
|
||||||
|
{ return m_it != other.m_it; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
/* The current element. */
|
||||||
|
Iterator m_it {};
|
||||||
|
|
||||||
|
/* The next element. Always one element ahead of M_IT. */
|
||||||
|
Iterator m_next {};
|
||||||
|
|
||||||
|
/* A one-past-end iterator. */
|
||||||
|
Iterator m_end {};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* SAFE_ITERATOR_H */
|
|
@ -421,12 +421,6 @@ core_target_open (const char *arg, int from_tty)
|
||||||
push_target (target);
|
push_target (target);
|
||||||
target_holder.release ();
|
target_holder.release ();
|
||||||
|
|
||||||
/* Do this before acknowledging the inferior, so if
|
|
||||||
post_create_inferior throws (can happen easilly if you're loading
|
|
||||||
a core file with the wrong exec), we aren't left with threads
|
|
||||||
from the previous inferior. */
|
|
||||||
init_thread_list ();
|
|
||||||
|
|
||||||
inferior_ptid = null_ptid;
|
inferior_ptid = null_ptid;
|
||||||
|
|
||||||
/* Need to flush the register cache (and the frame cache) from a
|
/* Need to flush the register cache (and the frame cache) from a
|
||||||
|
|
|
@ -1707,19 +1707,15 @@ darwin_attach_pid (struct inferior *inf)
|
||||||
static struct thread_info *
|
static struct thread_info *
|
||||||
thread_info_from_private_thread_info (darwin_thread_info *pti)
|
thread_info_from_private_thread_info (darwin_thread_info *pti)
|
||||||
{
|
{
|
||||||
struct thread_info *it;
|
for (struct thread_info *it : all_threads ())
|
||||||
|
|
||||||
ALL_THREADS (it)
|
|
||||||
{
|
{
|
||||||
darwin_thread_info *iter_pti = get_darwin_thread_info (it);
|
darwin_thread_info *iter_pti = get_darwin_thread_info (it);
|
||||||
|
|
||||||
if (iter_pti->gdb_port == pti->gdb_port)
|
if (iter_pti->gdb_port == pti->gdb_port)
|
||||||
break;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
gdb_assert (it != NULL);
|
gdb_assert_not_reached ("did not find gdb thread for darwin thread");
|
||||||
|
|
||||||
return it;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -1158,13 +1158,11 @@ fbsd_nat_target::resume (ptid_t ptid, int step, enum gdb_signal signo)
|
||||||
if (ptid.lwp_p ())
|
if (ptid.lwp_p ())
|
||||||
{
|
{
|
||||||
/* If ptid is a specific LWP, suspend all other LWPs in the process. */
|
/* If ptid is a specific LWP, suspend all other LWPs in the process. */
|
||||||
struct thread_info *tp;
|
inferior *inf = find_inferior_ptid (ptid);
|
||||||
int request;
|
|
||||||
|
|
||||||
ALL_NON_EXITED_THREADS (tp)
|
for (thread_info *tp : inf->non_exited_threads ())
|
||||||
{
|
{
|
||||||
if (tp->ptid.pid () != ptid.pid ())
|
int request;
|
||||||
continue;
|
|
||||||
|
|
||||||
if (tp->ptid.lwp () == ptid.lwp ())
|
if (tp->ptid.lwp () == ptid.lwp ())
|
||||||
request = PT_RESUME;
|
request = PT_RESUME;
|
||||||
|
@ -1179,16 +1177,9 @@ fbsd_nat_target::resume (ptid_t ptid, int step, enum gdb_signal signo)
|
||||||
{
|
{
|
||||||
/* If ptid is a wildcard, resume all matching threads (they won't run
|
/* If ptid is a wildcard, resume all matching threads (they won't run
|
||||||
until the process is continued however). */
|
until the process is continued however). */
|
||||||
struct thread_info *tp;
|
for (thread_info *tp : all_non_exited_threads (ptid))
|
||||||
|
if (ptrace (PT_RESUME, tp->ptid.lwp (), NULL, 0) == -1)
|
||||||
ALL_NON_EXITED_THREADS (tp)
|
perror_with_name (("ptrace"));
|
||||||
{
|
|
||||||
if (!tp->ptid.matches (ptid))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (ptrace (PT_RESUME, tp->ptid.lwp (), NULL, 0) == -1)
|
|
||||||
perror_with_name (("ptrace"));
|
|
||||||
}
|
|
||||||
ptid = inferior_ptid;
|
ptid = inferior_ptid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -653,7 +653,7 @@ fbsd_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
|
||||||
struct fbsd_corefile_thread_data thread_args;
|
struct fbsd_corefile_thread_data thread_args;
|
||||||
char *note_data = NULL;
|
char *note_data = NULL;
|
||||||
Elf_Internal_Ehdr *i_ehdrp;
|
Elf_Internal_Ehdr *i_ehdrp;
|
||||||
struct thread_info *curr_thr, *signalled_thr, *thr;
|
struct thread_info *curr_thr, *signalled_thr;
|
||||||
|
|
||||||
/* Put a "FreeBSD" label in the ELF header. */
|
/* Put a "FreeBSD" label in the ELF header. */
|
||||||
i_ehdrp = elf_elfheader (obfd);
|
i_ehdrp = elf_elfheader (obfd);
|
||||||
|
@ -706,12 +706,10 @@ fbsd_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
|
||||||
thread_args.stop_signal = signalled_thr->suspend.stop_signal;
|
thread_args.stop_signal = signalled_thr->suspend.stop_signal;
|
||||||
|
|
||||||
fbsd_corefile_thread (signalled_thr, &thread_args);
|
fbsd_corefile_thread (signalled_thr, &thread_args);
|
||||||
ALL_NON_EXITED_THREADS (thr)
|
for (thread_info *thr : current_inferior ()->non_exited_threads ())
|
||||||
{
|
{
|
||||||
if (thr == signalled_thr)
|
if (thr == signalled_thr)
|
||||||
continue;
|
continue;
|
||||||
if (thr->ptid.pid () != inferior_ptid.pid ())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
fbsd_corefile_thread (thr, &thread_args);
|
fbsd_corefile_thread (thr, &thread_args);
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,12 +78,7 @@ prefork_hook (const char *args)
|
||||||
void
|
void
|
||||||
postfork_hook (pid_t pid)
|
postfork_hook (pid_t pid)
|
||||||
{
|
{
|
||||||
struct inferior *inf;
|
inferior *inf = current_inferior ();
|
||||||
|
|
||||||
if (!have_inferiors ())
|
|
||||||
init_thread_list ();
|
|
||||||
|
|
||||||
inf = current_inferior ();
|
|
||||||
|
|
||||||
inferior_appeared (inf, pid);
|
inferior_appeared (inf, pid);
|
||||||
|
|
||||||
|
|
|
@ -86,7 +86,7 @@ register_to_value_test (struct gdbarch *gdbarch)
|
||||||
thread_info mock_thread (&mock_inferior, mock_ptid);
|
thread_info mock_thread (&mock_inferior, mock_ptid);
|
||||||
|
|
||||||
scoped_restore restore_thread_list
|
scoped_restore restore_thread_list
|
||||||
= make_scoped_restore (&thread_list, &mock_thread);
|
= make_scoped_restore (&mock_inferior.thread_list, &mock_thread);
|
||||||
|
|
||||||
/* Add the mock inferior to the inferior list so that look ups by
|
/* Add the mock inferior to the inferior list so that look ups by
|
||||||
target+ptid can find it. */
|
target+ptid can find it. */
|
||||||
|
|
|
@ -26,7 +26,6 @@ struct symtab;
|
||||||
#include "breakpoint.h"
|
#include "breakpoint.h"
|
||||||
#include "frame.h"
|
#include "frame.h"
|
||||||
#include "ui-out.h"
|
#include "ui-out.h"
|
||||||
#include "inferior.h"
|
|
||||||
#include "btrace.h"
|
#include "btrace.h"
|
||||||
#include "common/vec.h"
|
#include "common/vec.h"
|
||||||
#include "target/waitstatus.h"
|
#include "target/waitstatus.h"
|
||||||
|
@ -34,6 +33,8 @@ struct symtab;
|
||||||
#include "common/refcounted-object.h"
|
#include "common/refcounted-object.h"
|
||||||
#include "common-gdbthread.h"
|
#include "common-gdbthread.h"
|
||||||
|
|
||||||
|
struct inferior;
|
||||||
|
|
||||||
/* Frontend view of the thread state. Possible extensions: stepping,
|
/* Frontend view of the thread state. Possible extensions: stepping,
|
||||||
finishing, until(ling),... */
|
finishing, until(ling),... */
|
||||||
enum thread_state
|
enum thread_state
|
||||||
|
@ -43,6 +44,17 @@ enum thread_state
|
||||||
THREAD_EXITED,
|
THREAD_EXITED,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* STEP_OVER_ALL means step over all subroutine calls.
|
||||||
|
STEP_OVER_UNDEBUGGABLE means step over calls to undebuggable functions.
|
||||||
|
STEP_OVER_NONE means don't step over any subroutine calls. */
|
||||||
|
|
||||||
|
enum step_over_calls_kind
|
||||||
|
{
|
||||||
|
STEP_OVER_NONE,
|
||||||
|
STEP_OVER_ALL,
|
||||||
|
STEP_OVER_UNDEBUGGABLE
|
||||||
|
};
|
||||||
|
|
||||||
/* Inferior thread specific part of `struct infcall_control_state'.
|
/* Inferior thread specific part of `struct infcall_control_state'.
|
||||||
|
|
||||||
Inferior process counterpart is `struct inferior_control_state'. */
|
Inferior process counterpart is `struct inferior_control_state'. */
|
||||||
|
@ -213,12 +225,7 @@ public:
|
||||||
explicit thread_info (inferior *inf, ptid_t ptid);
|
explicit thread_info (inferior *inf, ptid_t ptid);
|
||||||
~thread_info ();
|
~thread_info ();
|
||||||
|
|
||||||
bool deletable () const
|
bool deletable () const;
|
||||||
{
|
|
||||||
/* If this is the current thread, or there's code out there that
|
|
||||||
relies on it existing (refcount > 0) we can't delete yet. */
|
|
||||||
return (refcount () == 0 && ptid != inferior_ptid);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Mark this thread as running and notify observers. */
|
/* Mark this thread as running and notify observers. */
|
||||||
void set_running (bool running);
|
void set_running (bool running);
|
||||||
|
@ -449,6 +456,10 @@ extern int valid_global_thread_id (int global_id);
|
||||||
/* Search function to lookup a thread by 'pid'. */
|
/* Search function to lookup a thread by 'pid'. */
|
||||||
extern struct thread_info *find_thread_ptid (ptid_t ptid);
|
extern struct thread_info *find_thread_ptid (ptid_t ptid);
|
||||||
|
|
||||||
|
/* Search function to lookup a thread by 'ptid'. Only searches in
|
||||||
|
threads of INF. */
|
||||||
|
extern struct thread_info *find_thread_ptid (inferior *inf, ptid_t ptid);
|
||||||
|
|
||||||
/* Find thread by GDB global thread ID. */
|
/* Find thread by GDB global thread ID. */
|
||||||
struct thread_info *find_thread_global_id (int global_id);
|
struct thread_info *find_thread_global_id (int global_id);
|
||||||
|
|
||||||
|
@ -475,32 +486,61 @@ void thread_change_ptid (ptid_t old_ptid, ptid_t new_ptid);
|
||||||
typedef int (*thread_callback_func) (struct thread_info *, void *);
|
typedef int (*thread_callback_func) (struct thread_info *, void *);
|
||||||
extern struct thread_info *iterate_over_threads (thread_callback_func, void *);
|
extern struct thread_info *iterate_over_threads (thread_callback_func, void *);
|
||||||
|
|
||||||
/* Traverse all threads. */
|
/* Pull in the internals of the inferiors/threads ranges and
|
||||||
#define ALL_THREADS(T) \
|
iterators. Must be done after struct thread_info is defined. */
|
||||||
for (T = thread_list; T; T = T->next) \
|
#include "thread-iter.h"
|
||||||
|
|
||||||
/* Traverse over all threads, sorted by inferior. */
|
/* Return a range that can be used to walk over all threads of all
|
||||||
#define ALL_THREADS_BY_INFERIOR(inf, tp) \
|
inferiors, with range-for. Used like this:
|
||||||
ALL_INFERIORS (inf) \
|
|
||||||
ALL_THREADS (tp) \
|
|
||||||
if (inf == tp->inf)
|
|
||||||
|
|
||||||
/* Traverse all threads, except those that have THREAD_EXITED
|
for (thread_info *thr : all_threads ())
|
||||||
state. */
|
{ .... }
|
||||||
|
*/
|
||||||
|
inline all_threads_range
|
||||||
|
all_threads ()
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
#define ALL_NON_EXITED_THREADS(T) \
|
/* Likewise, but accept a filter PTID. */
|
||||||
for (T = thread_list; T; T = T->next) \
|
|
||||||
if ((T)->state != THREAD_EXITED)
|
|
||||||
|
|
||||||
/* Traverse all threads, including those that have THREAD_EXITED
|
inline all_matching_threads_range
|
||||||
state. Allows deleting the currently iterated thread. */
|
all_threads (ptid_t filter_ptid)
|
||||||
#define ALL_THREADS_SAFE(T, TMP) \
|
{
|
||||||
for ((T) = thread_list; \
|
return all_matching_threads_range (filter_ptid);
|
||||||
(T) != NULL ? ((TMP) = (T)->next, 1): 0; \
|
}
|
||||||
(T) = (TMP))
|
|
||||||
|
/* Return a range that can be used to walk over all non-exited threads
|
||||||
|
of all inferiors, with range-for. FILTER_PTID can be used to
|
||||||
|
filter out thread that don't match. */
|
||||||
|
|
||||||
|
inline all_non_exited_threads_range
|
||||||
|
all_non_exited_threads (ptid_t filter_ptid = minus_one_ptid)
|
||||||
|
{
|
||||||
|
return all_non_exited_threads_range (filter_ptid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return a range that can be used to walk over all threads of all
|
||||||
|
inferiors, with range-for, safely. I.e., it is safe to delete the
|
||||||
|
currently-iterated thread. When combined with range-for, this
|
||||||
|
allow convenient patterns like this:
|
||||||
|
|
||||||
|
for (thread_info *t : all_threads_safe ())
|
||||||
|
if (some_condition ())
|
||||||
|
delete f;
|
||||||
|
*/
|
||||||
|
|
||||||
|
inline all_threads_safe_range
|
||||||
|
all_threads_safe ()
|
||||||
|
{
|
||||||
|
return all_threads_safe_range ();
|
||||||
|
}
|
||||||
|
|
||||||
extern int thread_count (void);
|
extern int thread_count (void);
|
||||||
|
|
||||||
|
/* Return true if we have any thread in any inferior. */
|
||||||
|
extern bool any_thread_p ();
|
||||||
|
|
||||||
/* Switch context to thread THR. Also sets the STOP_PC global. */
|
/* Switch context to thread THR. Also sets the STOP_PC global. */
|
||||||
extern void switch_to_thread (struct thread_info *thr);
|
extern void switch_to_thread (struct thread_info *thr);
|
||||||
|
|
||||||
|
@ -748,6 +788,4 @@ extern void print_selected_thread_frame (struct ui_out *uiout,
|
||||||
alive anymore. */
|
alive anymore. */
|
||||||
extern void thread_select (const char *tidstr, class thread_info *thr);
|
extern void thread_select (const char *tidstr, class thread_info *thr);
|
||||||
|
|
||||||
extern struct thread_info *thread_list;
|
|
||||||
|
|
||||||
#endif /* GDBTHREAD_H */
|
#endif /* GDBTHREAD_H */
|
||||||
|
|
69
gdb/infcmd.c
69
gdb/infcmd.c
|
@ -1339,20 +1339,16 @@ signal_command (const char *signum_exp, int from_tty)
|
||||||
of the wrong thread. */
|
of the wrong thread. */
|
||||||
if (!non_stop)
|
if (!non_stop)
|
||||||
{
|
{
|
||||||
struct thread_info *tp;
|
|
||||||
ptid_t resume_ptid;
|
|
||||||
int must_confirm = 0;
|
int must_confirm = 0;
|
||||||
|
|
||||||
/* This indicates what will be resumed. Either a single thread,
|
/* This indicates what will be resumed. Either a single thread,
|
||||||
a whole process, or all threads of all processes. */
|
a whole process, or all threads of all processes. */
|
||||||
resume_ptid = user_visible_resume_ptid (0);
|
ptid_t resume_ptid = user_visible_resume_ptid (0);
|
||||||
|
|
||||||
ALL_NON_EXITED_THREADS (tp)
|
for (thread_info *tp : all_non_exited_threads (resume_ptid))
|
||||||
{
|
{
|
||||||
if (tp->ptid == inferior_ptid)
|
if (tp->ptid == inferior_ptid)
|
||||||
continue;
|
continue;
|
||||||
if (!tp->ptid.matches (resume_ptid))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (tp->suspend.stop_signal != GDB_SIGNAL_0
|
if (tp->suspend.stop_signal != GDB_SIGNAL_0
|
||||||
&& signal_pass_state (tp->suspend.stop_signal))
|
&& signal_pass_state (tp->suspend.stop_signal))
|
||||||
|
@ -2620,34 +2616,13 @@ kill_command (const char *arg, int from_tty)
|
||||||
bfd_cache_close_all ();
|
bfd_cache_close_all ();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Used in `attach&' command. ARG is a point to an integer
|
/* Used in `attach&' command. Proceed threads of inferior INF iff
|
||||||
representing a process id. Proceed threads of this process iff
|
|
||||||
they stopped due to debugger request, and when they did, they
|
they stopped due to debugger request, and when they did, they
|
||||||
reported a clean stop (GDB_SIGNAL_0). Do not proceed threads
|
reported a clean stop (GDB_SIGNAL_0). Do not proceed threads that
|
||||||
that have been explicitly been told to stop. */
|
have been explicitly been told to stop. */
|
||||||
|
|
||||||
static int
|
|
||||||
proceed_after_attach_callback (struct thread_info *thread,
|
|
||||||
void *arg)
|
|
||||||
{
|
|
||||||
int pid = * (int *) arg;
|
|
||||||
|
|
||||||
if (thread->ptid.pid () == pid
|
|
||||||
&& thread->state != THREAD_EXITED
|
|
||||||
&& !thread->executing
|
|
||||||
&& !thread->stop_requested
|
|
||||||
&& thread->suspend.stop_signal == GDB_SIGNAL_0)
|
|
||||||
{
|
|
||||||
switch_to_thread (thread);
|
|
||||||
clear_proceed_status (0);
|
|
||||||
proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
proceed_after_attach (int pid)
|
proceed_after_attach (inferior *inf)
|
||||||
{
|
{
|
||||||
/* Don't error out if the current thread is running, because
|
/* Don't error out if the current thread is running, because
|
||||||
there may be other stopped threads. */
|
there may be other stopped threads. */
|
||||||
|
@ -2655,7 +2630,15 @@ proceed_after_attach (int pid)
|
||||||
/* Backup current thread and selected frame. */
|
/* Backup current thread and selected frame. */
|
||||||
scoped_restore_current_thread restore_thread;
|
scoped_restore_current_thread restore_thread;
|
||||||
|
|
||||||
iterate_over_threads (proceed_after_attach_callback, &pid);
|
for (thread_info *thread : inf->non_exited_threads ())
|
||||||
|
if (!thread->executing
|
||||||
|
&& !thread->stop_requested
|
||||||
|
&& thread->suspend.stop_signal == GDB_SIGNAL_0)
|
||||||
|
{
|
||||||
|
switch_to_thread (thread);
|
||||||
|
clear_proceed_status (0);
|
||||||
|
proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See inferior.h. */
|
/* See inferior.h. */
|
||||||
|
@ -2722,7 +2705,7 @@ attach_post_wait (const char *args, int from_tty, enum attach_post_wait_mode mod
|
||||||
already running threads. If a thread has been stopped with a
|
already running threads. If a thread has been stopped with a
|
||||||
signal, leave it be. */
|
signal, leave it be. */
|
||||||
if (non_stop)
|
if (non_stop)
|
||||||
proceed_after_attach (inferior->pid);
|
proceed_after_attach (inferior);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (inferior_thread ()->suspend.stop_signal == GDB_SIGNAL_0)
|
if (inferior_thread ()->suspend.stop_signal == GDB_SIGNAL_0)
|
||||||
|
@ -2748,9 +2731,7 @@ attach_post_wait (const char *args, int from_tty, enum attach_post_wait_mode mod
|
||||||
target_stop (ptid_t (inferior->pid));
|
target_stop (ptid_t (inferior->pid));
|
||||||
else if (target_is_non_stop_p ())
|
else if (target_is_non_stop_p ())
|
||||||
{
|
{
|
||||||
struct thread_info *thread;
|
|
||||||
struct thread_info *lowest = inferior_thread ();
|
struct thread_info *lowest = inferior_thread ();
|
||||||
int pid = current_inferior ()->pid;
|
|
||||||
|
|
||||||
stop_all_threads ();
|
stop_all_threads ();
|
||||||
|
|
||||||
|
@ -2758,15 +2739,10 @@ attach_post_wait (const char *args, int from_tty, enum attach_post_wait_mode mod
|
||||||
stop. For consistency, always select the thread with
|
stop. For consistency, always select the thread with
|
||||||
lowest GDB number, which should be the main thread, if it
|
lowest GDB number, which should be the main thread, if it
|
||||||
still exists. */
|
still exists. */
|
||||||
ALL_NON_EXITED_THREADS (thread)
|
for (thread_info *thread : current_inferior ()->non_exited_threads ())
|
||||||
{
|
if (thread->inf->num < lowest->inf->num
|
||||||
if (thread->ptid.pid () == pid)
|
|| thread->per_inf_num < lowest->per_inf_num)
|
||||||
{
|
lowest = thread;
|
||||||
if (thread->inf->num < lowest->inf->num
|
|
||||||
|| thread->per_inf_num < lowest->per_inf_num)
|
|
||||||
lowest = thread;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch_to_thread (lowest);
|
switch_to_thread (lowest);
|
||||||
}
|
}
|
||||||
|
@ -3014,11 +2990,6 @@ detach_command (const char *args, int from_tty)
|
||||||
if (!gdbarch_has_global_solist (target_gdbarch ()))
|
if (!gdbarch_has_global_solist (target_gdbarch ()))
|
||||||
no_shared_libraries (NULL, from_tty);
|
no_shared_libraries (NULL, from_tty);
|
||||||
|
|
||||||
/* If we still have inferiors to debug, then don't mess with their
|
|
||||||
threads. */
|
|
||||||
if (!have_inferiors ())
|
|
||||||
init_thread_list ();
|
|
||||||
|
|
||||||
if (deprecated_detach_hook)
|
if (deprecated_detach_hook)
|
||||||
deprecated_detach_hook ();
|
deprecated_detach_hook ();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
/* Inferior iterators and ranges for GDB, the GNU debugger.
|
||||||
|
|
||||||
|
Copyright (C) 2018 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
This file is part of GDB.
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef INFERIOR_ITER_H
|
||||||
|
#define INFERIOR_ITER_H
|
||||||
|
|
||||||
|
#include "common/filtered-iterator.h"
|
||||||
|
#include "common/safe-iterator.h"
|
||||||
|
|
||||||
|
/* A forward iterator that iterates over all inferiors. */
|
||||||
|
|
||||||
|
class all_inferiors_iterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef all_inferiors_iterator self_type;
|
||||||
|
typedef struct inferior *value_type;
|
||||||
|
typedef struct inferior *&reference;
|
||||||
|
typedef struct inferior **pointer;
|
||||||
|
typedef std::forward_iterator_tag iterator_category;
|
||||||
|
typedef int difference_type;
|
||||||
|
|
||||||
|
/* Create an iterator pointing at HEAD. */
|
||||||
|
explicit all_inferiors_iterator (inferior *head)
|
||||||
|
: m_inf (head)
|
||||||
|
{}
|
||||||
|
|
||||||
|
/* Create a one-past-end iterator. */
|
||||||
|
all_inferiors_iterator ()
|
||||||
|
: m_inf (nullptr)
|
||||||
|
{}
|
||||||
|
|
||||||
|
all_inferiors_iterator &operator++ ()
|
||||||
|
{
|
||||||
|
m_inf = m_inf->next;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inferior *operator* () const
|
||||||
|
{ return m_inf; }
|
||||||
|
|
||||||
|
bool operator!= (const all_inferiors_iterator &other) const
|
||||||
|
{ return m_inf != other.m_inf; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
inferior *m_inf;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Filter for filtered_iterator. Filters out exited inferiors. */
|
||||||
|
|
||||||
|
struct exited_inferior_filter
|
||||||
|
{
|
||||||
|
bool operator() (inferior *inf)
|
||||||
|
{
|
||||||
|
return inf->pid != 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Iterate over all non-exited inferiors. */
|
||||||
|
|
||||||
|
using all_non_exited_inferiors_iterator
|
||||||
|
= filtered_iterator<all_inferiors_iterator, exited_inferior_filter>;
|
||||||
|
|
||||||
|
/* A range adapter that makes it possible to iterate over all
|
||||||
|
inferiors with range-for. */
|
||||||
|
struct all_inferiors_range
|
||||||
|
{
|
||||||
|
all_inferiors_iterator begin () const
|
||||||
|
{ return all_inferiors_iterator (inferior_list); }
|
||||||
|
all_inferiors_iterator end () const
|
||||||
|
{ return all_inferiors_iterator (); }
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Iterate over all inferiors, safely. */
|
||||||
|
|
||||||
|
using all_inferiors_safe_iterator
|
||||||
|
= basic_safe_iterator<all_inferiors_iterator>;
|
||||||
|
|
||||||
|
/* A range adapter that makes it possible to iterate over all
|
||||||
|
inferiors with range-for "safely". I.e., it is safe to delete the
|
||||||
|
currently-iterated inferior. */
|
||||||
|
|
||||||
|
struct all_inferiors_safe_range
|
||||||
|
{
|
||||||
|
all_inferiors_safe_iterator begin () const
|
||||||
|
{ return all_inferiors_safe_iterator (inferior_list); }
|
||||||
|
all_inferiors_safe_iterator end () const
|
||||||
|
{ return all_inferiors_safe_iterator (); }
|
||||||
|
};
|
||||||
|
|
||||||
|
/* A range adapter that makes it possible to iterate over all
|
||||||
|
non-exited inferiors with range-for. */
|
||||||
|
|
||||||
|
struct all_non_exited_inferiors_range
|
||||||
|
{
|
||||||
|
all_non_exited_inferiors_iterator begin () const
|
||||||
|
{ return all_non_exited_inferiors_iterator (inferior_list); }
|
||||||
|
all_non_exited_inferiors_iterator end () const
|
||||||
|
{ return all_non_exited_inferiors_iterator (); }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* !defined (INFERIOR_ITER_H) */
|
135
gdb/inferior.c
135
gdb/inferior.c
|
@ -134,34 +134,10 @@ add_inferior (int pid)
|
||||||
return inf;
|
return inf;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct delete_thread_of_inferior_arg
|
|
||||||
{
|
|
||||||
int pid;
|
|
||||||
int silent;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int
|
|
||||||
delete_thread_of_inferior (struct thread_info *tp, void *data)
|
|
||||||
{
|
|
||||||
struct delete_thread_of_inferior_arg *arg
|
|
||||||
= (struct delete_thread_of_inferior_arg *) data;
|
|
||||||
|
|
||||||
if (tp->ptid.pid () == arg->pid)
|
|
||||||
{
|
|
||||||
if (arg->silent)
|
|
||||||
delete_thread_silent (tp);
|
|
||||||
else
|
|
||||||
delete_thread (tp);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
delete_inferior (struct inferior *todel)
|
delete_inferior (struct inferior *todel)
|
||||||
{
|
{
|
||||||
struct inferior *inf, *infprev;
|
struct inferior *inf, *infprev;
|
||||||
struct delete_thread_of_inferior_arg arg;
|
|
||||||
|
|
||||||
infprev = NULL;
|
infprev = NULL;
|
||||||
|
|
||||||
|
@ -172,10 +148,8 @@ delete_inferior (struct inferior *todel)
|
||||||
if (!inf)
|
if (!inf)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
arg.pid = inf->pid;
|
for (thread_info *tp : inf->threads_safe ())
|
||||||
arg.silent = 1;
|
delete_thread_silent (tp);
|
||||||
|
|
||||||
iterate_over_threads (delete_thread_of_inferior, &arg);
|
|
||||||
|
|
||||||
if (infprev)
|
if (infprev)
|
||||||
infprev->next = inf->next;
|
infprev->next = inf->next;
|
||||||
|
@ -198,7 +172,6 @@ static void
|
||||||
exit_inferior_1 (struct inferior *inftoex, int silent)
|
exit_inferior_1 (struct inferior *inftoex, int silent)
|
||||||
{
|
{
|
||||||
struct inferior *inf;
|
struct inferior *inf;
|
||||||
struct delete_thread_of_inferior_arg arg;
|
|
||||||
|
|
||||||
for (inf = inferior_list; inf; inf = inf->next)
|
for (inf = inferior_list; inf; inf = inf->next)
|
||||||
if (inf == inftoex)
|
if (inf == inftoex)
|
||||||
|
@ -207,10 +180,13 @@ exit_inferior_1 (struct inferior *inftoex, int silent)
|
||||||
if (!inf)
|
if (!inf)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
arg.pid = inf->pid;
|
for (thread_info *tp : inf->threads_safe ())
|
||||||
arg.silent = silent;
|
{
|
||||||
|
if (silent)
|
||||||
iterate_over_threads (delete_thread_of_inferior, &arg);
|
delete_thread_silent (tp);
|
||||||
|
else
|
||||||
|
delete_thread (tp);
|
||||||
|
}
|
||||||
|
|
||||||
gdb::observers::inferior_exit.notify (inf);
|
gdb::observers::inferior_exit.notify (inf);
|
||||||
|
|
||||||
|
@ -273,6 +249,11 @@ detach_inferior (inferior *inf)
|
||||||
void
|
void
|
||||||
inferior_appeared (struct inferior *inf, int pid)
|
inferior_appeared (struct inferior *inf, int pid)
|
||||||
{
|
{
|
||||||
|
/* If this is the first inferior with threads, reset the global
|
||||||
|
thread id. */
|
||||||
|
if (!any_thread_p ())
|
||||||
|
init_thread_list ();
|
||||||
|
|
||||||
inf->pid = pid;
|
inf->pid = pid;
|
||||||
inf->has_exit_code = 0;
|
inf->has_exit_code = 0;
|
||||||
inf->exit_code = 0;
|
inf->exit_code = 0;
|
||||||
|
@ -283,21 +264,14 @@ inferior_appeared (struct inferior *inf, int pid)
|
||||||
void
|
void
|
||||||
discard_all_inferiors (void)
|
discard_all_inferiors (void)
|
||||||
{
|
{
|
||||||
struct inferior *inf;
|
for (inferior *inf : all_non_exited_inferiors ())
|
||||||
|
exit_inferior_silent (inf);
|
||||||
for (inf = inferior_list; inf; inf = inf->next)
|
|
||||||
{
|
|
||||||
if (inf->pid != 0)
|
|
||||||
exit_inferior_silent (inf);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct inferior *
|
struct inferior *
|
||||||
find_inferior_id (int num)
|
find_inferior_id (int num)
|
||||||
{
|
{
|
||||||
struct inferior *inf;
|
for (inferior *inf : all_inferiors ())
|
||||||
|
|
||||||
for (inf = inferior_list; inf; inf = inf->next)
|
|
||||||
if (inf->num == num)
|
if (inf->num == num)
|
||||||
return inf;
|
return inf;
|
||||||
|
|
||||||
|
@ -307,14 +281,12 @@ find_inferior_id (int num)
|
||||||
struct inferior *
|
struct inferior *
|
||||||
find_inferior_pid (int pid)
|
find_inferior_pid (int pid)
|
||||||
{
|
{
|
||||||
struct inferior *inf;
|
|
||||||
|
|
||||||
/* Looking for inferior pid == 0 is always wrong, and indicative of
|
/* Looking for inferior pid == 0 is always wrong, and indicative of
|
||||||
a bug somewhere else. There may be more than one with pid == 0,
|
a bug somewhere else. There may be more than one with pid == 0,
|
||||||
for instance. */
|
for instance. */
|
||||||
gdb_assert (pid != 0);
|
gdb_assert (pid != 0);
|
||||||
|
|
||||||
for (inf = inferior_list; inf; inf = inf->next)
|
for (inferior *inf : all_inferiors ())
|
||||||
if (inf->pid == pid)
|
if (inf->pid == pid)
|
||||||
return inf;
|
return inf;
|
||||||
|
|
||||||
|
@ -334,16 +306,14 @@ find_inferior_ptid (ptid_t ptid)
|
||||||
struct inferior *
|
struct inferior *
|
||||||
find_inferior_for_program_space (struct program_space *pspace)
|
find_inferior_for_program_space (struct program_space *pspace)
|
||||||
{
|
{
|
||||||
struct inferior *inf = current_inferior ();
|
struct inferior *cur_inf = current_inferior ();
|
||||||
|
|
||||||
if (inf->pspace == pspace)
|
if (cur_inf->pspace == pspace)
|
||||||
return inf;
|
return cur_inf;
|
||||||
|
|
||||||
for (inf = inferior_list; inf != NULL; inf = inf->next)
|
for (inferior *inf : all_inferiors ())
|
||||||
{
|
if (inf->pspace == pspace)
|
||||||
if (inf->pspace == pspace)
|
return inf;
|
||||||
return inf;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -352,14 +322,9 @@ struct inferior *
|
||||||
iterate_over_inferiors (int (*callback) (struct inferior *, void *),
|
iterate_over_inferiors (int (*callback) (struct inferior *, void *),
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
struct inferior *inf, *infnext;
|
for (inferior *inf : all_inferiors_safe ())
|
||||||
|
if ((*callback) (inf, data))
|
||||||
for (inf = inferior_list; inf; inf = infnext)
|
return inf;
|
||||||
{
|
|
||||||
infnext = inf->next;
|
|
||||||
if ((*callback) (inf, data))
|
|
||||||
return inf;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -367,11 +332,8 @@ iterate_over_inferiors (int (*callback) (struct inferior *, void *),
|
||||||
int
|
int
|
||||||
have_inferiors (void)
|
have_inferiors (void)
|
||||||
{
|
{
|
||||||
struct inferior *inf;
|
for (inferior *inf ATTRIBUTE_UNUSED : all_non_exited_inferiors ())
|
||||||
|
return 1;
|
||||||
for (inf = inferior_list; inf; inf = inf->next)
|
|
||||||
if (inf->pid != 0)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -383,24 +345,17 @@ have_inferiors (void)
|
||||||
int
|
int
|
||||||
number_of_live_inferiors (void)
|
number_of_live_inferiors (void)
|
||||||
{
|
{
|
||||||
struct inferior *inf;
|
|
||||||
int num_inf = 0;
|
int num_inf = 0;
|
||||||
|
|
||||||
for (inf = inferior_list; inf; inf = inf->next)
|
for (inferior *inf : all_non_exited_inferiors ())
|
||||||
if (inf->pid != 0)
|
if (target_has_execution_1 (ptid_t (inf->pid)))
|
||||||
{
|
for (thread_info *tp ATTRIBUTE_UNUSED : inf->non_exited_threads ())
|
||||||
struct thread_info *tp;
|
{
|
||||||
|
/* Found a live thread in this inferior, go to the next
|
||||||
ALL_NON_EXITED_THREADS (tp)
|
inferior. */
|
||||||
if (tp && tp->ptid.pid () == inf->pid)
|
++num_inf;
|
||||||
if (target_has_execution_1 (tp->ptid))
|
break;
|
||||||
{
|
}
|
||||||
/* Found a live thread in this inferior, go to the next
|
|
||||||
inferior. */
|
|
||||||
++num_inf;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return num_inf;
|
return num_inf;
|
||||||
}
|
}
|
||||||
|
@ -445,13 +400,8 @@ prune_inferiors (void)
|
||||||
int
|
int
|
||||||
number_of_inferiors (void)
|
number_of_inferiors (void)
|
||||||
{
|
{
|
||||||
struct inferior *inf;
|
auto rng = all_inferiors ();
|
||||||
int count = 0;
|
return std::distance (rng.begin (), rng.end ());
|
||||||
|
|
||||||
for (inf = inferior_list; inf != NULL; inf = inf->next)
|
|
||||||
count++;
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Converts an inferior process id to a string. Like
|
/* Converts an inferior process id to a string. Like
|
||||||
|
@ -491,11 +441,10 @@ print_selected_inferior (struct ui_out *uiout)
|
||||||
static void
|
static void
|
||||||
print_inferior (struct ui_out *uiout, const char *requested_inferiors)
|
print_inferior (struct ui_out *uiout, const char *requested_inferiors)
|
||||||
{
|
{
|
||||||
struct inferior *inf;
|
|
||||||
int inf_count = 0;
|
int inf_count = 0;
|
||||||
|
|
||||||
/* Compute number of inferiors we will print. */
|
/* Compute number of inferiors we will print. */
|
||||||
for (inf = inferior_list; inf; inf = inf->next)
|
for (inferior *inf : all_inferiors ())
|
||||||
{
|
{
|
||||||
if (!number_is_in_list (requested_inferiors, inf->num))
|
if (!number_is_in_list (requested_inferiors, inf->num))
|
||||||
continue;
|
continue;
|
||||||
|
@ -516,7 +465,7 @@ print_inferior (struct ui_out *uiout, const char *requested_inferiors)
|
||||||
uiout->table_header (17, ui_left, "exec", "Executable");
|
uiout->table_header (17, ui_left, "exec", "Executable");
|
||||||
|
|
||||||
uiout->table_body ();
|
uiout->table_body ();
|
||||||
for (inf = inferior_list; inf; inf = inf->next)
|
for (inferior *inf : all_inferiors ())
|
||||||
{
|
{
|
||||||
if (!number_is_in_list (requested_inferiors, inf->num))
|
if (!number_is_in_list (requested_inferiors, inf->num))
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -53,6 +53,7 @@ struct thread_info;
|
||||||
#include "common/refcounted-object.h"
|
#include "common/refcounted-object.h"
|
||||||
|
|
||||||
#include "common-inferior.h"
|
#include "common-inferior.h"
|
||||||
|
#include "gdbthread.h"
|
||||||
|
|
||||||
struct infcall_suspend_state;
|
struct infcall_suspend_state;
|
||||||
struct infcall_control_state;
|
struct infcall_control_state;
|
||||||
|
@ -245,17 +246,6 @@ extern int stopped_by_random_signal;
|
||||||
`set print inferior-events'. */
|
`set print inferior-events'. */
|
||||||
extern int print_inferior_events;
|
extern int print_inferior_events;
|
||||||
|
|
||||||
/* STEP_OVER_ALL means step over all subroutine calls.
|
|
||||||
STEP_OVER_UNDEBUGGABLE means step over calls to undebuggable functions.
|
|
||||||
STEP_OVER_NONE means don't step over any subroutine calls. */
|
|
||||||
|
|
||||||
enum step_over_calls_kind
|
|
||||||
{
|
|
||||||
STEP_OVER_NONE,
|
|
||||||
STEP_OVER_ALL,
|
|
||||||
STEP_OVER_UNDEBUGGABLE
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Anything but NO_STOP_QUIETLY means we expect a trap and the caller
|
/* Anything but NO_STOP_QUIETLY means we expect a trap and the caller
|
||||||
will handle it themselves. STOP_QUIETLY is used when running in
|
will handle it themselves. STOP_QUIETLY is used when running in
|
||||||
the shell before the child program has been exec'd and when running
|
the shell before the child program has been exec'd and when running
|
||||||
|
@ -360,6 +350,38 @@ public:
|
||||||
/* Pointer to next inferior in singly-linked list of inferiors. */
|
/* Pointer to next inferior in singly-linked list of inferiors. */
|
||||||
struct inferior *next = NULL;
|
struct inferior *next = NULL;
|
||||||
|
|
||||||
|
/* This inferior's thread list. */
|
||||||
|
thread_info *thread_list = nullptr;
|
||||||
|
|
||||||
|
/* Returns a range adapter covering the inferior's threads,
|
||||||
|
including exited threads. Used like this:
|
||||||
|
|
||||||
|
for (thread_info *thr : inf->threads ())
|
||||||
|
{ .... }
|
||||||
|
*/
|
||||||
|
inf_threads_range threads ()
|
||||||
|
{ return inf_threads_range (this->thread_list); }
|
||||||
|
|
||||||
|
/* Returns a range adapter covering the inferior's non-exited
|
||||||
|
threads. Used like this:
|
||||||
|
|
||||||
|
for (thread_info *thr : inf->non_exited_threads ())
|
||||||
|
{ .... }
|
||||||
|
*/
|
||||||
|
inf_non_exited_threads_range non_exited_threads ()
|
||||||
|
{ return inf_non_exited_threads_range (this->thread_list); }
|
||||||
|
|
||||||
|
/* Like inferior::threads(), but returns a range adapter that can be
|
||||||
|
used with range-for, safely. I.e., it is safe to delete the
|
||||||
|
currently-iterated thread, like this:
|
||||||
|
|
||||||
|
for (thread_info *t : inf->threads_safe ())
|
||||||
|
if (some_condition ())
|
||||||
|
delete f;
|
||||||
|
*/
|
||||||
|
inline safe_inf_threads_range threads_safe ()
|
||||||
|
{ return safe_inf_threads_range (this->thread_list); }
|
||||||
|
|
||||||
/* Convenient handle (GDB inferior id). Unique across all
|
/* Convenient handle (GDB inferior id). Unique across all
|
||||||
inferiors. */
|
inferiors. */
|
||||||
int num = 0;
|
int num = 0;
|
||||||
|
@ -575,17 +597,50 @@ private:
|
||||||
|
|
||||||
/* Traverse all inferiors. */
|
/* Traverse all inferiors. */
|
||||||
|
|
||||||
#define ALL_INFERIORS(I) \
|
|
||||||
for ((I) = inferior_list; (I); (I) = (I)->next)
|
|
||||||
|
|
||||||
/* Traverse all non-exited inferiors. */
|
|
||||||
|
|
||||||
#define ALL_NON_EXITED_INFERIORS(I) \
|
|
||||||
ALL_INFERIORS (I) \
|
|
||||||
if ((I)->pid != 0)
|
|
||||||
|
|
||||||
extern struct inferior *inferior_list;
|
extern struct inferior *inferior_list;
|
||||||
|
|
||||||
|
/* Pull in the internals of the inferiors ranges and iterators. Must
|
||||||
|
be done after struct inferior is defined. */
|
||||||
|
#include "inferior-iter.h"
|
||||||
|
|
||||||
|
/* Return a range that can be used to walk over all inferiors
|
||||||
|
inferiors, with range-for, safely. I.e., it is safe to delete the
|
||||||
|
currently-iterated inferior. When combined with range-for, this
|
||||||
|
allow convenient patterns like this:
|
||||||
|
|
||||||
|
for (inferior *inf : all_inferiors_safe ())
|
||||||
|
if (some_condition ())
|
||||||
|
delete inf;
|
||||||
|
*/
|
||||||
|
|
||||||
|
inline all_inferiors_safe_range
|
||||||
|
all_inferiors_safe ()
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns a range representing all inferiors, suitable to use with
|
||||||
|
range-for, like this:
|
||||||
|
|
||||||
|
for (inferior *inf : all_inferiors ())
|
||||||
|
[...]
|
||||||
|
*/
|
||||||
|
|
||||||
|
inline all_inferiors_range
|
||||||
|
all_inferiors ()
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return a range that can be used to walk over all inferiors with PID
|
||||||
|
not zero, with range-for. */
|
||||||
|
|
||||||
|
inline all_non_exited_inferiors_range
|
||||||
|
all_non_exited_inferiors ()
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
/* Prune away automatically added inferiors that aren't required
|
/* Prune away automatically added inferiors that aren't required
|
||||||
anymore. */
|
anymore. */
|
||||||
extern void prune_inferiors (void);
|
extern void prune_inferiors (void);
|
||||||
|
|
|
@ -546,9 +546,8 @@ void
|
||||||
child_interrupt (struct target_ops *self)
|
child_interrupt (struct target_ops *self)
|
||||||
{
|
{
|
||||||
/* Interrupt the first inferior that has a resumed thread. */
|
/* Interrupt the first inferior that has a resumed thread. */
|
||||||
thread_info *thr;
|
|
||||||
thread_info *resumed = NULL;
|
thread_info *resumed = NULL;
|
||||||
ALL_NON_EXITED_THREADS (thr)
|
for (thread_info *thr : all_non_exited_threads ())
|
||||||
{
|
{
|
||||||
if (thr->executing)
|
if (thr->executing)
|
||||||
{
|
{
|
||||||
|
@ -605,8 +604,7 @@ child_pass_ctrlc (struct target_ops *self)
|
||||||
|
|
||||||
/* Otherwise, pass the Ctrl-C to the first inferior that was resumed
|
/* Otherwise, pass the Ctrl-C to the first inferior that was resumed
|
||||||
in the foreground. */
|
in the foreground. */
|
||||||
inferior *inf;
|
for (inferior *inf : all_inferiors ())
|
||||||
ALL_INFERIORS (inf)
|
|
||||||
{
|
{
|
||||||
if (inf->terminal_state != target_terminal_state::is_ours)
|
if (inf->terminal_state != target_terminal_state::is_ours)
|
||||||
{
|
{
|
||||||
|
|
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
|
static void
|
||||||
follow_exec (ptid_t ptid, char *exec_file_target)
|
follow_exec (ptid_t ptid, char *exec_file_target)
|
||||||
{
|
{
|
||||||
struct thread_info *th, *tmp;
|
|
||||||
struct inferior *inf = current_inferior ();
|
struct inferior *inf = current_inferior ();
|
||||||
int pid = ptid.pid ();
|
int pid = ptid.pid ();
|
||||||
ptid_t process_ptid;
|
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
|
them. Deleting them now rather than at the next user-visible
|
||||||
stop provides a nicer sequence of events for user and MI
|
stop provides a nicer sequence of events for user and MI
|
||||||
notifications. */
|
notifications. */
|
||||||
ALL_THREADS_SAFE (th, tmp)
|
for (thread_info *th : all_threads_safe ())
|
||||||
if (th->ptid.pid () == pid && th->ptid != ptid)
|
if (th->ptid.pid () == pid && th->ptid != ptid)
|
||||||
delete_thread (th);
|
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
|
leader/event thread. E.g., if there was any step-resume
|
||||||
breakpoint or similar, it's gone now. We cannot truly
|
breakpoint or similar, it's gone now. We cannot truly
|
||||||
step-to-next statement through an exec(). */
|
step-to-next statement through an exec(). */
|
||||||
th = inferior_thread ();
|
thread_info *th = inferior_thread ();
|
||||||
th->control.step_resume_breakpoint = NULL;
|
th->control.step_resume_breakpoint = NULL;
|
||||||
th->control.exception_resume_breakpoint = NULL;
|
th->control.exception_resume_breakpoint = NULL;
|
||||||
th->control.single_step_breakpoints = NULL;
|
th->control.single_step_breakpoints = NULL;
|
||||||
|
@ -2851,21 +2850,14 @@ clear_proceed_status (int step)
|
||||||
execution_direction))
|
execution_direction))
|
||||||
target_record_stop_replaying ();
|
target_record_stop_replaying ();
|
||||||
|
|
||||||
if (!non_stop)
|
if (!non_stop && inferior_ptid != null_ptid)
|
||||||
{
|
{
|
||||||
struct thread_info *tp;
|
ptid_t resume_ptid = user_visible_resume_ptid (step);
|
||||||
ptid_t resume_ptid;
|
|
||||||
|
|
||||||
resume_ptid = user_visible_resume_ptid (step);
|
|
||||||
|
|
||||||
/* In all-stop mode, delete the per-thread status of all threads
|
/* In all-stop mode, delete the per-thread status of all threads
|
||||||
we're about to resume, implicitly and explicitly. */
|
we're about to resume, implicitly and explicitly. */
|
||||||
ALL_NON_EXITED_THREADS (tp)
|
for (thread_info *tp : all_non_exited_threads (resume_ptid))
|
||||||
{
|
clear_proceed_status_thread (tp);
|
||||||
if (!tp->ptid.matches (resume_ptid))
|
|
||||||
continue;
|
|
||||||
clear_proceed_status_thread (tp);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inferior_ptid != null_ptid)
|
if (inferior_ptid != null_ptid)
|
||||||
|
@ -2954,7 +2946,6 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
|
||||||
{
|
{
|
||||||
struct regcache *regcache;
|
struct regcache *regcache;
|
||||||
struct gdbarch *gdbarch;
|
struct gdbarch *gdbarch;
|
||||||
struct thread_info *tp;
|
|
||||||
CORE_ADDR pc;
|
CORE_ADDR pc;
|
||||||
ptid_t resume_ptid;
|
ptid_t resume_ptid;
|
||||||
struct execution_control_state ecss;
|
struct execution_control_state ecss;
|
||||||
|
@ -2981,16 +2972,16 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
|
||||||
const address_space *aspace = regcache->aspace ();
|
const address_space *aspace = regcache->aspace ();
|
||||||
|
|
||||||
pc = regcache_read_pc (regcache);
|
pc = regcache_read_pc (regcache);
|
||||||
tp = inferior_thread ();
|
thread_info *cur_thr = inferior_thread ();
|
||||||
|
|
||||||
/* Fill in with reasonable starting values. */
|
/* 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 (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
|
&& breakpoint_here_p (aspace, pc) == ordinary_breakpoint_here
|
||||||
&& execution_direction != EXEC_REVERSE)
|
&& execution_direction != EXEC_REVERSE)
|
||||||
/* There is a breakpoint at the address we will resume at,
|
/* 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
|
Note, we don't do this in reverse, because we won't
|
||||||
actually be executing the breakpoint insn anyway.
|
actually be executing the breakpoint insn anyway.
|
||||||
We'll be (un-)executing the previous instruction. */
|
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)
|
else if (gdbarch_single_step_through_delay_p (gdbarch)
|
||||||
&& gdbarch_single_step_through_delay (gdbarch,
|
&& gdbarch_single_step_through_delay (gdbarch,
|
||||||
get_current_frame ()))
|
get_current_frame ()))
|
||||||
/* We stepped onto an instruction that needs to be stepped
|
/* We stepped onto an instruction that needs to be stepped
|
||||||
again before re-inserting the breakpoint, do so. */
|
again before re-inserting the breakpoint, do so. */
|
||||||
tp->stepping_over_breakpoint = 1;
|
cur_thr->stepping_over_breakpoint = 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -3015,9 +3006,9 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (siggnal != GDB_SIGNAL_DEFAULT)
|
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
|
/* If an exception is thrown from this point on, make sure to
|
||||||
propagate GDB's knowledge of the executing state to the
|
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
|
threads in RESUME_PTID are now running. Unless we're calling an
|
||||||
inferior function, as in that case we pretend the inferior
|
inferior function, as in that case we pretend the inferior
|
||||||
doesn't run at all. */
|
doesn't run at all. */
|
||||||
if (!tp->control.in_infcall)
|
if (!cur_thr->control.in_infcall)
|
||||||
set_running (resume_ptid, 1);
|
set_running (resume_ptid, 1);
|
||||||
|
|
||||||
if (debug_infrun)
|
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
|
/* If scheduler locking applies, we can avoid iterating over all
|
||||||
threads. */
|
threads. */
|
||||||
if (!non_stop && !schedlock_applies (tp))
|
if (!non_stop && !schedlock_applies (cur_thr))
|
||||||
{
|
{
|
||||||
struct thread_info *current = tp;
|
for (thread_info *tp : all_non_exited_threads (resume_ptid))
|
||||||
|
{
|
||||||
ALL_NON_EXITED_THREADS (tp)
|
|
||||||
{
|
|
||||||
/* Ignore the current thread here. It's handled
|
/* Ignore the current thread here. It's handled
|
||||||
afterwards. */
|
afterwards. */
|
||||||
if (tp == current)
|
if (tp == cur_thr)
|
||||||
continue;
|
|
||||||
|
|
||||||
/* Ignore threads of processes we're not resuming. */
|
|
||||||
if (!tp->ptid.matches (resume_ptid))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!thread_still_needs_step_over (tp))
|
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);
|
thread_step_over_chain_enqueue (tp);
|
||||||
}
|
}
|
||||||
|
|
||||||
tp = current;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enqueue the current thread last, so that we move all other
|
/* Enqueue the current thread last, so that we move all other
|
||||||
threads over their breakpoints first. */
|
threads over their breakpoints first. */
|
||||||
if (tp->stepping_over_breakpoint)
|
if (cur_thr->stepping_over_breakpoint)
|
||||||
thread_step_over_chain_enqueue (tp);
|
thread_step_over_chain_enqueue (cur_thr);
|
||||||
|
|
||||||
/* If the thread isn't started, we'll still need to set its prev_pc,
|
/* 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
|
so that switch_back_to_stepped_thread knows the thread hasn't
|
||||||
advanced. Must do this before resuming any thread, as in
|
advanced. Must do this before resuming any thread, as in
|
||||||
all-stop/remote, once we resume we can't send any other packet
|
all-stop/remote, once we resume we can't send any other packet
|
||||||
until the target stops again. */
|
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 ();
|
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.
|
/* In all-stop, but the target is always in non-stop mode.
|
||||||
Start all other threads that are implicitly resumed too. */
|
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 (tp->resumed)
|
||||||
{
|
{
|
||||||
if (debug_infrun)
|
if (debug_infrun)
|
||||||
|
@ -3164,11 +3143,11 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
|
||||||
error (_("Command aborted."));
|
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. */
|
/* The thread wasn't started, and isn't queued, run it now. */
|
||||||
reset_ecs (ecs, tp);
|
reset_ecs (ecs, cur_thr);
|
||||||
switch_to_thread (tp);
|
switch_to_thread (cur_thr);
|
||||||
keep_going_pass_signal (ecs);
|
keep_going_pass_signal (ecs);
|
||||||
if (!ecs->wait_some_more)
|
if (!ecs->wait_some_more)
|
||||||
error (_("Command aborted."));
|
error (_("Command aborted."));
|
||||||
|
@ -3235,9 +3214,6 @@ init_wait_for_inferior (void)
|
||||||
target_last_wait_ptid = minus_one_ptid;
|
target_last_wait_ptid = minus_one_ptid;
|
||||||
|
|
||||||
previous_inferior_ptid = inferior_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
|
static void
|
||||||
infrun_thread_stop_requested (ptid_t ptid)
|
infrun_thread_stop_requested (ptid_t ptid)
|
||||||
{
|
{
|
||||||
struct thread_info *tp;
|
|
||||||
|
|
||||||
/* PTID was requested to stop. If the thread was already stopped,
|
/* PTID was requested to stop. If the thread was already stopped,
|
||||||
but the user/frontend doesn't know about that yet (e.g., the
|
but the user/frontend doesn't know about that yet (e.g., the
|
||||||
thread had been temporarily paused for some step-over), set up
|
thread had been temporarily paused for some step-over), set up
|
||||||
for reporting the stop now. */
|
for reporting the stop now. */
|
||||||
ALL_NON_EXITED_THREADS (tp)
|
for (thread_info *tp : all_threads (ptid))
|
||||||
if (tp->ptid.matches (ptid))
|
{
|
||||||
{
|
if (tp->state != THREAD_RUNNING)
|
||||||
if (tp->state != THREAD_RUNNING)
|
continue;
|
||||||
continue;
|
if (tp->executing)
|
||||||
if (tp->executing)
|
continue;
|
||||||
continue;
|
|
||||||
|
|
||||||
/* Remove matching threads from the step-over queue, so
|
/* Remove matching threads from the step-over queue, so
|
||||||
start_step_over doesn't try to resume them
|
start_step_over doesn't try to resume them
|
||||||
automatically. */
|
automatically. */
|
||||||
if (thread_is_in_step_over_chain (tp))
|
if (thread_is_in_step_over_chain (tp))
|
||||||
thread_step_over_chain_remove (tp);
|
thread_step_over_chain_remove (tp);
|
||||||
|
|
||||||
/* If the thread is stopped, but the user/frontend doesn't
|
/* If the thread is stopped, but the user/frontend doesn't
|
||||||
know about that yet, queue a pending event, as if the
|
know about that yet, queue a pending event, as if the
|
||||||
thread had just stopped now. Unless the thread already had
|
thread had just stopped now. Unless the thread already had
|
||||||
a pending event. */
|
a pending event. */
|
||||||
if (!tp->suspend.waitstatus_pending_p)
|
if (!tp->suspend.waitstatus_pending_p)
|
||||||
{
|
{
|
||||||
tp->suspend.waitstatus_pending_p = 1;
|
tp->suspend.waitstatus_pending_p = 1;
|
||||||
tp->suspend.waitstatus.kind = TARGET_WAITKIND_STOPPED;
|
tp->suspend.waitstatus.kind = TARGET_WAITKIND_STOPPED;
|
||||||
tp->suspend.waitstatus.value.sig = GDB_SIGNAL_0;
|
tp->suspend.waitstatus.value.sig = GDB_SIGNAL_0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear the inline-frame state, since we're re-processing the
|
/* Clear the inline-frame state, since we're re-processing the
|
||||||
stop. */
|
stop. */
|
||||||
clear_inline_frame_state (tp->ptid);
|
clear_inline_frame_state (tp->ptid);
|
||||||
|
|
||||||
/* If this thread was paused because some other thread was
|
/* If this thread was paused because some other thread was
|
||||||
doing an inline-step over, let that finish first. Once
|
doing an inline-step over, let that finish first. Once
|
||||||
that happens, we'll restart all threads and consume pending
|
that happens, we'll restart all threads and consume pending
|
||||||
stop events then. */
|
stop events then. */
|
||||||
if (step_over_info_valid_p ())
|
if (step_over_info_valid_p ())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Otherwise we can process the (new) pending event now. Set
|
/* Otherwise we can process the (new) pending event now. Set
|
||||||
it so this pending event is considered by
|
it so this pending event is considered by
|
||||||
do_target_wait. */
|
do_target_wait. */
|
||||||
tp->resumed = 1;
|
tp->resumed = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -3352,13 +3325,9 @@ for_each_just_stopped_thread (for_each_just_stopped_thread_callback_func func)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
struct thread_info *tp;
|
|
||||||
|
|
||||||
/* In all-stop mode, all threads have stopped. */
|
/* In all-stop mode, all threads have stopped. */
|
||||||
ALL_NON_EXITED_THREADS (tp)
|
for (thread_info *tp : all_non_exited_threads ())
|
||||||
{
|
func (tp);
|
||||||
func (tp);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3427,24 +3396,26 @@ print_target_wait_results (ptid_t waiton_ptid, ptid_t result_ptid,
|
||||||
static struct thread_info *
|
static struct thread_info *
|
||||||
random_pending_event_thread (ptid_t waiton_ptid)
|
random_pending_event_thread (ptid_t waiton_ptid)
|
||||||
{
|
{
|
||||||
struct thread_info *event_tp;
|
|
||||||
int num_events = 0;
|
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
|
/* First see how many events we have. Count only resumed threads
|
||||||
that have an event pending. */
|
that have an event pending. */
|
||||||
ALL_NON_EXITED_THREADS (event_tp)
|
for (thread_info *tp : all_non_exited_threads (waiton_ptid))
|
||||||
if (event_tp->ptid.matches (waiton_ptid)
|
if (has_event (tp))
|
||||||
&& event_tp->resumed
|
|
||||||
&& event_tp->suspend.waitstatus_pending_p)
|
|
||||||
num_events++;
|
num_events++;
|
||||||
|
|
||||||
if (num_events == 0)
|
if (num_events == 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* Now randomly pick a thread out of those that have had events. */
|
/* Now randomly pick a thread out of those that have had events. */
|
||||||
random_selector = (int)
|
int random_selector = (int) ((num_events * (double) rand ())
|
||||||
((num_events * (double) rand ()) / (RAND_MAX + 1.0));
|
/ (RAND_MAX + 1.0));
|
||||||
|
|
||||||
if (debug_infrun && num_events > 1)
|
if (debug_infrun && num_events > 1)
|
||||||
fprintf_unfiltered (gdb_stdlog,
|
fprintf_unfiltered (gdb_stdlog,
|
||||||
|
@ -3452,14 +3423,12 @@ random_pending_event_thread (ptid_t waiton_ptid)
|
||||||
num_events, random_selector);
|
num_events, random_selector);
|
||||||
|
|
||||||
/* Select the Nth thread that has had an event. */
|
/* Select the Nth thread that has had an event. */
|
||||||
ALL_NON_EXITED_THREADS (event_tp)
|
for (thread_info *tp : all_non_exited_threads (waiton_ptid))
|
||||||
if (event_tp->ptid.matches (waiton_ptid)
|
if (has_event (tp))
|
||||||
&& event_tp->resumed
|
|
||||||
&& event_tp->suspend.waitstatus_pending_p)
|
|
||||||
if (random_selector-- == 0)
|
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
|
/* Wrapper for target_wait that first checks whether threads have
|
||||||
|
@ -3755,14 +3724,14 @@ reinstall_readline_callback_handler_cleanup (void *arg)
|
||||||
static void
|
static void
|
||||||
clean_up_just_stopped_threads_fsms (struct execution_control_state *ecs)
|
clean_up_just_stopped_threads_fsms (struct execution_control_state *ecs)
|
||||||
{
|
{
|
||||||
struct thread_info *thr = ecs->event_thread;
|
if (ecs->event_thread != NULL
|
||||||
|
&& ecs->event_thread->thread_fsm != NULL)
|
||||||
if (thr != NULL && thr->thread_fsm != NULL)
|
thread_fsm_clean_up (ecs->event_thread->thread_fsm,
|
||||||
thread_fsm_clean_up (thr->thread_fsm, thr);
|
ecs->event_thread);
|
||||||
|
|
||||||
if (!non_stop)
|
if (!non_stop)
|
||||||
{
|
{
|
||||||
ALL_NON_EXITED_THREADS (thr)
|
for (thread_info *thr : all_non_exited_threads ())
|
||||||
{
|
{
|
||||||
if (thr->thread_fsm == NULL)
|
if (thr->thread_fsm == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
@ -4461,13 +4430,12 @@ stop_all_threads (void)
|
||||||
ptid_t event_ptid;
|
ptid_t event_ptid;
|
||||||
struct target_waitstatus ws;
|
struct target_waitstatus ws;
|
||||||
int need_wait = 0;
|
int need_wait = 0;
|
||||||
struct thread_info *t;
|
|
||||||
|
|
||||||
update_thread_list ();
|
update_thread_list ();
|
||||||
|
|
||||||
/* Go through all threads looking for threads that we need
|
/* Go through all threads looking for threads that we need
|
||||||
to tell the target to stop. */
|
to tell the target to stop. */
|
||||||
ALL_NON_EXITED_THREADS (t)
|
for (thread_info *t : all_non_exited_threads ())
|
||||||
{
|
{
|
||||||
if (t->executing)
|
if (t->executing)
|
||||||
{
|
{
|
||||||
|
@ -4539,9 +4507,7 @@ stop_all_threads (void)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
inferior *inf;
|
thread_info *t = find_thread_ptid (event_ptid);
|
||||||
|
|
||||||
t = find_thread_ptid (event_ptid);
|
|
||||||
if (t == NULL)
|
if (t == NULL)
|
||||||
t = add_thread (event_ptid);
|
t = add_thread (event_ptid);
|
||||||
|
|
||||||
|
@ -4552,7 +4518,7 @@ stop_all_threads (void)
|
||||||
|
|
||||||
/* This may be the first time we see the inferior report
|
/* This may be the first time we see the inferior report
|
||||||
a stop. */
|
a stop. */
|
||||||
inf = find_inferior_ptid (event_ptid);
|
inferior *inf = find_inferior_ptid (event_ptid);
|
||||||
if (inf->needs_setup)
|
if (inf->needs_setup)
|
||||||
{
|
{
|
||||||
switch_to_thread_no_regs (t);
|
switch_to_thread_no_regs (t);
|
||||||
|
@ -4642,9 +4608,6 @@ stop_all_threads (void)
|
||||||
static int
|
static int
|
||||||
handle_no_resumed (struct execution_control_state *ecs)
|
handle_no_resumed (struct execution_control_state *ecs)
|
||||||
{
|
{
|
||||||
struct inferior *inf;
|
|
||||||
struct thread_info *thread;
|
|
||||||
|
|
||||||
if (target_can_async_p ())
|
if (target_can_async_p ())
|
||||||
{
|
{
|
||||||
struct ui *ui;
|
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. */
|
the synchronous command show "no unwaited-for " to the user. */
|
||||||
update_thread_list ();
|
update_thread_list ();
|
||||||
|
|
||||||
ALL_NON_EXITED_THREADS (thread)
|
for (thread_info *thread : all_non_exited_threads ())
|
||||||
{
|
{
|
||||||
if (thread->executing
|
if (thread->executing
|
||||||
|| thread->suspend.waitstatus_pending_p)
|
|| 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
|
process exited meanwhile (thus updating the thread list results
|
||||||
in an empty thread list). In this case we know we'll be getting
|
in an empty thread list). In this case we know we'll be getting
|
||||||
a process exit event shortly. */
|
a process exit event shortly. */
|
||||||
ALL_INFERIORS (inf)
|
for (inferior *inf : all_inferiors ())
|
||||||
{
|
{
|
||||||
if (inf->pid == 0)
|
if (inf->pid == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
thread = any_live_thread_of_inferior (inf);
|
thread_info *thread = any_live_thread_of_inferior (inf);
|
||||||
if (thread == NULL)
|
if (thread == NULL)
|
||||||
{
|
{
|
||||||
if (debug_infrun)
|
if (debug_infrun)
|
||||||
|
@ -5383,12 +5346,10 @@ handle_inferior_event (struct execution_control_state *ecs)
|
||||||
static void
|
static void
|
||||||
restart_threads (struct thread_info *event_thread)
|
restart_threads (struct thread_info *event_thread)
|
||||||
{
|
{
|
||||||
struct thread_info *tp;
|
|
||||||
|
|
||||||
/* In case the instruction just stepped spawned a new thread. */
|
/* In case the instruction just stepped spawned a new thread. */
|
||||||
update_thread_list ();
|
update_thread_list ();
|
||||||
|
|
||||||
ALL_NON_EXITED_THREADS (tp)
|
for (thread_info *tp : all_non_exited_threads ())
|
||||||
{
|
{
|
||||||
if (tp == event_thread)
|
if (tp == event_thread)
|
||||||
{
|
{
|
||||||
|
@ -6996,7 +6957,6 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs)
|
||||||
{
|
{
|
||||||
if (!target_is_non_stop_p ())
|
if (!target_is_non_stop_p ())
|
||||||
{
|
{
|
||||||
struct thread_info *tp;
|
|
||||||
struct thread_info *stepping_thread;
|
struct thread_info *stepping_thread;
|
||||||
|
|
||||||
/* If any thread is blocked on some internal breakpoint, and we
|
/* 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. */
|
/* Look for the stepping/nexting thread. */
|
||||||
stepping_thread = NULL;
|
stepping_thread = NULL;
|
||||||
|
|
||||||
ALL_NON_EXITED_THREADS (tp)
|
for (thread_info *tp : all_non_exited_threads ())
|
||||||
{
|
{
|
||||||
/* Ignore threads of processes the caller is not
|
/* Ignore threads of processes the caller is not
|
||||||
resuming. */
|
resuming. */
|
||||||
|
|
|
@ -3171,9 +3171,7 @@ linux_nat_filter_event (int lwpid, int status)
|
||||||
static void
|
static void
|
||||||
check_zombie_leaders (void)
|
check_zombie_leaders (void)
|
||||||
{
|
{
|
||||||
struct inferior *inf;
|
for (inferior *inf : all_inferiors ())
|
||||||
|
|
||||||
ALL_INFERIORS (inf)
|
|
||||||
{
|
{
|
||||||
struct lwp_info *leader_lp;
|
struct lwp_info *leader_lp;
|
||||||
|
|
||||||
|
@ -3678,28 +3676,25 @@ kill_wait_callback (struct lwp_info *lp, void *data)
|
||||||
static void
|
static void
|
||||||
kill_unfollowed_fork_children (struct inferior *inf)
|
kill_unfollowed_fork_children (struct inferior *inf)
|
||||||
{
|
{
|
||||||
struct thread_info *thread;
|
for (thread_info *thread : inf->non_exited_threads ())
|
||||||
|
{
|
||||||
|
struct target_waitstatus *ws = &thread->pending_follow;
|
||||||
|
|
||||||
ALL_NON_EXITED_THREADS (thread)
|
if (ws->kind == TARGET_WAITKIND_FORKED
|
||||||
if (thread->inf == inf)
|
|| ws->kind == TARGET_WAITKIND_VFORKED)
|
||||||
{
|
{
|
||||||
struct target_waitstatus *ws = &thread->pending_follow;
|
ptid_t child_ptid = ws->value.related_pid;
|
||||||
|
int child_pid = child_ptid.pid ();
|
||||||
|
int child_lwp = child_ptid.lwp ();
|
||||||
|
|
||||||
if (ws->kind == TARGET_WAITKIND_FORKED
|
kill_one_lwp (child_lwp);
|
||||||
|| ws->kind == TARGET_WAITKIND_VFORKED)
|
kill_wait_one_lwp (child_lwp);
|
||||||
{
|
|
||||||
ptid_t child_ptid = ws->value.related_pid;
|
|
||||||
int child_pid = child_ptid.pid ();
|
|
||||||
int child_lwp = child_ptid.lwp ();
|
|
||||||
|
|
||||||
kill_one_lwp (child_lwp);
|
/* Let the arch-specific native code know this process is
|
||||||
kill_wait_one_lwp (child_lwp);
|
gone. */
|
||||||
|
linux_target->low_forget_process (child_pid);
|
||||||
/* Let the arch-specific native code know this process is
|
}
|
||||||
gone. */
|
}
|
||||||
linux_target->low_forget_process (child_pid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -1913,7 +1913,7 @@ linux_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
|
||||||
struct linux_corefile_thread_data thread_args;
|
struct linux_corefile_thread_data thread_args;
|
||||||
struct elf_internal_linux_prpsinfo prpsinfo;
|
struct elf_internal_linux_prpsinfo prpsinfo;
|
||||||
char *note_data = NULL;
|
char *note_data = NULL;
|
||||||
struct thread_info *curr_thr, *signalled_thr, *thr;
|
struct thread_info *curr_thr, *signalled_thr;
|
||||||
|
|
||||||
if (! gdbarch_iterate_over_regset_sections_p (gdbarch))
|
if (! gdbarch_iterate_over_regset_sections_p (gdbarch))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1962,12 +1962,10 @@ linux_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
|
||||||
thread_args.stop_signal = signalled_thr->suspend.stop_signal;
|
thread_args.stop_signal = signalled_thr->suspend.stop_signal;
|
||||||
|
|
||||||
linux_corefile_thread (signalled_thr, &thread_args);
|
linux_corefile_thread (signalled_thr, &thread_args);
|
||||||
ALL_NON_EXITED_THREADS (thr)
|
for (thread_info *thr : current_inferior ()->non_exited_threads ())
|
||||||
{
|
{
|
||||||
if (thr == signalled_thr)
|
if (thr == signalled_thr)
|
||||||
continue;
|
continue;
|
||||||
if (thr->ptid.pid () != inferior_ptid.pid ())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
linux_corefile_thread (thr, &thread_args);
|
linux_corefile_thread (thr, &thread_args);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1587,11 +1587,10 @@ void
|
||||||
thread_db_target::update_thread_list ()
|
thread_db_target::update_thread_list ()
|
||||||
{
|
{
|
||||||
struct thread_db_info *info;
|
struct thread_db_info *info;
|
||||||
struct inferior *inf;
|
|
||||||
|
|
||||||
prune_threads ();
|
prune_threads ();
|
||||||
|
|
||||||
ALL_INFERIORS (inf)
|
for (inferior *inf : all_inferiors ())
|
||||||
{
|
{
|
||||||
struct thread_info *thread;
|
struct thread_info *thread;
|
||||||
|
|
||||||
|
@ -1671,7 +1670,6 @@ thread_db_target::thread_handle_to_thread_info (const gdb_byte *thread_handle,
|
||||||
int handle_len,
|
int handle_len,
|
||||||
inferior *inf)
|
inferior *inf)
|
||||||
{
|
{
|
||||||
struct thread_info *tp;
|
|
||||||
thread_t handle_tid;
|
thread_t handle_tid;
|
||||||
|
|
||||||
/* Thread handle sizes must match in order to proceed. We don't use an
|
/* Thread handle sizes must match in order to proceed. We don't use an
|
||||||
|
@ -1684,11 +1682,11 @@ thread_db_target::thread_handle_to_thread_info (const gdb_byte *thread_handle,
|
||||||
|
|
||||||
handle_tid = * (const thread_t *) thread_handle;
|
handle_tid = * (const thread_t *) thread_handle;
|
||||||
|
|
||||||
ALL_NON_EXITED_THREADS (tp)
|
for (thread_info *tp : inf->non_exited_threads ())
|
||||||
{
|
{
|
||||||
thread_db_thread_info *priv = get_thread_db_thread_info (tp);
|
thread_db_thread_info *priv = get_thread_db_thread_info (tp);
|
||||||
|
|
||||||
if (tp->inf == inf && priv != NULL && handle_tid == priv->tid)
|
if (priv != NULL && handle_tid == priv->tid)
|
||||||
return tp;
|
return tp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -951,6 +951,24 @@ mi_output_running (struct thread_info *thread)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return true if there are multiple inferiors loaded. This is used
|
||||||
|
for backwards compatibility -- if there's only one inferior, output
|
||||||
|
"all", otherwise, output each resumed thread individually. */
|
||||||
|
|
||||||
|
static bool
|
||||||
|
multiple_inferiors_p ()
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
for (inferior *inf ATTRIBUTE_UNUSED : all_non_exited_inferiors ())
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
if (count > 1)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mi_on_resume_1 (struct mi_interp *mi, ptid_t ptid)
|
mi_on_resume_1 (struct mi_interp *mi, ptid_t ptid)
|
||||||
{
|
{
|
||||||
|
@ -968,43 +986,15 @@ mi_on_resume_1 (struct mi_interp *mi, ptid_t ptid)
|
||||||
current_token ? current_token : "");
|
current_token ? current_token : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ptid.pid () == -1)
|
/* Backwards compatibility. If doing a wildcard resume and there's
|
||||||
|
only one inferior, output "all", otherwise, output each resumed
|
||||||
|
thread individually. */
|
||||||
|
if ((ptid == minus_one_ptid || ptid.is_pid ())
|
||||||
|
&& !multiple_inferiors_p ())
|
||||||
fprintf_unfiltered (mi->raw_stdout, "*running,thread-id=\"all\"\n");
|
fprintf_unfiltered (mi->raw_stdout, "*running,thread-id=\"all\"\n");
|
||||||
else if (ptid.is_pid ())
|
|
||||||
{
|
|
||||||
int count = 0;
|
|
||||||
inferior *inf;
|
|
||||||
|
|
||||||
/* Backwards compatibility. If there's only one inferior,
|
|
||||||
output "all", otherwise, output each resumed thread
|
|
||||||
individually. */
|
|
||||||
ALL_INFERIORS (inf)
|
|
||||||
if (inf->pid != 0)
|
|
||||||
{
|
|
||||||
count++;
|
|
||||||
if (count > 1)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count == 1)
|
|
||||||
fprintf_unfiltered (mi->raw_stdout, "*running,thread-id=\"all\"\n");
|
|
||||||
else
|
|
||||||
{
|
|
||||||
thread_info *tp;
|
|
||||||
inferior *curinf = current_inferior ();
|
|
||||||
|
|
||||||
ALL_NON_EXITED_THREADS (tp)
|
|
||||||
if (tp->inf == curinf)
|
|
||||||
mi_output_running (tp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
for (thread_info *tp : all_non_exited_threads (ptid))
|
||||||
thread_info *ti = find_thread_ptid (ptid);
|
mi_output_running (tp);
|
||||||
|
|
||||||
gdb_assert (ti);
|
|
||||||
mi_output_running (ti);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!running_result_record_printed && mi_proceeded)
|
if (!running_result_record_printed && mi_proceeded)
|
||||||
{
|
{
|
||||||
|
|
|
@ -587,8 +587,7 @@ mi_cmd_thread_list_ids (const char *command, char **argv, int argc)
|
||||||
{
|
{
|
||||||
ui_out_emit_tuple tuple_emitter (current_uiout, "thread-ids");
|
ui_out_emit_tuple tuple_emitter (current_uiout, "thread-ids");
|
||||||
|
|
||||||
struct thread_info *tp;
|
for (thread_info *tp : all_non_exited_threads ())
|
||||||
ALL_NON_EXITED_THREADS (tp)
|
|
||||||
{
|
{
|
||||||
if (tp->ptid == inferior_ptid)
|
if (tp->ptid == inferior_ptid)
|
||||||
current_thread = tp->global_num;
|
current_thread = tp->global_num;
|
||||||
|
@ -1995,7 +1994,7 @@ mi_execute_command (const char *cmd, int from_tty)
|
||||||
top_level_interpreter ()->interp_ui_out ()->is_mi_like_p ()
|
top_level_interpreter ()->interp_ui_out ()->is_mi_like_p ()
|
||||||
/* Don't try report anything if there are no threads --
|
/* Don't try report anything if there are no threads --
|
||||||
the program is dead. */
|
the program is dead. */
|
||||||
&& thread_count () != 0
|
&& any_thread_p ()
|
||||||
/* If the command already reports the thread change, no need to do it
|
/* If the command already reports the thread change, no need to do it
|
||||||
again. */
|
again. */
|
||||||
&& !command_notifies_uscc_observer (command.get ()))
|
&& !command_notifies_uscc_observer (command.get ()))
|
||||||
|
|
|
@ -214,8 +214,6 @@ nto_procfs_target::open (const char *arg, int from_tty)
|
||||||
nto_procfs_node = ND_LOCAL_NODE;
|
nto_procfs_node = ND_LOCAL_NODE;
|
||||||
nodestr = (arg != NULL) ? xstrdup (arg) : NULL;
|
nodestr = (arg != NULL) ? xstrdup (arg) : NULL;
|
||||||
|
|
||||||
init_thread_list ();
|
|
||||||
|
|
||||||
if (nodestr)
|
if (nodestr)
|
||||||
{
|
{
|
||||||
nto_procfs_node = netmgr_strtond (nodestr, &endstr);
|
nto_procfs_node = netmgr_strtond (nodestr, &endstr);
|
||||||
|
|
|
@ -379,7 +379,6 @@ record_btrace_target_open (const char *args, int from_tty)
|
||||||
/* If we fail to enable btrace for one thread, disable it for the threads for
|
/* If we fail to enable btrace for one thread, disable it for the threads for
|
||||||
which it was successfully enabled. */
|
which it was successfully enabled. */
|
||||||
scoped_btrace_disable btrace_disable;
|
scoped_btrace_disable btrace_disable;
|
||||||
struct thread_info *tp;
|
|
||||||
|
|
||||||
DEBUG ("open");
|
DEBUG ("open");
|
||||||
|
|
||||||
|
@ -388,7 +387,7 @@ record_btrace_target_open (const char *args, int from_tty)
|
||||||
if (!target_has_execution)
|
if (!target_has_execution)
|
||||||
error (_("The program is not being run."));
|
error (_("The program is not being run."));
|
||||||
|
|
||||||
ALL_NON_EXITED_THREADS (tp)
|
for (thread_info *tp : all_non_exited_threads ())
|
||||||
if (args == NULL || *args == 0 || number_is_in_list (args, tp->global_num))
|
if (args == NULL || *args == 0 || number_is_in_list (args, tp->global_num))
|
||||||
{
|
{
|
||||||
btrace_enable (tp, &record_btrace_conf);
|
btrace_enable (tp, &record_btrace_conf);
|
||||||
|
@ -406,13 +405,11 @@ record_btrace_target_open (const char *args, int from_tty)
|
||||||
void
|
void
|
||||||
record_btrace_target::stop_recording ()
|
record_btrace_target::stop_recording ()
|
||||||
{
|
{
|
||||||
struct thread_info *tp;
|
|
||||||
|
|
||||||
DEBUG ("stop recording");
|
DEBUG ("stop recording");
|
||||||
|
|
||||||
record_btrace_auto_disable ();
|
record_btrace_auto_disable ();
|
||||||
|
|
||||||
ALL_NON_EXITED_THREADS (tp)
|
for (thread_info *tp : all_non_exited_threads ())
|
||||||
if (tp->btrace.target != NULL)
|
if (tp->btrace.target != NULL)
|
||||||
btrace_disable (tp);
|
btrace_disable (tp);
|
||||||
}
|
}
|
||||||
|
@ -437,8 +434,6 @@ record_btrace_target::disconnect (const char *args,
|
||||||
void
|
void
|
||||||
record_btrace_target::close ()
|
record_btrace_target::close ()
|
||||||
{
|
{
|
||||||
struct thread_info *tp;
|
|
||||||
|
|
||||||
if (record_btrace_async_inferior_event_handler != NULL)
|
if (record_btrace_async_inferior_event_handler != NULL)
|
||||||
delete_async_event_handler (&record_btrace_async_inferior_event_handler);
|
delete_async_event_handler (&record_btrace_async_inferior_event_handler);
|
||||||
|
|
||||||
|
@ -448,7 +443,7 @@ record_btrace_target::close ()
|
||||||
|
|
||||||
/* We should have already stopped recording.
|
/* We should have already stopped recording.
|
||||||
Tear down btrace in case we have not. */
|
Tear down btrace in case we have not. */
|
||||||
ALL_NON_EXITED_THREADS (tp)
|
for (thread_info *tp : all_non_exited_threads ())
|
||||||
btrace_teardown (tp);
|
btrace_teardown (tp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1398,10 +1393,8 @@ record_btrace_target::record_method (ptid_t ptid)
|
||||||
bool
|
bool
|
||||||
record_btrace_target::record_is_replaying (ptid_t ptid)
|
record_btrace_target::record_is_replaying (ptid_t ptid)
|
||||||
{
|
{
|
||||||
struct thread_info *tp;
|
for (thread_info *tp : all_non_exited_threads (ptid))
|
||||||
|
if (btrace_is_replaying (tp))
|
||||||
ALL_NON_EXITED_THREADS (tp)
|
|
||||||
if (tp->ptid.matches (ptid) && btrace_is_replaying (tp))
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -2129,7 +2122,6 @@ record_btrace_stop_replaying_at_end (struct thread_info *tp)
|
||||||
void
|
void
|
||||||
record_btrace_target::resume (ptid_t ptid, int step, enum gdb_signal signal)
|
record_btrace_target::resume (ptid_t ptid, int step, enum gdb_signal signal)
|
||||||
{
|
{
|
||||||
struct thread_info *tp;
|
|
||||||
enum btrace_thread_flag flag, cflag;
|
enum btrace_thread_flag flag, cflag;
|
||||||
|
|
||||||
DEBUG ("resume %s: %s%s", target_pid_to_str (ptid),
|
DEBUG ("resume %s: %s%s", target_pid_to_str (ptid),
|
||||||
|
@ -2174,20 +2166,18 @@ record_btrace_target::resume (ptid_t ptid, int step, enum gdb_signal signal)
|
||||||
{
|
{
|
||||||
gdb_assert (inferior_ptid.matches (ptid));
|
gdb_assert (inferior_ptid.matches (ptid));
|
||||||
|
|
||||||
ALL_NON_EXITED_THREADS (tp)
|
for (thread_info *tp : all_non_exited_threads (ptid))
|
||||||
if (tp->ptid.matches (ptid))
|
{
|
||||||
{
|
if (tp->ptid.matches (inferior_ptid))
|
||||||
if (tp->ptid.matches (inferior_ptid))
|
record_btrace_resume_thread (tp, flag);
|
||||||
record_btrace_resume_thread (tp, flag);
|
else
|
||||||
else
|
record_btrace_resume_thread (tp, cflag);
|
||||||
record_btrace_resume_thread (tp, cflag);
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ALL_NON_EXITED_THREADS (tp)
|
for (thread_info *tp : all_non_exited_threads (ptid))
|
||||||
if (tp->ptid.matches (ptid))
|
record_btrace_resume_thread (tp, flag);
|
||||||
record_btrace_resume_thread (tp, flag);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Async support. */
|
/* Async support. */
|
||||||
|
@ -2544,16 +2534,9 @@ record_btrace_target::wait (ptid_t ptid, struct target_waitstatus *status,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Keep a work list of moving threads. */
|
/* Keep a work list of moving threads. */
|
||||||
{
|
for (thread_info *tp : all_non_exited_threads (ptid))
|
||||||
thread_info *tp;
|
if ((tp->btrace.flags & (BTHR_MOVE | BTHR_STOP)) != 0)
|
||||||
|
moving.push_back (tp);
|
||||||
ALL_NON_EXITED_THREADS (tp)
|
|
||||||
{
|
|
||||||
if (tp->ptid.matches (ptid)
|
|
||||||
&& ((tp->btrace.flags & (BTHR_MOVE | BTHR_STOP)) != 0))
|
|
||||||
moving.push_back (tp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (moving.empty ())
|
if (moving.empty ())
|
||||||
{
|
{
|
||||||
|
@ -2634,9 +2617,7 @@ record_btrace_target::wait (ptid_t ptid, struct target_waitstatus *status,
|
||||||
/* Stop all other threads. */
|
/* Stop all other threads. */
|
||||||
if (!target_is_non_stop_p ())
|
if (!target_is_non_stop_p ())
|
||||||
{
|
{
|
||||||
thread_info *tp;
|
for (thread_info *tp : all_non_exited_threads ())
|
||||||
|
|
||||||
ALL_NON_EXITED_THREADS (tp)
|
|
||||||
record_btrace_cancel_resume (tp);
|
record_btrace_cancel_resume (tp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2673,14 +2654,11 @@ record_btrace_target::stop (ptid_t ptid)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
struct thread_info *tp;
|
for (thread_info *tp : all_non_exited_threads (ptid))
|
||||||
|
{
|
||||||
ALL_NON_EXITED_THREADS (tp)
|
tp->btrace.flags &= ~BTHR_MOVE;
|
||||||
if (tp->ptid.matches (ptid))
|
tp->btrace.flags |= BTHR_STOP;
|
||||||
{
|
}
|
||||||
tp->btrace.flags &= ~BTHR_MOVE;
|
|
||||||
tp->btrace.flags |= BTHR_STOP;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2873,9 +2851,7 @@ record_btrace_target::goto_record (ULONGEST insn)
|
||||||
void
|
void
|
||||||
record_btrace_target::record_stop_replaying ()
|
record_btrace_target::record_stop_replaying ()
|
||||||
{
|
{
|
||||||
struct thread_info *tp;
|
for (thread_info *tp : all_non_exited_threads ())
|
||||||
|
|
||||||
ALL_NON_EXITED_THREADS (tp)
|
|
||||||
record_btrace_stop_replaying (tp);
|
record_btrace_stop_replaying (tp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1201,8 +1201,6 @@ record_full_wait_1 (struct target_ops *ops,
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
struct thread_info *tp;
|
|
||||||
|
|
||||||
ret = ops->beneath ()->wait (ptid, status, options);
|
ret = ops->beneath ()->wait (ptid, status, options);
|
||||||
if (status->kind == TARGET_WAITKIND_IGNORE)
|
if (status->kind == TARGET_WAITKIND_IGNORE)
|
||||||
{
|
{
|
||||||
|
@ -1213,7 +1211,7 @@ record_full_wait_1 (struct target_ops *ops,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ALL_NON_EXITED_THREADS (tp)
|
for (thread_info *tp : all_non_exited_threads ())
|
||||||
delete_single_step_breakpoints (tp);
|
delete_single_step_breakpoints (tp);
|
||||||
|
|
||||||
if (record_full_resume_step)
|
if (record_full_resume_step)
|
||||||
|
|
|
@ -1573,9 +1573,6 @@ cooked_read_test (struct gdbarch *gdbarch)
|
||||||
mock_inferior.aspace = &mock_aspace;
|
mock_inferior.aspace = &mock_aspace;
|
||||||
thread_info mock_thread (&mock_inferior, mock_ptid);
|
thread_info mock_thread (&mock_inferior, mock_ptid);
|
||||||
|
|
||||||
scoped_restore restore_thread_list
|
|
||||||
= make_scoped_restore (&thread_list, &mock_thread);
|
|
||||||
|
|
||||||
/* Add the mock inferior to the inferior list so that look ups by
|
/* Add the mock inferior to the inferior list so that look ups by
|
||||||
target+ptid can find it. */
|
target+ptid can find it. */
|
||||||
scoped_restore restore_inferior_list
|
scoped_restore restore_inferior_list
|
||||||
|
|
|
@ -674,9 +674,6 @@ gdbsim_target::create_inferior (const char *exec_file,
|
||||||
built_argv.reset (arg_buf);
|
built_argv.reset (arg_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!have_inferiors ())
|
|
||||||
init_thread_list ();
|
|
||||||
|
|
||||||
if (sim_create_inferior (sim_data->gdbsim_desc, exec_bfd,
|
if (sim_create_inferior (sim_data->gdbsim_desc, exec_bfd,
|
||||||
built_argv.get (), env)
|
built_argv.get (), env)
|
||||||
!= SIM_RC_OK)
|
!= SIM_RC_OK)
|
||||||
|
|
77
gdb/remote.c
77
gdb/remote.c
|
@ -3785,8 +3785,6 @@ remote_target::update_thread_list ()
|
||||||
|| remote_get_threads_with_qthreadinfo (&context)
|
|| remote_get_threads_with_qthreadinfo (&context)
|
||||||
|| remote_get_threads_with_ql (&context))
|
|| remote_get_threads_with_ql (&context))
|
||||||
{
|
{
|
||||||
struct thread_info *tp, *tmp;
|
|
||||||
|
|
||||||
got_list = 1;
|
got_list = 1;
|
||||||
|
|
||||||
if (context.items.empty ()
|
if (context.items.empty ()
|
||||||
|
@ -3803,7 +3801,7 @@ remote_target::update_thread_list ()
|
||||||
/* CONTEXT now holds the current thread list on the remote
|
/* CONTEXT now holds the current thread list on the remote
|
||||||
target end. Delete GDB-side threads no longer found on the
|
target end. Delete GDB-side threads no longer found on the
|
||||||
target. */
|
target. */
|
||||||
ALL_THREADS_SAFE (tp, tmp)
|
for (thread_info *tp : all_threads_safe ())
|
||||||
{
|
{
|
||||||
if (!context.contains_thread (tp->ptid))
|
if (!context.contains_thread (tp->ptid))
|
||||||
{
|
{
|
||||||
|
@ -3830,7 +3828,7 @@ remote_target::update_thread_list ()
|
||||||
|
|
||||||
remote_notice_new_inferior (item.ptid, executing);
|
remote_notice_new_inferior (item.ptid, executing);
|
||||||
|
|
||||||
tp = find_thread_ptid (item.ptid);
|
thread_info *tp = find_thread_ptid (item.ptid);
|
||||||
remote_thread_info *info = get_remote_thread_info (tp);
|
remote_thread_info *info = get_remote_thread_info (tp);
|
||||||
info->core = item.core;
|
info->core = item.core;
|
||||||
info->extra = std::move (item.extra);
|
info->extra = std::move (item.extra);
|
||||||
|
@ -4385,8 +4383,6 @@ void
|
||||||
remote_target::process_initial_stop_replies (int from_tty)
|
remote_target::process_initial_stop_replies (int from_tty)
|
||||||
{
|
{
|
||||||
int pending_stop_replies = stop_reply_queue_length ();
|
int pending_stop_replies = stop_reply_queue_length ();
|
||||||
struct inferior *inf;
|
|
||||||
struct thread_info *thread;
|
|
||||||
struct thread_info *selected = NULL;
|
struct thread_info *selected = NULL;
|
||||||
struct thread_info *lowest_stopped = NULL;
|
struct thread_info *lowest_stopped = NULL;
|
||||||
struct thread_info *first = NULL;
|
struct thread_info *first = NULL;
|
||||||
|
@ -4453,16 +4449,13 @@ remote_target::process_initial_stop_replies (int from_tty)
|
||||||
|
|
||||||
/* "Notice" the new inferiors before anything related to
|
/* "Notice" the new inferiors before anything related to
|
||||||
registers/memory. */
|
registers/memory. */
|
||||||
ALL_INFERIORS (inf)
|
for (inferior *inf : all_non_exited_inferiors ())
|
||||||
{
|
{
|
||||||
if (inf->pid == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
inf->needs_setup = 1;
|
inf->needs_setup = 1;
|
||||||
|
|
||||||
if (non_stop)
|
if (non_stop)
|
||||||
{
|
{
|
||||||
thread = any_live_thread_of_inferior (inf);
|
thread_info *thread = any_live_thread_of_inferior (inf);
|
||||||
notice_new_inferior (thread, thread->state == THREAD_RUNNING,
|
notice_new_inferior (thread, thread->state == THREAD_RUNNING,
|
||||||
from_tty);
|
from_tty);
|
||||||
}
|
}
|
||||||
|
@ -4477,14 +4470,11 @@ remote_target::process_initial_stop_replies (int from_tty)
|
||||||
|
|
||||||
/* If all threads of an inferior were already stopped, we
|
/* If all threads of an inferior were already stopped, we
|
||||||
haven't setup the inferior yet. */
|
haven't setup the inferior yet. */
|
||||||
ALL_INFERIORS (inf)
|
for (inferior *inf : all_non_exited_inferiors ())
|
||||||
{
|
{
|
||||||
if (inf->pid == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (inf->needs_setup)
|
if (inf->needs_setup)
|
||||||
{
|
{
|
||||||
thread = any_live_thread_of_inferior (inf);
|
thread_info *thread = any_live_thread_of_inferior (inf);
|
||||||
switch_to_thread_no_regs (thread);
|
switch_to_thread_no_regs (thread);
|
||||||
setup_inferior (0);
|
setup_inferior (0);
|
||||||
}
|
}
|
||||||
|
@ -4494,7 +4484,7 @@ remote_target::process_initial_stop_replies (int from_tty)
|
||||||
/* Now go over all threads that are stopped, and print their current
|
/* Now go over all threads that are stopped, and print their current
|
||||||
frame. If all-stop, then if there's a signalled thread, pick
|
frame. If all-stop, then if there's a signalled thread, pick
|
||||||
that as current. */
|
that as current. */
|
||||||
ALL_NON_EXITED_THREADS (thread)
|
for (thread_info *thread : all_non_exited_threads ())
|
||||||
{
|
{
|
||||||
if (first == NULL)
|
if (first == NULL)
|
||||||
first = thread;
|
first = thread;
|
||||||
|
@ -4521,7 +4511,7 @@ remote_target::process_initial_stop_replies (int from_tty)
|
||||||
others with their status pending. */
|
others with their status pending. */
|
||||||
if (!non_stop)
|
if (!non_stop)
|
||||||
{
|
{
|
||||||
thread = selected;
|
thread_info *thread = selected;
|
||||||
if (thread == NULL)
|
if (thread == NULL)
|
||||||
thread = lowest_stopped;
|
thread = lowest_stopped;
|
||||||
if (thread == NULL)
|
if (thread == NULL)
|
||||||
|
@ -4531,7 +4521,7 @@ remote_target::process_initial_stop_replies (int from_tty)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For "info program". */
|
/* For "info program". */
|
||||||
thread = inferior_thread ();
|
thread_info *thread = inferior_thread ();
|
||||||
if (thread->state == THREAD_STOPPED)
|
if (thread->state == THREAD_STOPPED)
|
||||||
set_last_target_status (inferior_ptid, thread->suspend.waitstatus);
|
set_last_target_status (inferior_ptid, thread->suspend.waitstatus);
|
||||||
}
|
}
|
||||||
|
@ -4730,7 +4720,7 @@ remote_target::start_remote (int from_tty, int extended_p)
|
||||||
"warning: couldn't determine remote "
|
"warning: couldn't determine remote "
|
||||||
"current thread; picking first in list.\n");
|
"current thread; picking first in list.\n");
|
||||||
|
|
||||||
inferior_ptid = thread_list->ptid;
|
inferior_ptid = inferior_list->thread_list->ptid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5612,9 +5602,6 @@ remote_target::open_1 (const char *name, int from_tty, int extended_p)
|
||||||
/* First delete any symbols previously loaded from shared libraries. */
|
/* First delete any symbols previously loaded from shared libraries. */
|
||||||
no_shared_libraries (NULL, 0);
|
no_shared_libraries (NULL, 0);
|
||||||
|
|
||||||
/* Start afresh. */
|
|
||||||
init_thread_list ();
|
|
||||||
|
|
||||||
/* Start the remote connection. If error() or QUIT, discard this
|
/* Start the remote connection. If error() or QUIT, discard this
|
||||||
target (we'd otherwise be in an inconsistent state) and then
|
target (we'd otherwise be in an inconsistent state) and then
|
||||||
propogate the error on up the exception chain. This ensures that
|
propogate the error on up the exception chain. This ensures that
|
||||||
|
@ -6112,11 +6099,8 @@ char *
|
||||||
remote_target::append_pending_thread_resumptions (char *p, char *endp,
|
remote_target::append_pending_thread_resumptions (char *p, char *endp,
|
||||||
ptid_t ptid)
|
ptid_t ptid)
|
||||||
{
|
{
|
||||||
struct thread_info *thread;
|
for (thread_info *thread : all_non_exited_threads (ptid))
|
||||||
|
if (inferior_ptid != thread->ptid
|
||||||
ALL_NON_EXITED_THREADS (thread)
|
|
||||||
if (thread->ptid.matches (ptid)
|
|
||||||
&& inferior_ptid != thread->ptid
|
|
||||||
&& thread->suspend.stop_signal != GDB_SIGNAL_0)
|
&& thread->suspend.stop_signal != GDB_SIGNAL_0)
|
||||||
{
|
{
|
||||||
p = append_resumption (p, endp, thread->ptid,
|
p = append_resumption (p, endp, thread->ptid,
|
||||||
|
@ -6136,7 +6120,6 @@ remote_target::remote_resume_with_hc (ptid_t ptid, int step,
|
||||||
gdb_signal siggnal)
|
gdb_signal siggnal)
|
||||||
{
|
{
|
||||||
struct remote_state *rs = get_remote_state ();
|
struct remote_state *rs = get_remote_state ();
|
||||||
struct thread_info *thread;
|
|
||||||
char *buf;
|
char *buf;
|
||||||
|
|
||||||
rs->last_sent_signal = siggnal;
|
rs->last_sent_signal = siggnal;
|
||||||
|
@ -6149,7 +6132,7 @@ remote_target::remote_resume_with_hc (ptid_t ptid, int step,
|
||||||
else
|
else
|
||||||
set_continue_thread (ptid);
|
set_continue_thread (ptid);
|
||||||
|
|
||||||
ALL_NON_EXITED_THREADS (thread)
|
for (thread_info *thread : all_non_exited_threads ())
|
||||||
resume_clear_thread_private_info (thread);
|
resume_clear_thread_private_info (thread);
|
||||||
|
|
||||||
buf = rs->buf;
|
buf = rs->buf;
|
||||||
|
@ -6457,8 +6440,6 @@ vcont_builder::push_action (ptid_t ptid, bool step, gdb_signal siggnal)
|
||||||
void
|
void
|
||||||
remote_target::commit_resume ()
|
remote_target::commit_resume ()
|
||||||
{
|
{
|
||||||
struct inferior *inf;
|
|
||||||
struct thread_info *tp;
|
|
||||||
int any_process_wildcard;
|
int any_process_wildcard;
|
||||||
int may_global_wildcard_vcont;
|
int may_global_wildcard_vcont;
|
||||||
|
|
||||||
|
@ -6521,7 +6502,7 @@ remote_target::commit_resume ()
|
||||||
may_global_wildcard_vcont = 1;
|
may_global_wildcard_vcont = 1;
|
||||||
|
|
||||||
/* And assume every process is individually wildcard-able too. */
|
/* And assume every process is individually wildcard-able too. */
|
||||||
ALL_NON_EXITED_INFERIORS (inf)
|
for (inferior *inf : all_non_exited_inferiors ())
|
||||||
{
|
{
|
||||||
remote_inferior *priv = get_remote_inferior (inf);
|
remote_inferior *priv = get_remote_inferior (inf);
|
||||||
|
|
||||||
|
@ -6532,7 +6513,7 @@ remote_target::commit_resume ()
|
||||||
disable process and global wildcard resumes appropriately. */
|
disable process and global wildcard resumes appropriately. */
|
||||||
check_pending_events_prevent_wildcard_vcont (&may_global_wildcard_vcont);
|
check_pending_events_prevent_wildcard_vcont (&may_global_wildcard_vcont);
|
||||||
|
|
||||||
ALL_NON_EXITED_THREADS (tp)
|
for (thread_info *tp : all_non_exited_threads ())
|
||||||
{
|
{
|
||||||
/* If a thread of a process is not meant to be resumed, then we
|
/* If a thread of a process is not meant to be resumed, then we
|
||||||
can't wildcard that process. */
|
can't wildcard that process. */
|
||||||
|
@ -6561,7 +6542,7 @@ remote_target::commit_resume ()
|
||||||
struct vcont_builder vcont_builder (this);
|
struct vcont_builder vcont_builder (this);
|
||||||
|
|
||||||
/* Threads first. */
|
/* Threads first. */
|
||||||
ALL_NON_EXITED_THREADS (tp)
|
for (thread_info *tp : all_non_exited_threads ())
|
||||||
{
|
{
|
||||||
remote_thread_info *remote_thr = get_remote_thread_info (tp);
|
remote_thread_info *remote_thr = get_remote_thread_info (tp);
|
||||||
|
|
||||||
|
@ -6590,7 +6571,7 @@ remote_target::commit_resume ()
|
||||||
supposed to be resumed. */
|
supposed to be resumed. */
|
||||||
any_process_wildcard = 0;
|
any_process_wildcard = 0;
|
||||||
|
|
||||||
ALL_NON_EXITED_INFERIORS (inf)
|
for (inferior *inf : all_non_exited_inferiors ())
|
||||||
{
|
{
|
||||||
if (get_remote_inferior (inf)->may_wildcard_vcont)
|
if (get_remote_inferior (inf)->may_wildcard_vcont)
|
||||||
{
|
{
|
||||||
|
@ -6611,7 +6592,7 @@ remote_target::commit_resume ()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ALL_NON_EXITED_INFERIORS (inf)
|
for (inferior *inf : all_non_exited_inferiors ())
|
||||||
{
|
{
|
||||||
if (get_remote_inferior (inf)->may_wildcard_vcont)
|
if (get_remote_inferior (inf)->may_wildcard_vcont)
|
||||||
{
|
{
|
||||||
|
@ -7018,13 +6999,12 @@ is_pending_fork_parent_thread (struct thread_info *thread)
|
||||||
void
|
void
|
||||||
remote_target::remove_new_fork_children (threads_listing_context *context)
|
remote_target::remove_new_fork_children (threads_listing_context *context)
|
||||||
{
|
{
|
||||||
struct thread_info * thread;
|
|
||||||
int pid = -1;
|
int pid = -1;
|
||||||
struct notif_client *notif = ¬if_client_stop;
|
struct notif_client *notif = ¬if_client_stop;
|
||||||
|
|
||||||
/* For any threads stopped at a fork event, remove the corresponding
|
/* For any threads stopped at a fork event, remove the corresponding
|
||||||
fork child threads from the CONTEXT list. */
|
fork child threads from the CONTEXT list. */
|
||||||
ALL_NON_EXITED_THREADS (thread)
|
for (thread_info *thread : all_non_exited_threads ())
|
||||||
{
|
{
|
||||||
struct target_waitstatus *ws = thread_pending_fork_status (thread);
|
struct target_waitstatus *ws = thread_pending_fork_status (thread);
|
||||||
|
|
||||||
|
@ -9716,12 +9696,11 @@ void
|
||||||
remote_target::kill_new_fork_children (int pid)
|
remote_target::kill_new_fork_children (int pid)
|
||||||
{
|
{
|
||||||
remote_state *rs = get_remote_state ();
|
remote_state *rs = get_remote_state ();
|
||||||
struct thread_info *thread;
|
|
||||||
struct notif_client *notif = ¬if_client_stop;
|
struct notif_client *notif = ¬if_client_stop;
|
||||||
|
|
||||||
/* Kill the fork child threads of any threads in process PID
|
/* Kill the fork child threads of any threads in process PID
|
||||||
that are stopped at a fork event. */
|
that are stopped at a fork event. */
|
||||||
ALL_NON_EXITED_THREADS (thread)
|
for (thread_info *thread : all_non_exited_threads ())
|
||||||
{
|
{
|
||||||
struct target_waitstatus *ws = &thread->pending_follow;
|
struct target_waitstatus *ws = &thread->pending_follow;
|
||||||
|
|
||||||
|
@ -10163,15 +10142,6 @@ Remote replied unexpectedly while setting startup-with-shell: %s"),
|
||||||
extended_remote_restart ();
|
extended_remote_restart ();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!have_inferiors ())
|
|
||||||
{
|
|
||||||
/* Clean up from the last time we ran, before we mark the target
|
|
||||||
running again. This will mark breakpoints uninserted, and
|
|
||||||
get_offsets may insert breakpoints. */
|
|
||||||
init_thread_list ();
|
|
||||||
init_wait_for_inferior ();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* vRun's success return is a stop reply. */
|
/* vRun's success return is a stop reply. */
|
||||||
stop_reply = run_worked ? rs->buf : NULL;
|
stop_reply = run_worked ? rs->buf : NULL;
|
||||||
add_current_inferior_and_thread (stop_reply);
|
add_current_inferior_and_thread (stop_reply);
|
||||||
|
@ -13770,7 +13740,6 @@ void
|
||||||
remote_target::remote_btrace_maybe_reopen ()
|
remote_target::remote_btrace_maybe_reopen ()
|
||||||
{
|
{
|
||||||
struct remote_state *rs = get_remote_state ();
|
struct remote_state *rs = get_remote_state ();
|
||||||
struct thread_info *tp;
|
|
||||||
int btrace_target_pushed = 0;
|
int btrace_target_pushed = 0;
|
||||||
#if !defined (HAVE_LIBIPT)
|
#if !defined (HAVE_LIBIPT)
|
||||||
int warned = 0;
|
int warned = 0;
|
||||||
|
@ -13778,7 +13747,7 @@ remote_target::remote_btrace_maybe_reopen ()
|
||||||
|
|
||||||
scoped_restore_current_thread restore_thread;
|
scoped_restore_current_thread restore_thread;
|
||||||
|
|
||||||
ALL_NON_EXITED_THREADS (tp)
|
for (thread_info *tp : all_non_exited_threads ())
|
||||||
{
|
{
|
||||||
set_general_thread (tp->ptid);
|
set_general_thread (tp->ptid);
|
||||||
|
|
||||||
|
@ -14062,9 +14031,7 @@ remote_target::thread_handle_to_thread_info (const gdb_byte *thread_handle,
|
||||||
int handle_len,
|
int handle_len,
|
||||||
inferior *inf)
|
inferior *inf)
|
||||||
{
|
{
|
||||||
struct thread_info *tp;
|
for (thread_info *tp : all_non_exited_threads ())
|
||||||
|
|
||||||
ALL_NON_EXITED_THREADS (tp)
|
|
||||||
{
|
{
|
||||||
remote_thread_info *priv = get_remote_thread_info (tp);
|
remote_thread_info *priv = get_remote_thread_info (tp);
|
||||||
|
|
||||||
|
|
|
@ -473,9 +473,8 @@ target_terminal::restore_inferior (void)
|
||||||
|
|
||||||
{
|
{
|
||||||
scoped_restore_current_inferior restore_inferior;
|
scoped_restore_current_inferior restore_inferior;
|
||||||
struct inferior *inf;
|
|
||||||
|
|
||||||
ALL_INFERIORS (inf)
|
for (struct inferior *inf : all_inferiors ())
|
||||||
{
|
{
|
||||||
if (inf->terminal_state == target_terminal_state::is_ours_for_output)
|
if (inf->terminal_state == target_terminal_state::is_ours_for_output)
|
||||||
{
|
{
|
||||||
|
@ -501,14 +500,13 @@ static void
|
||||||
target_terminal_is_ours_kind (target_terminal_state desired_state)
|
target_terminal_is_ours_kind (target_terminal_state desired_state)
|
||||||
{
|
{
|
||||||
scoped_restore_current_inferior restore_inferior;
|
scoped_restore_current_inferior restore_inferior;
|
||||||
struct inferior *inf;
|
|
||||||
|
|
||||||
/* Must do this in two passes. First, have all inferiors save the
|
/* Must do this in two passes. First, have all inferiors save the
|
||||||
current terminal settings. Then, after all inferiors have add a
|
current terminal settings. Then, after all inferiors have add a
|
||||||
chance to safely save the terminal settings, restore GDB's
|
chance to safely save the terminal settings, restore GDB's
|
||||||
terminal settings. */
|
terminal settings. */
|
||||||
|
|
||||||
ALL_INFERIORS (inf)
|
for (inferior *inf : all_inferiors ())
|
||||||
{
|
{
|
||||||
if (inf->terminal_state == target_terminal_state::is_inferior)
|
if (inf->terminal_state == target_terminal_state::is_inferior)
|
||||||
{
|
{
|
||||||
|
@ -517,7 +515,7 @@ target_terminal_is_ours_kind (target_terminal_state desired_state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ALL_INFERIORS (inf)
|
for (inferior *inf : all_inferiors ())
|
||||||
{
|
{
|
||||||
/* Note we don't check is_inferior here like above because we
|
/* Note we don't check is_inferior here like above because we
|
||||||
need to handle 'is_ours_for_output -> is_ours' too. Careful
|
need to handle 'is_ours_for_output -> is_ours' too. Careful
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
/* Thread iterators and ranges for GDB, the GNU debugger.
|
||||||
|
|
||||||
|
Copyright (C) 2018 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
This file is part of GDB.
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#include "defs.h"
|
||||||
|
#include "gdbthread.h"
|
||||||
|
#include "inferior.h"
|
||||||
|
|
||||||
|
/* See thread-iter.h. */
|
||||||
|
|
||||||
|
all_threads_iterator::all_threads_iterator (begin_t)
|
||||||
|
{
|
||||||
|
/* Advance M_INF/M_THR to the first thread's position. */
|
||||||
|
for (m_inf = inferior_list; m_inf != NULL; m_inf = m_inf->next)
|
||||||
|
if ((m_thr = m_inf->thread_list) != NULL)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See thread-iter.h. */
|
||||||
|
|
||||||
|
void
|
||||||
|
all_threads_iterator::advance ()
|
||||||
|
{
|
||||||
|
/* The loop below is written in the natural way as-if we'd always
|
||||||
|
start at the beginning of the inferior list. This fast forwards
|
||||||
|
the algorithm to the actual current position. */
|
||||||
|
goto start;
|
||||||
|
|
||||||
|
for (; m_inf != NULL; m_inf = m_inf->next)
|
||||||
|
{
|
||||||
|
m_thr = m_inf->thread_list;
|
||||||
|
while (m_thr != NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
start:
|
||||||
|
m_thr = m_thr->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See thread-iter.h. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
all_matching_threads_iterator::m_inf_matches ()
|
||||||
|
{
|
||||||
|
return (m_filter_ptid == minus_one_ptid
|
||||||
|
|| m_filter_ptid.pid () == m_inf->pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See thread-iter.h. */
|
||||||
|
|
||||||
|
all_matching_threads_iterator::all_matching_threads_iterator
|
||||||
|
(ptid_t filter_ptid)
|
||||||
|
: m_filter_ptid (filter_ptid)
|
||||||
|
{
|
||||||
|
m_thr = nullptr;
|
||||||
|
for (m_inf = inferior_list; m_inf != NULL; m_inf = m_inf->next)
|
||||||
|
if (m_inf_matches ())
|
||||||
|
for (m_thr = m_inf->thread_list; m_thr != NULL; m_thr = m_thr->next)
|
||||||
|
if (m_thr->ptid.matches (m_filter_ptid))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See thread-iter.h. */
|
||||||
|
|
||||||
|
void
|
||||||
|
all_matching_threads_iterator::advance ()
|
||||||
|
{
|
||||||
|
/* The loop below is written in the natural way as-if we'd always
|
||||||
|
start at the beginning of the inferior list. This fast forwards
|
||||||
|
the algorithm to the actual current position. */
|
||||||
|
goto start;
|
||||||
|
|
||||||
|
for (; m_inf != NULL; m_inf = m_inf->next)
|
||||||
|
if (m_inf_matches ())
|
||||||
|
{
|
||||||
|
m_thr = m_inf->thread_list;
|
||||||
|
while (m_thr != NULL)
|
||||||
|
{
|
||||||
|
if (m_thr->ptid.matches (m_filter_ptid))
|
||||||
|
return;
|
||||||
|
start:
|
||||||
|
m_thr = m_thr->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,311 @@
|
||||||
|
/* Thread iterators and ranges for GDB, the GNU debugger.
|
||||||
|
Copyright (C) 2018 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
This file is part of GDB.
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef THREAD_ITER_H
|
||||||
|
#define THREAD_ITER_H
|
||||||
|
|
||||||
|
#include "common/filtered-iterator.h"
|
||||||
|
#include "common/safe-iterator.h"
|
||||||
|
|
||||||
|
/* A forward iterator that iterates over a given inferior's
|
||||||
|
threads. */
|
||||||
|
|
||||||
|
class inf_threads_iterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef inf_threads_iterator self_type;
|
||||||
|
typedef struct thread_info *value_type;
|
||||||
|
typedef struct thread_info *&reference;
|
||||||
|
typedef struct thread_info **pointer;
|
||||||
|
typedef std::forward_iterator_tag iterator_category;
|
||||||
|
typedef int difference_type;
|
||||||
|
|
||||||
|
/* Create an iterator pointing at HEAD. This takes a thread pointer
|
||||||
|
instead of an inferior pointer to avoid circular dependencies
|
||||||
|
between the thread and inferior header files. */
|
||||||
|
explicit inf_threads_iterator (struct thread_info *head)
|
||||||
|
: m_thr (head)
|
||||||
|
{}
|
||||||
|
|
||||||
|
/* Create a one-past-end iterator. */
|
||||||
|
inf_threads_iterator ()
|
||||||
|
: m_thr (nullptr)
|
||||||
|
{}
|
||||||
|
|
||||||
|
inf_threads_iterator& operator++ ()
|
||||||
|
{
|
||||||
|
m_thr = m_thr->next;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_info *operator* () const { return m_thr; }
|
||||||
|
|
||||||
|
bool operator!= (const inf_threads_iterator &other) const
|
||||||
|
{ return m_thr != other.m_thr; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
/* The currently-iterated thread. NULL if we reached the end of the
|
||||||
|
list. */
|
||||||
|
thread_info *m_thr;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* A range adapter that makes it possible to iterate over an
|
||||||
|
inferior's thread list with range-for. */
|
||||||
|
template<typename Iterator>
|
||||||
|
struct basic_inf_threads_range
|
||||||
|
{
|
||||||
|
friend struct inferior;
|
||||||
|
private:
|
||||||
|
explicit basic_inf_threads_range (struct thread_info *head)
|
||||||
|
: m_head (head)
|
||||||
|
{}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Iterator begin () const { return Iterator (m_head); }
|
||||||
|
Iterator end () const { return Iterator (); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
thread_info *m_head;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* A forward iterator that iterates over all threads of all
|
||||||
|
inferiors. */
|
||||||
|
|
||||||
|
class all_threads_iterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef all_threads_iterator self_type;
|
||||||
|
typedef struct thread_info *value_type;
|
||||||
|
typedef struct thread_info *&reference;
|
||||||
|
typedef struct thread_info **pointer;
|
||||||
|
typedef std::forward_iterator_tag iterator_category;
|
||||||
|
typedef int difference_type;
|
||||||
|
|
||||||
|
/* Tag type. */
|
||||||
|
struct begin_t {};
|
||||||
|
|
||||||
|
/* Create an iterator that points to the first thread of the first
|
||||||
|
inferior. */
|
||||||
|
explicit all_threads_iterator (begin_t);
|
||||||
|
|
||||||
|
/* Create a one-past-end iterator. */
|
||||||
|
all_threads_iterator ()
|
||||||
|
: m_thr (nullptr)
|
||||||
|
{}
|
||||||
|
|
||||||
|
thread_info *operator* () const { return m_thr; }
|
||||||
|
|
||||||
|
all_threads_iterator &operator++ ()
|
||||||
|
{
|
||||||
|
advance ();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator== (const all_threads_iterator &other) const
|
||||||
|
{ return m_thr == other.m_thr; }
|
||||||
|
|
||||||
|
bool operator!= (const all_threads_iterator &other) const
|
||||||
|
{ return m_thr != other.m_thr; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
/* Advance to the next thread. */
|
||||||
|
void advance ();
|
||||||
|
|
||||||
|
private:
|
||||||
|
/* The current inferior and thread. M_THR is NULL if we reached the
|
||||||
|
end of the threads list of the last inferior. */
|
||||||
|
inferior *m_inf;
|
||||||
|
thread_info *m_thr;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Iterate over all threads that match a given PTID. */
|
||||||
|
|
||||||
|
class all_matching_threads_iterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef all_matching_threads_iterator self_type;
|
||||||
|
typedef struct thread_info *value_type;
|
||||||
|
typedef struct thread_info *&reference;
|
||||||
|
typedef struct thread_info **pointer;
|
||||||
|
typedef std::forward_iterator_tag iterator_category;
|
||||||
|
typedef int difference_type;
|
||||||
|
|
||||||
|
/* Creates an iterator that iterates over all threads that match
|
||||||
|
FILTER_PTID. */
|
||||||
|
explicit all_matching_threads_iterator (ptid_t filter_ptid);
|
||||||
|
|
||||||
|
/* Create a one-past-end iterator. */
|
||||||
|
all_matching_threads_iterator ()
|
||||||
|
: m_inf (nullptr),
|
||||||
|
m_thr (nullptr),
|
||||||
|
m_filter_ptid (minus_one_ptid)
|
||||||
|
{}
|
||||||
|
|
||||||
|
thread_info *operator* () const { return m_thr; }
|
||||||
|
|
||||||
|
all_matching_threads_iterator &operator++ ()
|
||||||
|
{
|
||||||
|
advance ();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator== (const all_matching_threads_iterator &other) const
|
||||||
|
{ return m_thr == other.m_thr; }
|
||||||
|
|
||||||
|
bool operator!= (const all_matching_threads_iterator &other) const
|
||||||
|
{ return m_thr != other.m_thr; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
/* Advance to next thread, skipping filtered threads. */
|
||||||
|
void advance ();
|
||||||
|
|
||||||
|
/* True if M_INF matches the process identified by
|
||||||
|
M_FILTER_PTID. */
|
||||||
|
bool m_inf_matches ();
|
||||||
|
|
||||||
|
private:
|
||||||
|
/* The current inferior. */
|
||||||
|
inferior *m_inf;
|
||||||
|
|
||||||
|
/* The current thread. */
|
||||||
|
thread_info *m_thr;
|
||||||
|
|
||||||
|
/* The filter. */
|
||||||
|
ptid_t m_filter_ptid;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Filter for filtered_iterator. Filters out exited threads. */
|
||||||
|
|
||||||
|
struct non_exited_thread_filter
|
||||||
|
{
|
||||||
|
bool operator() (struct thread_info *thr) const
|
||||||
|
{
|
||||||
|
return thr->state != THREAD_EXITED;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Iterate over all non-exited threads that match a given PTID. */
|
||||||
|
|
||||||
|
using all_non_exited_threads_iterator
|
||||||
|
= filtered_iterator<all_matching_threads_iterator, non_exited_thread_filter>;
|
||||||
|
|
||||||
|
/* Iterate over all non-exited threads of an inferior. */
|
||||||
|
|
||||||
|
using inf_non_exited_threads_iterator
|
||||||
|
= filtered_iterator<inf_threads_iterator, non_exited_thread_filter>;
|
||||||
|
|
||||||
|
/* Iterate over all threads of all inferiors, safely. */
|
||||||
|
|
||||||
|
using all_threads_safe_iterator
|
||||||
|
= basic_safe_iterator<all_threads_iterator>;
|
||||||
|
|
||||||
|
/* Iterate over all threads of an inferior, safely. */
|
||||||
|
|
||||||
|
using safe_inf_threads_iterator
|
||||||
|
= basic_safe_iterator<inf_threads_iterator>;
|
||||||
|
|
||||||
|
/* A range adapter that makes it possible to iterate over all threads
|
||||||
|
of an inferior with range-for. */
|
||||||
|
|
||||||
|
using inf_threads_range
|
||||||
|
= basic_inf_threads_range<inf_threads_iterator>;
|
||||||
|
|
||||||
|
/* A range adapter that makes it possible to iterate over all
|
||||||
|
non-exited threads of an inferior with range-for. */
|
||||||
|
|
||||||
|
using inf_non_exited_threads_range
|
||||||
|
= basic_inf_threads_range<inf_non_exited_threads_iterator>;
|
||||||
|
|
||||||
|
/* A range adapter that makes it possible to iterate over all threads
|
||||||
|
of an inferior with range-for, safely. */
|
||||||
|
|
||||||
|
using safe_inf_threads_range
|
||||||
|
= basic_inf_threads_range<safe_inf_threads_iterator>;
|
||||||
|
|
||||||
|
/* A range adapter that makes it possible to iterate over all threads
|
||||||
|
of all inferiors with range-for. */
|
||||||
|
|
||||||
|
struct all_threads_range
|
||||||
|
{
|
||||||
|
all_threads_iterator begin () const
|
||||||
|
{ return all_threads_iterator (all_threads_iterator::begin_t {}); }
|
||||||
|
all_threads_iterator end () const
|
||||||
|
{ return all_threads_iterator (); }
|
||||||
|
};
|
||||||
|
|
||||||
|
/* A range adapter that makes it possible to iterate over all threads
|
||||||
|
with range-for "safely". I.e., it is safe to delete the
|
||||||
|
currently-iterated thread. */
|
||||||
|
|
||||||
|
struct all_threads_safe_range
|
||||||
|
{
|
||||||
|
all_threads_safe_iterator begin () const
|
||||||
|
{ return all_threads_safe_iterator (all_threads_iterator::begin_t {}); }
|
||||||
|
all_threads_safe_iterator end () const
|
||||||
|
{ return all_threads_safe_iterator (); }
|
||||||
|
};
|
||||||
|
|
||||||
|
/* A range adapter that makes it possible to iterate over all threads
|
||||||
|
that match a PTID filter with range-for. */
|
||||||
|
|
||||||
|
struct all_matching_threads_range
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit all_matching_threads_range (ptid_t filter_ptid)
|
||||||
|
: m_filter_ptid (filter_ptid)
|
||||||
|
{}
|
||||||
|
all_matching_threads_range ()
|
||||||
|
: m_filter_ptid (minus_one_ptid)
|
||||||
|
{}
|
||||||
|
|
||||||
|
all_matching_threads_iterator begin () const
|
||||||
|
{ return all_matching_threads_iterator (m_filter_ptid); }
|
||||||
|
all_matching_threads_iterator end () const
|
||||||
|
{ return all_matching_threads_iterator (); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
/* The filter. */
|
||||||
|
ptid_t m_filter_ptid;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* A range adapter that makes it possible to iterate over all
|
||||||
|
non-exited threads of all inferiors, with range-for.
|
||||||
|
Threads/inferiors that do not match FILTER_PTID are filtered
|
||||||
|
out. */
|
||||||
|
|
||||||
|
class all_non_exited_threads_range
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit all_non_exited_threads_range (ptid_t filter_ptid)
|
||||||
|
: m_filter_ptid (filter_ptid)
|
||||||
|
{}
|
||||||
|
|
||||||
|
all_non_exited_threads_range ()
|
||||||
|
: m_filter_ptid (minus_one_ptid)
|
||||||
|
{}
|
||||||
|
|
||||||
|
all_non_exited_threads_iterator begin () const
|
||||||
|
{ return all_non_exited_threads_iterator (m_filter_ptid); }
|
||||||
|
all_non_exited_threads_iterator end () const
|
||||||
|
{ return all_non_exited_threads_iterator (); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
ptid_t m_filter_ptid;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* THREAD_ITER_H */
|
346
gdb/thread.c
346
gdb/thread.c
|
@ -45,12 +45,12 @@
|
||||||
#include "tid-parse.h"
|
#include "tid-parse.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include "common/gdb_optional.h"
|
#include "common/gdb_optional.h"
|
||||||
|
#include "inline-frame.h"
|
||||||
|
|
||||||
/* Definition of struct thread_info exported to gdbthread.h. */
|
/* Definition of struct thread_info exported to gdbthread.h. */
|
||||||
|
|
||||||
/* Prototypes for local functions. */
|
/* Prototypes for local functions. */
|
||||||
|
|
||||||
struct thread_info *thread_list = NULL;
|
|
||||||
static int highest_thread_num;
|
static int highest_thread_num;
|
||||||
|
|
||||||
/* True if any thread is, or may be executing. We need to track this
|
/* True if any thread is, or may be executing. We need to track this
|
||||||
|
@ -194,6 +194,8 @@ clear_thread_inferior_resources (struct thread_info *tp)
|
||||||
btrace_teardown (tp);
|
btrace_teardown (tp);
|
||||||
|
|
||||||
thread_cancel_execution_command (tp);
|
thread_cancel_execution_command (tp);
|
||||||
|
|
||||||
|
clear_inline_frame_state (tp->ptid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the TP's state as exited. */
|
/* Set the TP's state as exited. */
|
||||||
|
@ -220,20 +222,19 @@ set_thread_exited (thread_info *tp, int silent)
|
||||||
void
|
void
|
||||||
init_thread_list (void)
|
init_thread_list (void)
|
||||||
{
|
{
|
||||||
struct thread_info *tp, *tmp;
|
|
||||||
|
|
||||||
highest_thread_num = 0;
|
highest_thread_num = 0;
|
||||||
|
|
||||||
ALL_THREADS_SAFE (tp, tmp)
|
for (thread_info *tp : all_threads_safe ())
|
||||||
{
|
{
|
||||||
|
inferior *inf = tp->inf;
|
||||||
|
|
||||||
if (tp->deletable ())
|
if (tp->deletable ())
|
||||||
delete tp;
|
delete tp;
|
||||||
else
|
else
|
||||||
set_thread_exited (tp, 1);
|
set_thread_exited (tp, 1);
|
||||||
}
|
|
||||||
|
|
||||||
thread_list = NULL;
|
inf->thread_list = NULL;
|
||||||
threads_executing = 0;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate a new thread of inferior INF with target id PTID and add
|
/* Allocate a new thread of inferior INF with target id PTID and add
|
||||||
|
@ -244,13 +245,13 @@ new_thread (struct inferior *inf, ptid_t ptid)
|
||||||
{
|
{
|
||||||
thread_info *tp = new thread_info (inf, ptid);
|
thread_info *tp = new thread_info (inf, ptid);
|
||||||
|
|
||||||
if (thread_list == NULL)
|
if (inf->thread_list == NULL)
|
||||||
thread_list = tp;
|
inf->thread_list = tp;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
struct thread_info *last;
|
struct thread_info *last;
|
||||||
|
|
||||||
for (last = thread_list; last->next != NULL; last = last->next)
|
for (last = inf->thread_list; last->next != NULL; last = last->next)
|
||||||
;
|
;
|
||||||
last->next = tp;
|
last->next = tp;
|
||||||
}
|
}
|
||||||
|
@ -261,11 +262,10 @@ new_thread (struct inferior *inf, ptid_t ptid)
|
||||||
struct thread_info *
|
struct thread_info *
|
||||||
add_thread_silent (ptid_t ptid)
|
add_thread_silent (ptid_t ptid)
|
||||||
{
|
{
|
||||||
struct thread_info *tp;
|
|
||||||
struct inferior *inf = find_inferior_ptid (ptid);
|
struct inferior *inf = find_inferior_ptid (ptid);
|
||||||
gdb_assert (inf != NULL);
|
gdb_assert (inf != NULL);
|
||||||
|
|
||||||
tp = find_thread_ptid (ptid);
|
thread_info *tp = find_thread_ptid (inf, ptid);
|
||||||
if (tp)
|
if (tp)
|
||||||
/* Found an old thread with the same id. It has to be dead,
|
/* Found an old thread with the same id. It has to be dead,
|
||||||
otherwise we wouldn't be adding a new thread with the same id.
|
otherwise we wouldn't be adding a new thread with the same id.
|
||||||
|
@ -352,6 +352,16 @@ thread_info::~thread_info ()
|
||||||
xfree (this->name);
|
xfree (this->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* See gdbthread.h. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
thread_info::deletable () const
|
||||||
|
{
|
||||||
|
/* If this is the current thread, or there's code out there that
|
||||||
|
relies on it existing (refcount > 0) we can't delete yet. */
|
||||||
|
return refcount () == 0 && ptid != inferior_ptid;
|
||||||
|
}
|
||||||
|
|
||||||
/* Add TP to the end of the step-over chain LIST_P. */
|
/* Add TP to the end of the step-over chain LIST_P. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -442,7 +452,7 @@ delete_thread_1 (thread_info *thr, bool silent)
|
||||||
|
|
||||||
tpprev = NULL;
|
tpprev = NULL;
|
||||||
|
|
||||||
for (tp = thread_list; tp; tpprev = tp, tp = tp->next)
|
for (tp = thr->inf->thread_list; tp; tpprev = tp, tp = tp->next)
|
||||||
if (tp == thr)
|
if (tp == thr)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -460,7 +470,7 @@ delete_thread_1 (thread_info *thr, bool silent)
|
||||||
if (tpprev)
|
if (tpprev)
|
||||||
tpprev->next = tp->next;
|
tpprev->next = tp->next;
|
||||||
else
|
else
|
||||||
thread_list = tp->next;
|
tp->inf->thread_list = tp->next;
|
||||||
|
|
||||||
delete tp;
|
delete tp;
|
||||||
}
|
}
|
||||||
|
@ -485,9 +495,7 @@ delete_thread_silent (thread_info *thread)
|
||||||
struct thread_info *
|
struct thread_info *
|
||||||
find_thread_global_id (int global_id)
|
find_thread_global_id (int global_id)
|
||||||
{
|
{
|
||||||
struct thread_info *tp;
|
for (thread_info *tp : all_threads ())
|
||||||
|
|
||||||
for (tp = thread_list; tp; tp = tp->next)
|
|
||||||
if (tp->global_num == global_id)
|
if (tp->global_num == global_id)
|
||||||
return tp;
|
return tp;
|
||||||
|
|
||||||
|
@ -497,10 +505,8 @@ find_thread_global_id (int global_id)
|
||||||
static struct thread_info *
|
static struct thread_info *
|
||||||
find_thread_id (struct inferior *inf, int thr_num)
|
find_thread_id (struct inferior *inf, int thr_num)
|
||||||
{
|
{
|
||||||
struct thread_info *tp;
|
for (thread_info *tp : inf->threads ())
|
||||||
|
if (tp->per_inf_num == thr_num)
|
||||||
for (tp = thread_list; tp; tp = tp->next)
|
|
||||||
if (tp->inf == inf && tp->per_inf_num == thr_num)
|
|
||||||
return tp;
|
return tp;
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -511,9 +517,18 @@ find_thread_id (struct inferior *inf, int thr_num)
|
||||||
struct thread_info *
|
struct thread_info *
|
||||||
find_thread_ptid (ptid_t ptid)
|
find_thread_ptid (ptid_t ptid)
|
||||||
{
|
{
|
||||||
struct thread_info *tp;
|
inferior *inf = find_inferior_ptid (ptid);
|
||||||
|
if (inf == NULL)
|
||||||
|
return NULL;
|
||||||
|
return find_thread_ptid (inf, ptid);
|
||||||
|
}
|
||||||
|
|
||||||
for (tp = thread_list; tp; tp = tp->next)
|
/* See gdbthread.h. */
|
||||||
|
|
||||||
|
struct thread_info *
|
||||||
|
find_thread_ptid (inferior *inf, ptid_t ptid)
|
||||||
|
{
|
||||||
|
for (thread_info *tp : inf->threads ())
|
||||||
if (tp->ptid == ptid)
|
if (tp->ptid == ptid)
|
||||||
return tp;
|
return tp;
|
||||||
|
|
||||||
|
@ -549,28 +564,28 @@ struct thread_info *
|
||||||
iterate_over_threads (int (*callback) (struct thread_info *, void *),
|
iterate_over_threads (int (*callback) (struct thread_info *, void *),
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
struct thread_info *tp, *next;
|
for (thread_info *tp : all_threads_safe ())
|
||||||
|
if ((*callback) (tp, data))
|
||||||
for (tp = thread_list; tp; tp = next)
|
return tp;
|
||||||
{
|
|
||||||
next = tp->next;
|
|
||||||
if ((*callback) (tp, data))
|
|
||||||
return tp;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* See gdbthread.h. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
any_thread_p ()
|
||||||
|
{
|
||||||
|
for (thread_info *tp ATTRIBUTE_UNUSED : all_threads ())
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
thread_count (void)
|
thread_count (void)
|
||||||
{
|
{
|
||||||
int result = 0;
|
auto rng = all_threads ();
|
||||||
struct thread_info *tp;
|
return std::distance (rng.begin (), rng.end ());
|
||||||
|
|
||||||
for (tp = thread_list; tp; tp = tp->next)
|
|
||||||
++result;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the number of non-exited threads in the thread list. */
|
/* Return the number of non-exited threads in the thread list. */
|
||||||
|
@ -578,21 +593,14 @@ thread_count (void)
|
||||||
static int
|
static int
|
||||||
live_threads_count (void)
|
live_threads_count (void)
|
||||||
{
|
{
|
||||||
int result = 0;
|
auto rng = all_non_exited_threads ();
|
||||||
struct thread_info *tp;
|
return std::distance (rng.begin (), rng.end ());
|
||||||
|
|
||||||
ALL_NON_EXITED_THREADS (tp)
|
|
||||||
++result;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
valid_global_thread_id (int global_id)
|
valid_global_thread_id (int global_id)
|
||||||
{
|
{
|
||||||
struct thread_info *tp;
|
for (thread_info *tp : all_threads ())
|
||||||
|
|
||||||
for (tp = thread_list; tp; tp = tp->next)
|
|
||||||
if (tp->global_num == global_id)
|
if (tp->global_num == global_id)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
@ -602,13 +610,7 @@ valid_global_thread_id (int global_id)
|
||||||
int
|
int
|
||||||
in_thread_list (ptid_t ptid)
|
in_thread_list (ptid_t ptid)
|
||||||
{
|
{
|
||||||
struct thread_info *tp;
|
return find_thread_ptid (ptid) != nullptr;
|
||||||
|
|
||||||
for (tp = thread_list; tp; tp = tp->next)
|
|
||||||
if (tp->ptid == ptid)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
return 0; /* Never heard of 'im. */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Finds the first thread of the inferior. */
|
/* Finds the first thread of the inferior. */
|
||||||
|
@ -616,30 +618,20 @@ in_thread_list (ptid_t ptid)
|
||||||
thread_info *
|
thread_info *
|
||||||
first_thread_of_inferior (inferior *inf)
|
first_thread_of_inferior (inferior *inf)
|
||||||
{
|
{
|
||||||
struct thread_info *tp, *ret = NULL;
|
return inf->thread_list;
|
||||||
|
|
||||||
for (tp = thread_list; tp; tp = tp->next)
|
|
||||||
if (tp->inf == inf)
|
|
||||||
if (ret == NULL || tp->global_num < ret->global_num)
|
|
||||||
ret = tp;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
thread_info *
|
thread_info *
|
||||||
any_thread_of_inferior (inferior *inf)
|
any_thread_of_inferior (inferior *inf)
|
||||||
{
|
{
|
||||||
struct thread_info *tp;
|
|
||||||
|
|
||||||
gdb_assert (inf->pid != 0);
|
gdb_assert (inf->pid != 0);
|
||||||
|
|
||||||
/* Prefer the current thread. */
|
/* Prefer the current thread. */
|
||||||
if (inf == current_inferior ())
|
if (inf == current_inferior ())
|
||||||
return inferior_thread ();
|
return inferior_thread ();
|
||||||
|
|
||||||
ALL_NON_EXITED_THREADS (tp)
|
for (thread_info *tp : inf->non_exited_threads ())
|
||||||
if (tp->inf == inf)
|
return tp;
|
||||||
return tp;
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -648,7 +640,6 @@ thread_info *
|
||||||
any_live_thread_of_inferior (inferior *inf)
|
any_live_thread_of_inferior (inferior *inf)
|
||||||
{
|
{
|
||||||
struct thread_info *curr_tp = NULL;
|
struct thread_info *curr_tp = NULL;
|
||||||
struct thread_info *tp;
|
|
||||||
struct thread_info *tp_executing = NULL;
|
struct thread_info *tp_executing = NULL;
|
||||||
|
|
||||||
gdb_assert (inf != NULL && inf->pid != 0);
|
gdb_assert (inf != NULL && inf->pid != 0);
|
||||||
|
@ -666,14 +657,13 @@ any_live_thread_of_inferior (inferior *inf)
|
||||||
return curr_tp;
|
return curr_tp;
|
||||||
}
|
}
|
||||||
|
|
||||||
ALL_NON_EXITED_THREADS (tp)
|
for (thread_info *tp : inf->non_exited_threads ())
|
||||||
if (tp->inf == inf)
|
{
|
||||||
{
|
if (!tp->executing)
|
||||||
if (!tp->executing)
|
return tp;
|
||||||
return tp;
|
|
||||||
|
|
||||||
tp_executing = tp;
|
tp_executing = tp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If both the current thread and all live threads are executing,
|
/* If both the current thread and all live threads are executing,
|
||||||
prefer the current thread. */
|
prefer the current thread. */
|
||||||
|
@ -700,13 +690,9 @@ thread_alive (struct thread_info *tp)
|
||||||
void
|
void
|
||||||
prune_threads (void)
|
prune_threads (void)
|
||||||
{
|
{
|
||||||
struct thread_info *tp, *tmp;
|
for (thread_info *tp : all_threads_safe ())
|
||||||
|
if (!thread_alive (tp))
|
||||||
ALL_THREADS_SAFE (tp, tmp)
|
delete_thread (tp);
|
||||||
{
|
|
||||||
if (!thread_alive (tp))
|
|
||||||
delete_thread (tp);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See gdbthreads.h. */
|
/* See gdbthreads.h. */
|
||||||
|
@ -714,13 +700,9 @@ prune_threads (void)
|
||||||
void
|
void
|
||||||
delete_exited_threads (void)
|
delete_exited_threads (void)
|
||||||
{
|
{
|
||||||
struct thread_info *tp, *tmp;
|
for (thread_info *tp : all_threads_safe ())
|
||||||
|
if (tp->state == THREAD_EXITED)
|
||||||
ALL_THREADS_SAFE (tp, tmp)
|
delete_thread (tp);
|
||||||
{
|
|
||||||
if (tp->state == THREAD_EXITED)
|
|
||||||
delete_thread (tp);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return true value if stack temporaies are enabled for the thread
|
/* Return true value if stack temporaies are enabled for the thread
|
||||||
|
@ -785,7 +767,7 @@ thread_change_ptid (ptid_t old_ptid, ptid_t new_ptid)
|
||||||
inf = find_inferior_ptid (old_ptid);
|
inf = find_inferior_ptid (old_ptid);
|
||||||
inf->pid = new_ptid.pid ();
|
inf->pid = new_ptid.pid ();
|
||||||
|
|
||||||
tp = find_thread_ptid (old_ptid);
|
tp = find_thread_ptid (inf, old_ptid);
|
||||||
tp->ptid = new_ptid;
|
tp->ptid = new_ptid;
|
||||||
|
|
||||||
gdb::observers::thread_ptid_changed.notify (old_ptid, new_ptid);
|
gdb::observers::thread_ptid_changed.notify (old_ptid, new_ptid);
|
||||||
|
@ -796,21 +778,8 @@ thread_change_ptid (ptid_t old_ptid, ptid_t new_ptid)
|
||||||
void
|
void
|
||||||
set_resumed (ptid_t ptid, int resumed)
|
set_resumed (ptid_t ptid, int resumed)
|
||||||
{
|
{
|
||||||
struct thread_info *tp;
|
for (thread_info *tp : all_non_exited_threads (ptid))
|
||||||
int all = ptid == minus_one_ptid;
|
tp->resumed = resumed;
|
||||||
|
|
||||||
if (all || ptid.is_pid ())
|
|
||||||
{
|
|
||||||
for (tp = thread_list; tp; tp = tp->next)
|
|
||||||
if (all || tp->ptid.pid () == ptid.pid ())
|
|
||||||
tp->resumed = resumed;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tp = find_thread_ptid (ptid);
|
|
||||||
gdb_assert (tp != NULL);
|
|
||||||
tp->resumed = resumed;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Helper for set_running, that marks one thread either running or
|
/* Helper for set_running, that marks one thread either running or
|
||||||
|
@ -849,74 +818,20 @@ thread_info::set_running (bool running)
|
||||||
void
|
void
|
||||||
set_running (ptid_t ptid, int running)
|
set_running (ptid_t ptid, int running)
|
||||||
{
|
{
|
||||||
struct thread_info *tp;
|
/* We try not to notify the observer if no thread has actually
|
||||||
int all = ptid == minus_one_ptid;
|
changed the running state -- merely to reduce the number of
|
||||||
int any_started = 0;
|
messages to the MI frontend. A frontend is supposed to handle
|
||||||
|
multiple *running notifications just fine. */
|
||||||
|
bool any_started = false;
|
||||||
|
|
||||||
/* We try not to notify the observer if no thread has actually changed
|
for (thread_info *tp : all_non_exited_threads (ptid))
|
||||||
the running state -- merely to reduce the number of messages to
|
if (set_running_thread (tp, running))
|
||||||
frontend. Frontend is supposed to handle multiple *running just fine. */
|
any_started = true;
|
||||||
if (all || ptid.is_pid ())
|
|
||||||
{
|
|
||||||
for (tp = thread_list; tp; tp = tp->next)
|
|
||||||
if (all || tp->ptid.pid () == ptid.pid ())
|
|
||||||
{
|
|
||||||
if (tp->state == THREAD_EXITED)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (set_running_thread (tp, running))
|
|
||||||
any_started = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tp = find_thread_ptid (ptid);
|
|
||||||
gdb_assert (tp != NULL);
|
|
||||||
gdb_assert (tp->state != THREAD_EXITED);
|
|
||||||
if (set_running_thread (tp, running))
|
|
||||||
any_started = 1;
|
|
||||||
}
|
|
||||||
if (any_started)
|
if (any_started)
|
||||||
gdb::observers::target_resumed.notify (ptid);
|
gdb::observers::target_resumed.notify (ptid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
is_thread_state (ptid_t ptid, enum thread_state state)
|
|
||||||
{
|
|
||||||
struct thread_info *tp;
|
|
||||||
|
|
||||||
tp = find_thread_ptid (ptid);
|
|
||||||
gdb_assert (tp);
|
|
||||||
return tp->state == state;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
is_stopped (ptid_t ptid)
|
|
||||||
{
|
|
||||||
return is_thread_state (ptid, THREAD_STOPPED);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
is_exited (ptid_t ptid)
|
|
||||||
{
|
|
||||||
return is_thread_state (ptid, THREAD_EXITED);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
is_running (ptid_t ptid)
|
|
||||||
{
|
|
||||||
return is_thread_state (ptid, THREAD_RUNNING);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
is_executing (ptid_t ptid)
|
|
||||||
{
|
|
||||||
struct thread_info *tp;
|
|
||||||
|
|
||||||
tp = find_thread_ptid (ptid);
|
|
||||||
gdb_assert (tp);
|
|
||||||
return tp->executing;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Helper for set_executing. Set's the thread's 'executing' field
|
/* Helper for set_executing. Set's the thread's 'executing' field
|
||||||
from EXECUTING, and if EXECUTING is true also clears the thread's
|
from EXECUTING, and if EXECUTING is true also clears the thread's
|
||||||
|
@ -933,23 +848,10 @@ set_executing_thread (thread_info *thr, bool executing)
|
||||||
void
|
void
|
||||||
set_executing (ptid_t ptid, int executing)
|
set_executing (ptid_t ptid, int executing)
|
||||||
{
|
{
|
||||||
struct thread_info *tp;
|
for (thread_info *tp : all_non_exited_threads (ptid))
|
||||||
int all = ptid == minus_one_ptid;
|
set_executing_thread (tp, executing);
|
||||||
|
|
||||||
if (all || ptid.is_pid ())
|
/* It only takes one running thread to spawn more threads. */
|
||||||
{
|
|
||||||
for (tp = thread_list; tp; tp = tp->next)
|
|
||||||
if (all || tp->ptid.pid () == ptid.pid ())
|
|
||||||
set_executing_thread (tp, executing);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tp = find_thread_ptid (ptid);
|
|
||||||
gdb_assert (tp);
|
|
||||||
set_executing_thread (tp, executing);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* It only takes one running thread to spawn more threads.*/
|
|
||||||
if (executing)
|
if (executing)
|
||||||
threads_executing = 1;
|
threads_executing = 1;
|
||||||
/* Only clear the flag if the caller is telling us everything is
|
/* Only clear the flag if the caller is telling us everything is
|
||||||
|
@ -969,21 +871,8 @@ threads_are_executing (void)
|
||||||
void
|
void
|
||||||
set_stop_requested (ptid_t ptid, int stop)
|
set_stop_requested (ptid_t ptid, int stop)
|
||||||
{
|
{
|
||||||
struct thread_info *tp;
|
for (thread_info *tp : all_non_exited_threads (ptid))
|
||||||
int all = ptid == minus_one_ptid;
|
tp->stop_requested = stop;
|
||||||
|
|
||||||
if (all || ptid.is_pid ())
|
|
||||||
{
|
|
||||||
for (tp = thread_list; tp; tp = tp->next)
|
|
||||||
if (all || tp->ptid.pid () == ptid.pid ())
|
|
||||||
tp->stop_requested = stop;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tp = find_thread_ptid (ptid);
|
|
||||||
gdb_assert (tp);
|
|
||||||
tp->stop_requested = stop;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Call the stop requested observer so other components of GDB can
|
/* Call the stop requested observer so other components of GDB can
|
||||||
react to this request. */
|
react to this request. */
|
||||||
|
@ -994,35 +883,11 @@ set_stop_requested (ptid_t ptid, int stop)
|
||||||
void
|
void
|
||||||
finish_thread_state (ptid_t ptid)
|
finish_thread_state (ptid_t ptid)
|
||||||
{
|
{
|
||||||
struct thread_info *tp;
|
bool any_started = false;
|
||||||
int all;
|
|
||||||
int any_started = 0;
|
|
||||||
|
|
||||||
all = ptid == minus_one_ptid;
|
for (thread_info *tp : all_non_exited_threads (ptid))
|
||||||
|
if (set_running_thread (tp, tp->executing))
|
||||||
if (all || ptid.is_pid ())
|
any_started = true;
|
||||||
{
|
|
||||||
for (tp = thread_list; tp; tp = tp->next)
|
|
||||||
{
|
|
||||||
if (tp->state == THREAD_EXITED)
|
|
||||||
continue;
|
|
||||||
if (all || ptid.pid () == tp->ptid.pid ())
|
|
||||||
{
|
|
||||||
if (set_running_thread (tp, tp->executing))
|
|
||||||
any_started = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tp = find_thread_ptid (ptid);
|
|
||||||
gdb_assert (tp);
|
|
||||||
if (tp->state != THREAD_EXITED)
|
|
||||||
{
|
|
||||||
if (set_running_thread (tp, tp->executing))
|
|
||||||
any_started = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (any_started)
|
if (any_started)
|
||||||
gdb::observers::target_resumed.notify (ptid);
|
gdb::observers::target_resumed.notify (ptid);
|
||||||
|
@ -1148,8 +1013,6 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads,
|
||||||
int global_ids, int pid,
|
int global_ids, int pid,
|
||||||
int show_global_ids)
|
int show_global_ids)
|
||||||
{
|
{
|
||||||
struct thread_info *tp;
|
|
||||||
struct inferior *inf;
|
|
||||||
int default_inf_num = current_inferior ()->num;
|
int default_inf_num = current_inferior ()->num;
|
||||||
|
|
||||||
update_thread_list ();
|
update_thread_list ();
|
||||||
|
@ -1178,7 +1041,7 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads,
|
||||||
accommodate the largest entry. */
|
accommodate the largest entry. */
|
||||||
size_t target_id_col_width = 17;
|
size_t target_id_col_width = 17;
|
||||||
|
|
||||||
ALL_THREADS (tp)
|
for (thread_info *tp : all_threads ())
|
||||||
{
|
{
|
||||||
if (!should_print_thread (requested_threads, default_inf_num,
|
if (!should_print_thread (requested_threads, default_inf_num,
|
||||||
global_ids, pid, tp))
|
global_ids, pid, tp))
|
||||||
|
@ -1220,7 +1083,8 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads,
|
||||||
/* We'll be switching threads temporarily. */
|
/* We'll be switching threads temporarily. */
|
||||||
scoped_restore_current_thread restore_thread;
|
scoped_restore_current_thread restore_thread;
|
||||||
|
|
||||||
ALL_THREADS_BY_INFERIOR (inf, tp)
|
for (inferior *inf : all_inferiors ())
|
||||||
|
for (thread_info *tp : inf->threads ())
|
||||||
{
|
{
|
||||||
int core;
|
int core;
|
||||||
|
|
||||||
|
@ -1667,16 +1531,9 @@ thread_apply_all_command (const char *cmd, int from_tty)
|
||||||
std::vector<thread_info *> thr_list_cpy;
|
std::vector<thread_info *> thr_list_cpy;
|
||||||
thr_list_cpy.reserve (tc);
|
thr_list_cpy.reserve (tc);
|
||||||
|
|
||||||
{
|
for (thread_info *tp : all_non_exited_threads ())
|
||||||
thread_info *tp;
|
thr_list_cpy.push_back (tp);
|
||||||
|
gdb_assert (thr_list_cpy.size () == tc);
|
||||||
ALL_NON_EXITED_THREADS (tp)
|
|
||||||
{
|
|
||||||
thr_list_cpy.push_back (tp);
|
|
||||||
}
|
|
||||||
|
|
||||||
gdb_assert (thr_list_cpy.size () == tc);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Increment the refcounts, and restore them back on scope
|
/* Increment the refcounts, and restore them back on scope
|
||||||
exit. */
|
exit. */
|
||||||
|
@ -1869,7 +1726,6 @@ thread_name_command (const char *arg, int from_tty)
|
||||||
static void
|
static void
|
||||||
thread_find_command (const char *arg, int from_tty)
|
thread_find_command (const char *arg, int from_tty)
|
||||||
{
|
{
|
||||||
struct thread_info *tp;
|
|
||||||
const char *tmp;
|
const char *tmp;
|
||||||
unsigned long match = 0;
|
unsigned long match = 0;
|
||||||
|
|
||||||
|
@ -1881,7 +1737,7 @@ thread_find_command (const char *arg, int from_tty)
|
||||||
error (_("Invalid regexp (%s): %s"), tmp, arg);
|
error (_("Invalid regexp (%s): %s"), tmp, arg);
|
||||||
|
|
||||||
update_thread_list ();
|
update_thread_list ();
|
||||||
for (tp = thread_list; tp; tp = tp->next)
|
for (thread_info *tp : all_threads ())
|
||||||
{
|
{
|
||||||
if (tp->name != NULL && re_exec (tp->name))
|
if (tp->name != NULL && re_exec (tp->name))
|
||||||
{
|
{
|
||||||
|
@ -1993,10 +1849,8 @@ print_selected_thread_frame (struct ui_out *uiout,
|
||||||
static void
|
static void
|
||||||
update_threads_executing (void)
|
update_threads_executing (void)
|
||||||
{
|
{
|
||||||
struct thread_info *tp;
|
|
||||||
|
|
||||||
threads_executing = 0;
|
threads_executing = 0;
|
||||||
ALL_NON_EXITED_THREADS (tp)
|
for (thread_info *tp : all_non_exited_threads ())
|
||||||
{
|
{
|
||||||
if (tp->executing)
|
if (tp->executing)
|
||||||
{
|
{
|
||||||
|
|
|
@ -55,7 +55,6 @@ parse_thread_id (const char *tidstr, const char **end)
|
||||||
{
|
{
|
||||||
const char *number = tidstr;
|
const char *number = tidstr;
|
||||||
const char *dot, *p1;
|
const char *dot, *p1;
|
||||||
struct thread_info *tp;
|
|
||||||
struct inferior *inf;
|
struct inferior *inf;
|
||||||
int thr_num;
|
int thr_num;
|
||||||
int explicit_inf_id = 0;
|
int explicit_inf_id = 0;
|
||||||
|
@ -90,12 +89,13 @@ parse_thread_id (const char *tidstr, const char **end)
|
||||||
if (thr_num == 0)
|
if (thr_num == 0)
|
||||||
invalid_thread_id_error (number);
|
invalid_thread_id_error (number);
|
||||||
|
|
||||||
ALL_THREADS (tp)
|
thread_info *tp = nullptr;
|
||||||
{
|
for (thread_info *it : inf->threads ())
|
||||||
if (tp->ptid.pid () == inf->pid
|
if (it->per_inf_num == thr_num)
|
||||||
&& tp->per_inf_num == thr_num)
|
{
|
||||||
|
tp = it;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tp == NULL)
|
if (tp == NULL)
|
||||||
{
|
{
|
||||||
|
|
|
@ -67,7 +67,6 @@ x86bsd_dr_get (ptid_t ptid, int regnum)
|
||||||
static void
|
static void
|
||||||
x86bsd_dr_set (int regnum, unsigned long value)
|
x86bsd_dr_set (int regnum, unsigned long value)
|
||||||
{
|
{
|
||||||
struct thread_info *thread;
|
|
||||||
struct dbreg dbregs;
|
struct dbreg dbregs;
|
||||||
|
|
||||||
if (ptrace (PT_GETDBREGS, get_ptrace_pid (inferior_ptid),
|
if (ptrace (PT_GETDBREGS, get_ptrace_pid (inferior_ptid),
|
||||||
|
@ -81,13 +80,12 @@ x86bsd_dr_set (int regnum, unsigned long value)
|
||||||
|
|
||||||
DBREG_DRX ((&dbregs), regnum) = value;
|
DBREG_DRX ((&dbregs), regnum) = value;
|
||||||
|
|
||||||
ALL_NON_EXITED_THREADS (thread)
|
for (thread_info *thread : current_inferior ()->non_exited_threads ())
|
||||||
if (thread->inf == current_inferior ())
|
{
|
||||||
{
|
if (ptrace (PT_SETDBREGS, get_ptrace_pid (thread->ptid),
|
||||||
if (ptrace (PT_SETDBREGS, get_ptrace_pid (thread->ptid),
|
(PTRACE_TYPE_ARG3) &dbregs, 0) == -1)
|
||||||
(PTRACE_TYPE_ARG3) &dbregs, 0) == -1)
|
perror_with_name (_("Couldn't write debug registers"));
|
||||||
perror_with_name (_("Couldn't write debug registers"));
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
Loading…
Reference in New Issue