[gegl] buffer: improve thread-safety of tile-storage hot-tile manipulation
- From: N/A <ell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] buffer: improve thread-safety of tile-storage hot-tile manipulation
- Date: Tue, 15 May 2018 18:32:27 +0000 (UTC)
commit 1e2f7cbba76a478ef7bb8286e38fd8f25600995f
Author: Ell <ell_se yahoo com>
Date: Tue May 15 14:11:01 2018 -0400
buffer: improve thread-safety of tile-storage hot-tile manipulation
When inspecting the tile-storage's hot-tile, during a 1x1
gegl_buffer_{get,set}(), there is a window during which another
thread can replace the storage's hot-tile, dropping the current
hot-tile's reference, allowing it to be trimmed out from the
cache and freed, leaving us we a dangling pointer.
Add gegl_tile_storage_{steal,try_steal}_hot_tile(), which
atomically swap the storage's hot-tile with NULL, returning the
original tile, and gegl_tile_storage_take_hot_tile(), which
atomically sets the storage's hot-tile if it's NULL, and use these
functions to safely query and replace the storage's hot-tile.
This change does have a negative impact on the performance of 1x1
gegl_buffer_{get,set}() (as well as NEAREST gegl_buffer_sample()),
although it doesn't affect independent NEAREST samplers, since they
maintain a local hot-tile.
gegl/buffer/gegl-buffer-access.c | 20 ++++++---
gegl/buffer/gegl-buffer.c | 14 ++-----
gegl/buffer/gegl-tile-handler-cache.c | 17 +------
gegl/buffer/gegl-tile-storage.c | 71 +++++++++++++++++++++++++++++++++
gegl/buffer/gegl-tile-storage.h | 6 +++
5 files changed, 97 insertions(+), 31 deletions(-)
---
diff --git a/gegl/buffer/gegl-buffer-access.c b/gegl/buffer/gegl-buffer-access.c
index 36fbc52..1707f52 100644
--- a/gegl/buffer/gegl-buffer-access.c
+++ b/gegl/buffer/gegl-buffer-access.c
@@ -122,20 +122,21 @@ gegl_buffer_get_pixel (GeglBuffer *buffer,
gint indice_x = gegl_tile_indice (tiledx, tile_width);
gint indice_y = gegl_tile_indice (tiledy, tile_height);
- GeglTile *tile = buffer->tile_storage->hot_tile;
+ GeglTile *tile = gegl_tile_storage_steal_hot_tile (buffer->tile_storage);
if (!(tile &&
tile->x == indice_x &&
tile->y == indice_y))
{
if (gegl_config_threads()>1)
- g_rec_mutex_lock (&buffer->tile_storage->mutex);
+ g_rec_mutex_lock (&buffer->tile_storage->mutex);
+
+ if (tile)
+ gegl_tile_unref (tile);
- _gegl_buffer_drop_hot_tile (buffer);
tile = gegl_tile_source_get_tile ((GeglTileSource *) (buffer),
indice_x, indice_y,
0);
- buffer->tile_storage->hot_tile = tile;
if (gegl_config_threads()>1)
g_rec_mutex_unlock (&buffer->tile_storage->mutex);
@@ -158,6 +159,8 @@ gegl_buffer_get_pixel (GeglBuffer *buffer,
{
memcpy (buf, tp, px_size);
}
+
+ gegl_tile_storage_take_hot_tile (buffer->tile_storage, tile);
}
}
}
@@ -187,7 +190,7 @@ __gegl_buffer_set_pixel (GeglBuffer *buffer,
gint indice_x = gegl_tile_indice (tiledx, tile_width);
gint indice_y = gegl_tile_indice (tiledy, tile_height);
- GeglTile *tile = buffer->tile_storage->hot_tile;
+ GeglTile *tile = gegl_tile_storage_steal_hot_tile (buffer->tile_storage);
const Babl *fish = NULL;
gint px_size;
@@ -208,11 +211,12 @@ __gegl_buffer_set_pixel (GeglBuffer *buffer,
if (gegl_config_threads()>1)
g_rec_mutex_lock (&buffer->tile_storage->mutex);
- _gegl_buffer_drop_hot_tile (buffer);
+ if (tile)
+ gegl_tile_unref (tile);
+
tile = gegl_tile_source_get_tile ((GeglTileSource *) (buffer),
indice_x, indice_y,
0);
- buffer->tile_storage->hot_tile = tile;
if (gegl_config_threads()>1)
g_rec_mutex_unlock (&buffer->tile_storage->mutex);
@@ -235,6 +239,8 @@ __gegl_buffer_set_pixel (GeglBuffer *buffer,
memcpy (tp, buf, px_size);
gegl_tile_unlock (tile);
+
+ gegl_tile_storage_take_hot_tile (buffer->tile_storage, tile);
}
}
diff --git a/gegl/buffer/gegl-buffer.c b/gegl/buffer/gegl-buffer.c
index b4fa962..074d678 100644
--- a/gegl/buffer/gegl-buffer.c
+++ b/gegl/buffer/gegl-buffer.c
@@ -358,18 +358,12 @@ void
_gegl_buffer_drop_hot_tile (GeglBuffer *buffer)
{
GeglTileStorage *storage = buffer->tile_storage;
+ GeglTile *tile;
- if (gegl_config_threads()>1)
- g_rec_mutex_lock (&storage->mutex);
+ tile = gegl_tile_storage_steal_hot_tile (storage);
- if (storage->hot_tile)
- {
- gegl_tile_unref (storage->hot_tile);
- storage->hot_tile = NULL;
- }
-
- if (gegl_config_threads()>1)
- g_rec_mutex_unlock (&storage->mutex);
+ if (tile)
+ gegl_tile_unref (tile);
}
static void
diff --git a/gegl/buffer/gegl-tile-handler-cache.c b/gegl/buffer/gegl-tile-handler-cache.c
index cf76668..e7cdff9 100644
--- a/gegl/buffer/gegl-tile-handler-cache.c
+++ b/gegl/buffer/gegl-tile-handler-cache.c
@@ -126,21 +126,10 @@ drop_hot_tile (GeglTile *tile)
if (storage)
{
-#if 0 /* the storage's mutex should already be locked at this point */
- if (gegl_config_threads()>1)
- g_rec_mutex_lock (&storage->mutex);
-#endif
+ tile = gegl_tile_storage_try_steal_hot_tile (storage, tile);
- if (storage->hot_tile == tile)
- {
- gegl_tile_unref (storage->hot_tile);
- storage->hot_tile = NULL;
- }
-
-#if 0
- if (gegl_config_threads()>1)
- g_rec_mutex_unlock (&storage->mutex);
-#endif
+ if (tile)
+ gegl_tile_unref (tile);
}
}
diff --git a/gegl/buffer/gegl-tile-storage.c b/gegl/buffer/gegl-tile-storage.c
index 30a5ee3..9d162d1 100644
--- a/gegl/buffer/gegl-tile-storage.c
+++ b/gegl/buffer/gegl-tile-storage.c
@@ -26,6 +26,7 @@
#include "gegl-tile-handler-empty.h"
#include "gegl-tile-handler-zoom.h"
#include "gegl-tile-handler-private.h"
+#include "gegl-config.h"
G_DEFINE_TYPE (GeglTileStorage, gegl_tile_storage, GEGL_TYPE_TILE_HANDLER_CHAIN)
@@ -119,6 +120,76 @@ gegl_tile_storage_remove_handler (GeglTileStorage *tile_storage,
gegl_tile_handler_chain_bind (chain);
}
+GeglTile *
+gegl_tile_storage_steal_hot_tile (GeglTileStorage *tile_storage)
+{
+ GeglTile *tile;
+
+ if (gegl_config_threads()>1)
+ {
+ tile = g_atomic_pointer_get (&tile_storage->hot_tile);
+
+ if (tile &&
+ ! g_atomic_pointer_compare_and_exchange (&tile_storage->hot_tile,
+ tile, NULL))
+ {
+ tile = NULL;
+ }
+ }
+ else
+ {
+ tile = tile_storage->hot_tile;
+ tile_storage->hot_tile = NULL;
+ }
+
+ return tile;
+}
+
+GeglTile *
+gegl_tile_storage_try_steal_hot_tile (GeglTileStorage *tile_storage,
+ GeglTile *tile)
+{
+ if (gegl_config_threads()>1)
+ {
+ if (tile &&
+ ! g_atomic_pointer_compare_and_exchange (&tile_storage->hot_tile,
+ tile, NULL))
+ {
+ tile = NULL;
+ }
+ }
+ else
+ {
+ if (tile_storage->hot_tile == tile)
+ tile_storage->hot_tile = NULL;
+ else
+ tile = NULL;
+ }
+
+ return tile;
+}
+
+void
+gegl_tile_storage_take_hot_tile (GeglTileStorage *tile_storage,
+ GeglTile *tile)
+{
+ if (gegl_config_threads()>1)
+ {
+ if (! g_atomic_pointer_compare_and_exchange (&tile_storage->hot_tile,
+ NULL, tile))
+ {
+ gegl_tile_unref (tile);
+ }
+ }
+ else
+ {
+ if (! tile_storage->hot_tile)
+ tile_storage->hot_tile = tile;
+ else
+ gegl_tile_unref (tile);
+ }
+}
+
static void
gegl_tile_storage_dispose (GObject *object)
{
diff --git a/gegl/buffer/gegl-tile-storage.h b/gegl/buffer/gegl-tile-storage.h
index 2e256d5..1ce2515 100644
--- a/gegl/buffer/gegl-tile-storage.h
+++ b/gegl/buffer/gegl-tile-storage.h
@@ -65,4 +65,10 @@ gegl_tile_storage_new (GeglTileBackend *backend);
void gegl_tile_storage_add_handler (GeglTileStorage *tile_storage, GeglTileHandler *handler);
void gegl_tile_storage_remove_handler (GeglTileStorage *tile_storage, GeglTileHandler *handler);
+GeglTile * gegl_tile_storage_steal_hot_tile (GeglTileStorage *tile_storage);
+GeglTile * gegl_tile_storage_try_steal_hot_tile (GeglTileStorage *tile_storage,
+ GeglTile *tile);
+void gegl_tile_storage_take_hot_tile (GeglTileStorage *tile_storage,
+ GeglTile *tile);
+
#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]