[gegl] Bug 795597 - gegl crashes for a race ...



commit 60ae8750710f308d857fcc3cc0d6c04657e90f5b
Author: Ell <ell_se yahoo com>
Date:   Fri Apr 27 10:26:13 2018 -0400

    Bug 795597 - gegl crashes for a race ...
    
    ... between disposing a GeglTileHandlerChain and storing a tile
    (trimming the cache)
    
    Add gegl_tile_handler_cache_{connect,disconnect}(), which add/
    remove the cache to the global cache queue.  Cache handlers are
    connected upon construction, and disconnected upon destruction.
    While a cache is disconnected, it may not be accessed while
    trimming unrelated caches.
    
    In GeglTileStore, disconnect the cache before destroying the
    storage, so that other threads trimming an unrelated cache
    concurrently may not interfere with destruction.

 gegl/buffer/gegl-tile-handler-cache.c |   36 +++++++++++++++++++++++++++-----
 gegl/buffer/gegl-tile-handler-cache.h |    3 ++
 gegl/buffer/gegl-tile-storage.c       |   15 +++++++++++++
 3 files changed, 48 insertions(+), 6 deletions(-)
---
diff --git a/gegl/buffer/gegl-tile-handler-cache.c b/gegl/buffer/gegl-tile-handler-cache.c
index 6914fe1..cf76668 100644
--- a/gegl/buffer/gegl-tile-handler-cache.c
+++ b/gegl/buffer/gegl-tile-handler-cache.c
@@ -116,9 +116,7 @@ gegl_tile_handler_cache_init (GeglTileHandlerCache *cache)
   g_queue_init (&cache->queue);
   gegl_tile_cache_init ();
 
-  g_mutex_lock (&mutex);
-  g_queue_push_tail_link (&cache_queue, &cache->link);
-  g_mutex_unlock (&mutex);
+  gegl_tile_handler_cache_connect (cache);
 }
 
 static void
@@ -184,9 +182,7 @@ gegl_tile_handler_cache_dispose (GObject *object)
 {
   GeglTileHandlerCache *cache = GEGL_TILE_HANDLER_CACHE (object);
 
-  g_mutex_lock (&mutex);
-  g_queue_unlink (&cache_queue, &cache->link);
-  g_mutex_unlock (&mutex);
+  gegl_tile_handler_cache_disconnect (cache);
 
   gegl_tile_handler_cache_reinit (cache);
 
@@ -750,6 +746,34 @@ gegl_tile_handler_cache_new (void)
   return g_object_new (GEGL_TYPE_TILE_HANDLER_CACHE, NULL);
 }
 
+void
+gegl_tile_handler_cache_connect (GeglTileHandlerCache *cache)
+{
+  /* join the global cache queue */
+  if (! cache->link.data)
+    {
+      cache->link.data = cache;
+
+      g_mutex_lock (&mutex);
+      g_queue_push_tail_link (&cache_queue, &cache->link);
+      g_mutex_unlock (&mutex);
+    }
+}
+
+void
+gegl_tile_handler_cache_disconnect (GeglTileHandlerCache *cache)
+{
+  /* leave the global cache queue */
+  if (cache->link.data)
+    {
+      g_mutex_lock (&mutex);
+      g_queue_unlink (&cache_queue, &cache->link);
+      g_mutex_unlock (&mutex);
+
+      cache->link.data = NULL;
+    }
+}
+
 gsize
 gegl_tile_handler_cache_get_total (void)
 {
diff --git a/gegl/buffer/gegl-tile-handler-cache.h b/gegl/buffer/gegl-tile-handler-cache.h
index 094d716..ade3267 100644
--- a/gegl/buffer/gegl-tile-handler-cache.h
+++ b/gegl/buffer/gegl-tile-handler-cache.h
@@ -56,6 +56,9 @@ GType             gegl_tile_handler_cache_get_type           (void) G_GNUC_CONST
 
 GeglTileHandler * gegl_tile_handler_cache_new                (void);
 
+void              gegl_tile_handler_cache_connect            (GeglTileHandlerCache *cache);
+void              gegl_tile_handler_cache_disconnect         (GeglTileHandlerCache *cache);
+
 void              gegl_tile_handler_cache_insert             (GeglTileHandlerCache *cache,
                                                               GeglTile             *tile,
                                                               gint                  x,
diff --git a/gegl/buffer/gegl-tile-storage.c b/gegl/buffer/gegl-tile-storage.c
index 4a3c239..30a5ee3 100644
--- a/gegl/buffer/gegl-tile-storage.c
+++ b/gegl/buffer/gegl-tile-storage.c
@@ -120,6 +120,20 @@ gegl_tile_storage_remove_handler (GeglTileStorage *tile_storage,
 }
 
 static void
+gegl_tile_storage_dispose (GObject *object)
+{
+  GeglTileStorage *self = GEGL_TILE_STORAGE (object);
+
+  /* disconnect the cache before destruction, to avoid a race condition with
+   * other threads trimming the global cache through an unrelated cache
+   * handler.  see bug #795597.
+   */
+  gegl_tile_handler_cache_disconnect (self->cache);
+
+  (*G_OBJECT_CLASS (parent_class)->dispose)(object);
+}
+
+static void
 gegl_tile_storage_finalize (GObject *object)
 {
   GeglTileStorage *self = GEGL_TILE_STORAGE (object);
@@ -135,6 +149,7 @@ gegl_tile_storage_class_init (GeglTileStorageClass *class)
   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
 
   parent_class                = g_type_class_peek_parent (class);
+  gobject_class->dispose      = gegl_tile_storage_dispose;
   gobject_class->finalize     = gegl_tile_storage_finalize;
 
   gegl_tile_storage_signals[CHANGED] =


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]