diff options
Diffstat (limited to 'libnm/nm-libnm-aux/nm-libnm-aux.c')
| -rw-r--r-- | libnm/nm-libnm-aux/nm-libnm-aux.c | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/libnm/nm-libnm-aux/nm-libnm-aux.c b/libnm/nm-libnm-aux/nm-libnm-aux.c new file mode 100644 index 00000000..169416b9 --- /dev/null +++ b/libnm/nm-libnm-aux/nm-libnm-aux.c @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: LGPL-2.1+ + +#include "nm-default.h" + +#include "nm-libnm-aux.h" + +/*****************************************************************************/ + +NMClient * +nmc_client_new_async_valist (GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data, + const char *first_property_name, + va_list ap) +{ + NMClient *nmc; + + nmc = NM_CLIENT (g_object_new_valist (NM_TYPE_CLIENT, first_property_name, ap)); + g_async_initable_init_async (G_ASYNC_INITABLE (nmc), + G_PRIORITY_DEFAULT, + cancellable, + callback, + user_data); + return nmc; +} + +NMClient * +nmc_client_new_async (GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data, + const char *first_property_name, + ...) +{ + NMClient *nmc; + va_list ap; + + va_start (ap, first_property_name); + nmc = nmc_client_new_async_valist (cancellable, + callback, + user_data, + first_property_name, + ap); + va_end (ap); + return nmc; +} + +/*****************************************************************************/ + +typedef struct { + GMainLoop *main_loop; + NMClient *nmc; + GError *error; +} ClientCreateData; + +static void +_nmc_client_new_waitsync_cb (GObject *source_object, + GAsyncResult *result, + gpointer user_data) +{ + ClientCreateData *data = user_data; + + g_async_initable_init_finish (G_ASYNC_INITABLE (source_object), + result, + &data->error); + g_main_loop_quit (data->main_loop); +} + +/** + * nmc_client_new: + * @cancellable: the cancellable to abort the creation. + * @out_nmc: (out): (transfer full): if give, transfers a reference + * to the NMClient instance. Note that this never fails to create + * the NMClient GObject, but depending on the return value, + * the instance was successfully initialized or not. + * @error: the error if creation fails. + * @first_property_name: the name of the first property + * @...: the value of the first property, followed optionally by more + * name/value pairs, followed by %NULL + * + * Returns: %TRUE, if the client was successfully initalized. + * + * This uses nm_client_new_async() to create a NMClient instance, + * but it iterates the current GMainContext until the client is + * ready. As such, it waits for the client creation to complete + * (like sync nm_client_new()) but it iterates the caller's GMainContext + * (unlike sync nm_client_new()). This is often preferable, because + * sync nm_client_new() needs to create an additional internal GMainContext + * that it can iterate instead. That has a performance overhead that + * is often unnecessary. + */ +gboolean +nmc_client_new_waitsync (GCancellable *cancellable, + NMClient **out_nmc, + GError **error, + const char *first_property_name, + ...) +{ + gs_unref_object NMClient *nmc = NULL; + nm_auto_unref_gmainloop GMainLoop *main_loop = g_main_loop_new (g_main_context_get_thread_default (), FALSE); + ClientCreateData data = { + .main_loop = main_loop, + }; + va_list ap; + +#if NM_MORE_ASSERTS > 10 + /* The sync initialization of NMClient is generally a bad idea, because it + * brings the overhead of an additional GMainContext. Anyway, since our own + * code no longer uses that, we hardly test those code paths. But they should + * work just the same. Randomly use instead the sync initialization in a debug + * build... */ + if ((g_random_int () % 2) == 0) { + gboolean success; + + va_start (ap, first_property_name); + nmc = NM_CLIENT (g_object_new_valist (NM_TYPE_CLIENT, first_property_name, ap)); + va_end (ap); + + /* iterate the context at least once, just so that the behavior from POV of the + * caller is roughly the same. */ + g_main_context_iteration (nm_client_get_main_context (nmc), FALSE); + + success = g_initable_init (G_INITABLE (nmc), + cancellable, + error); + NM_SET_OUT (out_nmc, g_steal_pointer (&nmc)); + return success; + } +#endif + + va_start (ap, first_property_name); + nmc = nmc_client_new_async_valist (cancellable, + _nmc_client_new_waitsync_cb, + &data, + first_property_name, + ap); + va_end (ap); + + g_main_loop_run (main_loop); + + NM_SET_OUT (out_nmc, g_steal_pointer (&nmc)); + if (data.error) { + g_propagate_error (error, data.error); + return FALSE; + } + return TRUE; +} |