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