Home | History | Annotate | Line # | Download | only in gdb
      1 /* Thread iterators and ranges for GDB, the GNU debugger.
      2    Copyright (C) 2018-2024 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