27RCSID(
"$Id: 725c94ff00ea2c69d0031b064024a2766c0a4231 $")
 
   29#include <freeradius-devel/util/debug.h> 
   30#include <freeradius-devel/util/dlist.h> 
   31#include <freeradius-devel/util/atexit.h> 
   37#if defined(DEBUG_ATEXIT) && !defined(NDEBUG) 
   38#  define ATEXIT_DEBUG          FR_FAULT_LOG 
   40#  define ATEXIT_DEBUG(...) 
   73static pthread_mutex_t                  fr_atexit_global_mutex = PTHREAD_MUTEX_INITIALIZER;
 
   85        ATEXIT_DEBUG(
"%s - Thread %u freeing %p/%p func=%p, uctx=%p (alloced %s:%d)",
 
   86                     __FUNCTION__, (
unsigned int)pthread_self(),
 
 
  117        ATEXIT_DEBUG(
"%s - Thread %u arming %p/%p func=%p, uctx=%p (alloced %s:%d)",
 
  118                     __FUNCTION__, (
unsigned int)pthread_self(),
 
 
  132        ATEXIT_DEBUG(
"%s - Freeing destructor list %p", __FUNCTION__, list);
 
 
  144        pthread_mutex_lock(&fr_atexit_global_mutex);
 
  151        pthread_mutex_unlock(&fr_atexit_global_mutex);
 
  152        TALLOC_FREE(fr_atexit_threads); 
 
 
  174        if (
unlikely(!fr_atexit_threads)) 
return -1;
 
  176        ATEXIT_DEBUG(
"%s - Alloced threads destructor list %p", __FUNCTION__, fr_atexit_threads);
 
 
  188#define CHECK_GLOBAL_SETUP() \ 
  191        pthread_mutex_lock(&fr_atexit_global_mutex); \ 
  192        fr_cond_assert_msg(!is_exiting, "New atexit handlers should not be allocated whilst exiting"); \ 
  193        if (!fr_atexit_global) _ret = fr_atexit_global_setup(); \ 
  194        pthread_mutex_unlock(&fr_atexit_global_mutex); \ 
  195        if (_ret < 0) return _ret; \ 
  198#define CHECK_GLOBAL_SETUP() \ 
  201        fr_cond_assert_msg(!is_exiting, "New atexit handlers should not be allocated whilst exiting"); \ 
  202        if (!fr_atexit_global) _ret = fr_atexit_global_setup(); \ 
  203        if (_ret < 0) return _ret; \ 
 
  232        unsigned int            count = 0;
 
  237                if ((e->
func != func) || ((e->
uctx != uctx) && uctx_scope)) 
continue;
 
  239                ATEXIT_DEBUG(
"%s - Disarming %p/%p func=%p, uctx=%p (alloced %s:%d)",
 
  245                talloc_set_destructor(disarm, NULL);
 
 
  266                ATEXIT_DEBUG(
"%s - Disarming %p/%p func=%p, uctx=%p (alloced %s:%d)",
 
  270                talloc_set_destructor(e, NULL);
 
 
  289        unsigned int                    count = 0;
 
  297                ATEXIT_DEBUG(
"%s - Triggering %p/%p func=%p, uctx=%p (alloced %s:%d)",
 
  308                                                to_free->func, to_free->uctx,
 
  309                                                to_free->file, to_free->line);
 
 
  338        unsigned int                    count = 0;
 
  346                if ((e->
func != func) || ((e->
uctx != uctx) && uctx_scope)) 
continue;
 
  348                ATEXIT_DEBUG(
"%s - Triggering %p/%p func=%p, uctx=%p (alloced %s:%d)",
 
  359                                                to_free->func, to_free->uctx,
 
  360                                                to_free->file, to_free->line);
 
  368        if (!fr_atexit_threads) 
return 0;
 
  376                if (!e->
func) 
continue; 
 
  381                        if ((ee->
func != func) || ((ee->
uctx != uctx) && uctx_scope)) 
continue;
 
  383                        ATEXIT_DEBUG(
"%s - Thread %u triggering %p/%p func=%p, uctx=%p (alloced %s:%d)",
 
  385                                     (
unsigned int)pthread_self(),
 
  395                                                        to_free->func, to_free->uctx,
 
  396                                                        to_free->file, to_free->line);
 
 
  415        bool save_is_exiting;
 
  417        pthread_mutex_lock(&fr_atexit_global_mutex);
 
  419        pthread_mutex_unlock(&fr_atexit_global_mutex);
 
  421        return save_is_exiting;
 
 
  433        ATEXIT_DEBUG(
"%s - Freeing _Thread_local destructor list %p",  __FUNCTION__, list);
 
  436        pthread_mutex_lock(&fr_atexit_global_mutex);
 
  437        list->
e->
func = NULL;                   
 
  438        pthread_mutex_unlock(&fr_atexit_global_mutex);
 
  446static void _thread_local_pthread_free(
void *list)
 
  455static int _thread_local_free(
void *list)
 
  467int _fr_atexit_thread_local(
char const *
file, 
int line,
 
  486                ATEXIT_DEBUG(
"%s - Thread %u alloced _Thread_local destructor list %p",
 
  488                             (
unsigned int)pthread_self(), list);
 
  491                (void) pthread_key_create(&list->
key, _thread_local_pthread_free);
 
  500                (void) pthread_setspecific(list->
key, list);
 
  501                talloc_set_destructor(list, _thread_local_list_free);
 
  510                pthread_mutex_lock(&fr_atexit_global_mutex);
 
  516                pthread_mutex_unlock(&fr_atexit_global_mutex);
 
  542        unsigned int            count = 0;
 
  549                if ((e->
func != func) || ((e->
uctx != uctx) && uctx_scope)) 
continue;
 
  551                ATEXIT_DEBUG(
"%s - Thread %u disarming %p/%p func=%p, uctx=%p (alloced %s:%d)",
 
  553                             (
unsigned int)pthread_self(),
 
  557                talloc_set_destructor(disarm, NULL);
 
  578                ATEXIT_DEBUG(
"%s - Thread %u disarming %p/%p func=%p, uctx=%p (alloced %s:%d)",
 
  580                             (
unsigned int)pthread_self(),
 
  582                talloc_set_destructor(e, NULL);
 
  604        unsigned int                    count = 0;
 
  612                if (!e->
func) 
continue; 
 
  617                        ATEXIT_DEBUG(
"%s - Thread %u triggering %p/%p func=%p, uctx=%p (alloced %s:%d)",
 
  619                                     (
unsigned int)pthread_self(),
 
  620                                     list, ee, ee->func, ee->uctx, ee->file, ee->line);
 
  629                                                        to_free->func, to_free->uctx,
 
  630                                                        to_free->file, to_free->line
 
  643bool fr_atexit_thread_is_exiting(
void)
 
unsigned int fr_atexit_global_disarm(bool uctx_scope, fr_atexit_t func, void const *uctx)
Remove a specific global destructor (without executing it)
static fr_atexit_list_t * fr_atexit_global
char const  * file
File where this exit handler was added.
#define CHECK_GLOBAL_SETUP()
int fr_atexit_global_setup(void)
Setup the atexit handler, should be called at the start of a program's execution.
fr_dlist_t entry
Entry in the handler dlist.
static _Thread_local bool thread_is_exiting
pthread_key_t key
Key used to trigger thread local destructors.
fr_atexit_t func
Function to call.
#define ATEXIT_DEBUG(...)
fr_dlist_head_t head
Head of the list of destructors.
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)
Allocate a new exit handler entry.
void fr_atexit_global_disarm_all(void)
Remove all global destructors (without executing them)
fr_atexit_entry_t * e
Inserted into the global exit handler list to ensure this memory is cleaned up.
static int _atexit_entry_free(fr_atexit_entry_t *e)
Call the exit handler.
int line
Line where this exit handler was added.
static void _global_free(void)
Free any thread-local exit handler lists that pthread_key failed to fre.
bool fr_atexit_is_exiting(void)
Return whether we're currently in the teardown phase.
static int _destructor_list_free(fr_atexit_list_t *list)
Talloc destructor for freeing list elements in order.
int fr_atexit_global_trigger_all(void)
Cause all global free triggers to fire.
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.
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.
fr_atexit_list_t * list
List this entry is in.
Entry in exit handler list.
Head of a list of exit handlers.
int(* fr_atexit_t)(void *uctx)
Destructor callback.
#define fr_atexit_thread_trigger_all(...)
#define fr_atexit_thread_local_disarm(...)
#define fr_atexit_thread_local_disarm_all(...)
#define fr_atexit_thread_local(_name, _free, _uctx)
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
#define fr_cond_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
static void * fr_dlist_remove(fr_dlist_head_t *list_head, void *ptr)
Remove an item from the list.
static bool fr_dlist_entry_in_list(fr_dlist_t const *entry)
Check if a list entry is part of a list.
static void fr_dlist_talloc_free(fr_dlist_head_t *head)
Free all items in a doubly linked list (with talloc)
static void * fr_dlist_pop_head(fr_dlist_head_t *list_head)
Remove the head item in a list.
#define fr_dlist_talloc_init(_head, _type, _field)
Initialise the head structure of a doubly linked list.
static int fr_dlist_insert_head(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the head of a list.
static void * fr_dlist_next(fr_dlist_head_t const *list_head, void const *ptr)
Get the next item in a list.
Head of a doubly linked list.
Entry in a doubly linked list.
#define fr_strerror_printf_push(_fmt,...)
Add a message to an existing stack of messages at the tail.