From 1eae7be116ddabb13b34d2c2e8e0dc13fbae2a0d Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Fri, 23 Feb 2024 13:10:28 -0700 Subject: Rewrite final cleanups This patch rewrites final cleanups to use std::function and otherwise be more C++-ish. --- gdb/compile/compile.c | 30 +++++------- gdb/debuginfod-support.c | 14 ++---- gdb/python/python.c | 4 +- gdbsupport/cleanups.cc | 122 +++++------------------------------------------ gdbsupport/cleanups.h | 17 ++----- 5 files changed, 33 insertions(+), 154 deletions(-) diff --git a/gdb/compile/compile.c b/gdb/compile/compile.c index 8cb2e8ac..27cff25 100644 --- a/gdb/compile/compile.c +++ b/gdb/compile/compile.c @@ -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; } diff --git a/gdb/debuginfod-support.c b/gdb/debuginfod-support.c index 7d8ada3..9bb3748 100644 --- a/gdb/debuginfod-support.c +++ b/gdb/debuginfod-support.c @@ -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 (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); } } diff --git a/gdb/python/python.c b/gdb/python/python.c index 8aa674c..8f8ee7c 100644 --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -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; diff --git a/gdbsupport/cleanups.cc b/gdbsupport/cleanups.cc index 619db02..cc14523 100644 --- a/gdbsupport/cleanups.cc +++ b/gdbsupport/cleanups.cc @@ -19,126 +19,26 @@ #include "common-defs.h" #include "cleanups.h" +#include -/* 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> 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 -{ - 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; -} - -/* 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) +void +add_final_cleanup (std::function &&func) { - 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); - } + all_cleanups.emplace_back (std::move (func)); } -/* 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 (); } diff --git a/gdbsupport/cleanups.h b/gdbsupport/cleanups.h index 3e64f7d..985cf81 100644 --- a/gdbsupport/cleanups.h +++ b/gdbsupport/cleanups.h @@ -19,21 +19,12 @@ #ifndef COMMON_CLEANUPS_H #define COMMON_CLEANUPS_H -/* Outside of cleanups.c, this is an opaque type. */ -struct cleanup; +#include -/* 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 &&func); +/* Run all the registered functions. */ extern void do_final_cleanups (); #endif /* COMMON_CLEANUPS_H */ -- cgit v1.1