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