From: Lennart Poettering Date: Mon, 19 Nov 2018 19:08:04 +0000 (+0100) Subject: util: add set of macros for declaring _cleanup_-style destructors for static variables X-Git-Tag: v240~275^2~3 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=67e16c31e9c797e722b1a5ee427512eb8a974a4b;p=thirdparty%2Fsystemd.git util: add set of macros for declaring _cleanup_-style destructors for static variables --- diff --git a/src/basic/meson.build b/src/basic/meson.build index ac580c283c5..d6c03911ea6 100644 --- a/src/basic/meson.build +++ b/src/basic/meson.build @@ -183,6 +183,7 @@ basic_sources = files(''' special.h stat-util.c stat-util.h + static-destruct.h stdio-util.h strbuf.c strbuf.h diff --git a/src/basic/static-destruct.h b/src/basic/static-destruct.h new file mode 100644 index 00000000000..cad838083fa --- /dev/null +++ b/src/basic/static-destruct.h @@ -0,0 +1,51 @@ +#pragma once + +#include "macro.h" + +/* A framework for registering static variables that shall be freed on shutdown of a process. It's a bit like gcc's + * destructor attribute, but allows us to precisely schedule when we want to free the variables. This is supposed to + * feel a bit like the gcc cleanup attribute, but for static variables. Note that this does not work for static + * variables declared in .so's, as the list is private to the same linking unit. But maybe that's a good thing. */ + +typedef struct StaticDestructor { + void *data; + void (*destroy)(void *p); +} StaticDestructor; + +#define STATIC_DESTRUCTOR_REGISTER(variable, func) \ + _STATIC_DESTRUCTOR_REGISTER(UNIQ, variable, func) + +#define _STATIC_DESTRUCTOR_REGISTER(uq, variable, func) \ + /* Type-safe destructor */ \ + static void UNIQ_T(static_destructor_wrapper, uq)(void *p) { \ + typeof(variable) *q = p; \ + func(q); \ + } \ + /* The actual destructor structure */ \ + __attribute__ ((__section__("SYSTEMD_STATIC_DESTRUCT"))) \ + __attribute__ ((__aligned__(__BIGGEST_ALIGNMENT__))) \ + __attribute__ ((__used__)) \ + static const StaticDestructor UNIQ_T(static_destructor_entry, uq) = { \ + .data = &(variable), \ + .destroy = UNIQ_T(static_destructor_wrapper, uq), \ + } + +/* Beginning and end of our section listing the destructors. We define these as weak as we want this to work even if + * there's not a single destructor is defined in which case the section will be missing. */ +extern const struct StaticDestructor __attribute__((__weak__)) __start_SYSTEMD_STATIC_DESTRUCT[]; +extern const struct StaticDestructor __attribute__((__weak__)) __stop_SYSTEMD_STATIC_DESTRUCT[]; + +/* The function to destroy everything. (Note that this must be static inline, as it's key that it remains in the same + * linking unit as the variables we want to destroy. */ +static inline void static_destruct(void) { + const StaticDestructor *d; + + if (!__start_SYSTEMD_STATIC_DESTRUCT) + return; + + d = ALIGN_TO_PTR(__start_SYSTEMD_STATIC_DESTRUCT, __BIGGEST_ALIGNMENT__); + while (d < __stop_SYSTEMD_STATIC_DESTRUCT) { + d->destroy(d->data); + d = ALIGN_TO_PTR(d + 1, __BIGGEST_ALIGNMENT__); + } +}