summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2021-06-30 23:12:26 +0200
committerThomas Haller <thaller@redhat.com>2021-07-05 14:51:27 +0200
commitbec4a40437e4120cf115771b03f4aa5f0fa5fef4 (patch)
tree890b14c33faee24876f28a16e3bf02b70be81255
parent09fb7877a9ba3b14a98d0e3e40981ae7996d56b3 (diff)
downloadNetworkManager-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.c79
-rw-r--r--src/libnm-glib-aux/nm-shared-utils.h4
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__ */