From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 26122 invoked by alias); 27 Feb 2003 07:13:52 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 26115 invoked from network); 27 Feb 2003 07:13:48 -0000 Received: from unknown (HELO takamaka.act-europe.fr) (142.179.108.108) by 172.16.49.205 with SMTP; 27 Feb 2003 07:13:48 -0000 Received: by takamaka.act-europe.fr (Postfix, from userid 507) id 55877D34B6; Wed, 26 Feb 2003 23:13:46 -0800 (PST) Date: Thu, 27 Feb 2003 07:13:00 -0000 From: Joel Brobecker To: Andrew Cagney Cc: gdb-patches@sources.redhat.com Subject: Re: Re-initializing a list after the control returns to gdb... Message-ID: <20030227071346.GJ910@gnat.com> References: <20030219020101.GI2105@gnat.com> <3E53B97A.4090809@redhat.com> <20030219175056.GP2105@gnat.com> <3E53C88E.90807@redhat.com> <20030219192422.GS2105@gnat.com> <3E53EA7A.8070001@redhat.com> <20030225013722.GM910@gnat.com> <3E5C5CBD.2030201@redhat.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="NDin8bjvE/0mNLFQ" Content-Disposition: inline In-Reply-To: <3E5C5CBD.2030201@redhat.com> User-Agent: Mutt/1.4i X-SW-Source: 2003-02/txt/msg00763.txt.bz2 --NDin8bjvE/0mNLFQ Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-length: 2833 > So, can you get a prototype observer working for just your ada event > (but keep in mind that other events will be boiler-plated)? > > As for the names, just use the terminology found in the patterns book - > observer.[hc]. observer_update_xxx (or notify_xxx), > observer_attach_xxx, observer_detach_xxx I think. If GDB needs more > than one observer, there's a problem. Attached is a prototype that appears to be working. I assumed that you had in mind an approach were the exported interface is nice and clean and the implementation uses an underlying generic mechanism with nasty casts and marshalling/unmarshalling. While looking more closely at gdb-events, I understood better your comment about doco and gdbarch.sh. I think that with the current prototype, it should be relatively easy to generate observer.[hc]. There was another approach that came to my mind when I realized that observer.[hc] could be generated by a script: instead of using a internal generic observer, we could simply duplicate the code for each external observer... Although it does avoid the type casting et al, I discarded this approach as a bit too brutal and not very elegant. I tested this code by using a little test program. I will try not to forget to attach it. Would there be any way to build this program or some equivalent somewhere in our testsuite? My (very limited) first test was also inside GDB itself, where I added a ada-tasks as an observer for the normal_stop notification, and added a call to observer_notify_normal_stop in normal_stop. About the struct observer: the data field is currently used to hold the pointer to the real observer notification function. So there is no deallocation issue for now. I tried to make it clear that no deallocation mechanism has been put in place for this field by adding a comment next to the field declaration. It can later be extended to also hold some context data, if needed. However, if/when this happens, we'll have to extend the attach routine to accept 2 new parameters: a pointer to the context data, a pointer to a function to deallocate this data. I also have to admit upfront that choosing names has always been one of my big weaknesses. I warmly welcome suggestions. One last thing, I omitted the copyright headers for now. I'll make sure to add them when I submit the RFA. > (oh, unless you've an immediate need for that data/context parameter, > i'd leave it out - such a mechanis can be left to the person that > actually needs) Cools, that saves a bit of complexity for later, although there isn't much more needed. > (shh, doco - but I have a cunning plan - see my recent post about > revamping gdbarch.sh into doc/gdbarch.texi). Right, I will add the proper documentation too. Ideally, having the doco in an observer.sh script would be great. -- Joel --NDin8bjvE/0mNLFQ Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="observer.h" Content-length: 372 #ifndef OBSERVER_H #define OBSERVER_H struct observer; /* normal_stop notifications. */ typedef void (observer_normal_stop_ftype) (void); extern struct observer * observer_attach_normal_stop (observer_normal_stop_ftype *f); extern void observer_detach_normal_stop (struct observer *observer); extern void observer_notify_normal_stop (void); #endif /* OBSERVER_H */ --NDin8bjvE/0mNLFQ Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="observer.c" Content-length: 3066 #include "defs.h" #include "observer.h" typedef void (generic_observer_notification_ftype) (const void *data, const void *args); struct observer { generic_observer_notification_ftype *notify; void *data; /* No memory management needed for this field for now. */ }; struct observer_list { struct observer_list *next; struct observer *observer; }; static struct observer_list * xalloc_observer_list_node (void) { struct observer_list *node = XMALLOC (struct observer_list); node->observer = XMALLOC (struct observer); return node; } static void xfree_observer_list_node (struct observer_list *node) { xfree (node->observer); xfree (node); } static struct observer * generic_observer_attach (struct observer_list **list, generic_observer_notification_ftype *notify, void *data) { struct observer_list *observer_list = xalloc_observer_list_node (); observer_list->next = *list; observer_list->observer->notify = notify; observer_list->observer->data = data; *list = observer_list; return observer_list->observer; } static void generic_observer_detach (struct observer_list **list, const struct observer *observer) { struct observer_list *previous_node = NULL; struct observer_list *current_node = *list; while (current_node != NULL) { if (current_node->observer == observer) { if (previous_node != NULL) previous_node->next = current_node->next; else *list = current_node->next; xfree_observer_list_node (current_node); return; } previous_node = current_node; current_node = current_node->next; } /* We should never reach this point. However, this should not be a very serious error, so simply report a warning to the user. */ warning ("Failed to detach observer"); } static void generic_observer_notify (struct observer_list *list, const void *args) { struct observer_list *current_node = list; while (current_node != NULL) { (*current_node->observer->notify) (current_node->observer->data, args); current_node = current_node->next; } } /* normal_stop notifications. */ static struct observer_list *normal_stop_observers = NULL; void observer_normal_stop_notification_stub (const void *data, const void *unused_args) { observer_normal_stop_ftype *notify = (observer_normal_stop_ftype *) data; (*notify) (); } struct observer * observer_attach_normal_stop (observer_normal_stop_ftype *f) { return generic_observer_attach (&normal_stop_observers, &observer_normal_stop_notification_stub, (void *) f); } void observer_detach_normal_stop (struct observer *observer) { generic_observer_detach (&normal_stop_observers, observer); } void observer_notify_normal_stop (void) { generic_observer_notify (normal_stop_observers, NULL); } --NDin8bjvE/0mNLFQ Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="test_observer.c" Content-length: 3650 #include #include "observer.h" #include void *xmalloc (size_t size) { return malloc (size); } void xfree (void *ptr) { free (ptr); } void warning (const char *str, ...) { printf ("warning: %s.\n", str); } int first_observer = 0; int second_observer = 0; int third_observer = 0; void reset_counters (void) { first_observer = 0; second_observer = 0; third_observer = 0; } void check_counters (int first, int second, int third) { if (first_observer != first) printf ("ERROR: first observer incorrect count: %d (expected %d).\n", first_observer, first); if (second_observer != second) printf ("ERROR: second observer incorrect count: %d (expected %d).\n", second_observer, second); if (third_observer != third) printf ("ERROR: third observer incorrect count: %d (expected %d).\n", third_observer, third); } void test_notifications (int first, int second, int third, char *msg) { printf ("-- Sending notification (%s)...\n", msg); reset_counters (); observer_notify_normal_stop (); check_counters (first, second, third); } void first_observer_notification (void) { first_observer++; } void second_observer_notification (void) { second_observer++; } void third_observer_notification (void) { third_observer++; } void general_observer_test (void) { struct observer *first_obs = NULL; struct observer *second_obs = NULL; struct observer *third_obs = NULL; /* First, try sending a notification without any observers attached. */ test_notifications (0, 0, 0, "no observer"); /* Now, attach one observer, and send a notification. */ second_obs = observer_attach_normal_stop (&second_observer_notification); test_notifications (0, 1, 0, "one observer"); /* Remove the observer, and send a notification. */ observer_detach_normal_stop (second_obs); test_notifications (0, 0, 0, "no observer"); /* With a new observer. */ first_obs = observer_attach_normal_stop (&first_observer_notification); test_notifications (1, 0, 0, "a new observer"); /* With 2 observers. */ second_obs = observer_attach_normal_stop (&second_observer_notification); test_notifications (1, 1, 0, "2 observers"); /* With 3 observers. */ third_obs = observer_attach_normal_stop (&third_observer_notification); test_notifications (1, 1, 1, "3 observers"); /* Remove the middle observer. */ observer_detach_normal_stop (second_obs); test_notifications (1, 0, 1, "middle observer removed"); /* Remove first observer. */ observer_detach_normal_stop (first_obs); test_notifications (0, 0, 1, "first observer removed"); /* Remove last observer. */ observer_detach_normal_stop (third_obs); test_notifications (0, 0, 0, "last observer removed"); /* Go back to 3 observers, and remove them in a different order... */ first_obs = observer_attach_normal_stop (&first_observer_notification); second_obs = observer_attach_normal_stop (&second_observer_notification); third_obs = observer_attach_normal_stop (&third_observer_notification); test_notifications (1, 1, 1, "3 observers"); /* Remove the third observer... */ observer_detach_normal_stop (third_obs); test_notifications (1, 1, 0, "third observer removed"); /* Remove the second observer... */ observer_detach_normal_stop (second_obs); test_notifications (1, 0, 0, "second observer removed"); /* Remove the first observer... No more observers. */ observer_detach_normal_stop (first_obs); test_notifications (0, 0, 0, "first observer removed - no more observers"); } int main (void) { general_observer_test (); return 0; } --NDin8bjvE/0mNLFQ--