Skip to content

Commit 0d6d33e

Browse files
committed
HP_MALLOC: Add "re-scanning" logic
Given that HP_MALLOC has fine-grained locking, if the big fragment shifts down from hash bucket N to bucket N-1 due to another process performing the allocation, we may actually "lose" it during our own scan, since bucket N-1 was empty and we're now waiting for bucket N to unlock. When it does unlock, it will also be empty. As a solution: retry the scan up to N times, as long as it's feasible! Many thanks to 46Labs for supporting this work!
1 parent 3634b39 commit 0d6d33e

File tree

1 file changed

+17
-5
lines changed

1 file changed

+17
-5
lines changed

mem/hp_malloc_dyn.h

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -633,25 +633,37 @@ void *hp_shm_malloc(struct hp_block *hpb, unsigned long size,
633633
struct hp_frag *frag;
634634
unsigned int init_hash, hash, sec_hash;
635635
unsigned long old_size;
636-
int i;
636+
int i = 0;
637637

638638
/* size must be a multiple of ROUNDTO */
639639
size = ROUNDUP(size);
640640

641641
/*search for a suitable free frag*/
642-
hash = init_hash = GET_HASH(size);
642+
init_hash = GET_HASH(size);
643643

644-
if (!hpb->free_hash[hash].is_optimized) {
645-
for (; hash < HP_HASH_SIZE; hash++) {
644+
if (!hpb->free_hash[init_hash].is_optimized) {
645+
rescan:
646+
for (hash = init_hash; hash < HP_HASH_SIZE; hash++) {
646647
SHM_LOCK(hash);
647648
for (frag = hpb->free_hash[hash].first; frag; frag = frag->nxt_free)
648649
if (frag->size >= size)
649650
goto found;
650651

651652
SHM_UNLOCK(hash);
652653
}
654+
655+
/*
656+
* Given that HP_MALLOC has fine-grained locking, if the big frag
657+
* shifts down from hash bucket N to bucket N-1 due to another
658+
* process performing the allocation, we may actually "lose" it during
659+
* our own scan, since bucket N-1 was empty and we're now block-waiting
660+
* for bucket N to unlock. So retry the scan as long as it's feasible!
661+
*/
662+
if (i++ < 10 && (long)hpb->size - get_stat_val(shm_rused) > 20L * size)
663+
goto rescan;
664+
653665
} else {
654-
for (i = 0, sec_hash = HP_HASH_SIZE +
666+
for (hash = init_hash, sec_hash = HP_HASH_SIZE +
655667
hash * shm_secondary_hash_size +
656668
optimized_get_indexes[hash];
657669
i < shm_secondary_hash_size;

0 commit comments

Comments
 (0)