]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Flesh out the atexit debug functions more
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Tue, 4 Jan 2022 21:29:16 +0000 (15:29 -0600)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Tue, 4 Jan 2022 21:29:16 +0000 (15:29 -0600)
src/lib/eap_aka_sim/crypto.c
src/lib/server/trunk_tests.c
src/lib/util/atexit.c
src/lib/util/atexit.h
src/lib/util/talloc.c

index 7efa392918a5907a248b3e406946cc09f630bb20..a37f1b364040a89748ea958b042849b5ddb0c24f 100644 (file)
@@ -85,7 +85,7 @@ EVP_CIPHER_CTX *aka_sim_crypto_cipher_ctx(void)
  */
 void aka_sim_crypto_cipher_ctx_free(void)
 {
-       fr_atexit_trigger(_evp_cipher_ctx_free_on_exit);
+       fr_atexit_trigger(false, _evp_cipher_ctx_free_on_exit, NULL);
        evp_chipher_ctx = NULL;
 }
 
index 288cda821e5328750bef66ab41736f749c0310bd..a5c593e33d07ed927a05473388557c072abaf89a 100644 (file)
@@ -1054,7 +1054,6 @@ static void test_partial_to_complete_states(void)
        talloc_free(ctx);
 }
 
-#if 0
 /*
  *     Test calling reconnect with requests in each different state
  */
@@ -1098,7 +1097,7 @@ static void test_requeue_on_reconnect(void)
        preq->treq = treq;
 
        tconn = treq->pub.tconn;        /* Store the conn the request was assigned to */
-       TEST_CHECK(fr_trunk_request_count_by_state(trunk, FR_TRUNK_CONN_ALL, FR_TRUNK_REQUEST_STATE_PENDING) == 1);
+       TEST_CHECK_LEN(fr_trunk_request_count_by_state(trunk, FR_TRUNK_CONN_ALL, FR_TRUNK_REQUEST_STATE_PENDING), 1);
 
        fr_trunk_connection_signal_reconnect(tconn, FR_CONNECTION_FAILED);
 
@@ -1106,36 +1105,39 @@ static void test_requeue_on_reconnect(void)
         *      Should be reassigned to the other connection
         */
        TEST_CHECK(tconn != treq->pub.tconn);
-       TEST_CHECK(fr_trunk_request_count_by_state(trunk, FR_TRUNK_CONN_ALL, FR_TRUNK_REQUEST_STATE_PENDING) == 1);
+       TEST_CHECK_LEN(fr_trunk_request_count_by_state(trunk, FR_TRUNK_CONN_ALL, FR_TRUNK_REQUEST_STATE_PENDING), 1);
 
        /*
         *      Should be reassigned to the backlog
         */
        fr_trunk_connection_signal_reconnect(treq->pub.tconn, FR_CONNECTION_FAILED);
-       TEST_CHECK(fr_trunk_request_count_by_state(trunk, FR_TRUNK_CONN_ALL, FR_TRUNK_REQUEST_STATE_BACKLOG) == 1);
+       TEST_CHECK_LEN(fr_trunk_request_count_by_state(trunk, FR_TRUNK_CONN_ALL, FR_TRUNK_REQUEST_STATE_BACKLOG), 1);
        TEST_CHECK(!treq->pub.tconn);
 
        TEST_CASE("cancel on reconnect - FR_TRUNK_REQUEST_STATE_PARTIAL");
 
+       fr_debug_lvl = 4;
+
        /*
         *      Allow the connections to reconnect
         */
        test_time_base = fr_time_add_time_delta(test_time_base, fr_time_delta_from_sec(1));
        fr_event_corral(el, test_time_base, false);
-       fr_event_service(el);
+       fr_event_service(el);   /* run management function */
+       fr_event_service(el);   /* service any I/O callbacks */
 
        /*
         *      Request should now be assigned back to one of the reconnected
         *      connections.
         */
-       TEST_CHECK(fr_trunk_request_count_by_state(trunk, FR_TRUNK_CONN_ALL, FR_TRUNK_REQUEST_STATE_PENDING) == 1);
+       TEST_CHECK_LEN(fr_trunk_request_count_by_state(trunk, FR_TRUNK_CONN_ALL, FR_TRUNK_REQUEST_STATE_PENDING), 1);
        TEST_CHECK(treq->pub.tconn != NULL);
 
        test_time_base = fr_time_add_time_delta(test_time_base, fr_time_delta_from_sec(1));
        fr_event_corral(el, test_time_base, false);     /* Send the request (partially) */
        fr_event_service(el);
 
-       TEST_CHECK(fr_trunk_request_count_by_state(trunk, FR_TRUNK_CONN_ALL, FR_TRUNK_REQUEST_STATE_PARTIAL) == 1);
+       TEST_CHECK_LEN(fr_trunk_request_count_by_state(trunk, FR_TRUNK_CONN_ALL, FR_TRUNK_REQUEST_STATE_PARTIAL), 1);
 
        /*
         *      Reconnect the connection.
@@ -1153,7 +1155,7 @@ static void test_requeue_on_reconnect(void)
 
        preq->cancelled = false;                /* Reset */
 
-       TEST_CHECK(fr_trunk_request_count_by_state(trunk, FR_TRUNK_CONN_ALL, FR_TRUNK_REQUEST_STATE_PENDING) == 1);
+       TEST_CHECK_LEN(fr_trunk_request_count_by_state(trunk, FR_TRUNK_CONN_ALL, FR_TRUNK_REQUEST_STATE_PENDING), 1);
        TEST_CHECK(tconn != treq->pub.tconn);   /* Ensure it moved */
 
        TEST_CASE("cancel on reconnect - FR_TRUNK_REQUEST_STATE_SENT");
@@ -1164,12 +1166,12 @@ static void test_requeue_on_reconnect(void)
        fr_event_corral(el, test_time_base, false);     /* Send the request (partially) */
        fr_event_service(el);
 
-       TEST_CHECK(fr_trunk_request_count_by_state(trunk, FR_TRUNK_CONN_ALL, FR_TRUNK_REQUEST_STATE_SENT) == 1);
+       TEST_CHECK_LEN(fr_trunk_request_count_by_state(trunk, FR_TRUNK_CONN_ALL, FR_TRUNK_REQUEST_STATE_SENT), 1);
 
        tconn = treq->pub.tconn;
        fr_trunk_connection_signal_reconnect(treq->pub.tconn, FR_CONNECTION_FAILED);
 
-       TEST_CHECK(fr_trunk_request_count_by_state(trunk, FR_TRUNK_CONN_ALL, FR_TRUNK_REQUEST_STATE_PENDING) == 1);
+       TEST_CHECK_LEN(fr_trunk_request_count_by_state(trunk, FR_TRUNK_CONN_ALL, FR_TRUNK_REQUEST_STATE_PENDING), 1);
 
        /*
         *      Allow the connections to reconnect
@@ -1193,7 +1195,7 @@ static void test_requeue_on_reconnect(void)
         *      Signal the request should be cancelled
         */
        fr_trunk_request_signal_cancel(treq);
-       TEST_CHECK(fr_trunk_request_count_by_state(trunk, FR_TRUNK_CONN_ALL, FR_TRUNK_REQUEST_STATE_CANCEL) == 1);
+       TEST_CHECK_LEN(fr_trunk_request_count_by_state(trunk, FR_TRUNK_CONN_ALL, FR_TRUNK_REQUEST_STATE_CANCEL), 1);
 
        /*
         *      Requests in the cancel state, are
@@ -1228,7 +1230,7 @@ static void test_requeue_on_reconnect(void)
        treq = NULL;
        fr_trunk_request_enqueue(&treq, trunk, NULL, preq, NULL);
 
-       TEST_CHECK(fr_trunk_request_count_by_state(trunk, FR_TRUNK_CONN_ALL, FR_TRUNK_REQUEST_STATE_PENDING) == 1);
+       TEST_CHECK_LEN(fr_trunk_request_count_by_state(trunk, FR_TRUNK_CONN_ALL, FR_TRUNK_REQUEST_STATE_PENDING), 1);
 
        /*
         *      Sent the request (fully)
@@ -1237,10 +1239,10 @@ static void test_requeue_on_reconnect(void)
        fr_event_corral(el, test_time_base, false);     /* Send the request (fully) */
        fr_event_service(el);
 
-       TEST_CHECK(fr_trunk_request_count_by_state(trunk, FR_TRUNK_CONN_ALL, FR_TRUNK_REQUEST_STATE_SENT) == 1);
+       TEST_CHECK_LEN(fr_trunk_request_count_by_state(trunk, FR_TRUNK_CONN_ALL, FR_TRUNK_REQUEST_STATE_SENT), 1);
        fr_trunk_request_signal_cancel(treq);                   /* Cancel the request */
 
-       TEST_CHECK(fr_trunk_request_count_by_state(trunk, FR_TRUNK_CONN_ALL, FR_TRUNK_REQUEST_STATE_CANCEL) == 1);
+       TEST_CHECK_LEN(fr_trunk_request_count_by_state(trunk, FR_TRUNK_CONN_ALL, FR_TRUNK_REQUEST_STATE_CANCEL), 1);
 
        /*
         *      Transition to cancel partial
@@ -1249,7 +1251,7 @@ static void test_requeue_on_reconnect(void)
        fr_event_corral(el, test_time_base, false);
        fr_event_service(el);
 
-       TEST_CHECK(fr_trunk_request_count_by_state(trunk, FR_TRUNK_CONN_ALL, FR_TRUNK_REQUEST_STATE_CANCEL_PARTIAL) == 1);
+       TEST_CHECK_LEN(fr_trunk_request_count_by_state(trunk, FR_TRUNK_CONN_ALL, FR_TRUNK_REQUEST_STATE_CANCEL_PARTIAL), 1);
 
        /*
         *      Trigger a reconnection
@@ -1281,7 +1283,7 @@ static void test_requeue_on_reconnect(void)
        treq = NULL;
        fr_trunk_request_enqueue(&treq, trunk, NULL, preq, NULL);
 
-       TEST_CHECK(fr_trunk_request_count_by_state(trunk, FR_TRUNK_CONN_ALL, FR_TRUNK_REQUEST_STATE_PENDING) == 1);
+       TEST_CHECK_LEN(fr_trunk_request_count_by_state(trunk, FR_TRUNK_CONN_ALL, FR_TRUNK_REQUEST_STATE_PENDING), 1);
 
        /*
         *      Sent the request (fully)
@@ -1290,10 +1292,10 @@ static void test_requeue_on_reconnect(void)
        fr_event_corral(el, test_time_base, false);     /* Send the request (fully) */
        fr_event_service(el);
 
-       TEST_CHECK(fr_trunk_request_count_by_state(trunk, FR_TRUNK_CONN_ALL, FR_TRUNK_REQUEST_STATE_SENT) == 1);
+       TEST_CHECK_LEN(fr_trunk_request_count_by_state(trunk, FR_TRUNK_CONN_ALL, FR_TRUNK_REQUEST_STATE_SENT), 1);
        fr_trunk_request_signal_cancel(treq);                   /* Cancel the request */
 
-       TEST_CHECK(fr_trunk_request_count_by_state(trunk, FR_TRUNK_CONN_ALL, FR_TRUNK_REQUEST_STATE_CANCEL) == 1);
+       TEST_CHECK_LEN(fr_trunk_request_count_by_state(trunk, FR_TRUNK_CONN_ALL, FR_TRUNK_REQUEST_STATE_CANCEL), 1);
 
        /*
         *      Transition to cancel
@@ -1302,7 +1304,7 @@ static void test_requeue_on_reconnect(void)
        fr_event_corral(el, test_time_base, false);
        fr_event_service(el);
 
-       TEST_CHECK(fr_trunk_request_count_by_state(trunk, FR_TRUNK_CONN_ALL, FR_TRUNK_REQUEST_STATE_CANCEL_SENT) == 1);
+       TEST_CHECK_LEN(fr_trunk_request_count_by_state(trunk, FR_TRUNK_CONN_ALL, FR_TRUNK_REQUEST_STATE_CANCEL_SENT), 1);
 
        /*
         *      Trigger a reconnection
@@ -1322,7 +1324,6 @@ static void test_requeue_on_reconnect(void)
 
        talloc_free(ctx);
 }
-#endif
 
 static void test_connection_start_on_enqueue(void)
 {
@@ -1889,9 +1890,7 @@ TEST_LIST = {
        { "Enqueue - Basic",                            test_enqueue_basic },
        { "Enqueue - Cancellation points",              test_enqueue_cancellation_points },
        { "Enqueue - Partial state transitions",        test_partial_to_complete_states },
-#if 0
        { "Requeue - On reconnect",                     test_requeue_on_reconnect },
-#endif
 
        /*
         *      Rebalance
index 17642e4f76ed8a1872ccac2a86cf7446e59c8b8c..45ebb953c7d77dd5308bf0b3d5f90c06e6afba40 100644 (file)
@@ -33,10 +33,10 @@ RCSID("$Id$")
 
 #include <pthread.h>
 
-#if defined(DEBUG_THREAD_LOCAL) && !defined(NDEBUG)
-#  define THREAD_LOCAL_DEBUG           FR_FAULT_LOG
+#if defined(DEBUG_ATEXIT) && !defined(NDEBUG)
+#  define ATEXIT_DEBUG         FR_FAULT_LOG
 #else
-#  define THREAD_LOCAL_DEBUG(...)
+#  define ATEXIT_DEBUG(...)
 #endif
 
 typedef struct fr_exit_handler_list_s fr_atexit_list_t;
@@ -80,7 +80,7 @@ static bool                           is_exiting;
  */
 static int _atexit_entry_free(fr_atexit_entry_t *e)
 {
-       THREAD_LOCAL_DEBUG("%s - Thread %u freeing %p/%p func=%p, uctx=%p (alloced %s:%u)",
+       ATEXIT_DEBUG("%s - Thread %u freeing %p/%p func=%p, uctx=%p (alloced %s:%u)",
                           __FUNCTION__, (unsigned int)pthread_self(),
                           e->list, e, e->func, e->uctx, e->file, e->line);
 
@@ -115,7 +115,7 @@ static fr_atexit_entry_t *atexit_entry_alloc(NDEBUG_LOCATION_ARGS
        e->line = line;
 #endif
 
-       THREAD_LOCAL_DEBUG("%s - Thread %u arming %p/%p func=%p, uctx=%p (alloced %s:%u)",
+       ATEXIT_DEBUG("%s - Thread %u arming %p/%p func=%p, uctx=%p (alloced %s:%u)",
                           __FUNCTION__, (unsigned int)pthread_self(),
                           list, e, e->func, e->uctx, e->file, e->line);
 
@@ -130,7 +130,7 @@ static fr_atexit_entry_t *atexit_entry_alloc(NDEBUG_LOCATION_ARGS
  */
 static int _thread_local_list_free(fr_atexit_list_t *list)
 {
-       THREAD_LOCAL_DEBUG("%s - Freeing _Thread_local destructor list %p",
+       ATEXIT_DEBUG("%s - Freeing _Thread_local destructor list %p",
                           __FUNCTION__, list);
 
        fr_dlist_talloc_free(&list->head);      /* Free in order */
@@ -152,7 +152,7 @@ static void _thread_local_free(void *list)
  */
 static int _global_list_free(fr_atexit_list_t *list)
 {
-       THREAD_LOCAL_DEBUG("%s - Freeing global destructor list %p",
+       ATEXIT_DEBUG("%s - Freeing global destructor list %p",
                           __FUNCTION__, list);
 
        fr_dlist_talloc_free(&list->head);      /* Free in order */
@@ -183,7 +183,7 @@ int fr_atexit_global_setup(void)
        fr_atexit_global = talloc_zero(NULL, fr_atexit_list_t);
        if (unlikely(!fr_atexit_global)) return -1;
 
-       THREAD_LOCAL_DEBUG("%s - Alloced global destructor list %p", __FUNCTION__, fr_atexit_global);
+       ATEXIT_DEBUG("%s - Alloced global destructor list %p", __FUNCTION__, fr_atexit_global);
 
        fr_dlist_talloc_init(&fr_atexit_global->head, fr_atexit_entry_t, entry);
        talloc_set_destructor(fr_atexit_global, _global_list_free);
@@ -191,7 +191,7 @@ int fr_atexit_global_setup(void)
        fr_atexit_threads = talloc_zero(NULL, fr_atexit_list_t);
        if (unlikely(!fr_atexit_threads)) return -1;
 
-       THREAD_LOCAL_DEBUG("%s - Alloced threads destructor list %p", __FUNCTION__, fr_atexit_threads);
+       ATEXIT_DEBUG("%s - Alloced threads destructor list %p", __FUNCTION__, fr_atexit_threads);
 
        fr_dlist_talloc_init(&fr_atexit_threads->head, fr_atexit_entry_t, entry);
        talloc_set_destructor(fr_atexit_threads, _global_list_free);
@@ -247,7 +247,7 @@ int _fr_atexit_thread_local(NDEBUG_LOCATION_ARGS
                list = talloc_zero(NULL, fr_atexit_list_t);
                if (unlikely(!list)) return -1;
 
-               THREAD_LOCAL_DEBUG("%s - Thread %u alloced _Thread_local destructor list %p",
+               ATEXIT_DEBUG("%s - Thread %u alloced _Thread_local destructor list %p",
                                   __FUNCTION__,
                                   (unsigned int)pthread_self(), list);
 
@@ -290,34 +290,48 @@ int _fr_atexit_thread_local(NDEBUG_LOCATION_ARGS
        return 0;
 }
 
-/** Remove destructor
+/** Remove a specific destructor for this thread (without executing them)
  *
- * @return
- *     - 0 on success.
- *      - -1 if function and uctx could not be found.
+ * @note This function's primary purpose is to help diagnose issues with destructors
+ *      from within a debugger.
+ *
+ * @param[in] uctx_scope       Only process entries where the func and scope both match.
+ * @param[in] func             Entries matching this function will be disarmed.
+ * @param[in] uctx             associated with the entry.
+ * @return How many destructors were disarmed.
  */
-int fr_atexit_thread_local_disarm(fr_atexit_t func, void const *uctx)
+unsigned int fr_atexit_thread_local_disarm(bool uctx_scope, fr_atexit_t func, void const *uctx)
 {
-       fr_atexit_entry_t *e = NULL;
+       fr_atexit_entry_t       *e = NULL;
+       unsigned int            count = 0;
 
        if (!fr_atexit_thread_local) return -1;
 
        while ((e = fr_dlist_next(&fr_atexit_thread_local->head, e))) {
-               if ((e->func == func) && (e->uctx == uctx)) {
-                       THREAD_LOCAL_DEBUG("%s - Thread %u disarming %p/%p func=%p, uctx=%p (alloced %s:%u)",
-                                          __FUNCTION__,
-                                          (unsigned int)pthread_self(),
-                                          fr_atexit_thread_local, e, e->func, e->uctx, e->file, e->line);
-                       fr_dlist_remove(&fr_atexit_thread_local->head, e);
-                       talloc_set_destructor(e, NULL);
-                       talloc_free(e);
-                       return 0;
-               }
+               fr_atexit_entry_t *disarm;
+
+               if ((e->func != func) || !uctx_scope || (e->uctx != uctx)) continue;
+
+               ATEXIT_DEBUG("%s - Thread %u disarming %p/%p func=%p, uctx=%p (alloced %s:%u)",
+                            __FUNCTION__,
+                            (unsigned int)pthread_self(),
+                            fr_atexit_thread_local, e, e->func, e->uctx, e->file, e->line);
+               disarm = e;
+               e = fr_dlist_remove(&fr_atexit_thread_local->head, e);
+               talloc_set_destructor(disarm, NULL);
+               talloc_free(disarm);
+
+               count++;
        }
 
-       return -1;
+       return count;
 }
 
+/** Remove all destructors for this thread (without executing them)
+ *
+ * @note This function's primary purpose is to help diagnose issues with destructors
+ *      from within a debugger.
+ */
 void fr_atexit_thread_local_disarm_all(void)
 {
        fr_atexit_entry_t *e = NULL;
@@ -325,10 +339,68 @@ void fr_atexit_thread_local_disarm_all(void)
        if (!fr_atexit_thread_local) return;
 
        while ((e = fr_dlist_pop_head(&fr_atexit_thread_local->head))) {
-               THREAD_LOCAL_DEBUG("%s - Thread %u disarming %p/%p func=%p, uctx=%p (alloced %s:%u)",
-                                  __FUNCTION__,
-                                  (unsigned int)pthread_self(),
-                                  fr_atexit_thread_local, e, e->func, e->uctx, e->file, e->line);
+               ATEXIT_DEBUG("%s - Thread %u disarming %p/%p func=%p, uctx=%p (alloced %s:%u)",
+                            __FUNCTION__,
+                            (unsigned int)pthread_self(),
+                            fr_atexit_thread_local, e, e->func, e->uctx, e->file, e->line);
+               talloc_set_destructor(e, NULL);
+               talloc_free(e);
+       }
+}
+
+/** 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.
+ *
+ * @param[in] uctx_scope       Only process entries where the func and scope both match.
+ * @param[in] func             Entries matching this function will be disarmed.
+ * @param[in] uctx             associated with the entry.
+ * @return How many global destructors were disarmed.
+ */
+unsigned int fr_atexit_disarm(bool uctx_scope, fr_atexit_t func, void const *uctx)
+{
+       fr_atexit_entry_t       *e = NULL;
+       unsigned int            count = 0;
+
+       if (!fr_atexit_thread_local) return -1;
+
+       while ((e = fr_dlist_next(&fr_atexit_global->head, e))) {
+               fr_atexit_entry_t *disarm;
+
+               if ((e->func != func) || !uctx_scope || (e->uctx != uctx)) continue;
+
+               ATEXIT_DEBUG("%s - Disarming %p/%p func=%p, uctx=%p (alloced %s:%u)",
+                            __FUNCTION__,
+                            fr_atexit_global, e, e->func, e->uctx, e->file, e->line);
+
+               disarm = e;
+               e = fr_dlist_remove(&fr_atexit_global->head, e);
+               talloc_set_destructor(disarm, NULL);
+               talloc_free(disarm);
+
+               count++;
+       }
+
+       return count;
+}
+
+/** Remove all global destructors (without executing them)
+ *
+ * @note This function's primary purpose is to help diagnose issues with destructors
+ *      from within a debugger.
+ */
+void fr_atexit_disarm_all(void)
+{
+       fr_atexit_entry_t *e = NULL;
+
+       if (!fr_atexit_global) return;
+
+       while ((e = fr_dlist_pop_head(&fr_atexit_global->head))) {
+               ATEXIT_DEBUG("%s - Disarming %p/%p func=%p, uctx=%p (alloced %s:%u)",
+                            __FUNCTION__,
+                            fr_atexit_global, e, e->func, e->uctx, e->file, e->line);
+
                talloc_set_destructor(e, NULL);
                talloc_free(e);
        }
@@ -336,12 +408,17 @@ void fr_atexit_thread_local_disarm_all(void)
 
 /** Iterates through all thread local destructor lists, causing destructor to be triggered
  *
- * This should only be called by the main process, and not by threads.
+ * 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.
  *
- * @param[in] func     Entries matching this function will be triggered.
+ * @param[in] uctx_scope       Only process entries where the func and scope both match.
+ * @param[in] func             Entries matching this function will be triggered.
+ * @param[in] uctx             associated with the entry.
  * @return How many triggers fired.
  */
-int fr_atexit_trigger(fr_atexit_t func)
+unsigned int fr_atexit_trigger(bool uctx_scope, fr_atexit_t func, void const *uctx)
 {
        fr_atexit_entry_t               *e = NULL, *ee;
        fr_atexit_list_t                *list;
@@ -350,8 +427,24 @@ int fr_atexit_trigger(fr_atexit_t func)
        if (!fr_atexit_global) return 0;
 
        /*
-        *      Iterate over the list of thread local destructor
-        *      lists.
+        *      Iterate over the global destructors
+        */
+       while ((e = fr_dlist_next(&fr_atexit_global->head, e))) {
+               if ((e->func != func) || !uctx_scope || (e->uctx != uctx)) continue;
+
+               ATEXIT_DEBUG("%s - Triggering %p/%p func=%p, uctx=%p (alloced %s:%u)",
+                            __FUNCTION__,
+                            fr_atexit_global, e, e->func, e->uctx, e->file, e->line);
+
+               count++;
+               e = fr_dlist_talloc_free_item(&fr_atexit_global->head, e);
+       }
+       e = NULL;
+
+       /*
+        *      Iterate over the list of thread local
+        *      destructor lists running the
+        *      destructors.
         */
        while ((e = fr_dlist_next(&fr_atexit_threads->head, e))) {
                if (!e->func) continue; /* thread already joined */
@@ -359,7 +452,12 @@ int fr_atexit_trigger(fr_atexit_t func)
                list = talloc_get_type_abort(e->uctx, fr_atexit_list_t);
                ee = NULL;
                while ((ee = fr_dlist_next(&list->head, ee))) {
-                       if (ee->func != func) continue;
+                       if ((ee->func != func) || !uctx_scope || (e->uctx != uctx)) continue;
+
+                       ATEXIT_DEBUG("%s - Thread %u triggering %p/%p func=%p, uctx=%p (alloced %s:%u)",
+                                    __FUNCTION__,
+                                    (unsigned int)pthread_self(),
+                                    list, ee, ee->func, ee->uctx, ee->file, ee->line);
 
                        count++;
                        ee = fr_dlist_talloc_free_item(&list->head, ee);
index 26af45f4f8e7965f5ac26fe7613aff56bc306519..57f14c162986ef55eb89612577a586e582380f3d 100644 (file)
@@ -26,6 +26,8 @@
  */
 RCSIDH(atexit_h, "$Id$")
 
+#include <stdbool.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -106,11 +108,15 @@ do { \
 int    _fr_atexit_thread_local(NDEBUG_LOCATION_ARGS
                                fr_atexit_t func, void const *uctx);
 
-int    fr_atexit_thread_local_disarm(fr_atexit_t func, void const *uctx);
+unsigned int   fr_atexit_thread_local_disarm(bool uctx_scope, fr_atexit_t func, void const *uctx);
+
+void           fr_atexit_thread_local_disarm_all(void);
+
+unsigned int   fr_atexit_disarm(bool uctx_scope, fr_atexit_t func, void const *uctx);
 
-void   fr_atexit_thread_local_disarm_all(void);
+void           fr_atexit_disarm_all(void);
 
-int    fr_atexit_trigger(fr_atexit_t func);
+unsigned int   fr_atexit_trigger(bool uctx_scope, fr_atexit_t func, void const *uctx);
 
 #ifdef __cplusplus
 }
index 73d637b7fe929004ef930542b8c59375335a9010..6dba9ed25d6ac521adb3d4aced94629d46516932 100644 (file)
@@ -775,7 +775,7 @@ static void _autofree_on_thread_exit(void *af)
  */
 static int _autofree_destructor(TALLOC_CTX *af)
 {
-       return fr_atexit_thread_local_disarm(_autofree_on_thread_exit, af);
+       return fr_atexit_thread_local_disarm(true, _autofree_on_thread_exit, af);
 }
 
 /** Get a thread-safe autofreed ctx that will be freed when the thread or process exits