From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 8776 invoked by alias); 27 Feb 2003 18:44:30 -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 8769 invoked from network); 27 Feb 2003 18:44:29 -0000 Received: from unknown (HELO localhost.redhat.com) (172.16.49.200) by 172.16.49.205 with SMTP; 27 Feb 2003 18:44:28 -0000 Received: from redhat.com (localhost [127.0.0.1]) by localhost.redhat.com (Postfix) with ESMTP id 846B52A9C; Thu, 27 Feb 2003 13:46:41 -0500 (EST) Message-ID: <3E5E5D11.3000508@redhat.com> Date: Thu, 27 Feb 2003 18:44:00 -0000 From: Andrew Cagney User-Agent: Mozilla/5.0 (X11; U; NetBSD macppc; en-US; rv:1.0.2) Gecko/20030223 X-Accept-Language: en-us, en MIME-Version: 1.0 To: Joel Brobecker Cc: gdb-patches@sources.redhat.com Subject: Re: Re-initializing a list after the control returns to gdb... 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> <20030227071346.GJ910@gnat.com> Content-Type: text/plain; charset=us-ascii; format=flowed Content-Transfer-Encoding: 7bit X-SW-Source: 2003-02/txt/msg00773.txt.bz2 > 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]. Yes. gdbarch.[ch] and gdb-events.[ch] both started out as normal files. It is only when they grew beyond a certain point that they turned into scripts. In terms of getting it right, mumble something about `third time lucky' :-) > 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. It's an internal implementation detail. Provided the code is `interface' and `coding standard' compliant (doing no externally visible evil, indented using gdb_indent.sh, gets past gdb_ari.sh -Wari) can any one really complain about how version 1.0 is implemented using wire and bits of string :-) > 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. The testsuite/gdb.gdb directory was created for just this purpose! > 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. Ditto. That is why I suggested stealing terms from the patterns book - you get to blame the decision on someone else. > 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. I was thinking of something like: Chapter Observing changes in @value{GDBN} internals Light highlevel commentary largely refering the reader to the patterns book Appendix `observer' (observer.texi) @defun void normal_stop (void) Normal stop notification. @end defun observer.sh could then munge that into your file. Can you please add the missing (C) notice and then commit this part (adding it to the build & makefile). Then slap a summary of our `grand plans' somewhere in the header. Andrew > #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 */ > > > > #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); > } > > > > #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; > }