diff options
author | Lennart Poettering <lennart@poettering.net> | 2018-11-19 20:08:04 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2018-11-19 21:14:34 +0100 |
commit | 67e16c31e9c797e722b1a5ee427512eb8a974a4b (patch) | |
tree | 054384431e3c8a42738f5a9413a8b2db7c52704b | |
parent | 5e332028f20566d8b9aa0d01c60aff8b9f43bcb7 (diff) | |
download | systemd-67e16c31e9c797e722b1a5ee427512eb8a974a4b.tar.gz |
util: add set of macros for declaring _cleanup_-style destructors for static variables
-rw-r--r-- | src/basic/meson.build | 1 | ||||
-rw-r--r-- | src/basic/static-destruct.h | 51 |
2 files changed, 52 insertions, 0 deletions
diff --git a/src/basic/meson.build b/src/basic/meson.build index ac580c283c..d6c03911ea 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 0000000000..cad838083f --- /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__); + } +} |