From b10faa68a450b43f31b78cc11bd06774a256a0a4 Mon Sep 17 00:00:00 2001 From: Doug Evans Date: Thu, 19 Apr 2012 19:11:02 +0000 Subject: [PATCH] * 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. --- gdb/ChangeLog | 16 ++++++++++++++ gdb/cleanups.c | 60 +++++++++++++++++++++++++++++++++++++++++++++----- gdb/cleanups.h | 34 ++++++++-------------------- 3 files changed, 79 insertions(+), 31 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 1511fd4e03e..dd5f7ecf3e9 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,19 @@ +2012-04-19 Doug Evans + + * 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 * Makefile.in (GNULIB_BUILDDIR): New. diff --git a/gdb/cleanups.c b/gdb/cleanups.c index 988b92e6da1..d2f70fc4040 100644 --- a/gdb/cleanups.c +++ b/gdb/cleanups.c @@ -18,15 +18,53 @@ along with this program. If not, see . */ #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; } diff --git a/gdb/cleanups.h b/gdb/cleanups.h index 689c0d10901..ed627862771 100644 --- a/gdb/cleanups.h +++ b/gdb/cleanups.h @@ -19,28 +19,8 @@ #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 *); -- 2.30.2