diff options
author | Thomas Haller <thaller@redhat.com> | 2021-06-30 23:12:26 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2021-07-05 14:51:27 +0200 |
commit | bec4a40437e4120cf115771b03f4aa5f0fa5fef4 (patch) | |
tree | 890b14c33faee24876f28a16e3bf02b70be81255 | |
parent | 09fb7877a9ba3b14a98d0e3e40981ae7996d56b3 (diff) | |
download | NetworkManager-bec4a40437e4120cf115771b03f4aa5f0fa5fef4.tar.gz |
glib-aux: add nm_utils_thread_local_register_destroy() helper
_nm_thread_local is very neat, but when we allocate resources
we need to make sure that they are destroyed when the thread
exits.
We can use pthread_setspecific() for that, but using it is cumbersome.
Add a helper function to make that simpler.
Also, the number of possible pthread_key_t keys is limited. With this
way, we only need one key in total.
-rw-r--r-- | src/libnm-glib-aux/nm-shared-utils.c | 79 | ||||
-rw-r--r-- | src/libnm-glib-aux/nm-shared-utils.h | 4 |
2 files changed, 83 insertions, 0 deletions
diff --git a/src/libnm-glib-aux/nm-shared-utils.c b/src/libnm-glib-aux/nm-shared-utils.c index 68598728cb..1b4c3cbc4f 100644 --- a/src/libnm-glib-aux/nm-shared-utils.c +++ b/src/libnm-glib-aux/nm-shared-utils.c @@ -14,7 +14,9 @@ #include <sys/syscall.h> #include <net/if.h> #include <net/ethernet.h> +#include <pthread.h> +#include "c-list/src/c-list.h" #include "nm-errno.h" #include "nm-str-buf.h" @@ -6385,3 +6387,80 @@ nm_utils_validate_hostname(const char *hostname) return (p - hostname <= HOST_NAME_MAX); } + +/*****************************************************************************/ + +typedef struct { + CList lst; + gpointer tls_data; + GDestroyNotify destroy_notify; +} TlsRegData; + +static pthread_key_t _tls_reg_key; + +static void +_tls_reg_destroy(gpointer data) +{ + CList * lst_head = data; + TlsRegData *entry; + + if (!lst_head) + return; + + /* For no strong reason are we destroying the elements in reverse + * order than they were added. It seems a bit more sensible (but shouldn't + * matter nor should you rely on that). */ + while ((entry = c_list_last_entry(lst_head, TlsRegData, lst))) { + c_list_unlink_stale(&entry->lst); + entry->destroy_notify(entry->tls_data); + nm_g_slice_free(entry); + } + + nm_g_slice_free(lst_head); +} + +static void +_tls_reg_make_key(void) +{ + if (pthread_key_create(&_tls_reg_key, _tls_reg_destroy) != 0) + g_return_if_reached(); +} + +/** + * nm_utils_thread_local_register_destroy: + * @tls_data: the thread local storage data that should be destroyed when the thread + * exits. This pointer will be "owned" by the current thread. There is no way + * to un-register the destruction. + * @destroy_notify: the free function that will be called when the thread exits. + * + * If _nm_tread_local storage is heap allocated it requires freeing the pointer + * when the thread exits. Use this function to register the pointer to be + * released. + * + * This function does not change errno. + */ +void +nm_utils_thread_local_register_destroy(gpointer tls_data, GDestroyNotify destroy_notify) +{ + NM_AUTO_PROTECT_ERRNO(errsv); + static pthread_once_t key_once = PTHREAD_ONCE_INIT; + CList * lst_head; + TlsRegData * entry; + + nm_assert(destroy_notify); + + if (pthread_once(&key_once, _tls_reg_make_key) != 0) + g_return_if_reached(); + + if ((lst_head = pthread_getspecific(_tls_reg_key)) == NULL) { + lst_head = g_slice_new(CList); + c_list_init(lst_head); + if (pthread_setspecific(_tls_reg_key, lst_head) != 0) + g_return_if_reached(); + } + + entry = g_slice_new(TlsRegData); + entry->tls_data = tls_data; + entry->destroy_notify = destroy_notify; + c_list_link_tail(lst_head, &entry->lst); +} diff --git a/src/libnm-glib-aux/nm-shared-utils.h b/src/libnm-glib-aux/nm-shared-utils.h index 803a730c6a..06b7e164fa 100644 --- a/src/libnm-glib-aux/nm-shared-utils.h +++ b/src/libnm-glib-aux/nm-shared-utils.h @@ -2994,4 +2994,8 @@ char *nm_utils_get_process_exit_status_desc(int status); gboolean nm_utils_validate_hostname(const char *hostname); +/*****************************************************************************/ + +void nm_utils_thread_local_register_destroy(gpointer tls_data, GDestroyNotify destroy_notify); + #endif /* __NM_SHARED_UTILS_H__ */ |