/* Thread iterators and ranges for GDB, the GNU debugger. Copyright (C) 2018-2023 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 . */ #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::iterator inf_iter (m_inf); intrusive_list::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 = filter_target->find_thread (filter_ptid); } } } /* See thread-iter.h. */ void all_matching_threads_iterator::advance () { switch (m_mode) { case mode::ALL_THREADS: { intrusive_list::iterator inf_iter (m_inf); intrusive_list::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::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"); } }