diff options
Diffstat (limited to 'shared')
| -rw-r--r-- | shared/nm-glib-aux/nm-dbus-aux.c | 113 | ||||
| -rw-r--r-- | shared/nm-glib-aux/nm-dbus-aux.h | 16 | ||||
| -rw-r--r-- | shared/nm-glib-aux/nm-errno.c | 14 | ||||
| -rw-r--r-- | shared/nm-glib-aux/nm-macros-internal.h | 29 | ||||
| -rw-r--r-- | shared/nm-glib-aux/nm-random-utils.c | 4 | ||||
| -rw-r--r-- | shared/nm-glib-aux/nm-shared-utils.c | 79 | ||||
| -rw-r--r-- | shared/nm-glib-aux/nm-shared-utils.h | 4 | ||||
| -rw-r--r-- | shared/nm-platform/nmp-netns.c | 10 | ||||
| -rw-r--r-- | shared/nm-std-aux/nm-std-aux.h | 8 |
9 files changed, 244 insertions, 33 deletions
diff --git a/shared/nm-glib-aux/nm-dbus-aux.c b/shared/nm-glib-aux/nm-dbus-aux.c index ec409ff1..9fb02a3f 100644 --- a/shared/nm-glib-aux/nm-dbus-aux.c +++ b/shared/nm-glib-aux/nm-dbus-aux.c @@ -268,6 +268,119 @@ nm_dbus_connection_call_finish_variant_strip_dbus_error_cb(GObject * source, /*****************************************************************************/ +typedef struct { + char * bus_name; + char * object_path; + char * interface_name; + char * method_name; + GVariant * parameters; + GDBusConnection * connection; + const GVariantType *reply_type; + int timeout_msec; +} CallAsyncInfo; + +static void +call_async_info_destroy(CallAsyncInfo *info) +{ + g_free(info->bus_name); + g_free(info->object_path); + g_free(info->interface_name); + g_free(info->method_name); + g_variant_unref(info->parameters); + nm_g_object_unref(info->connection); + g_free(info); +} + +static void +call_cb(GObject *source, GAsyncResult *result, gpointer user_data) +{ + gs_unref_object GTask *task = user_data; + GError * error = NULL; + GVariant * ret; + + ret = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), result, &error); + if (!ret) { + g_task_return_error(task, error); + return; + } + + g_task_return_pointer(task, ret, (GDestroyNotify) g_variant_unref); +} + +static void +call_bus_get_cb(GObject *source, GAsyncResult *result, gpointer user_data) +{ + gs_unref_object GTask *task = user_data; + GCancellable * cancellable; + CallAsyncInfo * info; + GError * error = NULL; + + info = g_task_get_task_data(task); + info->connection = g_bus_get_finish(result, &error); + cancellable = g_task_get_cancellable(task); + + if (!info->connection) { + g_task_return_error(task, g_steal_pointer(&error)); + return; + } + + g_dbus_connection_call(info->connection, + info->bus_name, + info->object_path, + info->interface_name, + info->method_name, + info->parameters, + info->reply_type, + G_DBUS_CALL_FLAGS_NONE, + info->timeout_msec, + cancellable, + call_cb, + g_steal_pointer(&task)); +} + +void +nm_dbus_call(GBusType bus_type, + const char * bus_name, + const char * object_path, + const char * interface_name, + const char * method_name, + GVariant * parameters, + const GVariantType *reply_type, + GCancellable * cancellable, + int timeout_msec, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask * task; + CallAsyncInfo *info; + + info = g_new(CallAsyncInfo, 1); + *info = (CallAsyncInfo){ + .bus_name = g_strdup(bus_name), + .object_path = g_strdup(object_path), + .interface_name = g_strdup(interface_name), + .method_name = g_strdup(method_name), + .parameters = g_variant_ref_sink(parameters), + .reply_type = reply_type, + .timeout_msec = timeout_msec, + }; + + task = nm_g_task_new(NULL, cancellable, nm_dbus_call, callback, user_data); + g_task_set_task_data(task, info, (GDestroyNotify) call_async_info_destroy); + + g_bus_get(bus_type, cancellable, call_bus_get_cb, task); +} + +GVariant * +nm_dbus_call_finish(GAsyncResult *result, GError **error) +{ + nm_assert(nm_g_task_is_valid(result, NULL, nm_dbus_call)); + + return g_task_propagate_pointer(G_TASK(result), error); +} + +/*****************************************************************************/ + gboolean _nm_dbus_error_is(GError *error, ...) { diff --git a/shared/nm-glib-aux/nm-dbus-aux.h b/shared/nm-glib-aux/nm-dbus-aux.h index 4e3ae22d..c8107082 100644 --- a/shared/nm-glib-aux/nm-dbus-aux.h +++ b/shared/nm-glib-aux/nm-dbus-aux.h @@ -186,6 +186,22 @@ void nm_dbus_connection_call_finish_variant_strip_dbus_error_cb(GObject * so /*****************************************************************************/ +void nm_dbus_call(GBusType bus_type, + const char * bus_name, + const char * object_path, + const char * interface_name, + const char * method_name, + GVariant * parameters, + const GVariantType *reply_type, + GCancellable * cancellable, + int timeout_msec, + GAsyncReadyCallback callback, + gpointer user_data); + +GVariant *nm_dbus_call_finish(GAsyncResult *result, GError **error); + +/*****************************************************************************/ + gboolean _nm_dbus_error_is(GError *error, ...) G_GNUC_NULL_TERMINATED; #define nm_dbus_error_is(error, ...) \ diff --git a/shared/nm-glib-aux/nm-errno.c b/shared/nm-glib-aux/nm-errno.c index 668606ca..c05379ec 100644 --- a/shared/nm-glib-aux/nm-errno.c +++ b/shared/nm-glib-aux/nm-errno.c @@ -7,8 +7,6 @@ #include "nm-errno.h" -#include <pthread.h> - /*****************************************************************************/ static NM_UTILS_LOOKUP_STR_DEFINE( @@ -162,19 +160,9 @@ nm_strerror_native(int errsv) buf = buf_static; if (G_UNLIKELY(!buf)) { - int errno_saved = errno; - pthread_key_t key; - buf = g_malloc(NM_STRERROR_BUFSIZE); buf_static = buf; - - if (pthread_key_create(&key, g_free) != 0 || pthread_setspecific(key, buf) != 0) { - /* Failure. We will leak the buffer when the thread exits. - * - * Nothing we can do about it really. For Debug builds we fail with an assertion. */ - nm_assert_not_reached(); - } - errno = errno_saved; + nm_utils_thread_local_register_destroy(buf, g_free); } return nm_strerror_native_r(errsv, buf, NM_STRERROR_BUFSIZE); diff --git a/shared/nm-glib-aux/nm-macros-internal.h b/shared/nm-glib-aux/nm-macros-internal.h index 113a67a0..6f63f204 100644 --- a/shared/nm-glib-aux/nm-macros-internal.h +++ b/shared/nm-glib-aux/nm-macros-internal.h @@ -121,14 +121,6 @@ _nm_auto_free_gstring(GString **str) } #define nm_auto_free_gstring nm_auto(_nm_auto_free_gstring) -static inline void -_nm_auto_protect_errno(int *p_saved_errno) -{ - errno = *p_saved_errno; -} -#define NM_AUTO_PROTECT_ERRNO(errsv_saved) \ - nm_auto(_nm_auto_protect_errno) _nm_unused const int errsv_saved = (errno) - NM_AUTO_DEFINE_FCN0(GSource *, _nm_auto_unref_gsource, g_source_unref); #define nm_auto_unref_gsource nm_auto(_nm_auto_unref_gsource) @@ -1112,6 +1104,18 @@ nm_clear_g_variant(GVariant **variant) } static inline gboolean +nm_clear_g_string(GString **ptr) +{ + GString *s; + + if (ptr && (s = *ptr)) { + *ptr = NULL; + g_string_free(s, TRUE); + }; + return FALSE; +} + +static inline gboolean nm_clear_g_cancellable(GCancellable **cancellable) { GCancellable *v; @@ -1805,8 +1809,13 @@ NM_AUTO_DEFINE_FCN_VOID0(GMutex *, _nm_auto_unlock_g_mutex, g_mutex_unlock); #define nm_auto_unlock_g_mutex nm_auto(_nm_auto_unlock_g_mutex) -#define _NM_G_MUTEX_LOCKED(lock, uniq) \ - nm_auto_unlock_g_mutex GMutex *NM_UNIQ_T(nm_lock, uniq) = (lock) +#define _NM_G_MUTEX_LOCKED(lock, uniq) \ + _nm_unused nm_auto_unlock_g_mutex GMutex *NM_UNIQ_T(nm_lock, uniq) = ({ \ + GMutex *const _lock = (lock); \ + \ + g_mutex_lock(_lock); \ + _lock; \ + }) #define NM_G_MUTEX_LOCKED(lock) _NM_G_MUTEX_LOCKED(lock, NM_UNIQ) diff --git a/shared/nm-glib-aux/nm-random-utils.c b/shared/nm-glib-aux/nm-random-utils.c index c95d368d..97272ca3 100644 --- a/shared/nm-glib-aux/nm-random-utils.c +++ b/shared/nm-glib-aux/nm-random-utils.c @@ -122,8 +122,10 @@ fd_open: */ has_high_quality = FALSE; - if (G_UNLIKELY(!rand)) + if (G_UNLIKELY(!rand)) { rand = g_rand_new(); + nm_utils_thread_local_register_destroy(rand, (GDestroyNotify) g_rand_free); + } nm_assert(n > 0); i = 0; diff --git a/shared/nm-glib-aux/nm-shared-utils.c b/shared/nm-glib-aux/nm-shared-utils.c index 3215a33b..e7cea23a 100644 --- a/shared/nm-glib-aux/nm-shared-utils.c +++ b/shared/nm-glib-aux/nm-shared-utils.c @@ -15,7 +15,9 @@ #include <glib-unix.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" @@ -5708,3 +5710,80 @@ nm_utils_name_to_uid(const char *name, uid_t *out_uid) buf = buf_heap; } } + +/*****************************************************************************/ + +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/shared/nm-glib-aux/nm-shared-utils.h b/shared/nm-glib-aux/nm-shared-utils.h index 7d330458..f9c21a00 100644 --- a/shared/nm-glib-aux/nm-shared-utils.h +++ b/shared/nm-glib-aux/nm-shared-utils.h @@ -2477,4 +2477,8 @@ gboolean nm_utils_is_specific_hostname(const char *name); char * nm_utils_uid_to_name(uid_t uid); gboolean nm_utils_name_to_uid(const char *name, uid_t *out_uid); +/*****************************************************************************/ + +void nm_utils_thread_local_register_destroy(gpointer tls_data, GDestroyNotify destroy_notify); + #endif /* __NM_SHARED_UTILS_H__ */ diff --git a/shared/nm-platform/nmp-netns.c b/shared/nm-platform/nmp-netns.c index f97339a7..4dd9e848 100644 --- a/shared/nm-platform/nmp-netns.c +++ b/shared/nm-platform/nmp-netns.c @@ -11,7 +11,6 @@ #include <sys/mount.h> #include <sys/stat.h> #include <sys/types.h> -#include <pthread.h> #include "nm-log-core/nm-logging.h" @@ -151,20 +150,13 @@ _netns_stack_get_impl(void) { gs_unref_object NMPNetns *netns = NULL; gs_free_error GError *error = NULL; - pthread_key_t key; GArray * s; s = g_array_new(FALSE, FALSE, sizeof(NetnsInfo)); g_array_set_clear_func(s, _netns_stack_clear_cb); _netns_stack = s; - /* register a destructor function to cleanup the array. If we fail - * to do so, we will leak NMPNetns instances (and their file descriptor) when the - * thread exits. */ - if (pthread_key_create(&key, (void (*)(void *)) g_array_unref) != 0) - _LOGE(NULL, "failure to initialize thread-local storage"); - else if (pthread_setspecific(key, s) != 0) - _LOGE(NULL, "failure to set thread-local storage"); + nm_utils_thread_local_register_destroy(s, (GDestroyNotify) g_array_unref); /* at the bottom of the stack we must try to create a netns instance * that we never pop. It's the base to which we need to return. */ diff --git a/shared/nm-std-aux/nm-std-aux.h b/shared/nm-std-aux/nm-std-aux.h index 30adeb58..a619cebd 100644 --- a/shared/nm-std-aux/nm-std-aux.h +++ b/shared/nm-std-aux/nm-std-aux.h @@ -695,6 +695,14 @@ nm_close(int fd) NM_AUTO_DEFINE_FCN_VOID0(void *, _nm_auto_free_impl, free); #define nm_auto_free nm_auto(_nm_auto_free_impl) +static inline void +_nm_auto_protect_errno(const int *p_saved_errno) +{ + errno = *p_saved_errno; +} +#define NM_AUTO_PROTECT_ERRNO(errsv_saved) \ + nm_auto(_nm_auto_protect_errno) _nm_unused const int errsv_saved = (errno) + /*****************************************************************************/ static inline void |