* [PATCH v4 0/2] gdbserver: add thread map
@ 2024-10-22 15:02 Stephan Rohr
2024-10-22 15:02 ` [PATCH v4 1/2] gdbserver: introduce 'owning_introdusive_list' type Stephan Rohr
2024-10-22 15:02 ` [PATCH v4 2/2] gdbserver: add process specific thread list and map Stephan Rohr
0 siblings, 2 replies; 3+ messages in thread
From: Stephan Rohr @ 2024-10-22 15:02 UTC (permalink / raw)
To: gdb-patches; +Cc: simark, aburgess
Hi all,
this is version 4 of my patch that extends the 'process_info' struct
with a process specific thread map for faster lookup of threads.
You can find v3 of the patch at
https://sourceware.org/pipermail/gdb-patches/2024-October/212481.html
You can find Simon's feedback on v3 at
https://sourceware.org/pipermail/gdb-patches/2024-October/212490.html
https://sourceware.org/pipermail/gdb-patches/2024-October/212492.html
https://sourceware.org/pipermail/gdb-patches/2024-October/212493.html
You can find v2 of the patch at
https://sourceware.org/pipermail/gdb-patches/2024-September/211509.html
Simon's feedback on v2:
https://sourceware.org/pipermail/gdb-patches/2024-October/212207.html
My reply on v2:
https://sourceware.org/pipermail/gdb-patches/2024-October/212471.html
Changes from v3:
* Merged the patch introducing gdb::function_view.
* Fixed the review findings from Simon.
I appreciate your feedback.
Thanks
Stephan
Stephan Rohr (2):
gdbserver: introduce 'owning_introdusive_list' type
gdbserver: add process specific thread list and map
gdbserver/gdbthread.h | 28 ++++--
gdbserver/inferiors.cc | 222 ++++++++++++++++++++++++++---------------
gdbserver/inferiors.h | 46 +++++++--
gdbserver/server.cc | 68 ++++++++++---
4 files changed, 257 insertions(+), 107 deletions(-)
--
2.34.1
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH v4 1/2] gdbserver: introduce 'owning_introdusive_list' type
2024-10-22 15:02 [PATCH v4 0/2] gdbserver: add thread map Stephan Rohr
@ 2024-10-22 15:02 ` Stephan Rohr
2024-10-22 15:02 ` [PATCH v4 2/2] gdbserver: add process specific thread list and map Stephan Rohr
1 sibling, 0 replies; 3+ messages in thread
From: Stephan Rohr @ 2024-10-22 15:02 UTC (permalink / raw)
To: gdb-patches; +Cc: simark, aburgess
This patch replaces the 'std::list' type of 'all_processes' and
'all_threads' with the more lightweight 'owning_intrusive_list'
type.
---
gdbserver/gdbthread.h | 8 ++---
gdbserver/inferiors.cc | 75 +++++++++++++-----------------------------
gdbserver/inferiors.h | 7 ++--
gdbserver/server.cc | 16 ++++-----
4 files changed, 37 insertions(+), 69 deletions(-)
diff --git a/gdbserver/gdbthread.h b/gdbserver/gdbthread.h
index adc5857abfd..1c380d5ff22 100644
--- a/gdbserver/gdbthread.h
+++ b/gdbserver/gdbthread.h
@@ -21,14 +21,12 @@
#include "gdbsupport/common-gdbthread.h"
#include "gdbsupport/function-view.h"
-#include "inferiors.h"
-
-#include <list>
+#include "gdbsupport/owning_intrusive_list.h"
struct btrace_target_info;
struct regcache;
-struct thread_info
+struct thread_info : public intrusive_list_node<thread_info>
{
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<thread_info *> all_threads;
+extern owning_intrusive_list<thread_info> all_threads;
void remove_thread (struct thread_info *thread);
struct thread_info *add_thread (ptid_t ptid, void *target_data);
diff --git a/gdbserver/inferiors.cc b/gdbserver/inferiors.cc
index 5621db377fb..1d39a8d1a86 100644
--- a/gdbserver/inferiors.cc
+++ b/gdbserver/inferiors.cc
@@ -19,11 +19,12 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "gdbsupport/common-inferior.h"
+#include "gdbsupport/owning_intrusive_list.h"
#include "gdbthread.h"
#include "dll.h"
-std::list<process_info *> all_processes;
-std::list<thread_info *> all_threads;
+owning_intrusive_list<process_info> all_processes;
+owning_intrusive_list<thread_info> all_threads;
/* The current process. */
static process_info *current_process_;
@@ -40,14 +41,12 @@ static std::string current_inferior_cwd;
struct thread_info *
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);
+ auto &new_thread = all_threads.emplace_back (thread_id, target_data);
if (current_thread == NULL)
- switch_to_thread (new_thread);
+ switch_to_thread (&new_thread);
- return new_thread;
+ return &new_thread;
}
/* See gdbthread.h. */
@@ -56,7 +55,7 @@ struct thread_info *
get_first_thread (void)
{
if (!all_threads.empty ())
- return all_threads.front ();
+ return &(all_threads.front ());
else
return NULL;
}
@@ -88,12 +87,6 @@ find_any_thread_of_pid (int pid)
});
}
-static void
-free_one_thread (thread_info *thread)
-{
- delete thread;
-}
-
void
remove_thread (struct thread_info *thread)
{
@@ -101,10 +94,9 @@ remove_thread (struct thread_info *thread)
target_disable_btrace (thread->btrace);
discard_queued_stop_replies (ptid_of (thread));
- all_threads.remove (thread);
+ all_threads.erase (all_threads.iterator_to (*thread));
if (current_thread == thread)
switch_to_thread (nullptr);
- free_one_thread (thread);
}
void *
@@ -128,7 +120,6 @@ set_thread_regcache_data (struct thread_info *thread, struct regcache *data)
void
clear_inferiors (void)
{
- for_each_thread (free_one_thread);
all_threads.clear ();
clear_dlls ();
@@ -140,11 +131,8 @@ clear_inferiors (void)
struct process_info *
add_process (int pid, int attached)
{
- process_info *process = new process_info (pid, attached);
-
- all_processes.push_back (process);
-
- return process;
+ auto &process = all_processes.emplace_back (pid, attached);
+ return &process;
}
/* Remove a process from the common process list and free the memory
@@ -157,10 +145,9 @@ 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);
+ all_processes.erase (all_processes.iterator_to (*process));
if (current_process () == process)
switch_to_process (nullptr);
- delete process;
}
process_info *
@@ -177,7 +164,7 @@ process_info *
get_first_process (void)
{
if (!all_processes.empty ())
- return all_processes.front ();
+ return &(all_processes.front ());
else
return NULL;
}
@@ -220,13 +207,13 @@ current_process (void)
void
for_each_process (gdb::function_view<void (process_info *)> func)
{
- std::list<process_info *>::iterator next, cur = all_processes.begin ();
+ owning_intrusive_list<process_info>::iterator next, cur = all_processes.begin ();
while (cur != all_processes.end ())
{
next = cur;
next++;
- func (*cur);
+ func (&*cur);
cur = next;
}
}
@@ -236,18 +223,9 @@ for_each_process (gdb::function_view<void (process_info *)> func)
process_info *
find_process (gdb::function_view<bool (process_info *)> func)
{
- std::list<process_info *>::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;
}
@@ -257,18 +235,9 @@ find_process (gdb::function_view<bool (process_info *)> func)
thread_info *
find_thread (gdb::function_view<bool (thread_info *)> func)
{
- std::list<thread_info *>::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;
}
@@ -299,13 +268,13 @@ find_thread (ptid_t filter, gdb::function_view<bool (thread_info *)> func)
void
for_each_thread (gdb::function_view<void (thread_info *)> func)
{
- std::list<thread_info *>::iterator next, cur = all_threads.begin ();
+ owning_intrusive_list<thread_info>::iterator next, cur = all_threads.begin ();
while (cur != all_threads.end ())
{
next = cur;
next++;
- func (*cur);
+ func (&*cur);
cur = next;
}
}
diff --git a/gdbserver/inferiors.h b/gdbserver/inferiors.h
index 7d453260270..3f2c5c70a39 100644
--- a/gdbserver/inferiors.h
+++ b/gdbserver/inferiors.h
@@ -20,8 +20,9 @@
#define GDBSERVER_INFERIORS_H
#include "gdbsupport/gdb_vecs.h"
+#include "gdbsupport/owning_intrusive_list.h"
+
#include "dll.h"
-#include <list>
struct thread_info;
struct regcache;
@@ -32,7 +33,7 @@ struct raw_breakpoint;
struct fast_tracepoint_jump;
struct process_info_private;
-struct process_info
+struct process_info : public intrusive_list_node<process_info>
{
process_info (int pid_, int attached_)
: pid (pid_), attached (attached_)
@@ -99,7 +100,7 @@ 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<process_info *> all_processes;
+extern owning_intrusive_list<process_info> all_processes;
/* Invoke FUNC for each process. */
diff --git a/gdbserver/server.cc b/gdbserver/server.cc
index 5190df4aed5..5058428f58b 100644
--- a/gdbserver/server.cc
+++ b/gdbserver/server.cc
@@ -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)
@@ -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<thread_info *>::const_iterator thread_iter;
+ static owning_intrusive_list<thread_info>::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;
--
2.34.1
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH v4 2/2] gdbserver: add process specific thread list and map
2024-10-22 15:02 [PATCH v4 0/2] gdbserver: add thread map Stephan Rohr
2024-10-22 15:02 ` [PATCH v4 1/2] gdbserver: introduce 'owning_introdusive_list' type Stephan Rohr
@ 2024-10-22 15:02 ` Stephan Rohr
1 sibling, 0 replies; 3+ messages in thread
From: Stephan Rohr @ 2024-10-22 15:02 UTC (permalink / raw)
To: gdb-patches; +Cc: simark, aburgess
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.
---
gdbserver/gdbthread.h | 24 ++++--
gdbserver/inferiors.cc | 173 ++++++++++++++++++++++++++++++++---------
gdbserver/inferiors.h | 41 +++++++++-
gdbserver/server.cc | 54 +++++++++++--
4 files changed, 237 insertions(+), 55 deletions(-)
diff --git a/gdbserver/gdbthread.h b/gdbserver/gdbthread.h
index 1c380d5ff22..8e317724b4d 100644
--- a/gdbserver/gdbthread.h
+++ b/gdbserver/gdbthread.h
@@ -21,7 +21,7 @@
#include "gdbsupport/common-gdbthread.h"
#include "gdbsupport/function-view.h"
-#include "gdbsupport/owning_intrusive_list.h"
+#include "gdbsupport/intrusive_list.h"
struct btrace_target_info;
struct regcache;
@@ -84,8 +84,6 @@ struct thread_info : public intrusive_list_node<thread_info>
gdb_thread_options thread_options = 0;
};
-extern owning_intrusive_list<thread_info> all_threads;
-
void remove_thread (struct thread_info *thread);
struct thread_info *add_thread (ptid_t ptid, void *target_data);
@@ -97,10 +95,11 @@ struct thread_info *find_thread_ptid (ptid_t ptid);
/* Find any thread of the PID process. Returns NULL if none is
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 for which FUNC returns true. Return NULL if
+ no thread satisfying FUNC is found. */
thread_info *
find_thread (gdb::function_view<bool (thread_info *)> func);
@@ -126,12 +125,23 @@ for_each_thread (gdb::function_view<void (thread_info *)> func);
void
for_each_thread (int pid, gdb::function_view<void (thread_info *)> func);
-/* Find the a random thread for which FUNC (THREAD) returns true. If
- no entry is found then return NULL. */
+/* Like the above, but only consider threads matching PTID. */
+
+void
+for_each_thread (ptid_t ptid, gdb::function_view<void (thread_info *)> 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 (gdb::function_view<bool (thread_info *)> func);
+/* Like the above, but only consider threads matching PTID. */
+
+thread_info *
+find_thread_in_random (ptid_t ptid,
+ gdb::function_view<bool (thread_info *)> 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 1d39a8d1a86..c862e9653bb 100644
--- a/gdbserver/inferiors.cc
+++ b/gdbserver/inferiors.cc
@@ -24,7 +24,6 @@
#include "dll.h"
owning_intrusive_list<process_info> all_processes;
-owning_intrusive_list<thread_info> all_threads;
/* The current process. */
static process_info *current_process_;
@@ -41,7 +40,15 @@ static std::string current_inferior_cwd;
struct thread_info *
add_thread (ptid_t thread_id, void *target_data)
{
- auto &new_thread = all_threads.emplace_back (thread_id, target_data);
+ process_info *process = find_process_pid (thread_id.pid ());
+ gdb_assert (process != nullptr);
+
+ auto &new_thread = process->thread_list ().emplace_back (thread_id, target_data);
+ auto map_elem =
+ process->thread_map ().insert ({thread_id, &new_thread});
+
+ /* A thread with this ptid should not exist in the map yet. */
+ gdb_assert (map_elem.second);
if (current_thread == NULL)
switch_to_thread (&new_thread);
@@ -54,18 +61,26 @@ 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;
+
+ auto &thread_map = process->thread_map ();
+
+ if (auto it = thread_map.find (ptid);
+ it != thread_map.end ())
+ return it->second;
+
+ return nullptr;
}
/* Find a thread associated with the given PROCESS, or NULL if no
@@ -94,7 +109,16 @@ remove_thread (struct thread_info *thread)
target_disable_btrace (thread->btrace);
discard_queued_stop_replies (ptid_of (thread));
- all_threads.erase (all_threads.iterator_to (*thread));
+ 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);
+
+ process->thread_list ().erase (
+ process->thread_list ().iterator_to (*thread));
+
if (current_thread == thread)
switch_to_thread (nullptr);
}
@@ -120,9 +144,11 @@ set_thread_regcache_data (struct thread_info *thread, struct regcache *data)
void
clear_inferiors (void)
{
- all_threads.clear ();
-
- clear_dlls ();
+ for_each_process ([&] (process_info *process)
+ {
+ process->thread_list ().clear ();
+ process->thread_map ().clear ();
+ });
switch_to_thread (nullptr);
current_process_ = nullptr;
@@ -230,14 +256,30 @@ find_process (gdb::function_view<bool (process_info *)> func)
return NULL;
}
+/* See inferiors.h. */
+
+thread_info *
+process_info::find_thread (gdb::function_view<bool (thread_info *)> func)
+{
+ for (thread_info &thread : m_thread_list)
+ {
+ if (func (&thread))
+ return &thread;
+ }
+ return nullptr;
+}
+
/* See gdbthread.h. */
thread_info *
find_thread (gdb::function_view<bool (thread_info *)> func)
{
- for (thread_info &thread : all_threads)
- if (func (&thread))
- return &thread;
+ for (process_info &process : all_processes)
+ {
+ thread_info *thread = process.find_thread (func);
+ if (thread != nullptr)
+ return thread;
+ }
return NULL;
}
@@ -247,10 +289,11 @@ find_thread (gdb::function_view<bool (thread_info *)> func)
thread_info *
find_thread (int pid, gdb::function_view<bool (thread_info *)> func)
{
- return find_thread ([&] (thread_info *thread)
- {
- return thread->id.pid () == pid && func (thread);
- });
+ process_info *process = find_process_pid (pid);
+ if (process == nullptr)
+ return nullptr;
+
+ return process->find_thread (func);
}
/* See gdbthread.h. */
@@ -258,9 +301,23 @@ find_thread (int pid, gdb::function_view<bool (thread_info *)> func)
thread_info *
find_thread (ptid_t filter, gdb::function_view<bool (thread_info *)> 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 process->find_thread (func);
+
+ auto &thread_map = process->thread_map ();
+
+ if (auto it = thread_map.find (filter);
+ it != thread_map.end () && func (it->second))
+ return it->second;
+
+ return nullptr;
}
/* See gdbthread.h. */
@@ -268,10 +325,23 @@ find_thread (ptid_t filter, gdb::function_view<bool (thread_info *)> func)
void
for_each_thread (gdb::function_view<void (thread_info *)> func)
{
- owning_intrusive_list<thread_info>::iterator next, cur = all_threads.begin ();
+ for_each_process ([&] (process_info *proc)
+ {
+ proc->for_each_thread (func);
+ });
+}
+
+/* See inferiors.h. */
+
+void
+process_info::for_each_thread (gdb::function_view<void (thread_info *)> func)
+{
+ owning_intrusive_list<thread_info>::iterator next, cur
+ = m_thread_list.begin ();
- while (cur != all_threads.end ())
+ while (cur != m_thread_list.end ())
{
+ /* FUNC may alter the current iterator. */
next = cur;
next++;
func (&*cur);
@@ -284,43 +354,70 @@ for_each_thread (gdb::function_view<void (thread_info *)> func)
void
for_each_thread (int pid, gdb::function_view<void (thread_info *)> func)
{
- for_each_thread ([&] (thread_info *thread)
- {
- if (pid == thread->id.pid ())
+ process_info *process = find_process_pid (pid);
+ if (process == nullptr)
+ return;
+
+ process->for_each_thread (func);
+}
+
+/* See gdbthread.h. */
+
+void
+for_each_thread (ptid_t ptid, gdb::function_view<void (thread_info *)> 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<bool (thread_info *)> func)
+find_thread_in_random (ptid_t ptid,
+ gdb::function_view<bool (thread_info *)> 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<bool (thread_info *)> 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 3f2c5c70a39..21bafde1fcd 100644
--- a/gdbserver/inferiors.h
+++ b/gdbserver/inferiors.h
@@ -24,6 +24,8 @@
#include "dll.h"
+#include <unordered_map>
+
struct thread_info;
struct regcache;
struct target_desc;
@@ -32,9 +34,13 @@ struct breakpoint;
struct raw_breakpoint;
struct fast_tracepoint_jump;
struct process_info_private;
+struct process_info;
+
+extern owning_intrusive_list<process_info> all_processes;
-struct process_info : public intrusive_list_node<process_info>
+class process_info : public intrusive_list_node<process_info>
{
+public:
process_info (int pid_, int attached_)
: pid (pid_), attached (attached_)
{}
@@ -83,6 +89,33 @@ struct process_info : public intrusive_list_node<process_info>
not access inferior memory or registers, as we haven't determined
the target architecture/description. */
bool starting_up = false;
+
+ /* Return a reference to the private thread list. */
+ owning_intrusive_list<thread_info> &thread_list ()
+ {
+ return m_thread_list;
+ }
+
+ /* Return a reference to the private thread map. */
+ std::unordered_map<ptid_t, thread_info *> &thread_map ()
+ {
+ return m_ptid_thread_map;
+ }
+
+ /* Find the first thread for which FUNC returns true. Return NULL if no
+ such thread is found. */
+ thread_info *find_thread (gdb::function_view<bool (thread_info *)> func);
+
+ /* Invoke FUNC for each thread. */
+ void for_each_thread (gdb::function_view<void (thread_info *)> func);
+
+private:
+ /* This processes' thread list, sorted by creation order. */
+ owning_intrusive_list<thread_info> 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<ptid_t, thread_info *> m_ptid_thread_map;
};
/* Get the pid of PROC. */
@@ -93,9 +126,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 5058428f58b..3086f8b31a1 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 owning_intrusive_list<process_info>::iterator process_iter;
static owning_intrusive_list<thread_info>::iterator thread_iter;
+ auto init_thread_iter = [&] ()
+ {
+ process_iter = all_processes.begin ();
+ owning_intrusive_list<thread_info> *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. */
+ owning_intrusive_list<thread_info> *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
--
2.34.1
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2024-10-22 15:02 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-10-22 15:02 [PATCH v4 0/2] gdbserver: add thread map Stephan Rohr
2024-10-22 15:02 ` [PATCH v4 1/2] gdbserver: introduce 'owning_introdusive_list' type Stephan Rohr
2024-10-22 15:02 ` [PATCH v4 2/2] gdbserver: add process specific thread list and map Stephan Rohr
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).