mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-27 03:51:15 +08:00
0618ae4149
all_matching_threads_iterator is used extensively in some pretty fast paths, often under the all_non_exited_threads function. If a filter target and thread-specific ptid are given, it iterates on all threads of all inferiors of that target, to ultimately yield exactly on thread. And this happens quite often, which means we unnecessarily spend time iterating on threads to find the one we are looking for. The same thing happens if an inferior-specific ptid is given, although there the iterator yields all the threads of that inferior. In those cases, the callers of all_non_exited_threads could have different behaviors depending on the kind of ptid, to avoid this inefficiency, but that would be very tedious. Using all_non_exited_threads has the advantage that one simple implementation can work seamlessly on multiple threads or on one specific thread, just by playing with the ptid. Instead, optimize all_matching_threads_iterator directly to detect these different cases and limiting what we iterate on to just what we need. - if filter_ptid is minus_one_ptid, do as we do now: filter inferiors based on filter_target, iterate on all of the matching inferiors' threads - if filter_ptid is a pid-only ptid (then a filter_target must necessarily be given), look up that inferior and iterate on all its threads - otherwise, filter_ptid is a thread-specific ptid, so look up that specific thread and "iterate" only on it For the last case, what was an iteration on all threads of the filter target now becomes a call to find_thread_ptid, which is quite efficient now thanks to inferior::ptid_thread_map. gdb/ChangeLog: * thread-iter.h (class all_matching_threads_iterator) <all_matching_threads_iterator>: Use default. <enum class mode>: New. <m_inf, m_thr>: Initialize. <m_filter_ptid>: Remove. * thread-iter.c (all_matching_threads_iterator::m_inf_matches): Don't filter on m_filter_ptid. (all_matching_threads_iterator::all_matching_threads_iterator): Choose path based on filter_ptid (all threads, all threads of inferior, single thread). (all_matching_threads_iterator::advance): Likewise. Change-Id: Ic6a19845f5f760fa1b8eac8145793c0ff431bbc9
189 lines
4.4 KiB
C
189 lines
4.4 KiB
C
/* Thread iterators and ranges for GDB, the GNU debugger.
|
|
|
|
Copyright (C) 2018-2021 Free Software Foundation, Inc.
|
|
|
|
This file is part of GDB.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
#include "defs.h"
|
|
#include "gdbthread.h"
|
|
#include "inferior.h"
|
|
|
|
/* See thread-iter.h. */
|
|
|
|
all_threads_iterator::all_threads_iterator (begin_t)
|
|
{
|
|
/* Advance M_INF/M_THR to the first thread's position. */
|
|
|
|
for (inferior &inf : inferior_list)
|
|
{
|
|
auto thr_iter = inf.thread_list.begin ();
|
|
if (thr_iter != inf.thread_list.end ())
|
|
{
|
|
m_inf = &inf;
|
|
m_thr = &*thr_iter;
|
|
return;
|
|
}
|
|
}
|
|
m_inf = nullptr;
|
|
m_thr = nullptr;
|
|
}
|
|
|
|
/* See thread-iter.h. */
|
|
|
|
void
|
|
all_threads_iterator::advance ()
|
|
{
|
|
intrusive_list<inferior>::iterator inf_iter (m_inf);
|
|
intrusive_list<thread_info>::iterator thr_iter (m_thr);
|
|
|
|
/* The loop below is written in the natural way as-if we'd always
|
|
start at the beginning of the inferior list. This fast forwards
|
|
the algorithm to the actual current position. */
|
|
goto start;
|
|
|
|
for (; inf_iter != inferior_list.end (); ++inf_iter)
|
|
{
|
|
m_inf = &*inf_iter;
|
|
thr_iter = m_inf->thread_list.begin ();
|
|
while (thr_iter != m_inf->thread_list.end ())
|
|
{
|
|
m_thr = &*thr_iter;
|
|
return;
|
|
start:
|
|
++thr_iter;
|
|
}
|
|
}
|
|
|
|
m_thr = nullptr;
|
|
}
|
|
|
|
/* See thread-iter.h. */
|
|
|
|
bool
|
|
all_matching_threads_iterator::m_inf_matches ()
|
|
{
|
|
return (m_filter_target == nullptr
|
|
|| m_filter_target == m_inf->process_target ());
|
|
}
|
|
|
|
/* See thread-iter.h. */
|
|
|
|
all_matching_threads_iterator::all_matching_threads_iterator
|
|
(process_stratum_target *filter_target, ptid_t filter_ptid)
|
|
: m_filter_target (filter_target)
|
|
{
|
|
if (filter_ptid == minus_one_ptid)
|
|
{
|
|
/* Iterate on all threads of all inferiors, possibly filtering on
|
|
FILTER_TARGET. */
|
|
m_mode = mode::ALL_THREADS;
|
|
|
|
/* Seek the first thread of the first matching inferior. */
|
|
for (inferior &inf : inferior_list)
|
|
{
|
|
m_inf = &inf;
|
|
|
|
if (!m_inf_matches ()
|
|
|| inf.thread_list.empty ())
|
|
continue;
|
|
|
|
m_thr = &inf.thread_list.front ();
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gdb_assert (filter_target != nullptr);
|
|
|
|
if (filter_ptid.is_pid ())
|
|
{
|
|
/* Iterate on all threads of the given inferior. */
|
|
m_mode = mode::ALL_THREADS_OF_INFERIOR;
|
|
|
|
m_inf = find_inferior_pid (filter_target, filter_ptid.pid ());
|
|
if (m_inf != nullptr)
|
|
m_thr = &m_inf->thread_list.front ();
|
|
}
|
|
else
|
|
{
|
|
/* Iterate on a single thread. */
|
|
m_mode = mode::SINGLE_THREAD;
|
|
|
|
m_thr = find_thread_ptid (filter_target, filter_ptid);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* See thread-iter.h. */
|
|
|
|
void
|
|
all_matching_threads_iterator::advance ()
|
|
{
|
|
switch (m_mode)
|
|
{
|
|
case mode::ALL_THREADS:
|
|
{
|
|
intrusive_list<inferior>::iterator inf_iter (m_inf);
|
|
intrusive_list<thread_info>::iterator thr_iter
|
|
= m_inf->thread_list.iterator_to (*m_thr);
|
|
|
|
/* The loop below is written in the natural way as-if we'd always
|
|
start at the beginning of the inferior list. This fast forwards
|
|
the algorithm to the actual current position. */
|
|
goto start;
|
|
|
|
for (; inf_iter != inferior_list.end (); ++inf_iter)
|
|
{
|
|
m_inf = &*inf_iter;
|
|
|
|
if (!m_inf_matches ())
|
|
continue;
|
|
|
|
thr_iter = m_inf->thread_list.begin ();
|
|
while (thr_iter != m_inf->thread_list.end ())
|
|
{
|
|
m_thr = &*thr_iter;
|
|
return;
|
|
|
|
start:
|
|
++thr_iter;
|
|
}
|
|
}
|
|
}
|
|
m_thr = nullptr;
|
|
break;
|
|
|
|
case mode::ALL_THREADS_OF_INFERIOR:
|
|
{
|
|
intrusive_list<thread_info>::iterator thr_iter
|
|
= m_inf->thread_list.iterator_to (*m_thr);
|
|
++thr_iter;
|
|
if (thr_iter != m_inf->thread_list.end ())
|
|
m_thr = &*thr_iter;
|
|
else
|
|
m_thr = nullptr;
|
|
break;
|
|
}
|
|
|
|
case mode::SINGLE_THREAD:
|
|
m_thr = nullptr;
|
|
break;
|
|
|
|
default:
|
|
gdb_assert_not_reached ("invalid mode value");
|
|
}
|
|
}
|