GDB (API)
|
00001 /* Continuations for GDB, the GNU debugger. 00002 00003 Copyright (C) 1986-2013 Free Software Foundation, Inc. 00004 00005 This file is part of GDB. 00006 00007 This program is free software; you can redistribute it and/or modify 00008 it under the terms of the GNU General Public License as published by 00009 the Free Software Foundation; either version 3 of the License, or 00010 (at your option) any later version. 00011 00012 This program is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 GNU General Public License for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 00019 00020 #include "defs.h" 00021 #include "gdbthread.h" 00022 #include "inferior.h" 00023 #include "continuations.h" 00024 00025 struct continuation 00026 { 00027 struct continuation *next; 00028 continuation_ftype *function; 00029 continuation_free_arg_ftype *free_arg; 00030 void *arg; 00031 }; 00032 00033 /* Add a new continuation to the continuation chain. Args are 00034 FUNCTION to run the continuation up with, and ARG to pass to 00035 it. */ 00036 00037 static void 00038 make_continuation (struct continuation **pmy_chain, 00039 continuation_ftype *function, 00040 void *arg, void (*free_arg) (void *)) 00041 { 00042 struct continuation *new = XNEW (struct continuation); 00043 00044 new->next = *pmy_chain; 00045 new->function = function; 00046 new->free_arg = free_arg; 00047 new->arg = arg; 00048 *pmy_chain = new; 00049 } 00050 00051 static void 00052 do_my_continuations_1 (struct continuation **pmy_chain, int err) 00053 { 00054 struct continuation *ptr; 00055 00056 while ((ptr = *pmy_chain) != NULL) 00057 { 00058 *pmy_chain = ptr->next; /* Do this first in case of recursion. */ 00059 (*ptr->function) (ptr->arg, err); 00060 if (ptr->free_arg) 00061 (*ptr->free_arg) (ptr->arg); 00062 xfree (ptr); 00063 } 00064 } 00065 00066 static void 00067 do_my_continuations (struct continuation **list, int err) 00068 { 00069 struct continuation *continuations; 00070 00071 if (*list == NULL) 00072 return; 00073 00074 /* Copy the list header into another pointer, and set the global 00075 list header to null, so that the global list can change as a side 00076 effect of invoking the continuations and the processing of the 00077 preexisting continuations will not be affected. */ 00078 00079 continuations = *list; 00080 *list = NULL; 00081 00082 /* Work now on the list we have set aside. */ 00083 do_my_continuations_1 (&continuations, err); 00084 } 00085 00086 static void 00087 discard_my_continuations_1 (struct continuation **pmy_chain) 00088 { 00089 struct continuation *ptr; 00090 00091 while ((ptr = *pmy_chain) != NULL) 00092 { 00093 *pmy_chain = ptr->next; 00094 if (ptr->free_arg) 00095 (*ptr->free_arg) (ptr->arg); 00096 xfree (ptr); 00097 } 00098 } 00099 00100 static void 00101 discard_my_continuations (struct continuation **list) 00102 { 00103 discard_my_continuations_1 (list); 00104 *list = NULL; 00105 } 00106 00107 /* Add a continuation to the continuation list of INFERIOR. The new 00108 continuation will be added at the front. */ 00109 00110 void 00111 add_inferior_continuation (continuation_ftype *hook, void *args, 00112 continuation_free_arg_ftype *free_arg) 00113 { 00114 struct inferior *inf = current_inferior (); 00115 00116 make_continuation (&inf->continuations, hook, args, free_arg); 00117 } 00118 00119 /* Do all continuations of the current inferior. */ 00120 00121 void 00122 do_all_inferior_continuations (int err) 00123 { 00124 struct inferior *inf = current_inferior (); 00125 do_my_continuations (&inf->continuations, err); 00126 } 00127 00128 /* Get rid of all the inferior-wide continuations of INF. */ 00129 00130 void 00131 discard_all_inferior_continuations (struct inferior *inf) 00132 { 00133 discard_my_continuations (&inf->continuations); 00134 } 00135 00136 /* Add a continuation to the continuation list of THREAD. The new 00137 continuation will be added at the front. */ 00138 00139 void 00140 add_continuation (struct thread_info *thread, 00141 continuation_ftype *hook, void *args, 00142 continuation_free_arg_ftype *free_arg) 00143 { 00144 make_continuation (&thread->continuations, hook, args, free_arg); 00145 } 00146 00147 static void 00148 restore_thread_cleanup (void *arg) 00149 { 00150 ptid_t *ptid_p = arg; 00151 00152 switch_to_thread (*ptid_p); 00153 } 00154 00155 /* Walk down the continuation list of PTID, and execute all the 00156 continuations. There is a problem though. In some cases new 00157 continuations may be added while we are in the middle of this loop. 00158 If this happens they will be added in the front, and done before we 00159 have a chance of exhausting those that were already there. We need 00160 to then save the beginning of the list in a pointer and do the 00161 continuations from there on, instead of using the global beginning 00162 of list as our iteration pointer. */ 00163 00164 static void 00165 do_all_continuations_ptid (ptid_t ptid, 00166 struct continuation **continuations_p, 00167 int err) 00168 { 00169 struct cleanup *old_chain; 00170 ptid_t current_thread; 00171 00172 if (*continuations_p == NULL) 00173 return; 00174 00175 current_thread = inferior_ptid; 00176 00177 /* Restore selected thread on exit. Don't try to restore the frame 00178 as well, because: 00179 00180 - When running continuations, the selected frame is always #0. 00181 00182 - The continuations may trigger symbol file loads, which may 00183 change the frame layout (frame ids change), which would trigger 00184 a warning if we used make_cleanup_restore_current_thread. */ 00185 00186 old_chain = make_cleanup (restore_thread_cleanup, ¤t_thread); 00187 00188 /* Let the continuation see this thread as selected. */ 00189 switch_to_thread (ptid); 00190 00191 do_my_continuations (continuations_p, err); 00192 00193 do_cleanups (old_chain); 00194 } 00195 00196 /* Callback for iterate over threads. */ 00197 00198 static int 00199 do_all_continuations_thread_callback (struct thread_info *thread, void *data) 00200 { 00201 int err = * (int *) data; 00202 do_all_continuations_ptid (thread->ptid, &thread->continuations, err); 00203 return 0; 00204 } 00205 00206 /* Do all continuations of thread THREAD. */ 00207 00208 void 00209 do_all_continuations_thread (struct thread_info *thread, int err) 00210 { 00211 do_all_continuations_thread_callback (thread, &err); 00212 } 00213 00214 /* Do all continuations of all threads. */ 00215 00216 void 00217 do_all_continuations (int err) 00218 { 00219 iterate_over_threads (do_all_continuations_thread_callback, &err); 00220 } 00221 00222 /* Callback for iterate over threads. */ 00223 00224 static int 00225 discard_all_continuations_thread_callback (struct thread_info *thread, 00226 void *data) 00227 { 00228 discard_my_continuations (&thread->continuations); 00229 return 0; 00230 } 00231 00232 /* Get rid of all the continuations of THREAD. */ 00233 00234 void 00235 discard_all_continuations_thread (struct thread_info *thread) 00236 { 00237 discard_all_continuations_thread_callback (thread, NULL); 00238 } 00239 00240 /* Get rid of all the continuations of all threads. */ 00241 00242 void 00243 discard_all_continuations (void) 00244 { 00245 iterate_over_threads (discard_all_continuations_thread_callback, NULL); 00246 } 00247 00248 00249 /* Add a continuation to the intermediate continuation list of THREAD. 00250 The new continuation will be added at the front. */ 00251 00252 void 00253 add_intermediate_continuation (struct thread_info *thread, 00254 continuation_ftype *hook, 00255 void *args, 00256 continuation_free_arg_ftype *free_arg) 00257 { 00258 make_continuation (&thread->intermediate_continuations, hook, 00259 args, free_arg); 00260 } 00261 00262 /* Walk down the cmd_continuation list, and execute all the 00263 continuations. There is a problem though. In some cases new 00264 continuations may be added while we are in the middle of this 00265 loop. If this happens they will be added in the front, and done 00266 before we have a chance of exhausting those that were already 00267 there. We need to then save the beginning of the list in a pointer 00268 and do the continuations from there on, instead of using the 00269 global beginning of list as our iteration pointer. */ 00270 00271 static int 00272 do_all_intermediate_continuations_thread_callback (struct thread_info *thread, 00273 void *data) 00274 { 00275 int err = * (int *) data; 00276 00277 do_all_continuations_ptid (thread->ptid, 00278 &thread->intermediate_continuations, err); 00279 return 0; 00280 } 00281 00282 /* Do all intermediate continuations of thread THREAD. */ 00283 00284 void 00285 do_all_intermediate_continuations_thread (struct thread_info *thread, int err) 00286 { 00287 do_all_intermediate_continuations_thread_callback (thread, &err); 00288 } 00289 00290 /* Do all intermediate continuations of all threads. */ 00291 00292 void 00293 do_all_intermediate_continuations (int err) 00294 { 00295 iterate_over_threads (do_all_intermediate_continuations_thread_callback, 00296 &err); 00297 } 00298 00299 /* Callback for iterate over threads. */ 00300 00301 static int 00302 discard_all_intermediate_continuations_thread_callback (struct thread_info *thread, 00303 void *data) 00304 { 00305 discard_my_continuations (&thread->intermediate_continuations); 00306 return 0; 00307 } 00308 00309 /* Get rid of all the intermediate continuations of THREAD. */ 00310 00311 void 00312 discard_all_intermediate_continuations_thread (struct thread_info *thread) 00313 { 00314 discard_all_intermediate_continuations_thread_callback (thread, NULL); 00315 } 00316 00317 /* Get rid of all the intermediate continuations of all threads. */ 00318 00319 void 00320 discard_all_intermediate_continuations (void) 00321 { 00322 iterate_over_threads (discard_all_intermediate_continuations_thread_callback, 00323 NULL); 00324 }