xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/thread-iter.c (revision 6881a4007f077b54e5f51159c52b9b25f57deb0d)
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