diff options
Diffstat (limited to 'libguile/weak-set.c')
-rw-r--r-- | libguile/weak-set.c | 38 |
1 files changed, 37 insertions, 1 deletions
diff --git a/libguile/weak-set.c b/libguile/weak-set.c index a1ae4ea6b..476e88627 100644 --- a/libguile/weak-set.c +++ b/libguile/weak-set.c @@ -308,6 +308,42 @@ compute_size_index (scm_t_weak_set *set) return i; } +static int +is_acceptable_size_index (scm_t_weak_set *set, int size_index) +{ + int computed = compute_size_index (set); + + if (size_index == computed) + /* We were going to grow or shrink, and allocating the new vector + didn't change the target size. */ + return 1; + + if (size_index == computed + 1) + { + /* We were going to enlarge the set, but allocating the new + vector finalized some objects, making an enlargement + unnecessary. It might still be a good idea to use the larger + set, though. (This branch also gets hit if, while allocating + the vector, some other thread was actively removing items from + the set. That is less likely, though.) */ + unsigned long new_lower = hashset_size[size_index] / 5; + + return set->size > new_lower; + } + + if (size_index == computed - 1) + { + /* We were going to shrink the set, but when we dropped the lock + to allocate the new vector, some other thread added elements to + the set. */ + return 0; + } + + /* The computed size differs from our newly allocated size by more + than one size index -- recalculate. */ + return 0; +} + static void resize_set (scm_t_weak_set *set) { @@ -328,7 +364,7 @@ resize_set (scm_t_weak_set *set) "weak set"); scm_i_pthread_mutex_unlock (&set->lock); } - while (new_size_index != compute_size_index (set)); + while (!is_acceptable_size_index (set, new_size_index)); old_entries = set->entries; old_size = set->size; |