diff options
Diffstat (limited to 'src/libnm-client-aux-extern/nm-libnm-aux.c')
-rw-r--r-- | src/libnm-client-aux-extern/nm-libnm-aux.c | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/src/libnm-client-aux-extern/nm-libnm-aux.c b/src/libnm-client-aux-extern/nm-libnm-aux.c new file mode 100644 index 0000000000..2d17241db3 --- /dev/null +++ b/src/libnm-client-aux-extern/nm-libnm-aux.c @@ -0,0 +1,137 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "libnm-client-aux-extern/nm-default-client.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; +} |