GDB (API)
|
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"