xref: /dflybsd-src/contrib/gdb-7/gdb/continuations.c (revision de8e141f24382815c10a4012d209bbbf7abf1112)
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, &current_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