From patchwork Fri Sep 6 23:27:53 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pedro Alves X-Patchwork-Id: 34423 Received: (qmail 120356 invoked by alias); 6 Sep 2019 23:28:22 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 120304 invoked by uid 89); 6 Sep 2019 23:28:21 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-25.9 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, SPF_HELO_PASS autolearn=ham version=3.3.1 spammy=heard, sk:highest X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 06 Sep 2019 23:28:19 +0000 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id E29E1C044CC5 for ; Fri, 6 Sep 2019 23:28:17 +0000 (UTC) Received: from localhost.localdomain (ovpn04.gateway.prod.ext.ams2.redhat.com [10.39.146.4]) by smtp.corp.redhat.com (Postfix) with ESMTP id 7CCFC5D9D3 for ; Fri, 6 Sep 2019 23:28:17 +0000 (UTC) From: Pedro Alves To: gdb-patches@sourceware.org Subject: [PATCH 09/23] switch inferior/thread before calling target methods Date: Sat, 7 Sep 2019 00:27:53 +0100 Message-Id: <20190906232807.6191-10-palves@redhat.com> In-Reply-To: <20190906232807.6191-1-palves@redhat.com> References: <20190906232807.6191-1-palves@redhat.com> Once each inferior has its own target stack, we'll need to make sure that the right inferior is selected before we call into target methods. It kind of sounds worse than it is in practice. Not that many places need to be concerned. In thread.c, we add a new switch_to_thread_if_alive function that centralizes the switching before calls to target_thread_alive. Other cases are handled with explicit switching. gdb/ChangeLog: yyyy-mm-dd Pedro Alves * gdbthread.h (scoped_restore_current_thread) : Declare. * thread.c (thread_alive): Add assertion. Return bool. (switch_to_thread_if_alive): New. (prune_threads): Switch inferior/thread. (print_thread_info_1): Switch thread before calling target methods. (scoped_restore_current_thread::restore): New, factored out from ... (scoped_restore_current_thread::~scoped_restore_current_thread): ... this. (scoped_restore_current_thread::scoped_restore_current_thread): Add assertion. (thread_apply_all_command, thread_select): Use switch_to_thread_if_alive. * infrun.c (proceed, restart_threads, handle_signal_stop) (switch_back_to_stepped_thread): Switch current thread before calling target methods. --- gdb/infrun.c | 16 ++++++++++++-- gdb/thread.c | 72 +++++++++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 66 insertions(+), 22 deletions(-) diff --git a/gdb/infrun.c b/gdb/infrun.c index 9c888aa72f..61c99e36c4 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -2949,6 +2949,8 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal) { for (thread_info *tp : all_non_exited_threads (resume_ptid)) { + switch_to_thread_no_regs (tp); + /* Ignore the current thread here. It's handled afterwards. */ if (tp == cur_thr) @@ -2966,6 +2968,8 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal) thread_step_over_chain_enqueue (tp); } + + switch_to_thread (cur_thr); } /* Enqueue the current thread last, so that we move all other @@ -3002,6 +3006,8 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal) Start all other threads that are implicitly resumed too. */ for (thread_info *tp : all_non_exited_threads (resume_ptid)) { + switch_to_thread_no_regs (tp); + if (tp->resumed) { if (debug_infrun) @@ -4347,6 +4353,7 @@ stop_all_threads (void) "infrun: %s executing, " "need stop\n", target_pid_to_str (t->ptid).c_str ()); + switch_to_thread_no_regs (t); target_stop (t->ptid); t->stop_requested = 1; } @@ -5191,6 +5198,8 @@ restart_threads (struct thread_info *event_thread) for (thread_info *tp : all_non_exited_threads ()) { + switch_to_thread_no_regs (tp); + if (tp == event_thread) { if (debug_infrun) @@ -5449,9 +5458,8 @@ handle_signal_stop (struct execution_control_state *ecs) { struct regcache *regcache = get_thread_regcache (ecs->event_thread); struct gdbarch *reg_gdbarch = regcache->arch (); - scoped_restore save_inferior_ptid = make_scoped_restore (&inferior_ptid); - inferior_ptid = ecs->ptid; + switch_to_thread (ecs->event_thread); fprintf_unfiltered (gdb_stdlog, "infrun: stop_pc = %s\n", paddress (reg_gdbarch, @@ -6885,6 +6893,8 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs) for (thread_info *tp : all_non_exited_threads ()) { + switch_to_thread_no_regs (tp); + /* Ignore threads of processes the caller is not resuming. */ if (!sched_multi @@ -6936,6 +6946,8 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs) return 1; } } + + switch_to_thread (ecs->event_thread); } return 0; diff --git a/gdb/thread.c b/gdb/thread.c index f79507716b..9a5867306b 100644 --- a/gdb/thread.c +++ b/gdb/thread.c @@ -62,8 +62,6 @@ static int highest_thread_num; spawned new threads we haven't heard of yet. */ static int threads_executing; -static int thread_alive (struct thread_info *); - /* RAII type used to increase / decrease the refcount of each thread in a given list of threads. */ @@ -679,14 +677,38 @@ any_live_thread_of_inferior (inferior *inf) } /* Return true if TP is an active thread. */ -static int -thread_alive (struct thread_info *tp) +static bool +thread_alive (thread_info *tp) { if (tp->state == THREAD_EXITED) - return 0; - if (!target_thread_alive (tp->ptid)) - return 0; - return 1; + return false; + + /* Ensure we're looking at the right target stack. */ + gdb_assert (tp->inf == current_inferior ()); + + return target_thread_alive (tp->ptid); +} + +/* Switch to thread TP if it is alive. Returns true if successfully + switched, false otherwise. */ + +static bool +switch_to_thread_if_alive (thread_info *thr) +{ + scoped_restore_current_thread restore_thread; + + /* Switch inferior first, so that we're looking at the right target + stack. */ + switch_to_inferior_no_thread (thr->inf); + + if (thread_alive (thr)) + { + switch_to_thread (thr); + restore_thread.dont_restore (); + return true; + } + + return false; } /* See gdbthreads.h. */ @@ -694,9 +716,15 @@ thread_alive (struct thread_info *tp) void prune_threads (void) { + scoped_restore_current_thread restore_thread; + for (thread_info *tp : all_threads_safe ()) - if (!thread_alive (tp)) - delete_thread (tp); + { + switch_to_inferior_no_thread (tp->inf); + + if (!thread_alive (tp)) + delete_thread (tp); + } } /* See gdbthreads.h. */ @@ -1037,6 +1065,9 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads, gdb::optional list_emitter; gdb::optional table_emitter; + /* We'll be switching threads temporarily below. */ + scoped_restore_current_thread restore_thread; + if (uiout->is_mi_like_p ()) list_emitter.emplace (uiout, "threads"); else @@ -1054,6 +1085,10 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads, if (!uiout->is_mi_like_p ()) { + /* Switch inferiors so we're looking at the right + target stack. */ + switch_to_inferior_no_thread (tp->inf); + target_id_col_width = std::max (target_id_col_width, thread_target_id_str (tp).size ()); @@ -1085,9 +1120,6 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads, uiout->table_body (); } - /* We'll be switching threads temporarily. */ - scoped_restore_current_thread restore_thread; - for (inferior *inf : all_inferiors ()) for (thread_info *tp : inf->threads ()) { @@ -1116,6 +1148,9 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads, if (show_global_ids || uiout->is_mi_like_p ()) uiout->field_signed ("id", tp->global_num); + /* Switch to the thread (and inferior / target). */ + switch_to_thread (tp); + /* For the CLI, we stuff everything into the target-id field. This is a gross hack to make the output come out looking correct. The underlying problem here is that ui-out has no @@ -1147,9 +1182,8 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads, uiout->text ("(running)\n"); else { - /* The switch below puts us at the top of the stack (leaf + /* The switch above put us at the top of the stack (leaf frame). */ - switch_to_thread (tp); print_stack_frame (get_selected_frame (NULL), /* For MI output, print frame level. */ uiout->is_mi_like_p (), @@ -1662,7 +1696,7 @@ thread_apply_all_command (const char *cmd, int from_tty) scoped_restore_current_thread restore_thread; for (thread_info *thr : thr_list_cpy) - if (thread_alive (thr)) + if (switch_to_thread_if_alive (thr)) thr_try_catch_cmd (thr, cmd, from_tty, flags); } } @@ -1819,7 +1853,7 @@ thread_apply_command (const char *tidlist, int from_tty) continue; } - if (!thread_alive (tp)) + if (!switch_to_thread_if_alive (tp)) { warning (_("Thread %s has terminated."), print_thread_id (tp)); continue; @@ -1983,11 +2017,9 @@ show_print_thread_events (struct ui_file *file, int from_tty, void thread_select (const char *tidstr, thread_info *tp) { - if (!thread_alive (tp)) + if (!switch_to_thread_if_alive (tp)) error (_("Thread ID %s has terminated."), tidstr); - switch_to_thread (tp); - annotate_thread_changed (); /* Since the current thread may have changed, see if there is any