Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Andrew Cagney <ac131313@redhat.com>
To: Joel Brobecker <brobecker@gnat.com>
Cc: gdb-patches@sources.redhat.com
Subject: Re: Re-initializing a list after the control returns to gdb...
Date: Thu, 27 Feb 2003 18:44:00 -0000	[thread overview]
Message-ID: <3E5E5D11.3000508@redhat.com> (raw)
In-Reply-To: <20030227071346.GJ910@gnat.com>


> 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 <stdio.h>
> 
> #include "observer.h"
> 
> #include <stdlib.h>
> 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;
> }



  reply	other threads:[~2003-02-27 18:44 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2003-02-19  2:01 Joel Brobecker
2003-02-19 12:47 ` Andrew Cagney
2003-02-19 16:05   ` Joel Brobecker
2003-02-19 16:49     ` Andrew Cagney
2003-02-19 17:46       ` Joel Brobecker
2003-02-19 17:01 ` Andrew Cagney
2003-02-19 17:50   ` Joel Brobecker
2003-02-19 18:05     ` Andrew Cagney
2003-02-19 19:24       ` Joel Brobecker
2003-02-19 20:30         ` Andrew Cagney
2003-02-25  1:37           ` Joel Brobecker
2003-02-26 15:57             ` Andrew Cagney
2003-02-27  7:13               ` Joel Brobecker
2003-02-27 18:44                 ` Andrew Cagney [this message]
2003-02-28  7:42                   ` Joel Brobecker

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=3E5E5D11.3000508@redhat.com \
    --to=ac131313@redhat.com \
    --cc=brobecker@gnat.com \
    --cc=gdb-patches@sources.redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox