[gnome-builder] egg-task-cache: Fix cancellation when tasks are queued for a given key
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder] egg-task-cache: Fix cancellation when tasks are queued for a given key
- Date: Mon, 6 Mar 2017 21:59:48 +0000 (UTC)
commit f8762c97bc29cd8d8a28951d2c6ce5656b675e4a
Author: Debarshi Ray <debarshir gnome org>
Date: Mon Mar 6 20:06:22 2017 +0100
egg-task-cache: Fix cancellation when tasks are queued for a given key
The callers' GCancellables are monitored, and whenever one is cancelled
it is removed from the queue. A separate GCancellable is used with the
in-flight GTask that fetches the value. Fetching is aborted if, and
only if, all the queued tasks for a given key have been cancelled.
https://bugzilla.gnome.org/show_bug.cgi?id=779660
contrib/egg/egg-task-cache.c | 112 +++++++++++++++++++++++++++++++++++++++++-
1 files changed, 111 insertions(+), 1 deletions(-)
---
diff --git a/contrib/egg/egg-task-cache.c b/contrib/egg/egg-task-cache.c
index fed4985..e8c3fff 100644
--- a/contrib/egg/egg-task-cache.c
+++ b/contrib/egg/egg-task-cache.c
@@ -34,6 +34,14 @@ typedef struct
typedef struct
{
+ EggTaskCache *self;
+ GCancellable *cancellable;
+ gpointer key;
+ gulong cancelled_id;
+} CancelledData;
+
+typedef struct
+{
GSource source;
EggHeap *heap;
} EvictSource;
@@ -220,6 +228,40 @@ cache_item_new (EggTaskCache *self,
return ret;
}
+static void
+cancelled_data_free (gpointer data)
+{
+ CancelledData *cancelled = data;
+
+ cancelled->self->key_destroy_func (cancelled->key);
+ cancelled->key = NULL;
+
+ g_cancellable_disconnect (cancelled->cancellable, cancelled->cancelled_id);
+ g_clear_object (&cancelled->cancellable);
+ cancelled->cancelled_id = 0;
+
+ cancelled->self = NULL;
+
+ g_slice_free (CancelledData, cancelled);
+}
+
+static CancelledData *
+cancelled_data_new (EggTaskCache *self,
+ GCancellable *cancellable,
+ gconstpointer key,
+ gulong cancelled_id)
+{
+ CancelledData *ret;
+
+ ret = g_slice_new0 (CancelledData);
+ ret->self = self;
+ ret->cancellable = (cancellable != NULL) ? g_object_ref (cancellable) : NULL;
+ ret->key = self->key_copy_func ((gpointer)key);
+ ret->cancelled_id = cancelled_id;
+
+ return ret;
+}
+
static gpointer
egg_task_cache_dummy_copy_func (gpointer boxed)
{
@@ -424,6 +466,58 @@ egg_task_cache_propagate_pointer (EggTaskCache *self,
}
static void
+egg_task_cache_cancelled_cb (GCancellable *cancellable,
+ gpointer user_data)
+{
+ EggTaskCache *self;
+ CancelledData *data;
+ GPtrArray *queued;
+ GTask *task = (GTask *)user_data;
+ gboolean cancelled = FALSE;
+
+ self = (EggTaskCache *)g_task_get_source_object (task);
+ data = (CancelledData *)g_task_get_task_data (task);
+
+ if ((queued = g_hash_table_lookup (self->queued, data->key)))
+ {
+ gsize i;
+
+ for (i = 0; i < queued->len; i++)
+ {
+ GCancellable *queued_cancellable;
+ GTask *queued_task;
+
+ queued_task = g_ptr_array_index (queued, i);
+ queued_cancellable = g_task_get_cancellable (queued_task);
+
+ if (queued_task == task && queued_cancellable == cancellable)
+ {
+ cancelled = g_task_return_error_if_cancelled (task);
+ g_ptr_array_remove_index_fast (queued, (guint) i);
+
+ EGG_COUNTER_DEC (queued);
+ break;
+ }
+ }
+
+ if (queued->len == 0)
+ {
+ GTask *fetch_task;
+
+ if ((fetch_task = g_hash_table_lookup (self->in_flight, data->key)))
+ {
+ GCancellable *fetch_cancellable;
+
+ fetch_cancellable = g_task_get_cancellable (fetch_task);
+ g_cancellable_cancel (fetch_cancellable);
+ }
+ }
+ }
+
+ g_return_if_fail (cancelled);
+}
+
+static void
egg_task_cache_fetch_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
@@ -468,8 +562,10 @@ egg_task_cache_get_async (EggTaskCache *self,
{
g_autoptr(GTask) fetch_task = NULL;
g_autoptr(GTask) task = NULL;
+ CancelledData *data;
GPtrArray *queued;
gpointer ret;
+ gulong cancelled_id = 0;
g_return_if_fail (EGG_IS_TASK_CACHE (self));
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
@@ -511,8 +607,11 @@ egg_task_cache_get_async (EggTaskCache *self,
*/
if (!g_hash_table_contains (self->in_flight, key))
{
+ g_autoptr(GCancellable) fetch_cancellable = NULL;
+
+ fetch_cancellable = g_cancellable_new ();
fetch_task = g_task_new (self,
- cancellable,
+ fetch_cancellable,
egg_task_cache_fetch_cb,
self->key_copy_func ((gpointer)key));
g_hash_table_insert (self->in_flight,
@@ -520,6 +619,17 @@ egg_task_cache_get_async (EggTaskCache *self,
g_object_ref (fetch_task));
}
+ if (cancellable != NULL)
+ {
+ cancelled_id = g_cancellable_connect (cancellable,
+ G_CALLBACK (egg_task_cache_cancelled_cb),
+ task,
+ NULL);
+ }
+
+ data = cancelled_data_new (self, cancellable, key, cancelled_id);
+ g_task_set_task_data (task, data, cancelled_data_free);
+
if (fetch_task != NULL)
{
self->populate_callback (self,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]