diff options
author | Vicent Marti <tanoku@gmail.com> | 2011-05-17 00:51:52 +0300 |
---|---|---|
committer | Vicent Marti <tanoku@gmail.com> | 2011-05-17 00:51:52 +0300 |
commit | 3de79280e3aa79eb9bc95fa1e5a69499ba448bd9 (patch) | |
tree | e33382098e902f8e89e6994bab7296ec91601bc7 /src/cache.c | |
parent | 1e70b96e661302a6411eb49cf6ffd66e57c29e0c (diff) | |
download | libgit2-3de79280e3aa79eb9bc95fa1e5a69499ba448bd9.tar.gz |
cache: Fix deadlock
Do not try to adquire the same node lock twice when the cuckoo hashing
resolves to the same node.
Diffstat (limited to 'src/cache.c')
-rw-r--r-- | src/cache.c | 20 |
1 files changed, 14 insertions, 6 deletions
diff --git a/src/cache.c b/src/cache.c index 0509afd46..6e4ad4c9e 100644 --- a/src/cache.c +++ b/src/cache.c @@ -110,7 +110,7 @@ void *git_cache_try_store(git_cache *cache, void *entry) cache_node *nodes[GIT_CACHE_OPENADR], *lru_node; const uint32_t *hash; const git_oid *oid; - size_t i; + size_t i, j, node_count; oid = &((git_cached_obj*)entry)->oid; hash = (const uint32_t *)oid->id; @@ -119,16 +119,24 @@ void *git_cache_try_store(git_cache *cache, void *entry) * the cache now owns it */ git_cached_obj_incref(entry); + node_count = 0; for (i = 0; i < GIT_CACHE_OPENADR; ++i) { size_t pos = hash[i] & cache->size_mask; + cache_node *node = &cache->nodes[pos]; + + for (j = 0; j < node_count; ++j) + if (nodes[j] == node) + break; - nodes[i] = &cache->nodes[pos]; - git_mutex_lock(&nodes[i]->lock); + if (j == node_count) { + nodes[node_count++] = node; + git_mutex_lock(node); + } } lru_node = nodes[0]; - for (i = 0; i < GIT_CACHE_OPENADR; ++i) { + for (i = 0; i < node_count; ++i) { if (nodes[i]->ptr == NULL) { nodes[i]->ptr = entry; @@ -145,7 +153,7 @@ void *git_cache_try_store(git_cache *cache, void *entry) lru_node = nodes[i]; } - if (i == GIT_CACHE_OPENADR) { + if (i == node_count) { void *old_entry = lru_node->ptr; assert(old_entry); @@ -158,7 +166,7 @@ void *git_cache_try_store(git_cache *cache, void *entry) * returning it to the user */ git_cached_obj_incref(entry); - for (i = 0; i < GIT_CACHE_OPENADR; ++i) + for (i = 0; i < node_count; ++i) git_mutex_unlock(&nodes[i]->lock); return entry; |