* cleanups.h (struct cleanup): Move to cleanups.c.
authorDoug Evans <dje@google.com>
Thu, 19 Apr 2012 19:11:02 +0000 (19:11 +0000)
committerDoug Evans <dje@google.com>
Thu, 19 Apr 2012 19:11:02 +0000 (19:11 +0000)
(make_cleanup_dtor_ftype): New typedef.
(make_cleanup_dtor): Use it.
(ALL_CLEANUPS): Replace with ...
(all_cleanups): ... this.  Declare.  All uses updated.
* cleanups.c: #include "gdb_assert.h".
(sentinel_cleanup): New static global.
(SENTINEL_CLEANUP): Define.
(cleanup_chain, final_cleanup_chain): Initialize to SENTINEL_CLEANUP.
(make_my_cleanup2): Assert result is non-NULL.
(all_cleanups): New function.
(save_my_cleanups): Initialize new chain to SENTINEL_CLEANUP instead
of NULL.

gdb/ChangeLog
gdb/cleanups.c
gdb/cleanups.h

index 1511fd4..dd5f7ec 100644 (file)
@@ -1,3 +1,19 @@
+2012-04-19  Doug Evans  <dje@google.com>
+
+       * cleanups.h (struct cleanup): Move to cleanups.c.
+       (make_cleanup_dtor_ftype): New typedef.
+       (make_cleanup_dtor): Use it.
+       (ALL_CLEANUPS): Replace with ...
+       (all_cleanups): ... this.  Declare.  All uses updated.
+       * cleanups.c: #include "gdb_assert.h".
+       (sentinel_cleanup): New static global.
+       (SENTINEL_CLEANUP): Define.
+       (cleanup_chain, final_cleanup_chain): Initialize to SENTINEL_CLEANUP.
+       (make_my_cleanup2): Assert result is non-NULL.
+       (all_cleanups): New function.
+       (save_my_cleanups): Initialize new chain to SENTINEL_CLEANUP instead
+       of NULL.
+
 2012-04-19  Pedro Alves  <palves@redhat.com>
 
        * Makefile.in (GNULIB_BUILDDIR): New.
index 988b92e..d2f70fc 100644 (file)
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
+#include "gdb_assert.h"
+
+/* The cleanup list records things that have to be undone
+   if an error happens (descriptors to be closed, memory to be freed, etc.)
+   Each link in the chain records a function to call and an
+   argument to give it.
+
+   Use make_cleanup to add an element to the cleanup chain.
+   Use do_cleanups to do all cleanup actions back to a given
+   point in the chain.  Use discard_cleanups to remove cleanups
+   from the chain back to a given point, not doing them.
+
+   If the argument is pointer to allocated memory, then you need
+   to additionally set the 'free_arg' member to a function that will
+   free that memory.  This function will be called both when the cleanup
+   is executed and when it's discarded.  */
+
+struct cleanup
+{
+  struct cleanup *next;
+  void (*function) (void *);
+  void (*free_arg) (void *);
+  void *arg;
+};
+
+/* Used to mark the end of a cleanup chain.
+   The value is chosen so that it:
+   - is non-NULL so that make_cleanup never returns NULL,
+   - causes a segv if dereferenced
+     [though this won't catch errors that a value of, say,
+     ((struct cleanup *) -1) will]
+   - displays as something useful when printed in gdb.
+   This is const for a bit of extra robustness.
+   It is initialized to coax gcc into putting it into .rodata.
+   All fields are initialized to survive -Wextra.  */
+static const struct cleanup sentinel_cleanup = { 0, 0, 0, 0 };
+
+/* Handy macro to use when referring to sentinel_cleanup.  */
+#define SENTINEL_CLEANUP ((struct cleanup *) &sentinel_cleanup)
 
 /* Chain of cleanup actions established with make_cleanup,
    to be executed if an error happens.  */
+static struct cleanup *cleanup_chain = SENTINEL_CLEANUP;
 
-/* Cleaned up after a failed command.  */
-static struct cleanup *cleanup_chain;
-
-/* Cleaned up when gdb exits.  */
-static struct cleanup *final_cleanup_chain;
+/* Chain of cleanup actions established with make_final_cleanup,
+   to be executed when gdb exits.  */
+static struct cleanup *final_cleanup_chain = SENTINEL_CLEANUP;
 
 /* Main worker routine to create a cleanup.
    PMY_CHAIN is a pointer to either cleanup_chain or final_cleanup_chain.
@@ -51,6 +89,7 @@ make_my_cleanup2 (struct cleanup **pmy_chain, make_cleanup_ftype *function,
   new->arg = arg;
   *pmy_chain = new;
 
+  gdb_assert (old_chain != NULL);
   return old_chain;
 }
 
@@ -120,6 +159,15 @@ do_my_cleanups (struct cleanup **pmy_chain,
     }
 }
 
+/* Return a value that can be passed to do_cleanups, do_final_cleanups to
+   indicate perform all cleanups.  */
+
+struct cleanup *
+all_cleanups (void)
+{
+  return SENTINEL_CLEANUP;
+}
+
 /* Discard cleanups and do the actions they describe
    until we get back to the point OLD_CHAIN in the cleanup_chain.  */
 
@@ -185,7 +233,7 @@ save_my_cleanups (struct cleanup **pmy_chain)
 {
   struct cleanup *old_chain = *pmy_chain;
 
-  *pmy_chain = 0;
+  *pmy_chain = SENTINEL_CLEANUP;
   return old_chain;
 }
 
index 689c0d1..ed62786 100644 (file)
 #ifndef CLEANUPS_H
 #define CLEANUPS_H
 
-/* The cleanup list records things that have to be undone
-   if an error happens (descriptors to be closed, memory to be freed, etc.)
-   Each link in the chain records a function to call and an
-   argument to give it.
-
-   Use make_cleanup to add an element to the cleanup chain.
-   Use do_cleanups to do all cleanup actions back to a given
-   point in the chain.  Use discard_cleanups to remove cleanups
-   from the chain back to a given point, not doing them.
-
-   If the argument is pointer to allocated memory, then you need
-   to additionally set the 'free_arg' member to a function that will
-   free that memory.  This function will be called both when the cleanup
-   is executed and when it's discarded.  */
-
-struct cleanup
-  {
-    struct cleanup *next;
-    void (*function) (void *);
-    void (*free_arg) (void *);
-    void *arg;
-  };
+/* Outside of cleanups.c, this is an opaque type.  */
+struct cleanup;
 
 /* NOTE: cagney/2000-03-04: This typedef is strictly for the
    make_cleanup function declarations below.  Do not use this typedef
@@ -49,21 +29,25 @@ struct cleanup
    Calling a f(char*) function with f(void*) is non-portable.  */
 typedef void (make_cleanup_ftype) (void *);
 
+/* Function type for the dtor in make_cleanup_dtor.  */
+typedef void (make_cleanup_dtor_ftype) (void *);
+
 /* WARNING: The result of the "make cleanup" routines is not the intuitive
    choice of being a handle on the just-created cleanup.  Instead it is an
    opaque handle of the cleanup mechanism and represents all cleanups created
-   from that point onwards.  */
+   from that point onwards.
+   The result is guaranteed to be non-NULL though.  */
 
 extern struct cleanup *make_cleanup (make_cleanup_ftype *, void *);
 
 extern struct cleanup *make_cleanup_dtor (make_cleanup_ftype *, void *,
-                                         void (*dtor) (void *));
+                                         make_cleanup_dtor_ftype *);
 
 extern struct cleanup *make_final_cleanup (make_cleanup_ftype *, void *);
 
 /* A special value to pass to do_cleanups and do_final_cleanups
    to tell them to do all cleanups.  */
-#define        ALL_CLEANUPS    ((struct cleanup *)0)
+extern struct cleanup *all_cleanups (void);
 
 extern void do_cleanups (struct cleanup *);
 extern void do_final_cleanups (struct cleanup *);