[gegl] tile-backend-swap: make thread safe; move more work to writer thread
- From: N/A <ell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] tile-backend-swap: make thread safe; move more work to writer thread
- Date: Sun, 23 Jul 2017 17:44:36 +0000 (UTC)
commit 5f4414f0261778644ba96db98cb9d0ea09ff6a6a
Author: Ell <ell_se yahoo com>
Date: Fri Jul 21 08:20:56 2017 -0400
tile-backend-swap: make thread safe; move more work to writer thread
Make the swap tile backend thread safe, by adding locks as necessary,
and by moving more of the work to the writer thread, to avoid having
to synchronize.
In particular, all reader threads share the same file destrcriptor,
so they must not try to read from the swap in parallel. Likewise,
all manipulation of the gap list has to be synchronized, and was
moved to the writer thread. This has the additional benefit that
storage reclamation for dead entries now happens in the writer thread,
before any outstanding write operations are performed, while, in turn,
storage allocation also happens in the writer thread, right before an
entry is written to the swap; this helps minimize the gaps between swap
entries.
Additionally, TILE_GET commands for tiles that are queued for writing
now return a COWed copy of the queued data, instead of a new copy.
This fixes ceratin artifacts in multithreaded programs. See
bug #784907.
gegl/buffer/gegl-tile-backend-swap.c | 589 +++++++++++++++++++---------------
1 files changed, 324 insertions(+), 265 deletions(-)
---
diff --git a/gegl/buffer/gegl-tile-backend-swap.c b/gegl/buffer/gegl-tile-backend-swap.c
index 50a34a0..f7b6364 100644
--- a/gegl/buffer/gegl-tile-backend-swap.c
+++ b/gegl/buffer/gegl-tile-backend-swap.c
@@ -61,16 +61,16 @@ static GObjectClass * parent_class = NULL;
typedef enum
{
OP_WRITE,
- OP_TRUNCATE,
+ OP_DESTROY,
} ThreadOp;
typedef struct
{
- guint64 offset;
- GList *link;
- gint x;
- gint y;
- gint z;
+ gint64 offset;
+ GList *link;
+ gint x;
+ gint y;
+ gint z;
} SwapEntry;
typedef struct
@@ -83,29 +83,30 @@ typedef struct
typedef struct
{
- guint64 start;
- guint64 end;
+ gint64 start;
+ gint64 end;
} SwapGap;
-static void gegl_tile_backend_swap_push_queue (ThreadParams *params);
-static void gegl_tile_backend_swap_write (ThreadParams *params);
+static void gegl_tile_backend_swap_push_queue (ThreadParams *params,
+ gboolean head);
+static void gegl_tile_backend_swap_resize (gint64 size);
+static SwapGap * gegl_tile_backend_swap_gap_new (gint64 start,
+ gint64 end);
+static gint64 gegl_tile_backend_swap_find_offset (gint tile_size);
+static void gegl_tile_backend_swap_write (ThreadParams *params);
+static void gegl_tile_backend_swap_destroy (ThreadParams *params);
static gpointer gegl_tile_backend_swap_writer_thread (gpointer ignored);
-static void gegl_tile_backend_swap_entry_read (GeglTileBackendSwap *self,
- SwapEntry *entry,
- guchar *dest);
+static GeglTile *gegl_tile_backend_swap_entry_read (GeglTileBackendSwap *self,
+ SwapEntry *entry);
static void gegl_tile_backend_swap_entry_write (GeglTileBackendSwap *self,
SwapEntry *entry,
GeglTile *tile);
static SwapEntry * gegl_tile_backend_swap_entry_create (gint x,
gint y,
gint z);
-static guint64 gegl_tile_backend_swap_find_offset (gint tile_size);
-static SwapGap * gegl_tile_backend_swap_gap_new (guint64 start,
- guint64 end);
static void gegl_tile_backend_swap_entry_destroy (GeglTileBackendSwap *self,
SwapEntry *entry);
-static void gegl_tile_backend_swap_resize (guint64 size);
static SwapEntry * gegl_tile_backend_swap_lookup_entry (GeglTileBackendSwap *self,
gint x,
gint y,
@@ -146,43 +147,127 @@ static void gegl_tile_backend_swap_init (GeglTileBackendSwap *se
void gegl_tile_backend_swap_cleanup (void);
-static gchar *path = NULL;
-static gint in_fd = -1;
-static gint out_fd = -1;
-static guint64 in_offset = 0;
-static guint64 out_offset = 0;
-static GList *gap_list = NULL;
-static guint64 total = 0;
+static gchar *path = NULL;
+static gint in_fd = -1;
+static gint out_fd = -1;
+static gint64 in_offset = 0;
+static gint64 out_offset = 0;
+static GList *gap_list = NULL;
+static gint64 total = 0;
static GThread *writer_thread = NULL;
static GQueue *queue = NULL;
static ThreadParams *in_progress = NULL;
static gboolean exit_thread = FALSE;
-static GMutex mutex;
+static GMutex read_mutex;
+static GMutex queue_mutex;
static GCond queue_cond;
static void
-gegl_tile_backend_swap_push_queue (ThreadParams *params)
+gegl_tile_backend_swap_push_queue (ThreadParams *params,
+ gboolean head)
{
- g_mutex_lock (&mutex);
-
- g_queue_push_tail (queue, params);
+ if (head)
+ g_queue_push_head (queue, params);
+ else
+ g_queue_push_tail (queue, params);
- if (params->operation == OP_WRITE)
+ if (params->entry)
params->entry->link = g_queue_peek_tail_link (queue);
/* wake up the writer thread */
g_cond_signal (&queue_cond);
+}
+
+static void
+gegl_tile_backend_swap_resize (gint64 size)
+{
+ total = size;
+
+ if (ftruncate (out_fd, total) != 0)
+ {
+ g_warning ("failed to resize swap file: %s", g_strerror (errno));
+ return;
+ }
+
+ GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "resized swap to %i", (gint)total);
+}
- g_mutex_unlock (&mutex);
+static SwapGap *
+gegl_tile_backend_swap_gap_new (gint64 start,
+ gint64 end)
+{
+ SwapGap *gap = g_slice_new (SwapGap);
+
+ gap->start = start;
+ gap->end = end;
+
+ return gap;
+}
+
+static gint64
+gegl_tile_backend_swap_find_offset (gint tile_size)
+{
+ SwapGap *gap;
+ gint64 offset;
+
+ if (gap_list)
+ {
+ GList *link = gap_list;
+
+ while (link)
+ {
+ gint64 length;
+
+ gap = link->data;
+ length = gap->end - gap->start;
+
+ if (length > tile_size)
+ {
+ offset = gap->start;
+ gap->start += tile_size;
+
+ return offset;
+ }
+ else if (length == tile_size)
+ {
+ offset = gap->start;
+ g_slice_free (SwapGap, gap);
+ gap_list = g_list_delete_link (gap_list, link);
+
+ return offset;
+ }
+
+ link = link->next;
+ }
+ }
+
+ offset = total;
+
+ gegl_tile_backend_swap_resize (total + 32 * tile_size);
+
+ gap = gegl_tile_backend_swap_gap_new (offset + tile_size, total);
+ gap_list = g_list_append (gap_list, gap);
+
+ return offset;
}
static void
gegl_tile_backend_swap_write (ThreadParams *params)
{
- gint to_be_written = params->length;
- guint64 offset = params->entry->offset;
+ gint to_be_written = params->length;
+ gint64 offset = params->entry->offset;
+
+ gegl_tile_backend_swap_ensure_exist ();
+
+ if (offset < 0)
+ {
+ /* storage for entry not allocated yet. allocate now. */
+ offset = gegl_tile_backend_swap_find_offset (to_be_written);
+
+ params->entry->offset = offset;
+ }
if (out_offset != offset)
{
@@ -216,100 +301,199 @@ gegl_tile_backend_swap_write (ThreadParams *params)
GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "writer thread wrote at %i", (gint)offset);
}
+static void
+gegl_tile_backend_swap_destroy (ThreadParams *params)
+{
+ gint64 start, end;
+ GList *hlink;
+
+ start = params->entry->offset;
+ end = start + params->length;
+
+ g_assert (start >= 0);
+
+ g_slice_free (SwapEntry, params->entry);
+
+ if ((hlink = gap_list))
+ while (hlink)
+ {
+ GList *llink = hlink->prev;
+ SwapGap *lgap, *hgap;
+
+ if (llink)
+ lgap = llink->data;
+
+ hgap = hlink->data;
+
+ /* attempt to merge lower, upper and this gap */
+ if (llink != NULL && lgap->end == start &&
+ hgap->start == end)
+ {
+ llink->next = hlink->next;
+ if (hlink->next)
+ hlink->next->prev = llink;
+ lgap->end = hgap->end;
+
+ g_slice_free (SwapGap, hgap);
+ hlink->next = NULL;
+ hlink->prev = NULL;
+ g_list_free (hlink);
+ break;
+ }
+ /* attempt to merge with upper gap */
+ else if (hgap->start == end)
+ {
+ hgap->start = start;
+ break;
+ }
+ /* attempt to merge with lower gap */
+ else if (llink != NULL && lgap->end == start)
+ {
+ lgap->end = end;
+ break;
+ }
+ /* create new gap */
+ else if (hgap->start > end)
+ {
+ lgap = gegl_tile_backend_swap_gap_new (start, end);
+ gap_list = g_list_insert_before (gap_list, hlink, lgap);
+ break;
+ }
+
+ /* if there's no more elements in the list after this */
+ else if (hlink->next == NULL)
+ {
+ /* attempt to merge with the last gap */
+ if (hgap->end == start)
+ {
+ hgap->end = end;
+ }
+ /* create a new gap in the end of the list */
+ else
+ {
+ GList *new_link;
+ hgap = gegl_tile_backend_swap_gap_new (start, end);
+ new_link = g_list_alloc ();
+ new_link->next = NULL;
+ new_link->prev = hlink;
+ new_link->data = hgap;
+ hlink->next = new_link;
+ }
+ break;
+ }
+
+ hlink = hlink->next;
+ }
+ else
+ gap_list = g_list_prepend (NULL,
+ gegl_tile_backend_swap_gap_new (start, end));
+}
+
static gpointer
gegl_tile_backend_swap_writer_thread (gpointer ignored)
{
+ g_mutex_lock (&queue_mutex);
+
while (TRUE)
{
ThreadParams *params;
- g_mutex_lock (&mutex);
-
while (g_queue_is_empty (queue) && !exit_thread)
- g_cond_wait (&queue_cond, &mutex);
+ g_cond_wait (&queue_cond, &queue_mutex);
if (exit_thread)
- {
- g_mutex_unlock (&mutex);
- GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "exiting writer thread");
- return NULL;
- }
+ break;
params = (ThreadParams *)g_queue_pop_head (queue);
- if (params->operation == OP_WRITE)
+ if (params->entry)
{
in_progress = params;
params->entry->link = NULL;
}
- g_mutex_unlock (&mutex);
+ g_mutex_unlock (&queue_mutex);
switch (params->operation)
{
case OP_WRITE:
gegl_tile_backend_swap_write (params);
break;
- case OP_TRUNCATE:
- if (ftruncate (out_fd, total) != 0)
- g_warning ("failed to resize swap file: %s", g_strerror (errno));
+ case OP_DESTROY:
+ gegl_tile_backend_swap_destroy (params);
break;
}
- g_mutex_lock (&mutex);
+ g_mutex_lock (&queue_mutex);
in_progress = NULL;
- if (params->operation == OP_WRITE)
+ if (params->tile)
gegl_tile_unref (params->tile);
g_slice_free (ThreadParams, params);
-
- g_mutex_unlock (&mutex);
}
+ g_mutex_unlock (&queue_mutex);
+ GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "exiting writer thread");
return NULL;
}
-static void
+static GeglTile *
gegl_tile_backend_swap_entry_read (GeglTileBackendSwap *self,
- SwapEntry *entry,
- guchar *dest)
+ SwapEntry *entry)
{
- gint tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self));
- gint to_be_read = tile_size;
- guint64 offset = entry->offset;
+ gint tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self));
+ gint to_be_read = tile_size;
+ gint64 offset;
+ GeglTile *tile;
+ guchar *dest;
- gegl_tile_backend_swap_ensure_exist ();
+ g_mutex_lock (&queue_mutex);
if (entry->link || in_progress)
{
ThreadParams *queued_op = NULL;
- g_mutex_lock (&mutex);
if (entry->link)
queued_op = entry->link->data;
- else if (in_progress && in_progress->entry == entry)
+ else if (in_progress->entry == entry)
queued_op = in_progress;
if (queued_op)
{
- memcpy (dest, gegl_tile_get_data (queued_op->tile), to_be_read);
- g_mutex_unlock (&mutex);
+ tile = gegl_tile_dup (queued_op->tile);
+ g_mutex_unlock (&queue_mutex);
GEGL_NOTE(GEGL_DEBUG_TILE_BACKEND, "read entry %i, %i, %i from queue", entry->x, entry->y,
entry->z);
- return;
+ return tile;
}
+ }
- g_mutex_unlock (&mutex);
+ offset = entry->offset;
+
+ g_mutex_unlock (&queue_mutex);
+
+ if (offset < 0 || in_fd < 0)
+ {
+ g_warning ("no swap storage allocated for tile");
+ return NULL;
}
+ tile = gegl_tile_new (tile_size);
+ dest = gegl_tile_get_data (tile);
+ gegl_tile_mark_as_stored (tile);
+
+ g_mutex_lock (&read_mutex);
+
if (in_offset != offset)
{
if (lseek (in_fd, offset, SEEK_SET) < 0)
{
+ g_mutex_unlock (&read_mutex);
+
g_warning ("unable to seek to tile in buffer: %s", g_strerror (errno));
- return;
+ return tile;
}
in_offset = offset;
}
@@ -322,16 +506,22 @@ gegl_tile_backend_swap_entry_read (GeglTileBackendSwap *self,
byte_read = read (in_fd, dest + tile_size - to_be_read, to_be_read);
if (byte_read <= 0)
{
+ g_mutex_unlock (&read_mutex);
+
g_message ("unable to read tile data from swap: "
"%s (%d/%d bytes read) %s",
g_strerror (errno), byte_read, to_be_read, error?error->message:"--");
- return;
+ return tile;
}
to_be_read -= byte_read;
in_offset += byte_read;
}
+ g_mutex_unlock (&read_mutex);
+
GEGL_NOTE(GEGL_DEBUG_TILE_BACKEND, "read entry %i, %i, %i from %i", entry->x, entry->y, entry->z,
(gint)offset);
+
+ return tile;
}
static void
@@ -342,25 +532,19 @@ gegl_tile_backend_swap_entry_write (GeglTileBackendSwap *self,
ThreadParams *params;
gint length = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self));
- gegl_tile_backend_swap_ensure_exist ();
+ g_mutex_lock (&queue_mutex);
if (entry->link)
{
- g_mutex_lock (&mutex);
+ params = entry->link->data;
+ g_assert (params->operation == OP_WRITE);
+ gegl_tile_unref (params->tile);
+ params->tile = gegl_tile_dup (tile);
+ g_mutex_unlock (&queue_mutex);
- if (entry->link)
- {
- params = entry->link->data;
- gegl_tile_unref (params->tile);
- params->tile = gegl_tile_dup (tile);
- g_mutex_unlock (&mutex);
+ GEGL_NOTE(GEGL_DEBUG_TILE_BACKEND, "tile %i, %i, %i at %i is already enqueued, changed data",
entry->x, entry->y, entry->z, (gint)entry->offset);
- GEGL_NOTE(GEGL_DEBUG_TILE_BACKEND, "tile %i, %i, %i at %i is already enqueued, changed data",
entry->x, entry->y, entry->z, (gint)entry->offset);
-
- return;
- }
-
- g_mutex_unlock (&mutex);
+ return;
}
params = g_slice_new0 (ThreadParams);
@@ -369,7 +553,9 @@ gegl_tile_backend_swap_entry_write (GeglTileBackendSwap *self,
params->tile = gegl_tile_dup (tile);
params->entry = entry;
- gegl_tile_backend_swap_push_queue (params);
+ gegl_tile_backend_swap_push_queue (params, /* head = */ FALSE);
+
+ g_mutex_unlock (&queue_mutex);
GEGL_NOTE(GEGL_DEBUG_TILE_BACKEND, "pushed write of entry %i, %i, %i at %i", entry->x, entry->y, entry->z,
(gint)entry->offset);
}
@@ -381,191 +567,65 @@ gegl_tile_backend_swap_entry_create (gint x,
{
SwapEntry *entry = g_slice_new0 (SwapEntry);
- entry->x = x;
- entry->y = y;
- entry->z = z;
- entry->link = NULL;
+ entry->x = x;
+ entry->y = y;
+ entry->z = z;
+ entry->link = NULL;
+ entry->offset = -1;
return entry;
}
-static guint64
-gegl_tile_backend_swap_find_offset (gint tile_size)
-{
- SwapGap *gap;
- guint64 offset;
-
- if (gap_list)
- {
- GList *link = gap_list;
-
- while (link)
- {
- guint64 length;
-
- gap = link->data;
- length = gap->end - gap->start;
-
- if (length > tile_size)
- {
- offset = gap->start;
- gap->start += tile_size;
-
- return offset;
- }
- else if (length == tile_size)
- {
- offset = gap->start;
- g_slice_free (SwapGap, gap);
- gap_list = g_list_delete_link (gap_list, link);
-
- return offset;
- }
-
- link = link->next;
- }
- }
-
- offset = total;
-
- gegl_tile_backend_swap_resize (total + 32 * tile_size);
-
- gap = gegl_tile_backend_swap_gap_new (offset + tile_size, total);
- gap_list = g_list_append (gap_list, gap);
-
- return offset;
-}
-
-static SwapGap *
-gegl_tile_backend_swap_gap_new (guint64 start,
- guint64 end)
-{
- SwapGap *gap = g_slice_new (SwapGap);
-
- gap->start = start;
- gap->end = end;
-
- return gap;
-}
-
static void
gegl_tile_backend_swap_entry_destroy (GeglTileBackendSwap *self,
SwapEntry *entry)
{
- guint64 start, end;
- gint tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self));
- GList *hlink;
+ ThreadParams *params;
if (entry->link)
{
- GList *link;
+ GList *link = entry->link;
+ ThreadParams *queued_op = link->data;
- g_mutex_lock (&mutex);
+ if (queued_op->tile)
+ {
+ gegl_tile_unref (queued_op->tile);
+ queued_op->tile = NULL;
+ }
- if ((link = entry->link))
+ if (entry->offset >= 0)
+ {
+ /* the queued op's entry already has storage allocated to it, which
+ * needs to be reclaimed. change it to an OP_DESTROY, and move it to
+ * the top.
+ */
+ queued_op->operation = OP_DESTROY;
+
+ g_queue_unlink (queue, link);
+ g_queue_push_head_link (queue, link);
+ }
+ else
{
- ThreadParams *queued_op = link->data;
+ /* the queued op's entry doesn't have storage allocated to it, so we
+ * can simply free it here.
+ */
g_queue_delete_link (queue, link);
- gegl_tile_unref (queued_op->tile);
g_slice_free (ThreadParams, queued_op);
+ g_slice_free (SwapEntry, entry);
}
- g_mutex_unlock (&mutex);
+ return;
}
- start = entry->offset;
- end = start + tile_size;
-
- if ((hlink = gap_list))
- while (hlink)
- {
- GList *llink = hlink->prev;
- SwapGap *lgap, *hgap;
-
- if (llink)
- lgap = llink->data;
-
- hgap = hlink->data;
-
- /* attempt to merge lower, upper and this gap */
- if (llink != NULL && lgap->end == start &&
- hgap->start == end)
- {
- llink->next = hlink->next;
- if (hlink->next)
- hlink->next->prev = llink;
- lgap->end = hgap->end;
-
- g_slice_free (SwapGap, hgap);
- hlink->next = NULL;
- hlink->prev = NULL;
- g_list_free (hlink);
- break;
- }
- /* attempt to merge with upper gap */
- else if (hgap->start == end)
- {
- hgap->start = start;
- break;
- }
- /* attempt to merge with lower gap */
- else if (llink != NULL && lgap->end == start)
- {
- lgap->end = end;
- break;
- }
- /* create new gap */
- else if (hgap->start > end)
- {
- lgap = gegl_tile_backend_swap_gap_new (start, end);
- gap_list = g_list_insert_before (gap_list, hlink, lgap);
- break;
- }
-
- /* if there's no more elements in the list after this */
- else if (hlink->next == NULL)
- {
- /* attempt to merge with the last gap */
- if (hgap->end == start)
- {
- hgap->end = end;
- }
- /* create a new gap in the end of the list */
- else
- {
- GList *new_link;
- hgap = gegl_tile_backend_swap_gap_new (start, end);
- new_link = g_list_alloc ();
- new_link->next = NULL;
- new_link->prev = hlink;
- new_link->data = hgap;
- hlink->next = new_link;
- }
- break;
- }
-
- hlink = hlink->next;
- }
- else
- gap_list = g_list_prepend (NULL,
- gegl_tile_backend_swap_gap_new (start, end));
-
- g_hash_table_remove (self->index, entry);
- g_slice_free (SwapEntry, entry);
-}
-
-static void
-gegl_tile_backend_swap_resize (guint64 size)
-{
- ThreadParams *params;
-
- total = size;
- params = g_slice_new0 (ThreadParams);
- params->operation = OP_TRUNCATE;
-
- gegl_tile_backend_swap_push_queue (params);
+ params = g_slice_new0 (ThreadParams);
+ params->operation = OP_DESTROY;
+ params->length = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self));
+ params->entry = entry;
- GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "pushed resize to %i", (gint)total);
+ /* push the destroy op at the top of the queue, so that it gets served before
+ * any write ops, which are then free to reuse the reclaimed space.
+ */
+ gegl_tile_backend_swap_push_queue (params, /* head = */ TRUE);
}
static SwapEntry *
@@ -587,8 +647,6 @@ gegl_tile_backend_swap_get_tile (GeglTileSource *self,
{
GeglTileBackendSwap *tile_backend_swap;
SwapEntry *entry;
- GeglTile *tile = NULL;
- gint tile_size;
tile_backend_swap = GEGL_TILE_BACKEND_SWAP (self);
entry = gegl_tile_backend_swap_lookup_entry (tile_backend_swap, x, y, z);
@@ -596,13 +654,7 @@ gegl_tile_backend_swap_get_tile (GeglTileSource *self,
if (!entry)
return NULL;
- tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self));
- tile = gegl_tile_new (tile_size);
- gegl_tile_mark_as_stored (tile);
-
- gegl_tile_backend_swap_entry_read (tile_backend_swap, entry, gegl_tile_get_data (tile));
-
- return tile;
+ return gegl_tile_backend_swap_entry_read (tile_backend_swap, entry);
}
static gpointer
@@ -620,12 +672,9 @@ gegl_tile_backend_swap_set_tile (GeglTileSource *self,
tile_backend_swap = GEGL_TILE_BACKEND_SWAP (backend);
entry = gegl_tile_backend_swap_lookup_entry (tile_backend_swap, x, y, z);
- gegl_tile_backend_swap_ensure_exist ();
-
if (entry == NULL)
{
- entry = gegl_tile_backend_swap_entry_create (x, y, z);
- entry->offset = gegl_tile_backend_swap_find_offset (gegl_tile_backend_get_tile_size (backend));
+ entry = gegl_tile_backend_swap_entry_create (x, y, z);
g_hash_table_insert (tile_backend_swap->index, entry, entry);
}
@@ -655,7 +704,13 @@ gegl_tile_backend_swap_void_tile (GeglTileSource *self,
{
GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "void tile %i, %i, %i", x, y, z);
+ g_hash_table_remove (tile_backend_swap->index, entry);
+
+ g_mutex_lock (&queue_mutex);
+
gegl_tile_backend_swap_entry_destroy (tile_backend_swap, entry);
+
+ g_mutex_unlock (&queue_mutex);
}
return NULL;
@@ -769,17 +824,21 @@ gegl_tile_backend_swap_finalize (GObject *object)
if (self->index)
{
- GList *tiles = g_hash_table_get_keys (self->index);
-
- if (tiles != NULL)
+ if (g_hash_table_size (self->index) > 0)
{
- GList *iter;
+ GHashTableIter iter;
+ gpointer key;
+ gpointer value;
- for (iter = tiles; iter; iter = iter->next)
- gegl_tile_backend_swap_entry_destroy (self, iter->data);
- }
+ g_hash_table_iter_init (&iter, self->index);
+
+ g_mutex_lock (&queue_mutex);
- g_list_free (tiles);
+ while (g_hash_table_iter_next (&iter, &key, &value))
+ gegl_tile_backend_swap_entry_destroy (self, value);
+
+ g_mutex_unlock (&queue_mutex);
+ }
g_hash_table_unref (self->index);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]