From 9c7fc111aeced15e4478c6fd388fb6cbc826518d Mon Sep 17 00:00:00 2001 From: Marius Vollmer Date: Fri, 15 Mar 2013 12:37:48 +0200 Subject: [PATCH 8/8] When sleeping in the example provider, deal with immediate cancellation. * service/realm-example-provider.c (on_discover_sleep_done): Always complete in idle, as expected. * service/realm-usleep-async.c (realm_usleep_async): Check for immediate cancellation, to avoid calling on_sleep_async_cancelled before we are done initializing. Also, change ownership handling to be more straightforward and to allow both timeout and cancelling to occur at the same time. --- service/realm-example-provider.c | 2 +- service/realm-usleep-async.c | 61 ++++++++++++++++++++++++---------------- 2 files changed, 38 insertions(+), 25 deletions(-) diff --git a/service/realm-example-provider.c b/service/realm-example-provider.c index 1c12aea..adbb897 100644 --- a/service/realm-example-provider.c +++ b/service/realm-example-provider.c @@ -99,7 +99,7 @@ on_discover_sleep_done (GObject *source, if (!realm_usleep_finish (res, &error)) g_simple_async_result_take_error (async, error); - g_simple_async_result_complete (async); + g_simple_async_result_complete_in_idle (async); g_object_unref (async); } diff --git a/service/realm-usleep-async.c b/service/realm-usleep-async.c index 72c13e2..bbb26ec 100644 --- a/service/realm-usleep-async.c +++ b/service/realm-usleep-async.c @@ -17,31 +17,37 @@ #include "realm-usleep-async.h" typedef struct { - GSimpleAsyncResult *async; + gboolean completed; guint timeout_id; GCancellable *cancellable; guint cancel_id; } SleepAsyncData; static void -free_sleep_async_data (gpointer user_data) +complete_sleep_async (GSimpleAsyncResult *async) { - SleepAsyncData *data = user_data; - if (data->cancellable) { - /* g_cancellable_disconnect would dead-lock here - */ - g_signal_handler_disconnect (data->cancellable, data->cancel_id); - g_object_unref (data->cancellable); + SleepAsyncData *data = g_simple_async_result_get_op_res_gpointer (async); + g_object_ref (async); + if (!data->completed) { + if (data->timeout_id > 0) + g_source_remove (data->timeout_id); + if (data->cancel_id > 0) { + g_signal_handler_disconnect (data->cancellable, data->cancel_id); + g_object_unref (data->cancellable); + } + data->completed = TRUE; + g_simple_async_result_complete (async); } - g_object_unref (data->async); - g_free (data); + g_object_unref (async); } static gboolean on_sleep_async_done (gpointer user_data) { - SleepAsyncData *data = user_data; - g_simple_async_result_complete (data->async); + GSimpleAsyncResult *async = user_data; + SleepAsyncData *data = g_simple_async_result_get_op_res_gpointer (async); + data->timeout_id = 0; + complete_sleep_async (async); return FALSE; } @@ -49,9 +55,8 @@ static void on_sleep_async_cancelled (GCancellable *cancellable, gpointer user_data) { - SleepAsyncData *data = user_data; - g_simple_async_result_complete (data->async); - g_source_remove (data->timeout_id); + GSimpleAsyncResult *async = user_data; + complete_sleep_async (async); } void @@ -60,38 +65,46 @@ realm_usleep_async (gulong microseconds, GAsyncReadyCallback callback, gpointer user_data) { + GSimpleAsyncResult *async = g_simple_async_result_new (NULL, + callback, user_data, + realm_usleep_async); SleepAsyncData *data = g_new0(SleepAsyncData, 1); - data->async = g_simple_async_result_new (NULL, - callback, user_data, - realm_usleep_async); + g_simple_async_result_set_op_res_gpointer (async, data, g_free); if (cancellable) { + g_simple_async_result_set_check_cancellable (async, cancellable); + if (g_cancellable_is_cancelled (cancellable)) { + g_simple_async_result_complete_in_idle (async); + g_object_unref (async); + return; + } data->cancellable = g_object_ref (cancellable); data->cancel_id = g_cancellable_connect (cancellable, G_CALLBACK (on_sleep_async_cancelled), - data, NULL); - g_simple_async_result_set_check_cancellable (data->async, cancellable); + g_object_ref (async), g_object_unref); } data->timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT, microseconds / 1000, on_sleep_async_done, - data, (GDestroyNotify)free_sleep_async_data); + g_object_ref (async), g_object_unref); + + g_object_unref (async); } gboolean realm_usleep_finish (GAsyncResult *result, GError **error) { - GSimpleAsyncResult *simple; + GSimpleAsyncResult *async; g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL, realm_usleep_async), FALSE); - simple = (GSimpleAsyncResult *) result; - if (g_simple_async_result_propagate_error (simple, error)) + async = G_SIMPLE_ASYNC_RESULT (result); + if (g_simple_async_result_propagate_error (async, error)) return FALSE; return TRUE; -- 1.8.1.4