Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/libgit2.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVicent Marti <tanoku@gmail.com>2011-05-17 01:51:52 +0400
committerVicent Marti <tanoku@gmail.com>2011-05-17 01:51:52 +0400
commit3de79280e3aa79eb9bc95fa1e5a69499ba448bd9 (patch)
treee33382098e902f8e89e6994bab7296ec91601bc7 /src/cache.c
parent1e70b96e661302a6411eb49cf6ffd66e57c29e0c (diff)
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.c20
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;