From patchwork Fri Oct 18 15:20:50 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Rohr, Stephan" X-Patchwork-Id: 99214 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 5D54D3858C53 for ; Fri, 18 Oct 2024 15:23:09 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.16]) by sourceware.org (Postfix) with ESMTPS id B8F963858027 for ; Fri, 18 Oct 2024 15:21:39 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org B8F963858027 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=intel.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org B8F963858027 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=192.198.163.16 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1729264903; cv=none; b=F7rzI4vAvCMbtk1ZfITg+3U6begL6LYtlb/e19Osa6zqDweTFSNMSud9LqVZ0+nA8sBl+9GP0ZUyhomeW1yiY/I+8nfZOPUACbp5/z99HcpoBGxCSVEyovomH3x6zIw6DZPafAeLiqFLxzbeLRddRHypE70trZ93NIGjGpy5APE= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1729264903; c=relaxed/simple; bh=hnfOjvd/PliT3N/WyCzmTxXSZCjQFM8Ult6Zfp5ttAA=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=sm0HQ4Phcq5cogkLRmcXNuhTXYq/6eFFTl0GoV9RluquwXsh2yBgoqDxGHuHAA0ovtx9GKgd8Xdyb+2MPe7ZktFyD4OX7Gt5j2CpiEwIDzqgDorPtb3rCx8nSNWZVUuhbus6n8wfyNsO6ExnRuIxW1RkKC7VfxJjf7uzvvmlMs0= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1729264900; x=1760800900; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=hnfOjvd/PliT3N/WyCzmTxXSZCjQFM8Ult6Zfp5ttAA=; b=kpzU9qLkOWcNeAdASk2yT4LMwDwLls05xotWR6annCOUgcqRrlXPmjG4 TjEF1FGH/uxHqv6zkq8GsNOLhOWBQxsH6FDMrafzcdc4kWi8tLZASXRWD H+hr+TCCbM5dVQcQ/Ll4LgOCloxAonua6cqSMhsFrDT3LyMuMTwPnETwQ gHm7yCrJbKshCs7XiyNMKxyy5d1UDTw4mp/sEI0UP2bQNizC5ctQjxNCF +H02xfB+paFa6kpeevAjW/4gv6Y3Xz2uB3VJ4u/d8XqOYHqapeCdN7NLs S9kpbE0EPVwreyv8OfsYnwpAZu1Gjwni1GluKVbvt7nVR7YS+CGgmL1RR Q==; X-CSE-ConnectionGUID: nfcEiAQWT6u+wpSvWj7oxA== X-CSE-MsgGUID: 3eVBE4roRiqpCGbDKpWNrA== X-IronPort-AV: E=McAfee;i="6700,10204,11229"; a="16415742" X-IronPort-AV: E=Sophos;i="6.11,214,1725346800"; d="scan'208";a="16415742" Received: from orviesa006.jf.intel.com ([10.64.159.146]) by fmvoesa110.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 Oct 2024 08:21:40 -0700 X-CSE-ConnectionGUID: AdWAsnMyQsedawVeuusRiw== X-CSE-MsgGUID: d9UIOZZ9SLWU05Pl/JOC/A== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.11,214,1725346800"; d="scan'208";a="79039294" Received: from 984fee0031af.jf.intel.com (HELO localhost) ([10.165.54.65]) by orviesa006-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 Oct 2024 08:21:40 -0700 From: Stephan Rohr To: gdb-patches@sourceware.org Cc: simark@simark.ca, aburgess@redhat.com Subject: [PATCH v3 1/3] gdbserver: use 'gdb::function_view' in 'find_*' and 'for_each_*' Date: Fri, 18 Oct 2024 08:20:50 -0700 Message-Id: <20241018152052.1509373-2-stephan.rohr@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241018152052.1509373-1-stephan.rohr@intel.com> References: <20241018152052.1509373-1-stephan.rohr@intel.com> MIME-Version: 1.0 X-Spam-Status: No, score=-10.3 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org Remove the templated versions of 'find_thread', 'for_each_thread' and 'find_thread_in_random' and replace the template function argument with 'gdb::function_view'. --- gdbserver/gdbthread.h | 101 ++++-------------------------- gdbserver/inferiors.cc | 138 +++++++++++++++++++++++++++++++++++++++++ gdbserver/inferiors.h | 36 +---------- 3 files changed, 154 insertions(+), 121 deletions(-) diff --git a/gdbserver/gdbthread.h b/gdbserver/gdbthread.h index c5a5498088f..adc5857abfd 100644 --- a/gdbserver/gdbthread.h +++ b/gdbserver/gdbthread.h @@ -20,6 +20,7 @@ #define GDBSERVER_GDBTHREAD_H #include "gdbsupport/common-gdbthread.h" +#include "gdbsupport/function-view.h" #include "inferiors.h" #include @@ -103,111 +104,35 @@ struct thread_info *find_any_thread_of_pid (int pid); /* Find the first thread for which FUNC returns true. Return NULL if no thread satisfying FUNC is found. */ -template -static thread_info * -find_thread (Func func) -{ - std::list::iterator next, cur = all_threads.begin (); - - while (cur != all_threads.end ()) - { - next = cur; - next++; - - if (func (*cur)) - return *cur; - - cur = next; - } - - return NULL; -} +thread_info * +find_thread (gdb::function_view func); /* Like the above, but only consider threads with pid PID. */ -template -static thread_info * -find_thread (int pid, Func func) -{ - return find_thread ([&] (thread_info *thread) - { - return thread->id.pid () == pid && func (thread); - }); -} +thread_info * +find_thread (int pid, gdb::function_view func); /* Find the first thread that matches FILTER for which FUNC returns true. Return NULL if no thread satisfying these conditions is found. */ -template -static thread_info * -find_thread (ptid_t filter, Func func) -{ - return find_thread ([&] (thread_info *thread) { - return thread->id.matches (filter) && func (thread); - }); -} +thread_info * +find_thread (ptid_t filter, gdb::function_view func); /* Invoke FUNC for each thread. */ -template -static void -for_each_thread (Func func) -{ - std::list::iterator next, cur = all_threads.begin (); - - while (cur != all_threads.end ()) - { - next = cur; - next++; - func (*cur); - cur = next; - } -} +void +for_each_thread (gdb::function_view func); /* Like the above, but only consider threads with pid PID. */ -template -static void -for_each_thread (int pid, Func func) -{ - for_each_thread ([&] (thread_info *thread) - { - if (pid == thread->id.pid ()) - func (thread); - }); -} +void +for_each_thread (int pid, gdb::function_view func); /* Find the a random thread for which FUNC (THREAD) returns true. If no entry is found then return NULL. */ -template -static thread_info * -find_thread_in_random (Func func) -{ - int count = 0; - int random_selector; - - /* First count how many interesting entries we have. */ - for_each_thread ([&] (thread_info *thread) { - if (func (thread)) - count++; - }); - - if (count == 0) - return NULL; - - /* Now randomly pick an entry out of those. */ - random_selector = (int) - ((count * (double) rand ()) / (RAND_MAX + 1.0)); - - thread_info *thread = find_thread ([&] (thread_info *thr_arg) { - return func (thr_arg) && (random_selector-- == 0); - }); - - gdb_assert (thread != NULL); - - return thread; -} +thread_info * +find_thread_in_random (gdb::function_view func); /* Get current thread ID (Linux task ID). */ #define current_ptid (current_thread->id) diff --git a/gdbserver/inferiors.cc b/gdbserver/inferiors.cc index d088340474f..5621db377fb 100644 --- a/gdbserver/inferiors.cc +++ b/gdbserver/inferiors.cc @@ -215,6 +215,144 @@ current_process (void) return current_process_; } +/* See inferiors.h. */ + +void +for_each_process (gdb::function_view func) +{ + std::list::iterator next, cur = all_processes.begin (); + + while (cur != all_processes.end ()) + { + next = cur; + next++; + func (*cur); + cur = next; + } +} + +/* See inferiors.h. */ + +process_info * +find_process (gdb::function_view func) +{ + std::list::iterator next, cur = all_processes.begin (); + + while (cur != all_processes.end ()) + { + next = cur; + next++; + + if (func (*cur)) + return *cur; + + cur = next; + } + + return NULL; +} + +/* See gdbthread.h. */ + +thread_info * +find_thread (gdb::function_view func) +{ + std::list::iterator next, cur = all_threads.begin (); + + while (cur != all_threads.end ()) + { + next = cur; + next++; + + if (func (*cur)) + return *cur; + + cur = next; + } + + return NULL; +} + +/* See gdbthread.h. */ + +thread_info * +find_thread (int pid, gdb::function_view func) +{ + return find_thread ([&] (thread_info *thread) + { + return thread->id.pid () == pid && func (thread); + }); +} + +/* See gdbthread.h. */ + +thread_info * +find_thread (ptid_t filter, gdb::function_view func) +{ + return find_thread ([&] (thread_info *thread) { + return thread->id.matches (filter) && func (thread); + }); +} + +/* See gdbthread.h. */ + +void +for_each_thread (gdb::function_view func) +{ + std::list::iterator next, cur = all_threads.begin (); + + while (cur != all_threads.end ()) + { + next = cur; + next++; + func (*cur); + cur = next; + } +} + +/* See gdbthread.h. */ + +void +for_each_thread (int pid, gdb::function_view func) +{ + for_each_thread ([&] (thread_info *thread) + { + if (pid == thread->id.pid ()) + func (thread); + }); +} + +/* See gdbthread.h. */ + +thread_info * +find_thread_in_random (gdb::function_view func) +{ + int count = 0; + int random_selector; + + /* First count how many interesting entries we have. */ + for_each_thread ([&] (thread_info *thread) { + if (func (thread)) + count++; + }); + + if (count == 0) + return NULL; + + /* Now randomly pick an entry out of those. */ + random_selector = (int) + ((count * (double) rand ()) / (RAND_MAX + 1.0)); + + thread_info *thread = find_thread ([&] (thread_info *thr_arg) { + return func (thr_arg) && (random_selector-- == 0); + }); + + gdb_assert (thread != NULL); + + return thread; +} + + /* See gdbsupport/common-gdbthread.h. */ void diff --git a/gdbserver/inferiors.h b/gdbserver/inferiors.h index 00e42335014..5f865fa860a 100644 --- a/gdbserver/inferiors.h +++ b/gdbserver/inferiors.h @@ -103,43 +103,13 @@ extern std::list all_processes; /* Invoke FUNC for each process. */ -template -static void -for_each_process (Func func) -{ - std::list::iterator next, cur = all_processes.begin (); - - while (cur != all_processes.end ()) - { - next = cur; - next++; - func (*cur); - cur = next; - } -} +void for_each_process (gdb::function_view func); /* Find the first process for which FUNC returns true. Return NULL if no process satisfying FUNC is found. */ -template -static process_info * -find_process (Func func) -{ - std::list::iterator next, cur = all_processes.begin (); - - while (cur != all_processes.end ()) - { - next = cur; - next++; - - if (func (*cur)) - return *cur; - - cur = next; - } - - return NULL; -} +process_info * +find_process (gdb::function_view func); extern struct thread_info *current_thread; From patchwork Fri Oct 18 15:20:51 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Rohr, Stephan" X-Patchwork-Id: 99215 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 4B92A3858289 for ; Fri, 18 Oct 2024 15:23:58 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.16]) by sourceware.org (Postfix) with ESMTPS id 4352B3857C58 for ; Fri, 18 Oct 2024 15:21:44 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 4352B3857C58 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=intel.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 4352B3857C58 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=192.198.163.16 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1729264910; cv=none; b=GoqVY9pDAOE7okGBG1WtxOay6v2o27xOLlv9YGCH8NrIE556UCA8h3sFmJ44pTXzlPCgMk9hspmjEqjmmCTfd0Uz9vrX2xZcvnMf034byNWZZOX06VEkOWGa5jAJIhx+x7kPFwxd7UdvWJH7x0HV2guSvwVGrmprpw2b/xjnT2U= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1729264910; c=relaxed/simple; bh=xO0dPGvVieUh5DEw8WIcLy+88NhnkDnmxL7D1vg33hc=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=D0YI7SujxpZj7gYQpSXf1B/wLV8qyEkMtdG8eQucqxptY6Rmzyi1QMQoSwCZg6zUFjExpOPeILOYq6Okinsg7CpVCutzw0+wdqNEj8gMubjJhV7+NFb35S1Tw+VPEN91gC8/FOxR7oXq470CzBUpynDOkc+POqKaztigh59kjAo= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1729264905; x=1760800905; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=xO0dPGvVieUh5DEw8WIcLy+88NhnkDnmxL7D1vg33hc=; b=AbUEh1d3XZHXavALV8qumheVbUZshiEWZIRED9tgLXhkUSL9oBDrI/Eh ce06Q+vunjVHpvcTtQ9g4OmIsjusxDEuR7K0EWPOULt5UA95Wa0cArXx5 jsvEt3xrIojy8YzWmqBUs6uBFugLMOWZ5sEs1YtjS+wsoargdTMjAxCv4 J8n8++HI/k1FebiVho2vgfOXT3PB5Sgb12hdHx0Y+mcGwvYCsfH2L2Stq +ZL0h0FRu52T4BqtxlNJsP7lft+2lQ4SbLHVIKkTVUaH/aneDErFbADaJ UQXxIYXE4qwapnN+gyD1nlKV1vUW583na9DO+z49mjrhNxmRl/GwP37tP Q==; X-CSE-ConnectionGUID: 9zuuWIKGS5mZn+U2wf8mjA== X-CSE-MsgGUID: aL2+8QtbRGmjIxbQQLjLng== X-IronPort-AV: E=McAfee;i="6700,10204,11229"; a="16415773" X-IronPort-AV: E=Sophos;i="6.11,214,1725346800"; d="scan'208";a="16415773" Received: from orviesa006.jf.intel.com ([10.64.159.146]) by fmvoesa110.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 Oct 2024 08:21:44 -0700 X-CSE-ConnectionGUID: JAaWlnrOTRa8xItUbB7h6g== X-CSE-MsgGUID: o0+EIZXLQlCtw670a3QTfA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.11,214,1725346800"; d="scan'208";a="79039313" Received: from 984fee0031af.jf.intel.com (HELO localhost) ([10.165.54.65]) by orviesa006-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 Oct 2024 08:21:44 -0700 From: Stephan Rohr To: gdb-patches@sourceware.org Cc: simark@simark.ca, aburgess@redhat.com Subject: [PATCH v3 2/3] gdbserver: introduce 'introdusive_list' type Date: Fri, 18 Oct 2024 08:20:51 -0700 Message-Id: <20241018152052.1509373-3-stephan.rohr@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241018152052.1509373-1-stephan.rohr@intel.com> References: <20241018152052.1509373-1-stephan.rohr@intel.com> MIME-Version: 1.0 X-Spam-Status: No, score=-10.3 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, SPF_HELO_NONE, SPF_NONE, TXREP, URIBL_SBL_A autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org This patch replaces the 'std::list' type of 'all_processes' and 'all_threads' with the more lightweight 'intrusive_list' type. --- gdbserver/dll.cc | 4 +- gdbserver/gdbthread.h | 18 ++-- gdbserver/inferiors.cc | 116 +++++++++------------- gdbserver/inferiors.h | 10 +- gdbserver/linux-low.cc | 196 ++++++++++++++++++------------------- gdbserver/linux-low.h | 2 +- gdbserver/linux-x86-low.cc | 4 +- gdbserver/regcache.cc | 12 +-- gdbserver/regcache.h | 2 +- gdbserver/server.cc | 114 ++++++++++----------- 10 files changed, 228 insertions(+), 250 deletions(-) diff --git a/gdbserver/dll.cc b/gdbserver/dll.cc index ff637a03fed..f3f062316d7 100644 --- a/gdbserver/dll.cc +++ b/gdbserver/dll.cc @@ -93,8 +93,8 @@ unloaded_dll (process_info *proc, const char *name, CORE_ADDR base_addr) void clear_dlls (void) { - for_each_process ([] (process_info *proc) + for_each_process ([] (process_info &proc) { - proc->all_dlls.clear (); + proc.all_dlls.clear (); }); } diff --git a/gdbserver/gdbthread.h b/gdbserver/gdbthread.h index adc5857abfd..8e6f81afad2 100644 --- a/gdbserver/gdbthread.h +++ b/gdbserver/gdbthread.h @@ -23,12 +23,10 @@ #include "gdbsupport/function-view.h" #include "inferiors.h" -#include - struct btrace_target_info; struct regcache; -struct thread_info +struct thread_info : public intrusive_list_node { thread_info (ptid_t id, void *target_data) : id (id), target_data (target_data) @@ -86,7 +84,7 @@ struct thread_info gdb_thread_options thread_options = 0; }; -extern std::list all_threads; +extern intrusive_list all_threads; void remove_thread (struct thread_info *thread); struct thread_info *add_thread (ptid_t ptid, void *target_data); @@ -105,34 +103,34 @@ struct thread_info *find_any_thread_of_pid (int pid); satisfying FUNC is found. */ thread_info * -find_thread (gdb::function_view func); +find_thread (gdb::function_view func); /* Like the above, but only consider threads with pid PID. */ thread_info * -find_thread (int pid, gdb::function_view func); +find_thread (int pid, gdb::function_view func); /* Find the first thread that matches FILTER for which FUNC returns true. Return NULL if no thread satisfying these conditions is found. */ thread_info * -find_thread (ptid_t filter, gdb::function_view func); +find_thread (ptid_t filter, gdb::function_view func); /* Invoke FUNC for each thread. */ void -for_each_thread (gdb::function_view func); +for_each_thread (gdb::function_view func); /* Like the above, but only consider threads with pid PID. */ void -for_each_thread (int pid, gdb::function_view func); +for_each_thread (int pid, gdb::function_view func); /* Find the a random thread for which FUNC (THREAD) returns true. If no entry is found then return NULL. */ thread_info * -find_thread_in_random (gdb::function_view func); +find_thread_in_random (gdb::function_view func); /* Get current thread ID (Linux task ID). */ #define current_ptid (current_thread->id) diff --git a/gdbserver/inferiors.cc b/gdbserver/inferiors.cc index 5621db377fb..1a2109ef9c8 100644 --- a/gdbserver/inferiors.cc +++ b/gdbserver/inferiors.cc @@ -22,8 +22,8 @@ #include "gdbthread.h" #include "dll.h" -std::list all_processes; -std::list all_threads; +intrusive_list all_processes; +intrusive_list all_threads; /* The current process. */ static process_info *current_process_; @@ -42,7 +42,7 @@ add_thread (ptid_t thread_id, void *target_data) { thread_info *new_thread = new thread_info (thread_id, target_data); - all_threads.push_back (new_thread); + all_threads.push_back (*new_thread); if (current_thread == NULL) switch_to_thread (new_thread); @@ -56,7 +56,7 @@ struct thread_info * get_first_thread (void) { if (!all_threads.empty ()) - return all_threads.front (); + return &(all_threads.front ()); else return NULL; } @@ -64,8 +64,8 @@ get_first_thread (void) struct thread_info * find_thread_ptid (ptid_t ptid) { - return find_thread ([&] (thread_info *thread) { - return thread->id == ptid; + return find_thread ([&] (thread_info &thread) { + return thread.id == ptid; }); } @@ -83,17 +83,11 @@ find_thread_process (const struct process_info *const process) struct thread_info * find_any_thread_of_pid (int pid) { - return find_thread (pid, [] (thread_info *thread) { + return find_thread (pid, [] (thread_info &thread) { return true; }); } -static void -free_one_thread (thread_info *thread) -{ - delete thread; -} - void remove_thread (struct thread_info *thread) { @@ -101,10 +95,11 @@ remove_thread (struct thread_info *thread) target_disable_btrace (thread->btrace); discard_queued_stop_replies (ptid_of (thread)); - all_threads.remove (thread); + auto it = all_threads.iterator_to (*thread); + all_threads.erase (it); if (current_thread == thread) switch_to_thread (nullptr); - free_one_thread (thread); + delete thread; } void * @@ -128,8 +123,10 @@ set_thread_regcache_data (struct thread_info *thread, struct regcache *data) void clear_inferiors (void) { - for_each_thread (free_one_thread); - all_threads.clear (); + all_threads.clear_and_dispose ([=] (thread_info *thr) + { + delete thr; + }); clear_dlls (); @@ -142,7 +139,7 @@ add_process (int pid, int attached) { process_info *process = new process_info (pid, attached); - all_processes.push_back (process); + all_processes.push_back (*process); return process; } @@ -157,7 +154,8 @@ remove_process (struct process_info *process) clear_symbol_cache (&process->symbol_cache); free_all_breakpoints (process); gdb_assert (find_thread_process (process) == NULL); - all_processes.remove (process); + auto it = all_processes.iterator_to (*process); + all_processes.erase (it); if (current_process () == process) switch_to_process (nullptr); delete process; @@ -166,8 +164,8 @@ remove_process (struct process_info *process) process_info * find_process_pid (int pid) { - return find_process ([&] (process_info *process) { - return process->pid == pid; + return find_process ([&] (process_info &process) { + return process.pid == pid; }); } @@ -177,7 +175,7 @@ process_info * get_first_process (void) { if (!all_processes.empty ()) - return all_processes.front (); + return &(all_processes.front ()); else return NULL; } @@ -188,8 +186,8 @@ get_first_process (void) int have_started_inferiors_p (void) { - return find_process ([] (process_info *process) { - return !process->attached; + return find_process ([] (process_info &process) { + return !process.attached; }) != NULL; } @@ -198,8 +196,8 @@ have_started_inferiors_p (void) int have_attached_inferiors_p (void) { - return find_process ([] (process_info *process) { - return process->attached; + return find_process ([] (process_info &process) { + return process.attached; }) != NULL; } @@ -218,9 +216,9 @@ current_process (void) /* See inferiors.h. */ void -for_each_process (gdb::function_view func) +for_each_process (gdb::function_view func) { - std::list::iterator next, cur = all_processes.begin (); + intrusive_list::iterator next, cur = all_processes.begin (); while (cur != all_processes.end ()) { @@ -234,20 +232,11 @@ for_each_process (gdb::function_view func) /* See inferiors.h. */ process_info * -find_process (gdb::function_view func) +find_process (gdb::function_view func) { - std::list::iterator next, cur = all_processes.begin (); - - while (cur != all_processes.end ()) - { - next = cur; - next++; - - if (func (*cur)) - return *cur; - - cur = next; - } + for (process_info &process : all_processes) + if (func (process)) + return &process; return NULL; } @@ -255,20 +244,11 @@ find_process (gdb::function_view func) /* See gdbthread.h. */ thread_info * -find_thread (gdb::function_view func) +find_thread (gdb::function_view func) { - std::list::iterator next, cur = all_threads.begin (); - - while (cur != all_threads.end ()) - { - next = cur; - next++; - - if (func (*cur)) - return *cur; - - cur = next; - } + for (thread_info &thread : all_threads) + if (func (thread)) + return &thread; return NULL; } @@ -276,30 +256,30 @@ find_thread (gdb::function_view func) /* See gdbthread.h. */ thread_info * -find_thread (int pid, gdb::function_view func) +find_thread (int pid, gdb::function_view func) { - return find_thread ([&] (thread_info *thread) + return find_thread ([&] (thread_info &thread) { - return thread->id.pid () == pid && func (thread); + return thread.id.pid () == pid && func (thread); }); } /* See gdbthread.h. */ thread_info * -find_thread (ptid_t filter, gdb::function_view func) +find_thread (ptid_t filter, gdb::function_view func) { - return find_thread ([&] (thread_info *thread) { - return thread->id.matches (filter) && func (thread); + return find_thread ([&] (thread_info &thread) { + return thread.id.matches (filter) && func (thread); }); } /* See gdbthread.h. */ void -for_each_thread (gdb::function_view func) +for_each_thread (gdb::function_view func) { - std::list::iterator next, cur = all_threads.begin (); + intrusive_list::iterator next, cur = all_threads.begin (); while (cur != all_threads.end ()) { @@ -313,11 +293,11 @@ for_each_thread (gdb::function_view func) /* See gdbthread.h. */ void -for_each_thread (int pid, gdb::function_view func) +for_each_thread (int pid, gdb::function_view func) { - for_each_thread ([&] (thread_info *thread) + for_each_thread ([&] (thread_info &thread) { - if (pid == thread->id.pid ()) + if (pid == thread.id.pid ()) func (thread); }); } @@ -325,13 +305,13 @@ for_each_thread (int pid, gdb::function_view func) /* See gdbthread.h. */ thread_info * -find_thread_in_random (gdb::function_view func) +find_thread_in_random (gdb::function_view func) { int count = 0; int random_selector; /* First count how many interesting entries we have. */ - for_each_thread ([&] (thread_info *thread) { + for_each_thread ([&] (thread_info &thread) { if (func (thread)) count++; }); @@ -343,7 +323,7 @@ find_thread_in_random (gdb::function_view func) random_selector = (int) ((count * (double) rand ()) / (RAND_MAX + 1.0)); - thread_info *thread = find_thread ([&] (thread_info *thr_arg) { + thread_info *thread = find_thread ([&] (thread_info &thr_arg) { return func (thr_arg) && (random_selector-- == 0); }); diff --git a/gdbserver/inferiors.h b/gdbserver/inferiors.h index 5f865fa860a..7605cb675d0 100644 --- a/gdbserver/inferiors.h +++ b/gdbserver/inferiors.h @@ -20,8 +20,8 @@ #define GDBSERVER_INFERIORS_H #include "gdbsupport/gdb_vecs.h" +#include "gdbsupport/intrusive_list.h" #include "dll.h" -#include struct thread_info; struct regcache; @@ -32,7 +32,7 @@ struct raw_breakpoint; struct fast_tracepoint_jump; struct process_info_private; -struct process_info +struct process_info : public intrusive_list_node { process_info (int pid_, int attached_) : pid (pid_), attached (attached_) @@ -99,17 +99,17 @@ pid_of (const process_info *proc) struct process_info *current_process (void); struct process_info *get_thread_process (const struct thread_info *); -extern std::list all_processes; +extern intrusive_list all_processes; /* Invoke FUNC for each process. */ -void for_each_process (gdb::function_view func); +void for_each_process (gdb::function_view func); /* Find the first process for which FUNC returns true. Return NULL if no process satisfying FUNC is found. */ process_info * -find_process (gdb::function_view func); +find_process (gdb::function_view func); extern struct thread_info *current_thread; diff --git a/gdbserver/linux-low.cc b/gdbserver/linux-low.cc index 79512c07a22..ceb47aef583 100644 --- a/gdbserver/linux-low.cc +++ b/gdbserver/linux-low.cc @@ -1249,7 +1249,7 @@ last_thread_of_process_p (int pid) { bool seen_one = false; - thread_info *thread = find_thread (pid, [&] (thread_info *thr_arg) + thread_info *thread = find_thread (pid, [&] (thread_info &thr_arg) { if (!seen_one) { @@ -1357,19 +1357,19 @@ kill_wait_lwp (struct lwp_info *lwp) except the leader. */ static void -kill_one_lwp_callback (thread_info *thread, int pid) +kill_one_lwp_callback (thread_info &thread, int pid) { - struct lwp_info *lwp = get_thread_lwp (thread); + struct lwp_info *lwp = get_thread_lwp (&thread); /* We avoid killing the first thread here, because of a Linux kernel (at least 2.6.0-test7 through 2.6.8-rc4) bug; if we kill the parent before the children get a chance to be reaped, it will remain a zombie forever. */ - if (lwpid_of (thread) == pid) + if (lwpid_of (&thread) == pid) { threads_debug_printf ("is last of process %s", - target_pid_to_str (thread->id).c_str ()); + target_pid_to_str (thread.id).c_str ()); return; } @@ -1385,7 +1385,7 @@ linux_process_target::kill (process_info *process) first, as PTRACE_KILL will not work otherwise. */ stop_all_lwps (0, NULL); - for_each_thread (pid, [&] (thread_info *thread) + for_each_thread (pid, [&] (thread_info &thread) { kill_one_lwp_callback (thread, pid); }); @@ -1509,7 +1509,7 @@ linux_process_target::detach_one_lwp (lwp_info *lwp) try { /* Flush any pending changes to the process's registers. */ - regcache_invalidate_thread (thread); + regcache_invalidate_thread (*thread); /* Finally, let it resume. */ low_prepare_to_resume (lwp); @@ -1588,15 +1588,15 @@ linux_process_target::detach (process_info *process) /* Detach from the clone lwps first. If the thread group exits just while we're detaching, we must reap the clone lwps before we're able to reap the leader. */ - for_each_thread (process->pid, [this] (thread_info *thread) + for_each_thread (process->pid, [this] (thread_info &thread) { /* We don't actually detach from the thread group leader just yet. If the thread group exits, we must reap the zombie clone lwps before we're able to reap the leader. */ - if (thread->id.pid () == thread->id.lwp ()) + if (thread.id.pid () == thread.id.lwp ()) return; - lwp_info *lwp = get_thread_lwp (thread); + lwp_info *lwp = get_thread_lwp (&thread); detach_one_lwp (lwp); }); @@ -1621,9 +1621,9 @@ linux_process_target::mourn (process_info *process) thread_db_mourn (process); #endif - for_each_thread (process->pid, [this] (thread_info *thread) + for_each_thread (process->pid, [this] (thread_info &thread) { - delete_lwp (get_thread_lwp (thread)); + delete_lwp (get_thread_lwp (&thread)); }); this->remove_linux_process (process); @@ -1745,9 +1745,9 @@ struct lwp_info * find_lwp_pid (ptid_t ptid) { long lwp = ptid.lwp () != 0 ? ptid.lwp () : ptid.pid (); - thread_info *thread = find_thread ([lwp] (thread_info *thr_arg) + thread_info *thread = find_thread ([lwp] (thread_info &thr_arg) { - return thr_arg->id.lwp () == lwp; + return thr_arg.id.lwp () == lwp; }); if (thread == NULL) @@ -1763,7 +1763,7 @@ num_lwps (int pid) { int count = 0; - for_each_thread (pid, [&] (thread_info *thread) + for_each_thread (pid, [&] (thread_info &thread) { count++; }); @@ -1777,9 +1777,9 @@ struct lwp_info * iterate_over_lwps (ptid_t filter, gdb::function_view callback) { - thread_info *thread = find_thread (filter, [&] (thread_info *thr_arg) + thread_info *thread = find_thread (filter, [&] (thread_info &thr_arg) { - lwp_info *lwp = get_thread_lwp (thr_arg); + lwp_info *lwp = get_thread_lwp (&thr_arg); return callback (lwp); }); @@ -1795,9 +1795,9 @@ linux_process_target::check_zombie_leaders () { bool new_pending_event = false; - for_each_process ([&] (process_info *proc) + for_each_process ([&] (process_info &proc) { - pid_t leader_pid = pid_of (proc); + pid_t leader_pid = pid_of (&proc); lwp_info *leader_lp = find_lwp_pid (ptid_t (leader_pid)); threads_debug_printf ("leader_pid=%d, leader_lp!=NULL=%d, " @@ -1883,12 +1883,12 @@ linux_process_target::check_zombie_leaders () stopped. */ static bool -not_stopped_callback (thread_info *thread, ptid_t filter) +not_stopped_callback (thread_info &thread, ptid_t filter) { - if (!thread->id.matches (filter)) + if (!thread.id.matches (filter)) return false; - lwp_info *lwp = get_thread_lwp (thread); + lwp_info *lwp = get_thread_lwp (&thread); return !lwp->stopped; } @@ -2291,9 +2291,9 @@ linux_process_target::filter_event (int lwpid, int wstat) forked and then it exits. However, note that we may have earlier deleted a leader of an inferior we're debugging, in check_zombie_leaders. Re-add it back here if so. */ - find_process ([&] (process_info *proc) + find_process ([&] (process_info &proc) { - if (proc->pid == lwpid) + if (proc.pid == lwpid) { threads_debug_printf ("Re-adding thread group leader LWP %d after exit.", @@ -2522,9 +2522,9 @@ linux_process_target::wait_for_event_filtered (ptid_t wait_ptid, if (filter_ptid == minus_one_ptid || filter_ptid.is_pid ()) { - event_thread = find_thread_in_random ([&] (thread_info *thread) + event_thread = find_thread_in_random ([&] (thread_info &thread) { - return status_pending_p_callback (thread, filter_ptid); + return status_pending_p_callback (&thread, filter_ptid); }); if (event_thread != NULL) @@ -2631,16 +2631,16 @@ linux_process_target::wait_for_event_filtered (ptid_t wait_ptid, /* Now that we've pulled all events out of the kernel, resume LWPs that don't have an interesting event to report. */ if (stopping_threads == NOT_STOPPING_THREADS) - for_each_thread ([this] (thread_info *thread) + for_each_thread ([this] (thread_info &thread) { - resume_stopped_resumed_lwps (thread); + resume_stopped_resumed_lwps (&thread); }); /* ... and find an LWP with a status to report to the core, if any. */ - event_thread = find_thread_in_random ([&] (thread_info *thread) + event_thread = find_thread_in_random ([&] (thread_info &thread) { - return status_pending_p_callback (thread, filter_ptid); + return status_pending_p_callback (&thread, filter_ptid); }); if (event_thread != NULL) @@ -2657,7 +2657,7 @@ linux_process_target::wait_for_event_filtered (ptid_t wait_ptid, if (check_zombie_leaders ()) goto retry; - auto not_stopped = [&] (thread_info *thread) + auto not_stopped = [&] (thread_info &thread) { return not_stopped_callback (thread, wait_ptid); }; @@ -2724,12 +2724,12 @@ select_event_lwp (struct lwp_info **orig_lp) would report it to the user as a random signal. */ if (!non_stop) { - event_thread = find_thread ([] (thread_info *thread) + event_thread = find_thread ([] (thread_info &thread) { - lwp_info *lp = get_thread_lwp (thread); + lwp_info *lp = get_thread_lwp (&thread); - return (thread->last_status.kind () == TARGET_WAITKIND_IGNORE - && thread->last_resume_kind == resume_step + return (thread.last_status.kind () == TARGET_WAITKIND_IGNORE + && thread.last_resume_kind == resume_step && lp->status_pending_p); }); @@ -2743,12 +2743,12 @@ select_event_lwp (struct lwp_info **orig_lp) /* No single-stepping LWP. Select one at random, out of those which have had events. */ - event_thread = find_thread_in_random ([&] (thread_info *thread) + event_thread = find_thread_in_random ([&] (thread_info &thread) { - lwp_info *lp = get_thread_lwp (thread); + lwp_info *lp = get_thread_lwp (&thread); /* Only resumed LWPs that have an event pending. */ - return (thread->last_status.kind () == TARGET_WAITKIND_IGNORE + return (thread.last_status.kind () == TARGET_WAITKIND_IGNORE && lp->status_pending_p); }); } @@ -2768,16 +2768,16 @@ select_event_lwp (struct lwp_info **orig_lp) static void unsuspend_all_lwps (struct lwp_info *except) { - for_each_thread ([&] (thread_info *thread) + for_each_thread ([&] (thread_info &thread) { - lwp_info *lwp = get_thread_lwp (thread); + lwp_info *lwp = get_thread_lwp (&thread); if (lwp != except) lwp_suspended_decr (lwp); }); } -static bool lwp_running (thread_info *thread); +static bool lwp_running (thread_info &thread); /* Stabilize threads (move out of jump pads). @@ -2812,7 +2812,7 @@ static bool lwp_running (thread_info *thread); void linux_process_target::stabilize_threads () { - thread_info *thread_stuck = find_thread ([this] (thread_info *thread) + thread_info *thread_stuck = find_thread ([this] (thread_info &thread) { return stuck_in_jump_pad (thread); }); @@ -2829,9 +2829,9 @@ linux_process_target::stabilize_threads () stabilizing_threads = 1; /* Kick 'em all. */ - for_each_thread ([this] (thread_info *thread) + for_each_thread ([this] (thread_info &thread) { - move_out_of_jump_pad (thread); + move_out_of_jump_pad (&thread); }); /* Loop until all are stopped out of the jump pads. */ @@ -2868,7 +2868,7 @@ linux_process_target::stabilize_threads () if (debug_threads) { - thread_stuck = find_thread ([this] (thread_info *thread) + thread_stuck = find_thread ([this] (thread_info &thread) { return stuck_in_jump_pad (thread); }); @@ -3461,8 +3461,8 @@ linux_process_target::wait_1 (ptid_t ptid, target_waitstatus *ourstatus, /* In all-stop, a stop reply cancels all previous resume requests. Delete all single-step breakpoints. */ - find_thread ([&] (thread_info *thread) { - if (has_single_step_breakpoints (thread)) + find_thread ([&] (thread_info &thread) { + if (has_single_step_breakpoints (&thread)) { remove_single_step_breakpoints_p = 1; return true; @@ -3486,9 +3486,9 @@ linux_process_target::wait_1 (ptid_t ptid, target_waitstatus *ourstatus, } else { - for_each_thread ([] (thread_info *thread){ - if (has_single_step_breakpoints (thread)) - delete_single_step_breakpoints (thread); + for_each_thread ([] (thread_info &thread){ + if (has_single_step_breakpoints (&thread)) + delete_single_step_breakpoints (&thread); }); } @@ -3839,14 +3839,14 @@ linux_process_target::wait_for_sigstop () } bool -linux_process_target::stuck_in_jump_pad (thread_info *thread) +linux_process_target::stuck_in_jump_pad (thread_info &thread) { - struct lwp_info *lwp = get_thread_lwp (thread); + struct lwp_info *lwp = get_thread_lwp (&thread); if (lwp->suspended != 0) { internal_error ("LWP %ld is suspended, suspended=%d\n", - lwpid_of (thread), lwp->suspended); + lwpid_of (&thread), lwp->suspended); } gdb_assert (lwp->stopped); @@ -3855,7 +3855,7 @@ linux_process_target::stuck_in_jump_pad (thread_info *thread) && agent_loaded_p () && (gdb_breakpoint_here (lwp->stop_pc) || lwp->stop_reason == TARGET_STOPPED_BY_WATCHPOINT - || thread->last_resume_kind == resume_step) + || thread.last_resume_kind == resume_step) && (linux_fast_tracepoint_collecting (lwp, NULL) != fast_tpoint_collect_result::not_collecting)); } @@ -3904,9 +3904,9 @@ linux_process_target::move_out_of_jump_pad (thread_info *thread) } static bool -lwp_running (thread_info *thread) +lwp_running (thread_info &thread) { - struct lwp_info *lwp = get_thread_lwp (thread); + struct lwp_info *lwp = get_thread_lwp (&thread); if (lwp_is_marked_dead (lwp)) return false; @@ -3933,14 +3933,14 @@ linux_process_target::stop_all_lwps (int suspend, lwp_info *except) : STOPPING_THREADS); if (suspend) - for_each_thread ([&] (thread_info *thread) + for_each_thread ([&] (thread_info &thread) { - suspend_and_send_sigstop (thread, except); + suspend_and_send_sigstop (&thread, except); }); else - for_each_thread ([&] (thread_info *thread) + for_each_thread ([&] (thread_info &thread) { - send_sigstop (thread, except); + send_sigstop (&thread, except); }); wait_for_sigstop (); @@ -4169,7 +4169,7 @@ linux_process_target::resume_one_lwp_throw (lwp_info *lwp, int step, low_prepare_to_resume (lwp); - regcache_invalidate_thread (thread); + regcache_invalidate_thread (*thread); errno = 0; lwp->stepping = step; if (step) @@ -4277,29 +4277,29 @@ linux_process_target::resume_one_lwp (lwp_info *lwp, int step, int signal, suspension). */ static void -linux_set_resume_request (thread_info *thread, thread_resume *resume, size_t n) +linux_set_resume_request (thread_info &thread, thread_resume *resume, size_t n) { - struct lwp_info *lwp = get_thread_lwp (thread); + struct lwp_info *lwp = get_thread_lwp (&thread); for (int ndx = 0; ndx < n; ndx++) { ptid_t ptid = resume[ndx].thread; if (ptid == minus_one_ptid - || ptid == thread->id + || ptid == thread.id /* Handle both 'pPID' and 'pPID.-1' as meaning 'all threads of PID'. */ - || (ptid.pid () == pid_of (thread) + || (ptid.pid () == pid_of (&thread) && (ptid.is_pid () || ptid.lwp () == -1))) { if (resume[ndx].kind == resume_stop - && thread->last_resume_kind == resume_stop) + && thread.last_resume_kind == resume_stop) { threads_debug_printf ("already %s LWP %ld at GDB's request", - (thread->last_status.kind () == TARGET_WAITKIND_STOPPED + (thread.last_status.kind () == TARGET_WAITKIND_STOPPED ? "stopped" : "stopping"), - lwpid_of (thread)); + lwpid_of (&thread)); continue; } @@ -4307,13 +4307,13 @@ linux_set_resume_request (thread_info *thread, thread_resume *resume, size_t n) /* Ignore (wildcard) resume requests for already-resumed threads. */ if (resume[ndx].kind != resume_stop - && thread->last_resume_kind != resume_stop) + && thread.last_resume_kind != resume_stop) { threads_debug_printf ("already %s LWP %ld at GDB's request", - (thread->last_resume_kind == resume_step + (thread.last_resume_kind == resume_step ? "stepping" : "continuing"), - lwpid_of (thread)); + lwpid_of (&thread)); continue; } @@ -4328,7 +4328,7 @@ linux_set_resume_request (thread_info *thread, thread_resume *resume, size_t n) { threads_debug_printf ("not resuming LWP %ld: has queued stop reply", - lwpid_of (thread)); + lwpid_of (&thread)); continue; } } @@ -4337,16 +4337,16 @@ linux_set_resume_request (thread_info *thread, thread_resume *resume, size_t n) reported to GDBserver core, but GDB has not pulled the event out of the vStopped queue yet, likewise, ignore the (wildcard) resume request. */ - if (in_queued_stop_replies (thread->id)) + if (in_queued_stop_replies (thread.id)) { threads_debug_printf ("not resuming LWP %ld: has queued stop reply", - lwpid_of (thread)); + lwpid_of (&thread)); continue; } lwp->resume = &resume[ndx]; - thread->last_resume_kind = lwp->resume->kind; + thread.last_resume_kind = lwp->resume->kind; lwp->step_range_start = lwp->resume->step_range_start; lwp->step_range_end = lwp->resume->step_range_end; @@ -4364,7 +4364,7 @@ linux_set_resume_request (thread_info *thread, thread_resume *resume, size_t n) ("Dequeueing deferred signal %d for LWP %ld, " "leaving status pending.", WSTOPSIG (lwp->status_pending), - lwpid_of (thread)); + lwpid_of (&thread)); } return; @@ -4737,7 +4737,7 @@ linux_process_target::resume (thread_resume *resume_info, size_t n) THREADS_SCOPED_DEBUG_ENTER_EXIT; - for_each_thread ([&] (thread_info *thread) + for_each_thread ([&] (thread_info &thread) { linux_set_resume_request (thread, resume_info, n); }); @@ -4750,9 +4750,9 @@ linux_process_target::resume (thread_resume *resume_info, size_t n) before considering to start a step-over (in all-stop). */ bool any_pending = false; if (!non_stop) - any_pending = find_thread ([this] (thread_info *thread) + any_pending = find_thread ([this] (thread_info &thread) { - return resume_status_pending (thread); + return resume_status_pending (&thread); }) != nullptr; /* If there is a thread which would otherwise be resumed, which is @@ -4762,9 +4762,9 @@ linux_process_target::resume (thread_resume *resume_info, size_t n) to queue any signals that would otherwise be delivered or queued. */ if (!any_pending && low_supports_breakpoints ()) - need_step_over = find_thread ([this] (thread_info *thread) + need_step_over = find_thread ([this] (thread_info &thread) { - return thread_needs_step_over (thread); + return thread_needs_step_over (&thread); }); bool leave_all_stopped = (need_step_over != NULL || any_pending); @@ -4779,9 +4779,9 @@ linux_process_target::resume (thread_resume *resume_info, size_t n) /* Even if we're leaving threads stopped, queue all signals we'd otherwise deliver. */ - for_each_thread ([&] (thread_info *thread) + for_each_thread ([&] (thread_info &thread) { - resume_one_thread (thread, leave_all_stopped); + resume_one_thread (&thread, leave_all_stopped); }); if (need_step_over) @@ -4908,9 +4908,9 @@ linux_process_target::proceed_all_lwps () if (low_supports_breakpoints ()) { - need_step_over = find_thread ([this] (thread_info *thread) + need_step_over = find_thread ([this] (thread_info &thread) { - return thread_needs_step_over (thread); + return thread_needs_step_over (&thread); }); if (need_step_over != NULL) @@ -4925,9 +4925,9 @@ linux_process_target::proceed_all_lwps () threads_debug_printf ("Proceeding, no step-over needed"); - for_each_thread ([this] (thread_info *thread) + for_each_thread ([this] (thread_info &thread) { - proceed_one_lwp (thread, NULL); + proceed_one_lwp (&thread, NULL); }); } @@ -4943,14 +4943,14 @@ linux_process_target::unstop_all_lwps (int unsuspend, lwp_info *except) threads_debug_printf ("except=nullptr"); if (unsuspend) - for_each_thread ([&] (thread_info *thread) + for_each_thread ([&] (thread_info &thread) { - unsuspend_and_proceed_one_lwp (thread, except); + unsuspend_and_proceed_one_lwp (&thread, except); }); else - for_each_thread ([&] (thread_info *thread) + for_each_thread ([&] (thread_info &thread) { - proceed_one_lwp (thread, except); + proceed_one_lwp (&thread, except); }); } @@ -5975,9 +5975,9 @@ void linux_process_target::handle_new_gdb_connection () { /* Request that all the lwps reset their ptrace options. */ - for_each_thread ([] (thread_info *thread) + for_each_thread ([] (thread_info &thread) { - struct lwp_info *lwp = get_thread_lwp (thread); + struct lwp_info *lwp = get_thread_lwp (&thread); if (!lwp->stopped) { @@ -5988,10 +5988,10 @@ linux_process_target::handle_new_gdb_connection () else { /* Already stopped; go ahead and set the ptrace options. */ - struct process_info *proc = find_process_pid (pid_of (thread)); + struct process_info *proc = find_process_pid (pid_of (&thread)); int options = linux_low_ptrace_options (proc->attached); - linux_enable_event_reporting (lwpid_of (thread), options); + linux_enable_event_reporting (lwpid_of (&thread), options); lwp->must_set_ptrace_flags = 0; } }); @@ -6206,12 +6206,12 @@ linux_process_target::any_resumed () { bool any_resumed; - auto status_pending_p_any = [&] (thread_info *thread) + auto status_pending_p_any = [&] (thread_info &thread) { - return status_pending_p_callback (thread, minus_one_ptid); + return status_pending_p_callback (&thread, minus_one_ptid); }; - auto not_stopped = [&] (thread_info *thread) + auto not_stopped = [&] (thread_info &thread) { return not_stopped_callback (thread, minus_one_ptid); }; diff --git a/gdbserver/linux-low.h b/gdbserver/linux-low.h index 273c04626b8..0e82e06cd48 100644 --- a/gdbserver/linux-low.h +++ b/gdbserver/linux-low.h @@ -590,7 +590,7 @@ class linux_process_target : public process_stratum_target move it out, because we need to report the stop event to GDB. For example, if the user puts a breakpoint in the jump pad, it's because she wants to debug it. */ - bool stuck_in_jump_pad (thread_info *thread); + bool stuck_in_jump_pad (thread_info &thread); /* Convenience wrapper. Returns information about LWP's fast tracepoint collection status. */ diff --git a/gdbserver/linux-x86-low.cc b/gdbserver/linux-x86-low.cc index afb1954a1b3..8295cc21e93 100644 --- a/gdbserver/linux-x86-low.cc +++ b/gdbserver/linux-x86-low.cc @@ -918,8 +918,8 @@ x86_target::update_xmltarget () release the current regcache objects. */ regcache_release (); - for_each_process ([this] (process_info *proc) { - int pid = proc->pid; + for_each_process ([this] (process_info &proc) { + int pid = proc.pid; /* Look up any thread of this process. */ switch_to_thread (find_any_thread_of_pid (pid)); diff --git a/gdbserver/regcache.cc b/gdbserver/regcache.cc index 1bb71d10328..974b549106e 100644 --- a/gdbserver/regcache.cc +++ b/gdbserver/regcache.cc @@ -72,11 +72,11 @@ get_thread_regcache_for_ptid (ptid_t ptid) } void -regcache_invalidate_thread (struct thread_info *thread) +regcache_invalidate_thread (struct thread_info &thread) { struct regcache *regcache; - regcache = thread_regcache_data (thread); + regcache = thread_regcache_data (&thread); if (regcache == NULL) return; @@ -85,7 +85,7 @@ regcache_invalidate_thread (struct thread_info *thread) { scoped_restore_current_thread restore_thread; - switch_to_thread (thread); + switch_to_thread (&thread); store_inferior_registers (regcache, -1); } @@ -273,15 +273,15 @@ find_regno (const struct target_desc *tdesc, const char *name) } static void -free_register_cache_thread (struct thread_info *thread) +free_register_cache_thread (struct thread_info &thread) { - struct regcache *regcache = thread_regcache_data (thread); + struct regcache *regcache = thread_regcache_data (&thread); if (regcache != NULL) { regcache_invalidate_thread (thread); free_register_cache (regcache); - set_thread_regcache_data (thread, NULL); + set_thread_regcache_data (&thread, NULL); } } diff --git a/gdbserver/regcache.h b/gdbserver/regcache.h index 1752c3979d3..90915f2c967 100644 --- a/gdbserver/regcache.h +++ b/gdbserver/regcache.h @@ -77,7 +77,7 @@ void free_register_cache (struct regcache *regcache); /* Invalidate cached registers for one thread. */ -void regcache_invalidate_thread (struct thread_info *); +void regcache_invalidate_thread (struct thread_info &); /* Invalidate cached registers for all threads of the given process. */ diff --git a/gdbserver/server.cc b/gdbserver/server.cc index 69ffb722be7..6733ddee886 100644 --- a/gdbserver/server.cc +++ b/gdbserver/server.cc @@ -1005,10 +1005,10 @@ handle_general_set (char *own_buf) if (ptid.lwp () == -1) ptid = ptid_t (ptid.pid ()); - for_each_thread ([&] (thread_info *thread) + for_each_thread ([&] (thread_info &thread) { - if (ptid_of (thread).matches (ptid)) - set_options[thread] = options; + if (ptid_of (&thread).matches (ptid)) + set_options[&thread] = options; }); } @@ -1355,15 +1355,15 @@ handle_detach (char *own_buf) another process might delete the next thread in the iteration, which is the one saved by the safe iterator. We will never delete the currently iterated on thread, so standard iteration should be safe. */ - for (thread_info *thread : all_threads) + for (thread_info &thread : all_threads) { /* Only threads that are of the process we are detaching. */ - if (thread->id.pid () != pid) + if (thread.id.pid () != pid) continue; /* Only threads that have a pending fork event. */ target_waitkind kind; - thread_info *child = target_thread_pending_child (thread, &kind); + thread_info *child = target_thread_pending_child (&thread, &kind); if (child == nullptr || kind == TARGET_WAITKIND_THREAD_CLONED) continue; @@ -1375,7 +1375,7 @@ handle_detach (char *own_buf) if (detach_inferior (fork_child_process) != 0) warning (_("Failed to detach fork child %s, child of %s"), target_pid_to_str (ptid_t (fork_child_pid)).c_str (), - target_pid_to_str (thread->id).c_str ()); + target_pid_to_str (thread.id).c_str ()); } if (detach_inferior (process) != 0) @@ -2002,9 +2002,9 @@ handle_qxfer_statictrace (const char *annex, Emit the XML to describe the thread of INF. */ static void -handle_qxfer_threads_worker (thread_info *thread, std::string *buffer) +handle_qxfer_threads_worker (thread_info &thread, std::string *buffer) { - ptid_t ptid = ptid_of (thread); + ptid_t ptid = ptid_of (&thread); char ptid_s[100]; int core = target_core_of_thread (ptid); char core_s[21]; @@ -2017,7 +2017,7 @@ handle_qxfer_threads_worker (thread_info *thread, std::string *buffer) GDB does not yet know about this thread, and must not know about it until it gets the corresponding (v)fork/clone event. Exclude this thread from the list. */ - if (target_thread_pending_parent (thread) != nullptr) + if (target_thread_pending_parent (&thread) != nullptr) return; write_ptid (ptid_s, ptid); @@ -2061,7 +2061,7 @@ handle_qxfer_threads_proper (std::string *buffer) if (non_stop) target_pause_all (true); - for_each_thread ([&] (thread_info *thread) + for_each_thread ([&] (thread_info &thread) { handle_qxfer_threads_worker (thread, buffer); }); @@ -2523,7 +2523,7 @@ static void handle_query (char *own_buf, int packet_len, int *new_packet_len_p) { client_state &cs = get_client_state (); - static std::list::const_iterator thread_iter; + static intrusive_list::iterator thread_iter; /* Reply the current thread id. */ if (strcmp ("qC", own_buf) == 0 && !disable_packet_qC) @@ -2536,7 +2536,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) else { thread_iter = all_threads.begin (); - ptid = (*thread_iter)->id; + ptid = thread_iter->id; } sprintf (own_buf, "QC"); @@ -2599,7 +2599,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) thread_iter = all_threads.begin (); *own_buf++ = 'm'; - ptid_t ptid = (*thread_iter)->id; + ptid_t ptid = thread_iter->id; write_ptid (own_buf, ptid); thread_iter++; return; @@ -2611,7 +2611,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) if (thread_iter != all_threads.end ()) { *own_buf++ = 'm'; - ptid_t ptid = (*thread_iter)->id; + ptid_t ptid = thread_iter->id; write_ptid (own_buf, ptid); thread_iter++; return; @@ -3093,7 +3093,7 @@ typedef int (visit_actioned_threads_callback_ftype) Note: This function is itself a callback for find_thread. */ static bool -visit_actioned_threads (thread_info *thread, +visit_actioned_threads (thread_info &thread, const struct thread_resume *actions, size_t num_actions, visit_actioned_threads_callback_ftype *callback) @@ -3103,12 +3103,12 @@ visit_actioned_threads (thread_info *thread, const struct thread_resume *action = &actions[i]; if (action->thread == minus_one_ptid - || action->thread == thread->id + || action->thread == thread.id || ((action->thread.pid () - == thread->id.pid ()) + == thread.id.pid ()) && action->thread.lwp () == -1)) { - if ((*callback) (action, thread)) + if ((*callback) (action, &thread)) return true; } } @@ -3258,7 +3258,7 @@ resume (struct thread_resume *actions, size_t num_actions) resuming/stopping and report the pending event immediately. */ - thread_info *thread_with_status = find_thread ([&] (thread_info *thread) + thread_info *thread_with_status = find_thread ([&] (thread_info &thread) { return visit_actioned_threads (thread, actions, num_actions, handle_pending_status); @@ -3640,7 +3640,7 @@ myresume (char *own_buf, int step, int sig) stopped thread. */ static void -queue_stop_reply_callback (thread_info *thread) +queue_stop_reply_callback (thread_info &thread) { /* For now, assume targets that don't have this callback also don't manage the thread's last_status field. */ @@ -3648,26 +3648,26 @@ queue_stop_reply_callback (thread_info *thread) { struct vstop_notif *new_notif = new struct vstop_notif; - new_notif->ptid = thread->id; - new_notif->status = thread->last_status; + new_notif->ptid = thread.id; + new_notif->status = thread.last_status; /* Pass the last stop reply back to GDB, but don't notify yet. */ notif_event_enque (¬if_stop, new_notif); } else { - if (target_thread_stopped (thread)) + if (target_thread_stopped (&thread)) { threads_debug_printf ("Reporting thread %s as already stopped with %s", - target_pid_to_str (thread->id).c_str (), - thread->last_status.to_string ().c_str ()); + target_pid_to_str (thread.id).c_str (), + thread.last_status.to_string ().c_str ()); - gdb_assert (thread->last_status.kind () != TARGET_WAITKIND_IGNORE); + gdb_assert (thread.last_status.kind () != TARGET_WAITKIND_IGNORE); /* Pass the last stop reply back to GDB, but don't notify yet. */ - queue_stop_reply (thread->id, thread->last_status); + queue_stop_reply (thread.id, thread.last_status); } } } @@ -3677,15 +3677,15 @@ queue_stop_reply_callback (thread_info *thread) it. */ static void -gdb_wants_thread_stopped (thread_info *thread) +gdb_wants_thread_stopped (thread_info &thread) { - thread->last_resume_kind = resume_stop; + thread.last_resume_kind = resume_stop; - if (thread->last_status.kind () == TARGET_WAITKIND_IGNORE) + if (thread.last_status.kind () == TARGET_WAITKIND_IGNORE) { /* Most threads are stopped implicitly (all-stop); tag that with signal 0. */ - thread->last_status.set_stopped (GDB_SIGNAL_0); + thread.last_status.set_stopped (GDB_SIGNAL_0); } } @@ -3701,18 +3701,18 @@ gdb_wants_all_threads_stopped (void) interesting event, mark it as having a pending event. */ static void -set_pending_status_callback (thread_info *thread) +set_pending_status_callback (thread_info &thread) { - if (thread->last_status.kind () != TARGET_WAITKIND_STOPPED - || (thread->last_status.sig () != GDB_SIGNAL_0 + if (thread.last_status.kind () != TARGET_WAITKIND_STOPPED + || (thread.last_status.sig () != GDB_SIGNAL_0 /* A breakpoint, watchpoint or finished step from a previous GDB run isn't considered interesting for a new GDB run. If we left those pending, the new GDB could consider them random SIGTRAPs. This leaves out real async traps. We'd have to peek into the (target-specific) siginfo to distinguish those. */ - && thread->last_status.sig () != GDB_SIGNAL_TRAP)) - thread->status_pending_p = 1; + && thread.last_status.sig () != GDB_SIGNAL_TRAP)) + thread.status_pending_p = 1; } /* Status handler for the '?' packet. */ @@ -3723,8 +3723,8 @@ handle_status (char *own_buf) client_state &cs = get_client_state (); /* GDB is connected, don't forward events to the target anymore. */ - for_each_process ([] (process_info *process) { - process->gdb_detached = 0; + for_each_process ([] (process_info &process) { + process.gdb_detached = 0; }); /* In non-stop mode, we must send a stop reply for each stopped @@ -3766,9 +3766,9 @@ handle_status (char *own_buf) /* If the last event thread is not found for some reason, look for some other thread that might have an event to report. */ if (thread == NULL) - thread = find_thread ([] (thread_info *thr_arg) + thread = find_thread ([] (thread_info &thr_arg) { - return thr_arg->status_pending_p; + return thr_arg.status_pending_p; }); /* If we're still out of luck, simply pick the first thread in @@ -3913,10 +3913,10 @@ start_event_loop () } static void -kill_inferior_callback (process_info *process) +kill_inferior_callback (process_info &process) { - kill_inferior (process); - discard_queued_stop_replies (ptid_t (process->pid)); + kill_inferior (&process); + discard_queued_stop_replies (ptid_t (process.pid)); } /* Call this when exiting gdbserver with possible inferiors that need @@ -3934,9 +3934,9 @@ detach_or_kill_for_exit (void) { fprintf (stderr, "Killing process(es):"); - for_each_process ([] (process_info *process) { - if (!process->attached) - fprintf (stderr, " %d", process->pid); + for_each_process ([] (process_info &process) { + if (!process.attached) + fprintf (stderr, " %d", process.pid); }); fprintf (stderr, "\n"); @@ -3945,22 +3945,22 @@ detach_or_kill_for_exit (void) { fprintf (stderr, "Detaching process(es):"); - for_each_process ([] (process_info *process) { - if (process->attached) - fprintf (stderr, " %d", process->pid); + for_each_process ([] (process_info &process) { + if (process.attached) + fprintf (stderr, " %d", process.pid); }); fprintf (stderr, "\n"); } /* Now we can kill or detach the inferiors. */ - for_each_process ([] (process_info *process) { - int pid = process->pid; + for_each_process ([] (process_info &process) { + int pid = process.pid; - if (process->attached) - detach_inferior (process); + if (process.attached) + detach_inferior (&process); else - kill_inferior (process); + kill_inferior (&process); discard_queued_stop_replies (ptid_t (pid)); }); @@ -4434,9 +4434,9 @@ captured_main (int argc, char *argv[]) (by the same GDB instance or another) will refresh all its state from scratch. */ discard_queued_stop_replies (minus_one_ptid); - for_each_thread ([] (thread_info *thread) + for_each_thread ([] (thread_info &thread) { - thread->status_pending_p = 0; + thread.status_pending_p = 0; }); if (tracing) From patchwork Fri Oct 18 15:20:52 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Rohr, Stephan" X-Patchwork-Id: 99213 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 95892385843F for ; Fri, 18 Oct 2024 15:22:40 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.16]) by sourceware.org (Postfix) with ESMTPS id 5C68D385843D for ; Fri, 18 Oct 2024 15:21:47 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 5C68D385843D Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=intel.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 5C68D385843D Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=192.198.163.16 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1729264910; cv=none; b=cfcOrAh1/hXXNekwIRlm3tW3VPuH88yBUOTUbpmaJFF176/dBkLIeqcnCPGJ0cChrdpdN0wpZfgf6ca2DcAH5AKB1U1sMekdvDEYz8yxcSXlHJdH8d9ktsB2eXc7yFVdOeSDzUK9VVFJAzEs3Gguo5i0tbt/kxGPHIVKmbHEMo8= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1729264910; c=relaxed/simple; bh=4sysBdhqDTiushCgil+2SpQ3wP4kZZ5VXKJk0sEfYJs=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=TKGhr6vI4Q34Fw0SqnfgP7byUaPboZwK3thqNUOO2YGrVySa3L+lLCQ3YHuixdahOKPhV3ivecit0o097PO+d4Ay5J88q7y0/jlMiJ4uierecRTIOOIIPXM0sWnwFvkiCoFQubmln+poPuR0MnTlEve0A+IzNwQnfJKIAvkGMl4= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1729264908; x=1760800908; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=4sysBdhqDTiushCgil+2SpQ3wP4kZZ5VXKJk0sEfYJs=; b=hB2nSnRiyr7aCUvtXqCnPclxRgttLVfmDDcH5AuDBgIC6/QJpt3pvI1Q T/22Ss+PuvEhKtoIZzqYGbOE2KkONLNtwMee4CMGoab7r6NOFY3dDhpCq AijcVNgbcxxxbJikR5MnyTFmMXXdSr38lag3HiypczgX5LnSZGjcv6By5 3mrQA3fHSrDyHEkbIX8rFnV09lWMv7vHilZnIbgX+D3n2GzaiApHYvnAl Z9sgnkE4eA1lT/kIq+IGj2PHbQeX+d0tljLrX+WoiuMevib6XkXRRaDBL Qly4IVkESs1Pq29DC/KJT2BOQ9V+Rb9joIm62OPrHcCIvne84zQTekZZ3 w==; X-CSE-ConnectionGUID: Kdl0ZXnKRHqMZkw0Mcg6/Q== X-CSE-MsgGUID: V2ZWXaEERsq9OUNxJMcqtQ== X-IronPort-AV: E=McAfee;i="6700,10204,11229"; a="16415808" X-IronPort-AV: E=Sophos;i="6.11,214,1725346800"; d="scan'208";a="16415808" Received: from orviesa006.jf.intel.com ([10.64.159.146]) by fmvoesa110.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 Oct 2024 08:21:47 -0700 X-CSE-ConnectionGUID: 1vN1//HZQPa6J3EnigpzDw== X-CSE-MsgGUID: id8ZXGEfQ3yKh8vgN94VAg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.11,214,1725346800"; d="scan'208";a="79039363" Received: from 984fee0031af.jf.intel.com (HELO localhost) ([10.165.54.65]) by orviesa006-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 Oct 2024 08:21:47 -0700 From: Stephan Rohr To: gdb-patches@sourceware.org Cc: simark@simark.ca, aburgess@redhat.com Subject: [PATCH v3 3/3] gdbserver: add process specific thread list and map. Date: Fri, 18 Oct 2024 08:20:52 -0700 Message-Id: <20241018152052.1509373-4-stephan.rohr@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241018152052.1509373-1-stephan.rohr@intel.com> References: <20241018152052.1509373-1-stephan.rohr@intel.com> MIME-Version: 1.0 X-Spam-Status: No, score=-10.4 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org Replace the servers global thread list with a process specific thread list and a ptid -> thread map similar to 'inferior::ptid_thread_map' on GDB side. Optimize the 'find_thread' and 'find_thread_ptid' functions to use std::unordered_map::find for faster lookup of threads without iterating over all processes and threads, if applicable. This becomes important when debugging applications with a large thread count, e.g., in the context of GPU debugging. Add the following functions for performance improvements by limiting the iterator range, if applicable: - for_each_thread (ptid_t ptid, Func func) - for_each_thread (process_info *process, Func func) - find_thread_in_random (ptid_t ptid, Func func) --- gdbserver/gdbthread.h | 32 +++++++- gdbserver/inferiors.cc | 175 ++++++++++++++++++++++++++++++++--------- gdbserver/inferiors.h | 32 +++++++- gdbserver/server.cc | 54 +++++++++++-- 4 files changed, 243 insertions(+), 50 deletions(-) diff --git a/gdbserver/gdbthread.h b/gdbserver/gdbthread.h index 8e6f81afad2..6371558a359 100644 --- a/gdbserver/gdbthread.h +++ b/gdbserver/gdbthread.h @@ -84,8 +84,6 @@ struct thread_info : public intrusive_list_node gdb_thread_options thread_options = 0; }; -extern intrusive_list all_threads; - void remove_thread (struct thread_info *thread); struct thread_info *add_thread (ptid_t ptid, void *target_data); @@ -99,8 +97,16 @@ struct thread_info *find_thread_ptid (ptid_t ptid); found. */ struct thread_info *find_any_thread_of_pid (int pid); -/* Find the first thread for which FUNC returns true. Return NULL if no thread - satisfying FUNC is found. */ +/* Find the first thread of PROCESS for which FUNC returns true. + + Return NULL if no thread satisfying FUNC is found. */ + +thread_info * +find_thread (process_info &process, + gdb::function_view func); + + +/* Like the above, but consider threads of all processes. */ thread_info * find_thread (gdb::function_view func); @@ -116,6 +122,12 @@ find_thread (int pid, gdb::function_view func); thread_info * find_thread (ptid_t filter, gdb::function_view func); +/* Invoke FUNC for each thread of PROCESS. */ + +void +for_each_thread (process_info &process, + gdb::function_view func); + /* Invoke FUNC for each thread. */ void @@ -126,6 +138,18 @@ for_each_thread (gdb::function_view func); void for_each_thread (int pid, gdb::function_view func); +/* Like the above, but only consider threads matching PTID. */ + +void +for_each_thread (ptid_t ptid, gdb::function_view func); + +/* Find a random thread that matches PTID and FUNC (THREAD) + returns true. If no entry is found then return NULL. */ + +thread_info * +find_thread_in_random (ptid_t ptid, + gdb::function_view func); + /* Find the a random thread for which FUNC (THREAD) returns true. If no entry is found then return NULL. */ diff --git a/gdbserver/inferiors.cc b/gdbserver/inferiors.cc index 1a2109ef9c8..6bab64ddbef 100644 --- a/gdbserver/inferiors.cc +++ b/gdbserver/inferiors.cc @@ -23,8 +23,6 @@ #include "dll.h" intrusive_list all_processes; -intrusive_list all_threads; - /* The current process. */ static process_info *current_process_; @@ -41,8 +39,16 @@ struct thread_info * add_thread (ptid_t thread_id, void *target_data) { thread_info *new_thread = new thread_info (thread_id, target_data); + process_info *process = get_thread_process (new_thread); + + gdb_assert (process != nullptr); + + /* A thread with this ptid should not exist in the map yet. */ + gdb_assert (process->thread_map ()->find (thread_id) + == process->thread_map ()->end ()); - all_threads.push_back (*new_thread); + process->thread_list ()->push_back (*new_thread); + process->thread_map ()->insert ({thread_id, new_thread}); if (current_thread == NULL) switch_to_thread (new_thread); @@ -55,18 +61,28 @@ add_thread (ptid_t thread_id, void *target_data) struct thread_info * get_first_thread (void) { - if (!all_threads.empty ()) - return &(all_threads.front ()); - else - return NULL; + return find_thread ([] (thread_info &thread) + { + return true; + }); } struct thread_info * find_thread_ptid (ptid_t ptid) { - return find_thread ([&] (thread_info &thread) { - return thread.id == ptid; - }); + process_info *process = find_process_pid (ptid.pid ()); + if (process == nullptr) + return nullptr; + + std::unordered_map *thread_map + = process->thread_map (); + + std::unordered_map::iterator it + = thread_map->find (ptid); + if (it != thread_map->end ()) + return it->second; + + return nullptr; } /* Find a thread associated with the given PROCESS, or NULL if no @@ -95,8 +111,16 @@ remove_thread (struct thread_info *thread) target_disable_btrace (thread->btrace); discard_queued_stop_replies (ptid_of (thread)); - auto it = all_threads.iterator_to (*thread); - all_threads.erase (it); + process_info *process = get_thread_process (thread); + gdb_assert (process != nullptr); + + /* We should not try to remove a thread that was not added. */ + int num_erased = process->thread_map ()->erase (thread->id); + gdb_assert (num_erased > 0); + + auto it = process->thread_list ()->iterator_to (*thread); + process->thread_list ()->erase (it); + if (current_thread == thread) switch_to_thread (nullptr); delete thread; @@ -123,9 +147,13 @@ set_thread_regcache_data (struct thread_info *thread, struct regcache *data) void clear_inferiors (void) { - all_threads.clear_and_dispose ([=] (thread_info *thr) + for_each_process ([&] (process_info &process) { - delete thr; + process.thread_list ()->clear_and_dispose ([=] (thread_info *thr) + { + delete thr; + }); + process.thread_map ()->clear (); }); clear_dlls (); @@ -243,12 +271,29 @@ find_process (gdb::function_view func) /* See gdbthread.h. */ +thread_info * +find_thread (process_info &process, + gdb::function_view func) +{ + for (thread_info &thread : *(process.thread_list ())) + { + if (func (thread)) + return &thread; + } + + return nullptr; +} +/* See gdbthread.h. */ + thread_info * find_thread (gdb::function_view func) { - for (thread_info &thread : all_threads) - if (func (thread)) - return &thread; + for (process_info &process : all_processes) + { + thread_info *thread = find_thread (process, func); + if (thread != nullptr) + return thread; + } return NULL; } @@ -269,20 +314,39 @@ find_thread (int pid, gdb::function_view func) thread_info * find_thread (ptid_t filter, gdb::function_view func) { - return find_thread ([&] (thread_info &thread) { - return thread.id.matches (filter) && func (thread); - }); + if (filter == minus_one_ptid) + return find_thread (func); + + process_info *process = find_process_pid (filter.pid ()); + if (process == nullptr) + return nullptr; + + if (filter.is_pid ()) + return find_thread (*process, func); + + std::unordered_map *thread_map + = process->thread_map (); + std::unordered_map::iterator it + = thread_map->find (filter); + if (it != thread_map->end () && func (*(it->second))) + return it->second; + + return nullptr; } /* See gdbthread.h. */ void -for_each_thread (gdb::function_view func) +for_each_thread (process_info &process, + gdb::function_view func) { - intrusive_list::iterator next, cur = all_threads.begin (); + intrusive_list *thread_list = process.thread_list (); + intrusive_list::iterator next, cur + = thread_list->begin (); - while (cur != all_threads.end ()) + while (cur != thread_list->end ()) { + /* FUNC may alter the current iterator. */ next = cur; next++; func (*cur); @@ -293,45 +357,84 @@ for_each_thread (gdb::function_view func) /* See gdbthread.h. */ void -for_each_thread (int pid, gdb::function_view func) +for_each_thread (gdb::function_view func) { - for_each_thread ([&] (thread_info &thread) + for_each_process ([&] (process_info &proc) { - if (pid == thread.id.pid ()) - func (thread); + for_each_thread (proc, func); }); } /* See gdbthread.h. */ +void +for_each_thread (int pid, gdb::function_view func) +{ + process_info *process = find_process_pid (pid); + if (process == nullptr) + return; + + for_each_thread (*process, func); +} + +/* See gdbthread.h. */ + +void +for_each_thread (ptid_t ptid, gdb::function_view func) +{ + if (ptid == minus_one_ptid) + for_each_thread (func); + else if (ptid.is_pid ()) + for_each_thread (ptid.pid (), func); + else + find_thread (ptid, [func] (thread_info &thread) + { + func (thread); + return false; + }); +} + +/* See gdbthread.h. */ + thread_info * -find_thread_in_random (gdb::function_view func) +find_thread_in_random (ptid_t ptid, + gdb::function_view func) { int count = 0; int random_selector; /* First count how many interesting entries we have. */ - for_each_thread ([&] (thread_info &thread) { - if (func (thread)) - count++; - }); + for_each_thread (ptid, [&] (thread_info &thread) + { + if (func (thread)) + count++; + }); if (count == 0) - return NULL; + return nullptr; /* Now randomly pick an entry out of those. */ random_selector = (int) ((count * (double) rand ()) / (RAND_MAX + 1.0)); - thread_info *thread = find_thread ([&] (thread_info &thr_arg) { - return func (thr_arg) && (random_selector-- == 0); - }); + thread_info *thread = find_thread (ptid, [&] (thread_info &thr_arg) + { + return func (thr_arg) && (random_selector-- == 0); + }); gdb_assert (thread != NULL); return thread; } +/* See gdbthread.h. */ + +thread_info * +find_thread_in_random (gdb::function_view func) +{ + return find_thread_in_random (minus_one_ptid, func); +} + /* See gdbsupport/common-gdbthread.h. */ diff --git a/gdbserver/inferiors.h b/gdbserver/inferiors.h index 7605cb675d0..ac1d84e8228 100644 --- a/gdbserver/inferiors.h +++ b/gdbserver/inferiors.h @@ -23,6 +23,8 @@ #include "gdbsupport/intrusive_list.h" #include "dll.h" +#include + struct thread_info; struct regcache; struct target_desc; @@ -31,9 +33,13 @@ struct breakpoint; struct raw_breakpoint; struct fast_tracepoint_jump; struct process_info_private; +struct process_info; + +extern intrusive_list all_processes; -struct process_info : public intrusive_list_node +class process_info : public intrusive_list_node { +public: process_info (int pid_, int attached_) : pid (pid_), attached (attached_) {} @@ -82,6 +88,24 @@ struct process_info : public intrusive_list_node not access inferior memory or registers, as we haven't determined the target architecture/description. */ bool starting_up = false; + + intrusive_list* thread_list () + { + return &m_thread_list; + } + + std::unordered_map* thread_map () + { + return &m_ptid_thread_map; + } + +private: + /* This processes' thread list, sorted by creation order. */ + intrusive_list m_thread_list; + + /* A map of ptid_t to thread_info*, for average O(1) ptid_t lookup. + Exited threads do not appear in the map. */ + std::unordered_map m_ptid_thread_map; }; /* Get the pid of PROC. */ @@ -92,9 +116,9 @@ pid_of (const process_info *proc) return proc->pid; } -/* Return a pointer to the process that corresponds to the current - thread (current_thread). It is an error to call this if there is - no current thread selected. */ +/* Return a pointer to the current process. Note that the current + process may be non-null while the current thread (current_thread) + is null. */ struct process_info *current_process (void); struct process_info *get_thread_process (const struct thread_info *); diff --git a/gdbserver/server.cc b/gdbserver/server.cc index 6733ddee886..e7ddc37ad9e 100644 --- a/gdbserver/server.cc +++ b/gdbserver/server.cc @@ -1355,7 +1355,7 @@ handle_detach (char *own_buf) another process might delete the next thread in the iteration, which is the one saved by the safe iterator. We will never delete the currently iterated on thread, so standard iteration should be safe. */ - for (thread_info &thread : all_threads) + for (thread_info &thread : *(process->thread_list ())) { /* Only threads that are of the process we are detaching. */ if (thread.id.pid () != pid) @@ -2523,8 +2523,48 @@ static void handle_query (char *own_buf, int packet_len, int *new_packet_len_p) { client_state &cs = get_client_state (); + static intrusive_list::iterator process_iter; static intrusive_list::iterator thread_iter; + auto init_thread_iter = [&] () + { + process_iter = all_processes.begin (); + intrusive_list *thread_list; + + for (; process_iter != all_processes.end (); ++process_iter) + { + thread_list = process_iter->thread_list (); + thread_iter = thread_list->begin (); + if (thread_iter != thread_list->end ()) + break; + } + /* Make sure that there is at least one thread to iterate. */ + gdb_assert (process_iter != all_processes.end ()); + gdb_assert (thread_iter != thread_list->end ()); + }; + + auto advance_thread_iter = [&] () + { + /* 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. */ + intrusive_list *thread_list + = process_iter->thread_list (); + goto start; + + for (; process_iter != all_processes.end (); ++process_iter) + { + thread_list = process_iter->thread_list (); + thread_iter = thread_list->begin (); + while (thread_iter != thread_list->end ()) + { + return; + start: + ++thread_iter; + } + } + }; + /* Reply the current thread id. */ if (strcmp ("qC", own_buf) == 0 && !disable_packet_qC) { @@ -2535,7 +2575,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) ptid = cs.general_thread; else { - thread_iter = all_threads.begin (); + init_thread_iter (); ptid = thread_iter->id; } @@ -2596,24 +2636,26 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) if (strcmp ("qfThreadInfo", own_buf) == 0) { require_running_or_return (own_buf); - thread_iter = all_threads.begin (); + init_thread_iter (); *own_buf++ = 'm'; ptid_t ptid = thread_iter->id; write_ptid (own_buf, ptid); - thread_iter++; + advance_thread_iter (); return; } if (strcmp ("qsThreadInfo", own_buf) == 0) { require_running_or_return (own_buf); - if (thread_iter != all_threads.end ()) + /* We're done if the process iterator hit the end of the + process list. */ + if (process_iter != all_processes.end ()) { *own_buf++ = 'm'; ptid_t ptid = thread_iter->id; write_ptid (own_buf, ptid); - thread_iter++; + advance_thread_iter (); return; } else