2011-05-27 Pedro Alves <pedro@codesourcery.com>
[deliverable/binutils-gdb.git] / gdb / continuations.c
CommitLineData
50c0c017
PA
1/* Continuations for GDB, the GNU debugger.
2
3 Copyright (C) 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
4 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
5 2009, 2010, 2011 Free Software Foundation, Inc.
6
7 This file is part of GDB.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21
22#include "defs.h"
23#include "gdbthread.h"
24#include "inferior.h"
25
26struct continuation
27{
28 struct continuation *next;
29 void (*function) (void *);
30 void (*free_arg) (void *);
31 void *arg;
32};
33
34typedef void (make_continuation_ftype) (void *);
35
36/* Add a new continuation to the continuation chain, and return the
37 previous chain pointer to be passed later to do_continuations or
38 discard_continuations. Args are FUNCTION to run the continuation
39 up with, and ARG to pass to it. */
40
41static struct continuation *
42make_continuation (struct continuation **pmy_chain,
43 make_continuation_ftype *function,
44 void *arg, void (*free_arg) (void *))
45{
46 struct continuation *new = XNEW (struct continuation);
47 struct continuation *old_chain = *pmy_chain;
48
49 new->next = *pmy_chain;
50 new->function = function;
51 new->free_arg = free_arg;
52 new->arg = arg;
53 *pmy_chain = new;
54
55 return old_chain;
56}
57
58static void
59do_my_continuations (struct continuation **pmy_chain,
60 struct continuation *old_chain)
61{
62 struct continuation *ptr;
63
64 while ((ptr = *pmy_chain) != old_chain)
65 {
66 *pmy_chain = ptr->next; /* Do this first in case of recursion. */
67 (*ptr->function) (ptr->arg);
68 if (ptr->free_arg)
69 (*ptr->free_arg) (ptr->arg);
70 xfree (ptr);
71 }
72}
73
74void
75discard_my_continuations (struct continuation **pmy_chain,
76 struct continuation *old_chain)
77{
78 struct continuation *ptr;
79
80 while ((ptr = *pmy_chain) != old_chain)
81 {
82 *pmy_chain = ptr->next;
83 if (ptr->free_arg)
84 (*ptr->free_arg) (ptr->arg);
85 xfree (ptr);
86 }
87}
88
89/* Add a continuation to the continuation list of THREAD. The new
90 continuation will be added at the front. */
91
92void
93add_continuation (struct thread_info *thread,
94 void (*continuation_hook) (void *), void *args,
95 void (*continuation_free_args) (void *))
96{
97 struct continuation *continuations = thread->continuations;
98 make_cleanup_ftype *continuation_hook_fn = continuation_hook;
99
100 make_continuation (&continuations,
101 continuation_hook_fn,
102 args,
103 continuation_free_args);
104
105 thread->continuations = continuations;
106}
107
108/* Add a continuation to the continuation list of INFERIOR. The new
109 continuation will be added at the front. */
110
111void
112add_inferior_continuation (void (*continuation_hook) (void *), void *args,
113 void (*continuation_free_args) (void *))
114{
115 struct inferior *inf = current_inferior ();
116 struct continuation *continuations = inf->continuations;
117 make_cleanup_ftype *continuation_hook_fn = continuation_hook;
118
119 make_continuation (&continuations,
120 continuation_hook_fn,
121 args,
122 continuation_free_args);
123
124 inf->continuations = continuations;
125}
126
127/* Do all continuations of the current inferior. */
128
129void
130do_all_inferior_continuations (void)
131{
132 struct continuation *continuations;
133 struct inferior *inf = current_inferior ();
134
135 if (inf->continuations == NULL)
136 return;
137
138 /* Copy the list header into another pointer, and set the global
139 list header to null, so that the global list can change as a side
140 effect of invoking the continuations and the processing of the
141 preexisting continuations will not be affected. */
142
143 continuations = inf->continuations;
144 inf->continuations = NULL;
145
146 /* Work now on the list we have set aside. */
147 do_my_continuations (&continuations, NULL);
148}
149
150/* Get rid of all the inferior-wide continuations of INF. */
151
152void
153discard_all_inferior_continuations (struct inferior *inf)
154{
155 struct continuation *continuation_ptr = inf->continuations;
156
157 discard_my_continuations (&continuation_ptr, NULL);
158 inf->continuations = NULL;
159}
160
161static void
162restore_thread_cleanup (void *arg)
163{
164 ptid_t *ptid_p = arg;
165
166 switch_to_thread (*ptid_p);
167}
168
169/* Walk down the continuation list of PTID, and execute all the
170 continuations. There is a problem though. In some cases new
171 continuations may be added while we are in the middle of this loop.
172 If this happens they will be added in the front, and done before we
173 have a chance of exhausting those that were already there. We need
174 to then save the beginning of the list in a pointer and do the
175 continuations from there on, instead of using the global beginning
176 of list as our iteration pointer. */
177
178static void
179do_all_continuations_ptid (ptid_t ptid,
180 struct continuation **continuations_p)
181{
182 struct cleanup *old_chain;
183 struct continuation *continuations;
184 ptid_t current_thread;
185
186 if (*continuations_p == NULL)
187 return;
188
189 current_thread = inferior_ptid;
190
191 /* Restore selected thread on exit. Don't try to restore the frame
192 as well, because:
193
194 - When running continuations, the selected frame is always #0.
195
196 - The continuations may trigger symbol file loads, which may
197 change the frame layout (frame ids change), which would trigger
198 a warning if we used make_cleanup_restore_current_thread. */
199
200 old_chain = make_cleanup (restore_thread_cleanup, &current_thread);
201
202 /* Let the continuation see this thread as selected. */
203 switch_to_thread (ptid);
204
205 /* Copy the list header into another pointer, and set the global
206 list header to null, so that the global list can change as a side
207 effect of invoking the continuations and the processing of the
208 preexisting continuations will not be affected. */
209
210 continuations = *continuations_p;
211 *continuations_p = NULL;
212
213 /* Work now on the list we have set aside. */
214 do_my_continuations (&continuations, NULL);
215
216 do_cleanups (old_chain);
217}
218
219/* Callback for iterate over threads. */
220
221static int
222do_all_continuations_thread_callback (struct thread_info *thread, void *data)
223{
224 do_all_continuations_ptid (thread->ptid, &thread->continuations);
225 return 0;
226}
227
228/* Do all continuations of thread THREAD. */
229
230void
231do_all_continuations_thread (struct thread_info *thread)
232{
233 do_all_continuations_thread_callback (thread, NULL);
234}
235
236/* Do all continuations of all threads. */
237
238void
239do_all_continuations (void)
240{
241 iterate_over_threads (do_all_continuations_thread_callback, NULL);
242}
243
244/* Callback for iterate over threads. */
245
246static int
247discard_all_continuations_thread_callback (struct thread_info *thread,
248 void *data)
249{
250 struct continuation *continuation_ptr = thread->continuations;
251
252 discard_my_continuations (&continuation_ptr, NULL);
253 thread->continuations = NULL;
254 return 0;
255}
256
257/* Get rid of all the continuations of THREAD. */
258
259void
260discard_all_continuations_thread (struct thread_info *thread)
261{
262 discard_all_continuations_thread_callback (thread, NULL);
263}
264
265/* Get rid of all the continuations of all threads. */
266
267void
268discard_all_continuations (void)
269{
270 iterate_over_threads (discard_all_continuations_thread_callback, NULL);
271}
272
273
274/* Add a continuation to the intermediate continuation list of THREAD.
275 The new continuation will be added at the front. */
276
277void
278add_intermediate_continuation (struct thread_info *thread,
279 void (*continuation_hook)
280 (void *), void *args,
281 void (*continuation_free_args) (void *))
282{
283 struct continuation *continuations = thread->intermediate_continuations;
284 make_cleanup_ftype *continuation_hook_fn = continuation_hook;
285
286 make_continuation (&continuations,
287 continuation_hook_fn,
288 args,
289 continuation_free_args);
290
291 thread->intermediate_continuations = continuations;
292}
293
294/* Walk down the cmd_continuation list, and execute all the
295 continuations. There is a problem though. In some cases new
296 continuations may be added while we are in the middle of this
297 loop. If this happens they will be added in the front, and done
298 before we have a chance of exhausting those that were already
299 there. We need to then save the beginning of the list in a pointer
300 and do the continuations from there on, instead of using the
301 global beginning of list as our iteration pointer. */
302
303static int
304do_all_intermediate_continuations_thread_callback (struct thread_info *thread,
305 void *data)
306{
307 do_all_continuations_ptid (thread->ptid,
308 &thread->intermediate_continuations);
309 return 0;
310}
311
312/* Do all intermediate continuations of thread THREAD. */
313
314void
315do_all_intermediate_continuations_thread (struct thread_info *thread)
316{
317 do_all_intermediate_continuations_thread_callback (thread, NULL);
318}
319
320/* Do all intermediate continuations of all threads. */
321
322void
323do_all_intermediate_continuations (void)
324{
325 iterate_over_threads (do_all_intermediate_continuations_thread_callback,
326 NULL);
327}
328
329/* Callback for iterate over threads. */
330
331static int
332discard_all_intermediate_continuations_thread_callback (struct thread_info *thread,
333 void *data)
334{
335 struct continuation *continuation_ptr = thread->intermediate_continuations;
336
337 discard_my_continuations (&continuation_ptr, NULL);
338 thread->intermediate_continuations = NULL;
339 return 0;
340}
341
342/* Get rid of all the intermediate continuations of THREAD. */
343
344void
345discard_all_intermediate_continuations_thread (struct thread_info *thread)
346{
347 discard_all_intermediate_continuations_thread_callback (thread, NULL);
348}
349
350/* Get rid of all the intermediate continuations of all threads. */
351
352void
353discard_all_intermediate_continuations (void)
354{
355 iterate_over_threads (discard_all_intermediate_continuations_thread_callback,
356 NULL);
357}
This page took 0.039433 seconds and 4 git commands to generate.