diff options
author | Robin Watts <robin.watts@artifex.com> | 2013-04-22 15:14:38 +0100 |
---|---|---|
committer | Robin Watts <robin.watts@artifex.com> | 2013-04-22 15:22:29 +0100 |
commit | 2ea11eace69fe5a2d88f374a253a3deb05804f2d (patch) | |
tree | e6e1cfff1abdf62f3da53aa053897f7a26c535d3 /fitz/base_hash.c | |
parent | 784fc400b3415f5120e3eef59a43e519c6a06fe0 (diff) | |
download | mupdf-2ea11eace69fe5a2d88f374a253a3deb05804f2d.tar.xz |
Fix various multi-threading problems with the store.
When resizing the hash table, we have a special case to cope with
someone else resizing the table before we get a chance to. In this
rare situation we were unlocking (regardless of whether we should
have been), and failing to relock. Fixed here.
When storing an item, I recently changed the code to put the new
item into the hash before ensuring that we had enough space. This
change was motivated by us wanting not to evict to make room only
to find that we didn't need the room as there was a duplicate
entry anyway.
In so doing, this opened up a potential race condition where
another thread could 'find' the item from the hash before it had
been filled out. To solve this, we move the "filling out" of the
item entries earlier in the function.
Another problem is found due to the same block of code; as soon
as a new item is put into the hash, it can be found elsewhere.
Any attempt to manipulate it's linked list will fail. We therefore
set all new items with their prev/next pointers pointing to
themselves, enabling us to spot this special case and avoid
corrupting the linked list.
Diffstat (limited to 'fitz/base_hash.c')
-rw-r--r-- | fitz/base_hash.c | 7 |
1 files changed, 6 insertions, 1 deletions
diff --git a/fitz/base_hash.c b/fitz/base_hash.c index 48bab138..037988cb 100644 --- a/fitz/base_hash.c +++ b/fitz/base_hash.c @@ -141,6 +141,8 @@ do_hash_insert(fz_context *ctx, fz_hash_table *table, void *key, void *val, unsi } } +/* Entered with the lock taken, held throughout and at exit, UNLESS the lock + * is the alloc lock in which case it may be momentarily dropped. */ static void fz_resize_hash(fz_context *ctx, fz_hash_table *table, int newsize) { @@ -166,8 +168,11 @@ fz_resize_hash(fz_context *ctx, fz_hash_table *table, int newsize) if (table->size >= newsize) { /* Someone else fixed it before we could lock! */ - fz_unlock(ctx, table->lock); + if (table->lock == FZ_LOCK_ALLOC) + fz_unlock(ctx, table->lock); fz_free(ctx, newents); + if (table->lock == FZ_LOCK_ALLOC) + fz_lock(ctx, table->lock); return; } } |