Line data Source code
1 : #pragma once 2 : 3 : #include "alloc-util.h" 4 : #include "macro.h" 5 : 6 : /* A framework for registering static variables that shall be freed on shutdown of a process. It's a bit like gcc's 7 : * destructor attribute, but allows us to precisely schedule when we want to free the variables. This is supposed to 8 : * feel a bit like the gcc cleanup attribute, but for static variables. Note that this does not work for static 9 : * variables declared in .so's, as the list is private to the same linking unit. But maybe that's a good thing. */ 10 : 11 : typedef struct StaticDestructor { 12 : void *data; 13 : free_func_t destroy; 14 : } StaticDestructor; 15 : 16 : #define STATIC_DESTRUCTOR_REGISTER(variable, func) \ 17 : _STATIC_DESTRUCTOR_REGISTER(UNIQ, variable, func) 18 : 19 : #define _STATIC_DESTRUCTOR_REGISTER(uq, variable, func) \ 20 : /* Type-safe destructor */ \ 21 : static void UNIQ_T(static_destructor_wrapper, uq)(void *p) { \ 22 : typeof(variable) *q = p; \ 23 : func(q); \ 24 : } \ 25 : /* The actual destructor structure we place in a special section to find it */ \ 26 : _section_("SYSTEMD_STATIC_DESTRUCT") \ 27 : /* We pick pointer alignment, since that is apparently what gcc does for static variables */ \ 28 : _alignptr_ \ 29 : /* Make sure this is not dropped from the image because not explicitly referenced */ \ 30 : _used_ \ 31 : /* Make sure that AddressSanitizer doesn't pad this variable: we want everything in this section packed next to each other so that we can enumerate it. */ \ 32 : _variable_no_sanitize_address_ \ 33 : static const StaticDestructor UNIQ_T(static_destructor_entry, uq) = { \ 34 : .data = &(variable), \ 35 : .destroy = UNIQ_T(static_destructor_wrapper, uq), \ 36 : } 37 : 38 : /* Beginning and end of our section listing the destructors. We define these as weak as we want this to work even if 39 : * there's not a single destructor is defined in which case the section will be missing. */ 40 : extern const struct StaticDestructor _weak_ __start_SYSTEMD_STATIC_DESTRUCT[]; 41 : extern const struct StaticDestructor _weak_ __stop_SYSTEMD_STATIC_DESTRUCT[]; 42 : 43 : /* The function to destroy everything. (Note that this must be static inline, as it's key that it remains in the same 44 : * linking unit as the variables we want to destroy. */ 45 282 : static inline void static_destruct(void) { 46 : const StaticDestructor *d; 47 : 48 282 : if (!__start_SYSTEMD_STATIC_DESTRUCT) 49 127 : return; 50 : 51 155 : d = ALIGN_TO_PTR(__start_SYSTEMD_STATIC_DESTRUCT, sizeof(void*)); 52 1026 : while (d < __stop_SYSTEMD_STATIC_DESTRUCT) { 53 871 : d->destroy(d->data); 54 871 : d = ALIGN_TO_PTR(d + 1, sizeof(void*)); 55 : } 56 : }