1130803Smarcel/* GDB Notifications to Observers. 2130803Smarcel Copyright 2003 Free Software Foundation, Inc. 3130803Smarcel 4130803Smarcel This file is part of GDB. 5130803Smarcel 6130803Smarcel This program is free software; you can redistribute it and/or modify 7130803Smarcel it under the terms of the GNU General Public License as published by 8130803Smarcel the Free Software Foundation; either version 2 of the License, or 9130803Smarcel (at your option) any later version. 10130803Smarcel 11130803Smarcel This program is distributed in the hope that it will be useful, 12130803Smarcel but WITHOUT ANY WARRANTY; without even the implied warranty of 13130803Smarcel MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14130803Smarcel GNU General Public License for more details. 15130803Smarcel 16130803Smarcel You should have received a copy of the GNU General Public License 17130803Smarcel along with this program; if not, write to the Free Software 18130803Smarcel Foundation, Inc., 59 Temple Place - Suite 330, 19130803Smarcel Boston, MA 02111-1307, USA. */ 20130803Smarcel 21130803Smarcel/* An observer is an entity who is interested in being notified when GDB 22130803Smarcel reaches certain states, or certain events occur in GDB. The entity being 23130803Smarcel observed is called the Subject. To receive notifications, the observer 24130803Smarcel attaches a callback to the subject. One subject can have several 25130803Smarcel observers. 26130803Smarcel 27130803Smarcel This file implements an internal generic low-level event notification 28130803Smarcel mechanism based on the Observer paradigm described in the book "Design 29130803Smarcel Patterns". This generic event notification mechansim is then re-used 30130803Smarcel to implement the exported high-level notification management routines 31130803Smarcel for all possible notifications. 32130803Smarcel 33130803Smarcel The current implementation of the generic observer provides support 34130803Smarcel for contextual data. This contextual data is given to the subject 35130803Smarcel when attaching the callback. In return, the subject will provide 36130803Smarcel this contextual data back to the observer as a parameter of the 37130803Smarcel callback. 38130803Smarcel 39130803Smarcel FIXME: The current support for the contextual data is only partial, 40130803Smarcel as it lacks a mechanism that would deallocate this data when the 41130803Smarcel callback is detached. This is not a problem so far, as this contextual 42130803Smarcel data is only used internally to hold a function pointer. Later on, 43130803Smarcel if a certain observer needs to provide support for user-level 44130803Smarcel contextual data, then the generic notification mechanism will need 45130803Smarcel need to be enhanced to allow the observer to provide a routine to 46130803Smarcel deallocate the data when attaching the callback. 47130803Smarcel 48130803Smarcel This file is currently maintained by hand, but the long term plan 49130803Smarcel if the number of different notifications starts growing is to create 50130803Smarcel a new script (observer.sh) that would generate this file, and the 51130803Smarcel associated documentation. */ 52130803Smarcel 53130803Smarcel#include "defs.h" 54130803Smarcel#include "observer.h" 55130803Smarcel 56130803Smarcel/* The internal generic observer. */ 57130803Smarcel 58130803Smarceltypedef void (generic_observer_notification_ftype) (const void *data, 59130803Smarcel const void *args); 60130803Smarcel 61130803Smarcelstruct observer 62130803Smarcel{ 63130803Smarcel generic_observer_notification_ftype *notify; 64130803Smarcel /* No memory management needed for the following field for now. */ 65130803Smarcel void *data; 66130803Smarcel}; 67130803Smarcel 68130803Smarcel/* A list of observers, maintained by the subject. A subject is 69130803Smarcel actually represented by its list of observers. */ 70130803Smarcel 71130803Smarcelstruct observer_list 72130803Smarcel{ 73130803Smarcel struct observer_list *next; 74130803Smarcel struct observer *observer; 75130803Smarcel}; 76130803Smarcel 77130803Smarcel/* Allocate a struct observer_list, intended to be used as a node 78130803Smarcel in the list of observers maintained by a subject. */ 79130803Smarcel 80130803Smarcelstatic struct observer_list * 81130803Smarcelxalloc_observer_list_node (void) 82130803Smarcel{ 83130803Smarcel struct observer_list *node = XMALLOC (struct observer_list); 84130803Smarcel node->observer = XMALLOC (struct observer); 85130803Smarcel return node; 86130803Smarcel} 87130803Smarcel 88130803Smarcel/* The opposite of xalloc_observer_list_node, frees the memory for 89130803Smarcel the given node. */ 90130803Smarcel 91130803Smarcelstatic void 92130803Smarcelxfree_observer_list_node (struct observer_list *node) 93130803Smarcel{ 94130803Smarcel xfree (node->observer); 95130803Smarcel xfree (node); 96130803Smarcel} 97130803Smarcel 98130803Smarcel/* Attach the callback NOTIFY to a SUBJECT. The DATA is also stored, 99130803Smarcel in order for the subject to provide it back to the observer during 100130803Smarcel a notification. */ 101130803Smarcel 102130803Smarcelstatic struct observer * 103130803Smarcelgeneric_observer_attach (struct observer_list **subject, 104130803Smarcel generic_observer_notification_ftype * notify, 105130803Smarcel void *data) 106130803Smarcel{ 107130803Smarcel struct observer_list *observer_list = xalloc_observer_list_node (); 108130803Smarcel 109130803Smarcel observer_list->next = *subject; 110130803Smarcel observer_list->observer->notify = notify; 111130803Smarcel observer_list->observer->data = data; 112130803Smarcel *subject = observer_list; 113130803Smarcel 114130803Smarcel return observer_list->observer; 115130803Smarcel} 116130803Smarcel 117130803Smarcel/* Remove the given OBSERVER from the SUBJECT. Once detached, OBSERVER 118130803Smarcel should no longer be used, as it is no longer valid. */ 119130803Smarcel 120130803Smarcelstatic void 121130803Smarcelgeneric_observer_detach (struct observer_list **subject, 122130803Smarcel const struct observer *observer) 123130803Smarcel{ 124130803Smarcel struct observer_list *previous_node = NULL; 125130803Smarcel struct observer_list *current_node = *subject; 126130803Smarcel 127130803Smarcel while (current_node != NULL) 128130803Smarcel { 129130803Smarcel if (current_node->observer == observer) 130130803Smarcel { 131130803Smarcel if (previous_node != NULL) 132130803Smarcel previous_node->next = current_node->next; 133130803Smarcel else 134130803Smarcel *subject = current_node->next; 135130803Smarcel xfree_observer_list_node (current_node); 136130803Smarcel return; 137130803Smarcel } 138130803Smarcel previous_node = current_node; 139130803Smarcel current_node = current_node->next; 140130803Smarcel } 141130803Smarcel 142130803Smarcel /* We should never reach this point. However, this should not be 143130803Smarcel a very serious error, so simply report a warning to the user. */ 144130803Smarcel warning ("Failed to detach observer"); 145130803Smarcel} 146130803Smarcel 147130803Smarcel/* Send a notification to all the observers of SUBJECT. ARGS is passed to 148130803Smarcel all observers as an argument to the notification callback. */ 149130803Smarcel 150130803Smarcelstatic void 151130803Smarcelgeneric_observer_notify (struct observer_list *subject, const void *args) 152130803Smarcel{ 153130803Smarcel struct observer_list *current_node = subject; 154130803Smarcel 155130803Smarcel while (current_node != NULL) 156130803Smarcel { 157130803Smarcel (*current_node->observer->notify) (current_node->observer->data, args); 158130803Smarcel current_node = current_node->next; 159130803Smarcel } 160130803Smarcel} 161130803Smarcel 162130803Smarcel/* normal_stop notifications. */ 163130803Smarcel 164130803Smarcelstatic struct observer_list *normal_stop_subject = NULL; 165130803Smarcel 166130803Smarcelstatic void 167130803Smarcelobserver_normal_stop_notification_stub (const void *data, 168130803Smarcel const void *unused_args) 169130803Smarcel{ 170130803Smarcel observer_normal_stop_ftype *notify = (observer_normal_stop_ftype *) data; 171130803Smarcel (*notify) (); 172130803Smarcel} 173130803Smarcel 174130803Smarcelstruct observer * 175130803Smarcelobserver_attach_normal_stop (observer_normal_stop_ftype *f) 176130803Smarcel{ 177130803Smarcel return generic_observer_attach (&normal_stop_subject, 178130803Smarcel &observer_normal_stop_notification_stub, 179130803Smarcel (void *) f); 180130803Smarcel} 181130803Smarcel 182130803Smarcelvoid 183130803Smarcelobserver_detach_normal_stop (struct observer *observer) 184130803Smarcel{ 185130803Smarcel generic_observer_detach (&normal_stop_subject, observer); 186130803Smarcel} 187130803Smarcel 188130803Smarcelvoid 189130803Smarcelobserver_notify_normal_stop (void) 190130803Smarcel{ 191130803Smarcel generic_observer_notify (normal_stop_subject, NULL); 192130803Smarcel} 193130803Smarcel 194130803Smarcel/* The following code is only used to unit-test the observers from our 195130803Smarcel testsuite. DO NOT USE IT within observer.c (or anywhere else for 196130803Smarcel that matter)! */ 197130803Smarcel 198130803Smarcel/* If we define these variables and functions as `static', the 199130803Smarcel compiler will optimize them out. */ 200130803Smarcel 201130803Smarcelint observer_test_first_observer = 0; 202130803Smarcelint observer_test_second_observer = 0; 203130803Smarcelint observer_test_third_observer = 0; 204130803Smarcel 205130803Smarcelvoid 206130803Smarcelobserver_test_first_notification_function (void) 207130803Smarcel{ 208130803Smarcel observer_test_first_observer++; 209130803Smarcel} 210130803Smarcel 211130803Smarcelvoid 212130803Smarcelobserver_test_second_notification_function (void) 213130803Smarcel{ 214130803Smarcel observer_test_second_observer++; 215130803Smarcel} 216130803Smarcel 217130803Smarcelvoid 218130803Smarcelobserver_test_third_notification_function (void) 219130803Smarcel{ 220130803Smarcel observer_test_third_observer++; 221130803Smarcel} 222130803Smarcel 223