* 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.
This commit is contained in:
Doug Evans 2012-04-19 19:11:02 +00:00
parent ff188ee48b
commit b10faa68a4
3 changed files with 79 additions and 31 deletions

View 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> 2012-04-19 Pedro Alves <palves@redhat.com>
* Makefile.in (GNULIB_BUILDDIR): New. * Makefile.in (GNULIB_BUILDDIR): New.

View File

@ -18,15 +18,53 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h" #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, /* Chain of cleanup actions established with make_cleanup,
to be executed if an error happens. */ to be executed if an error happens. */
static struct cleanup *cleanup_chain = SENTINEL_CLEANUP;
/* Cleaned up after a failed command. */ /* Chain of cleanup actions established with make_final_cleanup,
static struct cleanup *cleanup_chain; to be executed when gdb exits. */
static struct cleanup *final_cleanup_chain = SENTINEL_CLEANUP;
/* Cleaned up when gdb exits. */
static struct cleanup *final_cleanup_chain;
/* Main worker routine to create a cleanup. /* Main worker routine to create a cleanup.
PMY_CHAIN is a pointer to either cleanup_chain or final_cleanup_chain. 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; new->arg = arg;
*pmy_chain = new; *pmy_chain = new;
gdb_assert (old_chain != NULL);
return old_chain; 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 /* Discard cleanups and do the actions they describe
until we get back to the point OLD_CHAIN in the cleanup_chain. */ 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; struct cleanup *old_chain = *pmy_chain;
*pmy_chain = 0; *pmy_chain = SENTINEL_CLEANUP;
return old_chain; return old_chain;
} }

View File

@ -19,28 +19,8 @@
#ifndef CLEANUPS_H #ifndef CLEANUPS_H
#define CLEANUPS_H #define CLEANUPS_H
/* The cleanup list records things that have to be undone /* Outside of cleanups.c, this is an opaque type. */
if an error happens (descriptors to be closed, memory to be freed, etc.) struct cleanup;
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;
};
/* NOTE: cagney/2000-03-04: This typedef is strictly for the /* NOTE: cagney/2000-03-04: This typedef is strictly for the
make_cleanup function declarations below. Do not use this typedef 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. */ Calling a f(char*) function with f(void*) is non-portable. */
typedef void (make_cleanup_ftype) (void *); 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 /* 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 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 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 (make_cleanup_ftype *, void *);
extern struct cleanup *make_cleanup_dtor (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 *); extern struct cleanup *make_final_cleanup (make_cleanup_ftype *, void *);
/* A special value to pass to do_cleanups and do_final_cleanups /* A special value to pass to do_cleanups and do_final_cleanups
to tell them to do all 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_cleanups (struct cleanup *);
extern void do_final_cleanups (struct cleanup *); extern void do_final_cleanups (struct cleanup *);