| /* 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 <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"); | |
| } | |
| } |