1 /* Thread iterators and ranges for GDB, the GNU debugger. 2 Copyright (C) 2018-2023 Free Software Foundation, Inc. 3 4 This file is part of GDB. 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 18 19 #ifndef THREAD_ITER_H 20 #define THREAD_ITER_H 21 22 #include "gdbsupport/filtered-iterator.h" 23 #include "gdbsupport/iterator-range.h" 24 #include "gdbsupport/next-iterator.h" 25 #include "gdbsupport/reference-to-pointer-iterator.h" 26 #include "gdbsupport/safe-iterator.h" 27 28 /* A forward iterator that iterates over a given inferior's 29 threads. */ 30 31 using inf_threads_iterator 32 = reference_to_pointer_iterator<intrusive_list<thread_info>::iterator>; 33 34 /* A forward iterator that iterates over all threads of all 35 inferiors. */ 36 37 class all_threads_iterator 38 { 39 public: 40 typedef all_threads_iterator self_type; 41 typedef struct thread_info *value_type; 42 typedef struct thread_info *&reference; 43 typedef struct thread_info **pointer; 44 typedef std::forward_iterator_tag iterator_category; 45 typedef int difference_type; 46 47 /* Tag type. */ 48 struct begin_t {}; 49 50 /* Create an iterator that points to the first thread of the first 51 inferior. */ 52 explicit all_threads_iterator (begin_t); 53 54 /* Create a one-past-end iterator. */ 55 all_threads_iterator () 56 : m_thr (nullptr) 57 {} 58 59 thread_info *operator* () const { return m_thr; } 60 61 all_threads_iterator &operator++ () 62 { 63 advance (); 64 return *this; 65 } 66 67 bool operator== (const all_threads_iterator &other) const 68 { return m_thr == other.m_thr; } 69 70 bool operator!= (const all_threads_iterator &other) const 71 { return m_thr != other.m_thr; } 72 73 private: 74 /* Advance to the next thread. */ 75 void advance (); 76 77 private: 78 /* The current inferior and thread. M_THR is NULL if we reached the 79 end of the threads list of the last inferior. */ 80 inferior *m_inf; 81 thread_info *m_thr; 82 }; 83 84 /* Iterate over all threads that match a given PTID. */ 85 86 class all_matching_threads_iterator 87 { 88 public: 89 typedef all_matching_threads_iterator self_type; 90 typedef struct thread_info *value_type; 91 typedef struct thread_info *&reference; 92 typedef struct thread_info **pointer; 93 typedef std::forward_iterator_tag iterator_category; 94 typedef int difference_type; 95 96 /* Creates an iterator that iterates over all threads that match 97 FILTER_PTID. */ 98 all_matching_threads_iterator (process_stratum_target *filter_target, 99 ptid_t filter_ptid); 100 101 /* Create a one-past-end iterator. */ 102 all_matching_threads_iterator () = default; 103 104 thread_info *operator* () const { return m_thr; } 105 106 all_matching_threads_iterator &operator++ () 107 { 108 advance (); 109 return *this; 110 } 111 112 bool operator== (const all_matching_threads_iterator &other) const 113 { return m_thr == other.m_thr; } 114 115 bool operator!= (const all_matching_threads_iterator &other) const 116 { return m_thr != other.m_thr; } 117 118 private: 119 /* Advance to next thread, skipping filtered threads. */ 120 void advance (); 121 122 /* True if M_INF has the process target M_FILTER_TARGET. */ 123 bool m_inf_matches (); 124 125 private: 126 enum class mode 127 { 128 /* All threads, possibly filtered down to a single target. */ 129 ALL_THREADS, 130 131 /* All threads of the given inferior. */ 132 ALL_THREADS_OF_INFERIOR, 133 134 /* A specific thread. */ 135 SINGLE_THREAD, 136 } m_mode; 137 138 /* The current inferior. */ 139 inferior *m_inf = nullptr; 140 141 /* The current thread. */ 142 thread_info *m_thr = nullptr; 143 144 /* The target we filter on (may be nullptr). */ 145 process_stratum_target *m_filter_target; 146 }; 147 148 /* Filter for filtered_iterator. Filters out exited threads. */ 149 150 struct non_exited_thread_filter 151 { 152 bool operator() (struct thread_info *thr) const 153 { 154 return thr->state != THREAD_EXITED; 155 } 156 }; 157 158 /* Iterate over all non-exited threads that match a given PTID. */ 159 160 using all_non_exited_threads_iterator 161 = filtered_iterator<all_matching_threads_iterator, non_exited_thread_filter>; 162 163 /* Iterate over all non-exited threads of an inferior. */ 164 165 using inf_non_exited_threads_iterator 166 = filtered_iterator<inf_threads_iterator, non_exited_thread_filter>; 167 168 /* Iterate over all threads of all inferiors, safely. */ 169 170 using all_threads_safe_iterator 171 = basic_safe_iterator<all_threads_iterator>; 172 173 /* Iterate over all threads of an inferior, safely. */ 174 175 using safe_inf_threads_iterator 176 = basic_safe_iterator<inf_threads_iterator>; 177 178 /* A range adapter that makes it possible to iterate over all threads 179 of an inferior with range-for. */ 180 181 using inf_threads_range = iterator_range<inf_threads_iterator>; 182 183 /* A range adapter that makes it possible to iterate over all 184 non-exited threads of an inferior with range-for. */ 185 186 using inf_non_exited_threads_range 187 = iterator_range<inf_non_exited_threads_iterator>; 188 189 /* A range adapter that makes it possible to iterate over all threads 190 of an inferior with range-for, safely. */ 191 192 using safe_inf_threads_range = iterator_range<safe_inf_threads_iterator>; 193 194 /* A range adapter that makes it possible to iterate over all threads 195 with range-for "safely". I.e., it is safe to delete the 196 currently-iterated thread. */ 197 198 using all_threads_safe_range = iterator_range<all_threads_safe_iterator>; 199 200 /* A range adapter that makes it possible to iterate over all threads 201 that match a PTID filter with range-for. */ 202 203 struct all_matching_threads_range 204 { 205 public: 206 all_matching_threads_range (process_stratum_target *filter_target, 207 ptid_t filter_ptid) 208 : m_filter_target (filter_target), m_filter_ptid (filter_ptid) 209 {} 210 all_matching_threads_range () 211 : m_filter_target (nullptr), m_filter_ptid (minus_one_ptid) 212 {} 213 214 all_matching_threads_iterator begin () const 215 { return all_matching_threads_iterator (m_filter_target, m_filter_ptid); } 216 all_matching_threads_iterator end () const 217 { return all_matching_threads_iterator (); } 218 219 private: 220 /* The filter. */ 221 process_stratum_target *m_filter_target; 222 ptid_t m_filter_ptid; 223 }; 224 225 /* A range adapter that makes it possible to iterate over all 226 non-exited threads of all inferiors, with range-for. 227 Threads/inferiors that do not match FILTER_PTID are filtered 228 out. */ 229 230 class all_non_exited_threads_range 231 { 232 public: 233 all_non_exited_threads_range (process_stratum_target *filter_target, 234 ptid_t filter_ptid) 235 : m_filter_target (filter_target), m_filter_ptid (filter_ptid) 236 {} 237 238 all_non_exited_threads_range () 239 : m_filter_target (nullptr), m_filter_ptid (minus_one_ptid) 240 {} 241 242 all_non_exited_threads_iterator begin () const 243 { return all_non_exited_threads_iterator (m_filter_target, m_filter_ptid); } 244 all_non_exited_threads_iterator end () const 245 { return all_non_exited_threads_iterator (); } 246 247 private: 248 process_stratum_target *m_filter_target; 249 ptid_t m_filter_ptid; 250 }; 251 252 #endif /* THREAD_ITER_H */ 253