mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-23 01:53:38 +08:00
Rewrite final cleanups
This patch rewrites final cleanups to use std::function and otherwise be more C++-ish.
This commit is contained in:
parent
cfe51255b8
commit
1eae7be116
@ -427,23 +427,6 @@ compile_print_command (const char *arg, int from_tty)
|
||||
}
|
||||
}
|
||||
|
||||
/* A cleanup function to remove a directory and all its contents. */
|
||||
|
||||
static void
|
||||
do_rmdir (void *arg)
|
||||
{
|
||||
const char *dir = (const char *) arg;
|
||||
char *zap;
|
||||
int wstat;
|
||||
|
||||
gdb_assert (startswith (dir, TMP_PREFIX));
|
||||
zap = concat ("rm -rf ", dir, (char *) NULL);
|
||||
wstat = system (zap);
|
||||
if (wstat == -1 || !WIFEXITED (wstat) || WEXITSTATUS (wstat) != 0)
|
||||
warning (_("Could not remove temporary directory %s"), dir);
|
||||
XDELETEVEC (zap);
|
||||
}
|
||||
|
||||
/* Return the name of the temporary directory to use for .o files, and
|
||||
arrange for the directory to be removed at shutdown. */
|
||||
|
||||
@ -465,7 +448,18 @@ get_compile_file_tempdir (void)
|
||||
perror_with_name (_("Could not make temporary directory"));
|
||||
|
||||
tempdir_name = xstrdup (tempdir_name);
|
||||
make_final_cleanup (do_rmdir, tempdir_name);
|
||||
add_final_cleanup ([] ()
|
||||
{
|
||||
char *zap;
|
||||
int wstat;
|
||||
|
||||
gdb_assert (startswith (tempdir_name, TMP_PREFIX));
|
||||
zap = concat ("rm -rf ", tempdir_name, (char *) NULL);
|
||||
wstat = system (zap);
|
||||
if (wstat == -1 || !WIFEXITED (wstat) || WEXITSTATUS (wstat) != 0)
|
||||
warning (_("Could not remove temporary directory %s"), tempdir_name);
|
||||
XDELETEVEC (zap);
|
||||
});
|
||||
return tempdir_name;
|
||||
}
|
||||
|
||||
|
@ -188,15 +188,6 @@ progressfn (debuginfod_client *c, long cur, long total)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Cleanup ARG, which is a debuginfod_client pointer. */
|
||||
|
||||
static void
|
||||
cleanup_debuginfod_client (void *arg)
|
||||
{
|
||||
debuginfod_client *client = static_cast<debuginfod_client *> (arg);
|
||||
debuginfod_end (client);
|
||||
}
|
||||
|
||||
/* Return a pointer to the single global debuginfod_client, initialising it
|
||||
first if needed. */
|
||||
|
||||
@ -221,7 +212,10 @@ get_debuginfod_client ()
|
||||
handlers, which is too late.
|
||||
|
||||
So instead, we make use of GDB's final cleanup mechanism. */
|
||||
make_final_cleanup (cleanup_debuginfod_client, global_client);
|
||||
add_final_cleanup ([] ()
|
||||
{
|
||||
debuginfod_end (global_client);
|
||||
});
|
||||
debuginfod_set_progressfn (global_client, progressfn);
|
||||
}
|
||||
}
|
||||
|
@ -2057,7 +2057,7 @@ static struct cmd_list_element *user_show_python_list;
|
||||
interpreter. This lets Python's 'atexit' work. */
|
||||
|
||||
static void
|
||||
finalize_python (void *ignore)
|
||||
finalize_python ()
|
||||
{
|
||||
struct active_ext_lang_state *previous_active;
|
||||
|
||||
@ -2297,7 +2297,7 @@ init_done:
|
||||
/* Release the GIL while gdb runs. */
|
||||
PyEval_SaveThread ();
|
||||
|
||||
make_final_cleanup (finalize_python, NULL);
|
||||
add_final_cleanup (finalize_python);
|
||||
|
||||
/* Only set this when initialization has succeeded. */
|
||||
gdb_python_initialized = 1;
|
||||
|
@ -19,126 +19,26 @@
|
||||
|
||||
#include "common-defs.h"
|
||||
#include "cleanups.h"
|
||||
#include <vector>
|
||||
|
||||
/* 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.
|
||||
/* All the cleanup functions. */
|
||||
|
||||
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.
|
||||
static std::vector<std::function<void ()>> all_cleanups;
|
||||
|
||||
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. */
|
||||
/* See cleanups.h. */
|
||||
|
||||
struct cleanup
|
||||
void
|
||||
add_final_cleanup (std::function<void ()> &&func)
|
||||
{
|
||||
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_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.
|
||||
FUNCTION is the function to call to perform the cleanup.
|
||||
ARG is passed to FUNCTION when called.
|
||||
FREE_ARG, if non-NULL, is called after the cleanup is performed.
|
||||
|
||||
The result is a pointer to the previous chain pointer
|
||||
to be passed later to do_cleanups or discard_cleanups. */
|
||||
|
||||
static struct cleanup *
|
||||
make_my_cleanup2 (struct cleanup **pmy_chain, make_cleanup_ftype *function,
|
||||
void *arg, void (*free_arg) (void *))
|
||||
{
|
||||
struct cleanup *newobj = XNEW (struct cleanup);
|
||||
struct cleanup *old_chain = *pmy_chain;
|
||||
|
||||
newobj->next = *pmy_chain;
|
||||
newobj->function = function;
|
||||
newobj->free_arg = free_arg;
|
||||
newobj->arg = arg;
|
||||
*pmy_chain = newobj;
|
||||
|
||||
gdb_assert (old_chain != NULL);
|
||||
return old_chain;
|
||||
all_cleanups.emplace_back (std::move (func));
|
||||
}
|
||||
|
||||
/* Worker routine to create a cleanup without a destructor.
|
||||
PMY_CHAIN is a pointer to either cleanup_chain or final_cleanup_chain.
|
||||
FUNCTION is the function to call to perform the cleanup.
|
||||
ARG is passed to FUNCTION when called.
|
||||
|
||||
The result is a pointer to the previous chain pointer
|
||||
to be passed later to do_cleanups or discard_cleanups. */
|
||||
|
||||
static struct cleanup *
|
||||
make_my_cleanup (struct cleanup **pmy_chain, make_cleanup_ftype *function,
|
||||
void *arg)
|
||||
{
|
||||
return make_my_cleanup2 (pmy_chain, function, arg, NULL);
|
||||
}
|
||||
|
||||
/* Add a new cleanup to the final cleanup_chain,
|
||||
and return the previous chain pointer
|
||||
to be passed later to do_cleanups or discard_cleanups.
|
||||
Args are FUNCTION to clean up with, and ARG to pass to it. */
|
||||
|
||||
struct cleanup *
|
||||
make_final_cleanup (make_cleanup_ftype *function, void *arg)
|
||||
{
|
||||
return make_my_cleanup (&final_cleanup_chain, function, arg);
|
||||
}
|
||||
|
||||
/* Worker routine to perform cleanups.
|
||||
PMY_CHAIN is a pointer to either cleanup_chain or final_cleanup_chain.
|
||||
OLD_CHAIN is the result of a "make" cleanup routine.
|
||||
Cleanups are performed until we get back to the old end of the chain. */
|
||||
|
||||
static void
|
||||
do_my_cleanups (struct cleanup **pmy_chain,
|
||||
struct cleanup *old_chain)
|
||||
{
|
||||
struct cleanup *ptr;
|
||||
|
||||
while ((ptr = *pmy_chain) != old_chain)
|
||||
{
|
||||
*pmy_chain = ptr->next; /* Do this first in case of recursion. */
|
||||
(*ptr->function) (ptr->arg);
|
||||
if (ptr->free_arg)
|
||||
(*ptr->free_arg) (ptr->arg);
|
||||
xfree (ptr);
|
||||
}
|
||||
}
|
||||
|
||||
/* Discard final cleanups and do the actions they describe. */
|
||||
/* See cleanups.h. */
|
||||
|
||||
void
|
||||
do_final_cleanups ()
|
||||
{
|
||||
do_my_cleanups (&final_cleanup_chain, SENTINEL_CLEANUP);
|
||||
for (auto &func : all_cleanups)
|
||||
func ();
|
||||
all_cleanups.clear ();
|
||||
}
|
||||
|
@ -19,21 +19,12 @@
|
||||
#ifndef COMMON_CLEANUPS_H
|
||||
#define COMMON_CLEANUPS_H
|
||||
|
||||
/* Outside of cleanups.c, this is an opaque type. */
|
||||
struct cleanup;
|
||||
#include <functional>
|
||||
|
||||
/* NOTE: cagney/2000-03-04: This typedef is strictly for the
|
||||
make_cleanup function declarations below. Do not use this typedef
|
||||
as a cast when passing functions into the make_cleanup() code.
|
||||
Instead either use a bounce function or add a wrapper function.
|
||||
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 *);
|
||||
|
||||
extern struct cleanup *make_final_cleanup (make_cleanup_ftype *, void *);
|
||||
/* Register a function that will be called on exit. */
|
||||
extern void add_final_cleanup (std::function<void ()> &&func);
|
||||
|
||||
/* Run all the registered functions. */
|
||||
extern void do_final_cleanups ();
|
||||
|
||||
#endif /* COMMON_CLEANUPS_H */
|
||||
|
Loading…
Reference in New Issue
Block a user