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