summaryrefslogtreecommitdiff
path: root/src/libnm-client-aux-extern/nm-libnm-aux.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libnm-client-aux-extern/nm-libnm-aux.c')
-rw-r--r--src/libnm-client-aux-extern/nm-libnm-aux.c137
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;
+}