shared: add nm_utils_invoke_on_timeout()

Add nm_utils_invoke_on_timeout() beside nm_utils_invoke_on_idle().
They are fundamentally similar, except one schedules an idle handler
and the other a timeout.

Also, use the current g_main_context_get_thread_default() as context
instead of the singleton instance. That is a change in behavior, but
the only caller of nm_utils_invoke_on_idle() is the daemon, which
doesn't use different main contexts. Anyway, to avoid anybody being
tripped up by this also change the order of arguments. It anyway
seems nicer to first pass the cancellable, and the callback and user
data as last arguments. It's more in line with glib's asynchronous
methods.

Also, in the unlikely case that the cancellable is already cancelled
from the start, always schedule an idle action to complete fast.
This commit is contained in:
Thomas Haller 2020-04-23 14:23:23 +02:00
parent 93b634f1a2
commit cd5157a0c3
9 changed files with 100 additions and 48 deletions

View file

@ -3655,9 +3655,9 @@ _nm_utils_user_data_unpack (gpointer user_data, int nargs, ...)
typedef struct {
gpointer callback_user_data;
GCancellable *cancellable;
GSource *source;
NMUtilsInvokeOnIdleCallback callback;
gulong cancelled_id;
guint idle_id;
} InvokeOnIdleData;
static gboolean
@ -3665,12 +3665,13 @@ _nm_utils_invoke_on_idle_cb_idle (gpointer user_data)
{
InvokeOnIdleData *data = user_data;
data->idle_id = 0;
nm_clear_g_signal_handler (data->cancellable, &data->cancelled_id);
data->callback (data->callback_user_data, data->cancellable);
nm_g_object_unref (data->cancellable);
g_slice_free (InvokeOnIdleData, data);
g_source_destroy (data->source);
nm_g_slice_free (data);
return G_SOURCE_REMOVE;
}
@ -3680,41 +3681,87 @@ _nm_utils_invoke_on_idle_cb_cancelled (GCancellable *cancellable,
{
/* on cancellation, we invoke the callback synchronously. */
nm_clear_g_signal_handler (data->cancellable, &data->cancelled_id);
nm_clear_g_source (&data->idle_id);
nm_clear_g_source_inst (&data->source);
data->callback (data->callback_user_data, data->cancellable);
nm_g_object_unref (data->cancellable);
g_slice_free (InvokeOnIdleData, data);
nm_g_slice_free (data);
}
void
nm_utils_invoke_on_idle (NMUtilsInvokeOnIdleCallback callback,
gpointer callback_user_data,
GCancellable *cancellable)
static void
_nm_utils_invoke_on_idle_start (gboolean use_timeout,
guint timeout_msec,
GCancellable *cancellable,
NMUtilsInvokeOnIdleCallback callback,
gpointer callback_user_data)
{
InvokeOnIdleData *data;
GSource *source;
g_return_if_fail (callback);
data = g_slice_new (InvokeOnIdleData);
data->callback = callback;
data->callback_user_data = callback_user_data;
data->cancellable = nm_g_object_ref (cancellable);
if ( cancellable
&& !g_cancellable_is_cancelled (cancellable)) {
/* if we are passed a non-cancelled cancellable, we register to the "cancelled"
* signal an invoke the callback synchronously (from the signal handler).
*
* We don't do that,
* - if the cancellable is already cancelled (because we don't want to invoke
* the callback synchronously from the caller).
* - if we have no cancellable at hand. */
data->cancelled_id = g_signal_connect (cancellable,
"cancelled",
G_CALLBACK (_nm_utils_invoke_on_idle_cb_cancelled),
data);
} else
data->cancelled_id = 0;
data->idle_id = g_idle_add (_nm_utils_invoke_on_idle_cb_idle, data);
*data = (InvokeOnIdleData) {
.callback = callback,
.callback_user_data = callback_user_data,
.cancellable = nm_g_object_ref (cancellable),
.cancelled_id = 0,
};
if (cancellable) {
if (g_cancellable_is_cancelled (cancellable)) {
/* the cancellable is already cancelled. We ignore the timeout
* and always schedule an idle action. */
use_timeout = FALSE;
} else {
/* if we are passed a non-cancelled cancellable, we register to the "cancelled"
* signal an invoke the callback synchronously (from the signal handler).
*
* We don't do that,
* - if the cancellable is already cancelled (because we don't want to invoke
* the callback synchronously from the caller).
* - if we have no cancellable at hand. */
data->cancelled_id = g_signal_connect (cancellable,
"cancelled",
G_CALLBACK (_nm_utils_invoke_on_idle_cb_cancelled),
data);
}
}
if (use_timeout) {
source = nm_g_timeout_source_new (timeout_msec,
G_PRIORITY_DEFAULT,
_nm_utils_invoke_on_idle_cb_idle,
data,
NULL);
} else {
source = nm_g_idle_source_new (G_PRIORITY_DEFAULT,
_nm_utils_invoke_on_idle_cb_idle,
data,
NULL);
}
/* use the current thread default context. */
g_source_attach (source,
g_main_context_get_thread_default ());
data->source = source;
}
void
nm_utils_invoke_on_idle (GCancellable *cancellable,
NMUtilsInvokeOnIdleCallback callback,
gpointer callback_user_data)
{
_nm_utils_invoke_on_idle_start (FALSE, 0, cancellable, callback, callback_user_data);
}
void
nm_utils_invoke_on_timeout (guint timeout_msec,
GCancellable *cancellable,
NMUtilsInvokeOnIdleCallback callback,
gpointer callback_user_data)
{
_nm_utils_invoke_on_idle_start (TRUE, timeout_msec, cancellable, callback, callback_user_data);
}
/*****************************************************************************/

View file

@ -1629,12 +1629,17 @@ void _nm_utils_user_data_unpack (gpointer user_data, int nargs, ...);
/*****************************************************************************/
typedef void (*NMUtilsInvokeOnIdleCallback) (gpointer callback_user_data,
typedef void (*NMUtilsInvokeOnIdleCallback) (gpointer user_data,
GCancellable *cancellable);
void nm_utils_invoke_on_idle (NMUtilsInvokeOnIdleCallback callback,
gpointer callback_user_data,
GCancellable *cancellable);
void nm_utils_invoke_on_idle (GCancellable *cancellable,
NMUtilsInvokeOnIdleCallback callback,
gpointer callback_user_data);
void nm_utils_invoke_on_timeout (guint timeout_msec,
GCancellable *cancellable,
NMUtilsInvokeOnIdleCallback callback,
gpointer callback_user_data);
/*****************************************************************************/

View file

@ -1251,9 +1251,9 @@ _network_server_unregister_bridge (NMBluezManager *self,
if (r_req_data) {
nm_clear_g_cancellable (&r_req_data->int_cancellable);
nm_utils_invoke_on_idle (_network_server_unregister_bridge_complete_on_idle_cb,
nm_utils_user_data_pack (r_req_data, g_strdup (reason)),
r_req_data->ext_cancellable);
nm_utils_invoke_on_idle (r_req_data->ext_cancellable,
_network_server_unregister_bridge_complete_on_idle_cb,
nm_utils_user_data_pack (r_req_data, g_strdup (reason)));
}
_nm_device_bridge_notify_unregister_bt_nap (device, reason);

View file

@ -310,7 +310,7 @@ deactivate_async (NMDevice *device,
nm_device_get_iface (device))) {
_LOGT (LOGD_CORE, "deactivate: link not present, proceeding");
nm_device_update_from_platform_link (NM_DEVICE (self), NULL);
nm_utils_invoke_on_idle (deactivate_cb_on_idle, data, cancellable);
nm_utils_invoke_on_idle (cancellable, deactivate_cb_on_idle, data);
return;
}

View file

@ -507,7 +507,7 @@ deactivate_async (NMDevice *device,
user_data = nm_utils_user_data_pack (g_object_ref (self), callback, callback_user_data);
if (!priv->dbus_obj) {
nm_utils_invoke_on_idle (disconnect_cb_on_idle, user_data, cancellable);
nm_utils_invoke_on_idle (cancellable, disconnect_cb_on_idle, user_data);
return;
}

View file

@ -684,7 +684,7 @@ deactivate_async (NMDevice *device,
user_data = nm_utils_user_data_pack (g_object_ref (self), callback, callback_user_data);
if (!priv->sup_iface) {
nm_utils_invoke_on_idle (disconnect_cb_on_idle, user_data, cancellable);
nm_utils_invoke_on_idle (cancellable, disconnect_cb_on_idle, user_data);
return;
}

View file

@ -1254,9 +1254,9 @@ disconnect (NMModem *modem,
/* Already cancelled or no simple-iface? We are done. */
if ( !ctx->self->_priv.simple_iface
|| g_cancellable_is_cancelled (cancellable)) {
nm_utils_invoke_on_idle (disconnect_context_complete_on_idle,
ctx,
cancellable);
nm_utils_invoke_on_idle (cancellable,
disconnect_context_complete_on_idle,
ctx);
return;
}

View file

@ -211,9 +211,9 @@ disconnect (NMModem *modem,
if ( state != NM_MODEM_STATE_CONNECTED
|| g_cancellable_is_cancelled (cancellable)) {
nm_utils_invoke_on_idle (disconnect_context_complete_on_idle,
ctx,
cancellable);
nm_utils_invoke_on_idle (cancellable,
disconnect_context_complete_on_idle,
ctx);
return;
}

View file

@ -5131,9 +5131,9 @@ sysctl_set_async (NMPlatform *platform,
callback,
data,
error);
nm_utils_invoke_on_idle (sysctl_set_async_return_idle,
packed,
cancellable);
nm_utils_invoke_on_idle (cancellable,
sysctl_set_async_return_idle,
packed);
return;
}
} else
@ -7390,7 +7390,7 @@ out_idle:
g_steal_pointer (&error),
callback,
data);
nm_utils_invoke_on_idle (sriov_idle_cb, packed, cancellable);
nm_utils_invoke_on_idle (cancellable, sriov_idle_cb, packed);
}
}