summaryrefslogtreecommitdiff
path: root/shared/nm-libnm-aux/nm-libnm-aux.c
blob: 169416b9c421588d137ee0640c6574e4e2c51c1e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
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;
}