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"
be34f849 25#include "continuations.h"
50c0c017
PA
26
27struct continuation
28{
29 struct continuation *next;
b0f260d6
PA
30 continuation_ftype *function;
31 continuation_free_arg_ftype *free_arg;
50c0c017
PA
32 void *arg;
33};
34
af1e9a32
PA
35/* Add a new continuation to the continuation chain. Args are
36 FUNCTION to run the continuation up with, and ARG to pass to
37 it. */
50c0c017 38
af1e9a32 39static void
50c0c017 40make_continuation (struct continuation **pmy_chain,
b0f260d6 41 continuation_ftype *function,
50c0c017
PA
42 void *arg, void (*free_arg) (void *))
43{
44 struct continuation *new = XNEW (struct continuation);
50c0c017
PA
45
46 new->next = *pmy_chain;
47 new->function = function;
48 new->free_arg = free_arg;
49 new->arg = arg;
50 *pmy_chain = new;
50c0c017
PA
51}
52
53static void
af1e9a32 54do_my_continuations_1 (struct continuation **pmy_chain)
50c0c017
PA
55{
56 struct continuation *ptr;
57
af1e9a32 58 while ((ptr = *pmy_chain) != NULL)
50c0c017
PA
59 {
60 *pmy_chain = ptr->next; /* Do this first in case of recursion. */
61 (*ptr->function) (ptr->arg);
62 if (ptr->free_arg)
63 (*ptr->free_arg) (ptr->arg);
64 xfree (ptr);
65 }
66}
67
af1e9a32
PA
68static void
69do_my_continuations (struct continuation **list)
70{
71 struct continuation *continuations;
72
73 if (*list == NULL)
74 return;
75
76 /* Copy the list header into another pointer, and set the global
77 list header to null, so that the global list can change as a side
78 effect of invoking the continuations and the processing of the
79 preexisting continuations will not be affected. */
80
81 continuations = *list;
82 *list = NULL;
83
84 /* Work now on the list we have set aside. */
85 do_my_continuations_1 (&continuations);
86}
87
88static void
89discard_my_continuations_1 (struct continuation **pmy_chain)
50c0c017
PA
90{
91 struct continuation *ptr;
92
af1e9a32 93 while ((ptr = *pmy_chain) != NULL)
50c0c017
PA
94 {
95 *pmy_chain = ptr->next;
96 if (ptr->free_arg)
97 (*ptr->free_arg) (ptr->arg);
98 xfree (ptr);
99 }
100}
101
af1e9a32
PA
102static void
103discard_my_continuations (struct continuation **list)
50c0c017 104{
af1e9a32 105 struct continuation *continuation_ptr = *list;
50c0c017 106
af1e9a32
PA
107 discard_my_continuations_1 (list);
108 *list = NULL;
50c0c017
PA
109}
110
111/* Add a continuation to the continuation list of INFERIOR. The new
112 continuation will be added at the front. */
113
114void
b0f260d6
PA
115add_inferior_continuation (continuation_ftype *hook, void *args,
116 continuation_free_arg_ftype *free_arg)
50c0c017
PA
117{
118 struct inferior *inf = current_inferior ();
50c0c017 119
b0f260d6 120 make_continuation (&inf->continuations, hook, args, free_arg);
50c0c017
PA
121}
122
123/* Do all continuations of the current inferior. */
124
125void
126do_all_inferior_continuations (void)
127{
50c0c017 128 struct inferior *inf = current_inferior ();
af1e9a32 129 do_my_continuations (&inf->continuations);
50c0c017
PA
130}
131
132/* Get rid of all the inferior-wide continuations of INF. */
133
134void
135discard_all_inferior_continuations (struct inferior *inf)
136{
af1e9a32
PA
137 discard_my_continuations (&inf->continuations);
138}
50c0c017 139
af1e9a32
PA
140/* Add a continuation to the continuation list of THREAD. The new
141 continuation will be added at the front. */
142
143void
144add_continuation (struct thread_info *thread,
b0f260d6
PA
145 continuation_ftype *hook, void *args,
146 continuation_free_arg_ftype *free_arg)
af1e9a32 147{
b0f260d6 148 make_continuation (&thread->continuations, hook, args, free_arg);
50c0c017
PA
149}
150
151static void
152restore_thread_cleanup (void *arg)
153{
154 ptid_t *ptid_p = arg;
155
156 switch_to_thread (*ptid_p);
157}
158
159/* Walk down the continuation list of PTID, and execute all the
160 continuations. There is a problem though. In some cases new
161 continuations may be added while we are in the middle of this loop.
162 If this happens they will be added in the front, and done before we
163 have a chance of exhausting those that were already there. We need
164 to then save the beginning of the list in a pointer and do the
165 continuations from there on, instead of using the global beginning
166 of list as our iteration pointer. */
167
168static void
169do_all_continuations_ptid (ptid_t ptid,
170 struct continuation **continuations_p)
171{
172 struct cleanup *old_chain;
50c0c017
PA
173 ptid_t current_thread;
174
175 if (*continuations_p == NULL)
176 return;
177
178 current_thread = inferior_ptid;
179
180 /* Restore selected thread on exit. Don't try to restore the frame
181 as well, because:
182
183 - When running continuations, the selected frame is always #0.
184
185 - The continuations may trigger symbol file loads, which may
186 change the frame layout (frame ids change), which would trigger
187 a warning if we used make_cleanup_restore_current_thread. */
188
189 old_chain = make_cleanup (restore_thread_cleanup, &current_thread);
190
191 /* Let the continuation see this thread as selected. */
192 switch_to_thread (ptid);
193
af1e9a32 194 do_my_continuations (continuations_p);
50c0c017
PA
195
196 do_cleanups (old_chain);
197}
198
199/* Callback for iterate over threads. */
200
201static int
202do_all_continuations_thread_callback (struct thread_info *thread, void *data)
203{
204 do_all_continuations_ptid (thread->ptid, &thread->continuations);
205 return 0;
206}
207
208/* Do all continuations of thread THREAD. */
209
210void
211do_all_continuations_thread (struct thread_info *thread)
212{
213 do_all_continuations_thread_callback (thread, NULL);
214}
215
216/* Do all continuations of all threads. */
217
218void
219do_all_continuations (void)
220{
221 iterate_over_threads (do_all_continuations_thread_callback, NULL);
222}
223
224/* Callback for iterate over threads. */
225
226static int
227discard_all_continuations_thread_callback (struct thread_info *thread,
228 void *data)
229{
af1e9a32 230 discard_my_continuations (&thread->continuations);
50c0c017
PA
231 return 0;
232}
233
234/* Get rid of all the continuations of THREAD. */
235
236void
237discard_all_continuations_thread (struct thread_info *thread)
238{
239 discard_all_continuations_thread_callback (thread, NULL);
240}
241
242/* Get rid of all the continuations of all threads. */
243
244void
245discard_all_continuations (void)
246{
247 iterate_over_threads (discard_all_continuations_thread_callback, NULL);
248}
249
250
251/* Add a continuation to the intermediate continuation list of THREAD.
252 The new continuation will be added at the front. */
253
254void
255add_intermediate_continuation (struct thread_info *thread,
b0f260d6
PA
256 continuation_ftype *hook,
257 void *args,
258 continuation_free_arg_ftype *free_arg)
50c0c017 259{
b0f260d6
PA
260 make_continuation (&thread->intermediate_continuations, hook,
261 args, free_arg);
50c0c017
PA
262}
263
264/* Walk down the cmd_continuation list, and execute all the
265 continuations. There is a problem though. In some cases new
266 continuations may be added while we are in the middle of this
267 loop. If this happens they will be added in the front, and done
268 before we have a chance of exhausting those that were already
269 there. We need to then save the beginning of the list in a pointer
270 and do the continuations from there on, instead of using the
271 global beginning of list as our iteration pointer. */
272
273static int
274do_all_intermediate_continuations_thread_callback (struct thread_info *thread,
275 void *data)
276{
277 do_all_continuations_ptid (thread->ptid,
278 &thread->intermediate_continuations);
279 return 0;
280}
281
282/* Do all intermediate continuations of thread THREAD. */
283
284void
285do_all_intermediate_continuations_thread (struct thread_info *thread)
286{
287 do_all_intermediate_continuations_thread_callback (thread, NULL);
288}
289
290/* Do all intermediate continuations of all threads. */
291
292void
293do_all_intermediate_continuations (void)
294{
295 iterate_over_threads (do_all_intermediate_continuations_thread_callback,
296 NULL);
297}
298
299/* Callback for iterate over threads. */
300
301static int
302discard_all_intermediate_continuations_thread_callback (struct thread_info *thread,
303 void *data)
304{
af1e9a32 305 discard_my_continuations (&thread->intermediate_continuations);
50c0c017
PA
306 return 0;
307}
308
309/* Get rid of all the intermediate continuations of THREAD. */
310
311void
312discard_all_intermediate_continuations_thread (struct thread_info *thread)
313{
314 discard_all_intermediate_continuations_thread_callback (thread, NULL);
315}
316
317/* Get rid of all the intermediate continuations of all threads. */
318
319void
320discard_all_intermediate_continuations (void)
321{
322 iterate_over_threads (discard_all_intermediate_continuations_thread_callback,
323 NULL);
324}
This page took 0.035012 seconds and 4 git commands to generate.