The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
Data Structures | Macros | Typedefs | Functions | Variables
atexit.c File Reference

Macros to abstract Thread Local Storage. More...

#include <freeradius-devel/util/debug.h>
#include <freeradius-devel/util/dlist.h>
#include <freeradius-devel/util/atexit.h>
#include <stdatomic.h>
+ Include dependency graph for atexit.c:

Go to the source code of this file.

Data Structures

struct  fr_atexit_entry_t
 Entry in exit handler list. More...
 
struct  fr_exit_handler_list_s
 Head of a list of exit handlers. More...
 

Macros

#define ATEXIT_DEBUG(...)
 
#define CHECK_GLOBAL_SETUP()
 

Typedefs

typedef struct fr_exit_handler_list_s fr_atexit_list_t
 

Functions

static int _atexit_entry_free (fr_atexit_entry_t *e)
 Call the exit handler.
 
int _atexit_global (char const *file, int line, fr_atexit_t func, void const *uctx)
 Add a free function to be called when the process exits.
 
static int _destructor_list_free (fr_atexit_list_t *list)
 Talloc destructor for freeing list elements in order.
 
static void _global_free (void)
 Free any thread-local exit handler lists that pthread_key failed to fre.
 
static fr_atexit_entry_tatexit_entry_alloc (char const *file, int line, fr_atexit_list_t *list, fr_atexit_t func, void const *uctx)
 Allocate a new exit handler entry.
 
unsigned int fr_atexit_global_disarm (bool uctx_scope, fr_atexit_t func, void const *uctx)
 Remove a specific global destructor (without executing it)
 
void fr_atexit_global_disarm_all (void)
 Remove all global destructors (without executing them)
 
int fr_atexit_global_setup (void)
 Setup the atexit handler, should be called at the start of a program's execution.
 
int fr_atexit_global_trigger_all (void)
 Cause all global free triggers to fire.
 
bool fr_atexit_is_exiting (void)
 Return whether we're currently in the teardown phase.
 
bool fr_atexit_thread_local_alloc_disabled (void)
 Has fr_atexit_thread_local_disable_alloc been called yet.
 
void fr_atexit_thread_local_disable_alloc (void)
 Disable lazy allocation of thread-local caches for the rest of the process.
 
int fr_atexit_trigger (bool uctx_scope, fr_atexit_t func, void const *uctx)
 Iterates through all thread local destructor lists, causing destructor to be triggered.
 

Variables

static fr_atexit_list_tfr_atexit_global = NULL
 
static bool is_exiting
 
static _Thread_local bool thread_is_exiting
 
static atomic_bool thread_local_alloc_disabled
 Latched once main has decided no more thread-local pools should be handed out.
 

Detailed Description

Macros to abstract Thread Local Storage.

Simplifies calling thread local destructors (called when the thread exits).

Definition in file atexit.c.


Data Structure Documentation

◆ fr_atexit_entry_t

struct fr_atexit_entry_t

Entry in exit handler list.

Definition at line 49 of file atexit.c.

+ Collaboration diagram for fr_atexit_entry_t:
Data Fields
fr_dlist_t entry Entry in the handler dlist.
char const * file File where this exit handler was added.
fr_atexit_t func Function to call.
int line Line where this exit handler was added.
fr_atexit_list_t * list List this entry is in.
void * uctx uctx to pass.

◆ fr_exit_handler_list_s

struct fr_exit_handler_list_s

Head of a list of exit handlers.

Definition at line 63 of file atexit.c.

+ Collaboration diagram for fr_exit_handler_list_s:
Data Fields
fr_atexit_entry_t * e Inserted into the global exit handler list to ensure this memory is cleaned up.
fr_dlist_head_t head Head of the list of destructors.
pthread_key_t key Key used to trigger thread local destructors.

Macro Definition Documentation

◆ ATEXIT_DEBUG

#define ATEXIT_DEBUG (   ...)

Definition at line 41 of file atexit.c.

◆ CHECK_GLOBAL_SETUP

#define CHECK_GLOBAL_SETUP ( )
Value:
do { \
int _ret = 0; \
fr_cond_assert_msg(!is_exiting, "New atexit handlers should not be allocated whilst exiting"); \
if (_ret < 0) return _ret; \
} while(0)
while(1)
Definition acutest.h:856
static fr_atexit_list_t * fr_atexit_global
Definition atexit.c:77
int fr_atexit_global_setup(void)
Setup the atexit handler, should be called at the start of a program's execution.
Definition atexit.c:179
static bool is_exiting
Definition atexit.c:78

Definition at line 217 of file atexit.c.

Typedef Documentation

◆ fr_atexit_list_t

Definition at line 44 of file atexit.c.

Function Documentation

◆ _atexit_entry_free()

static int _atexit_entry_free ( fr_atexit_entry_t e)
static

Call the exit handler.

Definition at line 102 of file atexit.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _atexit_global()

int _atexit_global ( char const *  file,
int  line,
fr_atexit_t  func,
void const *  uctx 
)

Add a free function to be called when the process exits.

Definition at line 229 of file atexit.c.

+ Here is the call graph for this function:

◆ _destructor_list_free()

static int _destructor_list_free ( fr_atexit_list_t list)
static

Talloc destructor for freeing list elements in order.

Definition at line 149 of file atexit.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _global_free()

static void _global_free ( void  )
static

Free any thread-local exit handler lists that pthread_key failed to fre.

Definition at line 160 of file atexit.c.

+ Here is the caller graph for this function:

◆ atexit_entry_alloc()

static fr_atexit_entry_t * atexit_entry_alloc ( char const *  file,
int  line,
fr_atexit_list_t list,
fr_atexit_t  func,
void const *  uctx 
)
static

Allocate a new exit handler entry.

Definition at line 121 of file atexit.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fr_atexit_global_disarm()

unsigned int fr_atexit_global_disarm ( bool  uctx_scope,
fr_atexit_t  func,
void const *  uctx 
)

Remove a specific global destructor (without executing it)

Note
This function's primary purpose is to help diagnose issues with destructors from within a debugger.
Parameters
[in]uctx_scopeOnly process entries where the func and scope both match.
[in]funcEntries matching this function will be disarmed.
[in]uctxassociated with the entry.
Returns
How many global destructors were disarmed.

Definition at line 248 of file atexit.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fr_atexit_global_disarm_all()

void fr_atexit_global_disarm_all ( void  )

Remove all global destructors (without executing them)

Note
This function's primary purpose is to help diagnose issues with destructors from within a debugger.

Definition at line 278 of file atexit.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fr_atexit_global_setup()

int fr_atexit_global_setup ( void  )

Setup the atexit handler, should be called at the start of a program's execution.

Definition at line 179 of file atexit.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fr_atexit_global_trigger_all()

int fr_atexit_global_trigger_all ( void  )

Cause all global free triggers to fire.

This is necessary when libraries (perl) register their own atexit handlers using the normal POSIX mechanism, and we need to ensure all our atexit handlers fire before so any global deinit is done explicitly by us.

Returns
  • >= 0 The number of atexit handlers triggered on success.
  • <0 the return code from any atexit handlers that returned an error.

Definition at line 305 of file atexit.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fr_atexit_is_exiting()

bool fr_atexit_is_exiting ( void  )

Return whether we're currently in the teardown phase.

When this function returns true no more thread local or global destructors can be added.

Definition at line 452 of file atexit.c.

+ Here is the caller graph for this function:

◆ fr_atexit_thread_local_alloc_disabled()

bool fr_atexit_thread_local_alloc_disabled ( void  )

Has fr_atexit_thread_local_disable_alloc been called yet.

Definition at line 442 of file atexit.c.

+ Here is the caller graph for this function:

◆ fr_atexit_thread_local_disable_alloc()

void fr_atexit_thread_local_disable_alloc ( void  )

Disable lazy allocation of thread-local caches for the rest of the process.

Call this from main before fr_atexit_thread_trigger_all(). After it returns, every TLS-pool initialiser that consults fr_atexit_thread_local_alloc_disabled() falls back to the un-cached path, so _Thread_local slots in other threads aren't read after the trigger frees their backing memory.

Definition at line 434 of file atexit.c.

◆ fr_atexit_trigger()

int fr_atexit_trigger ( bool  uctx_scope,
fr_atexit_t  func,
void const *  uctx 
)

Iterates through all thread local destructor lists, causing destructor to be triggered.

This should only be called by the main process not by threads.

The main purpose of the function is to force cleanups at a specific time for problematic destructors.

Parameters
[in]uctx_scopeOnly process entries where the func and scope both match.
[in]funcEntries matching this function will be triggered.
[in]uctxassociated with the entry.
Returns
  • >= 0 The number of atexit handlers triggered on success.
  • <0 the return code from any atexit handlers that returned an error.

Definition at line 350 of file atexit.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ fr_atexit_global

fr_atexit_list_t* fr_atexit_global = NULL
static

Definition at line 77 of file atexit.c.

◆ is_exiting

bool is_exiting
static

Definition at line 78 of file atexit.c.

◆ thread_is_exiting

_Thread_local bool thread_is_exiting
static

Definition at line 79 of file atexit.c.

◆ thread_local_alloc_disabled

atomic_bool thread_local_alloc_disabled
static

Latched once main has decided no more thread-local pools should be handed out.

fr_atexit_thread_trigger_all() runs every registered thread destructor on the calling (main) thread, including ones that free _Thread_local pools owned by threads we don't manage (librdkafka's bg threads, perl, etc.). We can free the underlying chunks but can't reset another thread's TLS slot, so those threads keep a dangling pointer in their per-thread cache. Code that lazily allocates a TLS-cached pool (log.c, sbuff.c, strerror.c, ...) checks this flag before reading its TLS slot and falls back to talloc_*(NULL, ...) (or returns NULL) when set, side-stepping the dangling pointer entirely.

Set once, never cleared. Relaxed atomic because this is a one-shot signal with no other state synchronised through it - readers tolerate observing the old value briefly.

Definition at line 97 of file atexit.c.