1/* Thread iterators and ranges for GDB, the GNU debugger. 2 Copyright (C) 2018-2020 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/next-iterator.h" 24#include "gdbsupport/safe-iterator.h" 25 26/* A forward iterator that iterates over a given inferior's 27 threads. */ 28 29using inf_threads_iterator = next_iterator<thread_info>; 30 31/* A forward iterator that iterates over all threads of all 32 inferiors. */ 33 34class all_threads_iterator 35{ 36public: 37 typedef all_threads_iterator self_type; 38 typedef struct thread_info *value_type; 39 typedef struct thread_info *&reference; 40 typedef struct thread_info **pointer; 41 typedef std::forward_iterator_tag iterator_category; 42 typedef int difference_type; 43 44 /* Tag type. */ 45 struct begin_t {}; 46 47 /* Create an iterator that points to the first thread of the first 48 inferior. */ 49 explicit all_threads_iterator (begin_t); 50 51 /* Create a one-past-end iterator. */ 52 all_threads_iterator () 53 : m_thr (nullptr) 54 {} 55 56 thread_info *operator* () const { return m_thr; } 57 58 all_threads_iterator &operator++ () 59 { 60 advance (); 61 return *this; 62 } 63 64 bool operator== (const all_threads_iterator &other) const 65 { return m_thr == other.m_thr; } 66 67 bool operator!= (const all_threads_iterator &other) const 68 { return m_thr != other.m_thr; } 69 70private: 71 /* Advance to the next thread. */ 72 void advance (); 73 74private: 75 /* The current inferior and thread. M_THR is NULL if we reached the 76 end of the threads list of the last inferior. */ 77 inferior *m_inf; 78 thread_info *m_thr; 79}; 80 81/* Iterate over all threads that match a given PTID. */ 82 83class all_matching_threads_iterator 84{ 85public: 86 typedef all_matching_threads_iterator self_type; 87 typedef struct thread_info *value_type; 88 typedef struct thread_info *&reference; 89 typedef struct thread_info **pointer; 90 typedef std::forward_iterator_tag iterator_category; 91 typedef int difference_type; 92 93 /* Creates an iterator that iterates over all threads that match 94 FILTER_PTID. */ 95 all_matching_threads_iterator (process_stratum_target *filter_target, 96 ptid_t filter_ptid); 97 98 /* Create a one-past-end iterator. */ 99 all_matching_threads_iterator () 100 : m_inf (nullptr), 101 m_thr (nullptr), 102 m_filter_target (nullptr), 103 m_filter_ptid (minus_one_ptid) 104 {} 105 106 thread_info *operator* () const { return m_thr; } 107 108 all_matching_threads_iterator &operator++ () 109 { 110 advance (); 111 return *this; 112 } 113 114 bool operator== (const all_matching_threads_iterator &other) const 115 { return m_thr == other.m_thr; } 116 117 bool operator!= (const all_matching_threads_iterator &other) const 118 { return m_thr != other.m_thr; } 119 120private: 121 /* Advance to next thread, skipping filtered threads. */ 122 void advance (); 123 124 /* True if M_INF matches the process identified by 125 M_FILTER_PTID. */ 126 bool m_inf_matches (); 127 128private: 129 /* The current inferior. */ 130 inferior *m_inf; 131 132 /* The current thread. */ 133 thread_info *m_thr; 134 135 /* The filter. */ 136 process_stratum_target *m_filter_target; 137 ptid_t m_filter_ptid; 138}; 139 140/* Filter for filtered_iterator. Filters out exited threads. */ 141 142struct non_exited_thread_filter 143{ 144 bool operator() (struct thread_info *thr) const 145 { 146 return thr->state != THREAD_EXITED; 147 } 148}; 149 150/* Iterate over all non-exited threads that match a given PTID. */ 151 152using all_non_exited_threads_iterator 153 = filtered_iterator<all_matching_threads_iterator, non_exited_thread_filter>; 154 155/* Iterate over all non-exited threads of an inferior. */ 156 157using inf_non_exited_threads_iterator 158 = filtered_iterator<inf_threads_iterator, non_exited_thread_filter>; 159 160/* Iterate over all threads of all inferiors, safely. */ 161 162using all_threads_safe_iterator 163 = basic_safe_iterator<all_threads_iterator>; 164 165/* Iterate over all threads of an inferior, safely. */ 166 167using safe_inf_threads_iterator 168 = basic_safe_iterator<inf_threads_iterator>; 169 170/* A range adapter that makes it possible to iterate over all threads 171 of an inferior with range-for. */ 172 173using inf_threads_range 174 = next_adapter<thread_info, inf_threads_iterator>; 175 176/* A range adapter that makes it possible to iterate over all 177 non-exited threads of an inferior with range-for. */ 178 179using inf_non_exited_threads_range 180 = next_adapter<thread_info, inf_non_exited_threads_iterator>; 181 182/* A range adapter that makes it possible to iterate over all threads 183 of an inferior with range-for, safely. */ 184 185using safe_inf_threads_range 186 = next_adapter<thread_info, safe_inf_threads_iterator>; 187 188/* A range adapter that makes it possible to iterate over all threads 189 of all inferiors with range-for. */ 190 191struct all_threads_range 192{ 193 all_threads_iterator begin () const 194 { return all_threads_iterator (all_threads_iterator::begin_t {}); } 195 all_threads_iterator end () const 196 { return all_threads_iterator (); } 197}; 198 199/* A range adapter that makes it possible to iterate over all threads 200 with range-for "safely". I.e., it is safe to delete the 201 currently-iterated thread. */ 202 203struct all_threads_safe_range 204{ 205 all_threads_safe_iterator begin () const 206 { return all_threads_safe_iterator (all_threads_iterator::begin_t {}); } 207 all_threads_safe_iterator end () const 208 { return all_threads_safe_iterator (); } 209}; 210 211/* A range adapter that makes it possible to iterate over all threads 212 that match a PTID filter with range-for. */ 213 214struct all_matching_threads_range 215{ 216public: 217 all_matching_threads_range (process_stratum_target *filter_target, 218 ptid_t filter_ptid) 219 : m_filter_target (filter_target), m_filter_ptid (filter_ptid) 220 {} 221 all_matching_threads_range () 222 : m_filter_target (nullptr), m_filter_ptid (minus_one_ptid) 223 {} 224 225 all_matching_threads_iterator begin () const 226 { return all_matching_threads_iterator (m_filter_target, m_filter_ptid); } 227 all_matching_threads_iterator end () const 228 { return all_matching_threads_iterator (); } 229 230private: 231 /* The filter. */ 232 process_stratum_target *m_filter_target; 233 ptid_t m_filter_ptid; 234}; 235 236/* A range adapter that makes it possible to iterate over all 237 non-exited threads of all inferiors, with range-for. 238 Threads/inferiors that do not match FILTER_PTID are filtered 239 out. */ 240 241class all_non_exited_threads_range 242{ 243public: 244 all_non_exited_threads_range (process_stratum_target *filter_target, 245 ptid_t filter_ptid) 246 : m_filter_target (filter_target), m_filter_ptid (filter_ptid) 247 {} 248 249 all_non_exited_threads_range () 250 : m_filter_target (nullptr), m_filter_ptid (minus_one_ptid) 251 {} 252 253 all_non_exited_threads_iterator begin () const 254 { return all_non_exited_threads_iterator (m_filter_target, m_filter_ptid); } 255 all_non_exited_threads_iterator end () const 256 { return all_non_exited_threads_iterator (); } 257 258private: 259 process_stratum_target *m_filter_target; 260 ptid_t m_filter_ptid; 261}; 262 263#endif /* THREAD_ITER_H */ 264