GDB (API)
/home/stan/gdb/src/gdb/continuations.c
Go to the documentation of this file.
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, &current_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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines