1 /* Thread iterators and ranges for GDB, the GNU debugger. 2 3 Copyright (C) 2018-2023 Free Software Foundation, Inc. 4 5 This file is part of GDB. 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 19 20 #include "defs.h" 21 #include "gdbthread.h" 22 #include "inferior.h" 23 24 /* See thread-iter.h. */ 25 26 all_threads_iterator::all_threads_iterator (begin_t) 27 { 28 /* Advance M_INF/M_THR to the first thread's position. */ 29 30 for (inferior &inf : inferior_list) 31 { 32 auto thr_iter = inf.thread_list.begin (); 33 if (thr_iter != inf.thread_list.end ()) 34 { 35 m_inf = &inf; 36 m_thr = &*thr_iter; 37 return; 38 } 39 } 40 m_inf = nullptr; 41 m_thr = nullptr; 42 } 43 44 /* See thread-iter.h. */ 45 46 void 47 all_threads_iterator::advance () 48 { 49 intrusive_list<inferior>::iterator inf_iter (m_inf); 50 intrusive_list<thread_info>::iterator thr_iter (m_thr); 51 52 /* The loop below is written in the natural way as-if we'd always 53 start at the beginning of the inferior list. This fast forwards 54 the algorithm to the actual current position. */ 55 goto start; 56 57 for (; inf_iter != inferior_list.end (); ++inf_iter) 58 { 59 m_inf = &*inf_iter; 60 thr_iter = m_inf->thread_list.begin (); 61 while (thr_iter != m_inf->thread_list.end ()) 62 { 63 m_thr = &*thr_iter; 64 return; 65 start: 66 ++thr_iter; 67 } 68 } 69 70 m_thr = nullptr; 71 } 72 73 /* See thread-iter.h. */ 74 75 bool 76 all_matching_threads_iterator::m_inf_matches () 77 { 78 return (m_filter_target == nullptr 79 || m_filter_target == m_inf->process_target ()); 80 } 81 82 /* See thread-iter.h. */ 83 84 all_matching_threads_iterator::all_matching_threads_iterator 85 (process_stratum_target *filter_target, ptid_t filter_ptid) 86 : m_filter_target (filter_target) 87 { 88 if (filter_ptid == minus_one_ptid) 89 { 90 /* Iterate on all threads of all inferiors, possibly filtering on 91 FILTER_TARGET. */ 92 m_mode = mode::ALL_THREADS; 93 94 /* Seek the first thread of the first matching inferior. */ 95 for (inferior &inf : inferior_list) 96 { 97 m_inf = &inf; 98 99 if (!m_inf_matches () 100 || inf.thread_list.empty ()) 101 continue; 102 103 m_thr = &inf.thread_list.front (); 104 return; 105 } 106 } 107 else 108 { 109 gdb_assert (filter_target != nullptr); 110 111 if (filter_ptid.is_pid ()) 112 { 113 /* Iterate on all threads of the given inferior. */ 114 m_mode = mode::ALL_THREADS_OF_INFERIOR; 115 116 m_inf = find_inferior_pid (filter_target, filter_ptid.pid ()); 117 if (m_inf != nullptr) 118 m_thr = &m_inf->thread_list.front (); 119 } 120 else 121 { 122 /* Iterate on a single thread. */ 123 m_mode = mode::SINGLE_THREAD; 124 125 m_thr = find_thread_ptid (filter_target, filter_ptid); 126 } 127 } 128 } 129 130 /* See thread-iter.h. */ 131 132 void 133 all_matching_threads_iterator::advance () 134 { 135 switch (m_mode) 136 { 137 case mode::ALL_THREADS: 138 { 139 intrusive_list<inferior>::iterator inf_iter (m_inf); 140 intrusive_list<thread_info>::iterator thr_iter 141 = m_inf->thread_list.iterator_to (*m_thr); 142 143 /* The loop below is written in the natural way as-if we'd always 144 start at the beginning of the inferior list. This fast forwards 145 the algorithm to the actual current position. */ 146 goto start; 147 148 for (; inf_iter != inferior_list.end (); ++inf_iter) 149 { 150 m_inf = &*inf_iter; 151 152 if (!m_inf_matches ()) 153 continue; 154 155 thr_iter = m_inf->thread_list.begin (); 156 while (thr_iter != m_inf->thread_list.end ()) 157 { 158 m_thr = &*thr_iter; 159 return; 160 161 start: 162 ++thr_iter; 163 } 164 } 165 } 166 m_thr = nullptr; 167 break; 168 169 case mode::ALL_THREADS_OF_INFERIOR: 170 { 171 intrusive_list<thread_info>::iterator thr_iter 172 = m_inf->thread_list.iterator_to (*m_thr); 173 ++thr_iter; 174 if (thr_iter != m_inf->thread_list.end ()) 175 m_thr = &*thr_iter; 176 else 177 m_thr = nullptr; 178 break; 179 } 180 181 case mode::SINGLE_THREAD: 182 m_thr = nullptr; 183 break; 184 185 default: 186 gdb_assert_not_reached ("invalid mode value"); 187 } 188 } 189