GDB (API)
/home/stan/gdb/src/gdb/observer.c
Go to the documentation of this file.
00001 /* GDB Notifications to Observers.
00002 
00003    Copyright (C) 2003-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 /* An observer is an entity who is interested in being notified when GDB
00021    reaches certain states, or certain events occur in GDB.  The entity being
00022    observed is called the Subject.  To receive notifications, the observer
00023    attaches a callback to the subject.  One subject can have several
00024    observers.
00025 
00026    This file implements an internal generic low-level event notification
00027    mechanism based on the Observer paradigm described in the book "Design
00028    Patterns".  This generic event notification mechansim is then re-used
00029    to implement the exported high-level notification management routines
00030    for all possible notifications.
00031 
00032    The current implementation of the generic observer provides support
00033    for contextual data.  This contextual data is given to the subject
00034    when attaching the callback.  In return, the subject will provide
00035    this contextual data back to the observer as a parameter of the
00036    callback.
00037 
00038    FIXME: The current support for the contextual data is only partial,
00039    as it lacks a mechanism that would deallocate this data when the
00040    callback is detached.  This is not a problem so far, as this contextual
00041    data is only used internally to hold a function pointer.  Later on,
00042    if a certain observer needs to provide support for user-level
00043    contextual data, then the generic notification mechanism will need
00044    need to be enhanced to allow the observer to provide a routine to
00045    deallocate the data when attaching the callback.
00046 
00047    This file is currently maintained by hand, but the long term plan
00048    if the number of different notifications starts growing is to create
00049    a new script (observer.sh) that would generate this file, and the
00050    associated documentation.  */
00051 
00052 #include "defs.h"
00053 #include "observer.h"
00054 #include "command.h"
00055 #include "gdbcmd.h"
00056 
00057 static unsigned int observer_debug;
00058 static void
00059 show_observer_debug (struct ui_file *file, int from_tty,
00060                      struct cmd_list_element *c, const char *value)
00061 {
00062   fprintf_filtered (file, _("Observer debugging is %s.\n"), value);
00063 }
00064 
00065 /* The internal generic observer.  */
00066 
00067 typedef void (generic_observer_notification_ftype) (const void *data,
00068                                                     const void *args);
00069 
00070 struct observer
00071 {
00072   generic_observer_notification_ftype *notify;
00073   /* No memory management needed for the following field for now.  */
00074   void *data;
00075 };
00076 
00077 /* A list of observers, maintained by the subject.  A subject is
00078    actually represented by its list of observers.  */
00079 
00080 struct observer_list
00081 {
00082   struct observer_list *next;
00083   struct observer *observer;
00084 };
00085 
00086 /* Allocate a struct observer_list, intended to be used as a node
00087    in the list of observers maintained by a subject.  */
00088 
00089 static struct observer_list *
00090 xalloc_observer_list_node (void)
00091 {
00092   struct observer_list *node = XMALLOC (struct observer_list);
00093 
00094   node->observer = XMALLOC (struct observer);
00095   return node;
00096 }
00097 
00098 /* The opposite of xalloc_observer_list_node, frees the memory for
00099    the given node.  */
00100 
00101 static void
00102 xfree_observer_list_node (struct observer_list *node)
00103 {
00104   xfree (node->observer);
00105   xfree (node);
00106 }
00107 
00108 /* Attach the callback NOTIFY to a SUBJECT.  The DATA is also stored,
00109    in order for the subject to provide it back to the observer during
00110    a notification.  */
00111 
00112 static struct observer *
00113 generic_observer_attach (struct observer_list **subject,
00114                          generic_observer_notification_ftype * notify,
00115                          void *data)
00116 {
00117   struct observer_list *observer_list = xalloc_observer_list_node ();
00118 
00119   observer_list->next = *subject;
00120   observer_list->observer->notify = notify;
00121   observer_list->observer->data = data;
00122   *subject = observer_list;
00123 
00124   return observer_list->observer;
00125 }
00126 
00127 /* Remove the given OBSERVER from the SUBJECT.  Once detached, OBSERVER
00128    should no longer be used, as it is no longer valid.  */
00129 
00130 static void
00131 generic_observer_detach (struct observer_list **subject,
00132                          const struct observer *observer)
00133 {
00134   struct observer_list *previous_node = NULL;
00135   struct observer_list *current_node = *subject;
00136 
00137   while (current_node != NULL)
00138     {
00139       if (current_node->observer == observer)
00140         {
00141           if (previous_node != NULL)
00142             previous_node->next = current_node->next;
00143           else
00144             *subject = current_node->next;
00145           xfree_observer_list_node (current_node);
00146           return;
00147         }
00148       previous_node = current_node;
00149       current_node = current_node->next;
00150     }
00151 
00152   /* We should never reach this point.  However, this should not be
00153      a very serious error, so simply report a warning to the user.  */
00154   warning (_("Failed to detach observer"));
00155 }
00156 
00157 /* Send a notification to all the observers of SUBJECT.  ARGS is passed to
00158    all observers as an argument to the notification callback.  */
00159 
00160 static void
00161 generic_observer_notify (struct observer_list *subject, const void *args)
00162 {
00163   struct observer_list *current_node = subject;
00164 
00165   while (current_node != NULL)
00166     {
00167       (*current_node->observer->notify) (current_node->observer->data, args);
00168       current_node = current_node->next;
00169     }
00170 }
00171 
00172 
00173 /* The following code is only used to unit-test the observers from our
00174    testsuite.  DO NOT USE IT within observer.c (or anywhere else for
00175    that matter)!  */
00176 
00177 /* If we define these variables and functions as `static', the
00178    compiler will optimize them out.  */
00179  
00180 int observer_test_first_observer = 0;
00181 int observer_test_second_observer = 0;
00182 int observer_test_third_observer = 0;
00183 
00184 /* Provide prototypes to silence -Wmissing-prototypes.  */
00185 extern void observer_test_first_notification_function (int arg);
00186 extern void observer_test_second_notification_function (int arg);
00187 extern void observer_test_third_notification_function (int arg);
00188 
00189 void
00190 observer_test_first_notification_function (int arg)
00191 {
00192   observer_test_first_observer++;
00193 }
00194 
00195 void
00196 observer_test_second_notification_function (int arg)
00197 {
00198   observer_test_second_observer++;
00199 }
00200 
00201 void
00202 observer_test_third_notification_function (int arg)
00203 {
00204   observer_test_third_observer++;
00205 }
00206 
00207 extern initialize_file_ftype _initialize_observer; /* -Wmissing-prototypes */
00208 
00209 void
00210 _initialize_observer (void)
00211 {
00212   add_setshow_zuinteger_cmd ("observer", class_maintenance,
00213                              &observer_debug, _("\
00214 Set observer debugging."), _("\
00215 Show observer debugging."), _("\
00216 When non-zero, observer debugging is enabled."),
00217                              NULL,
00218                              show_observer_debug,
00219                              &setdebuglist, &showdebuglist);
00220 }
00221 
00222 #include "observer.inc"
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines