Skip to content

Commit 65c4126

Browse files
committed
[WIP!] critnib: add refcount WIP!
Signed-off-by: Lukasz Dorau <lukasz.dorau@intel.com>
1 parent 78a16e1 commit 65c4126

File tree

6 files changed

+437
-104
lines changed

6 files changed

+437
-104
lines changed

src/critnib/critnib.c

Lines changed: 125 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ struct critnib_node {
116116
struct critnib_leaf {
117117
word key;
118118
void *value;
119+
void *to_be_freed;
120+
uint64_t ref_count;
119121
};
120122

121123
struct critnib {
@@ -194,7 +196,12 @@ struct critnib *critnib_new(free_leaf_t cb_free_leaf, void *leaf_allocator) {
194196
static void delete_node(struct critnib *c, struct critnib_node *__restrict n) {
195197
if (is_leaf(n)) {
196198
if (c->cb_free_leaf && to_leaf(n)) {
197-
c->cb_free_leaf(c->leaf_allocator, (void *)to_leaf(n)->value);
199+
if (to_leaf(n)->value) {
200+
c->cb_free_leaf(c->leaf_allocator, (void *)to_leaf(n)->value);
201+
} else if (to_leaf(n)->to_be_freed) {
202+
c->cb_free_leaf(c->leaf_allocator,
203+
(void *)to_leaf(n)->to_be_freed);
204+
}
198205
}
199206
umf_ba_global_free(to_leaf(n));
200207
} else {
@@ -233,8 +240,13 @@ void critnib_delete(struct critnib *c) {
233240
for (int i = 0; i < DELETED_LIFE; i++) {
234241
umf_ba_global_free(c->pending_del_nodes[i]);
235242
if (c->cb_free_leaf && c->pending_del_leaves[i]) {
236-
c->cb_free_leaf(c->leaf_allocator,
237-
(void *)c->pending_del_leaves[i]->value);
243+
if (c->pending_del_leaves[i]->value) {
244+
c->cb_free_leaf(c->leaf_allocator,
245+
(void *)c->pending_del_leaves[i]->value);
246+
} else if (c->pending_del_leaves[i]->to_be_freed) {
247+
c->cb_free_leaf(c->leaf_allocator,
248+
(void *)c->pending_del_leaves[i]->to_be_freed);
249+
}
238250
}
239251
umf_ba_global_free(c->pending_del_leaves[i]);
240252
}
@@ -288,8 +300,8 @@ static void free_leaf(struct critnib *__restrict c,
288300
return;
289301
}
290302

291-
if (c->cb_free_leaf && k && k->value) {
292-
c->cb_free_leaf(c->leaf_allocator, (void *)k->value);
303+
if (c->cb_free_leaf && k && k->to_be_freed) {
304+
c->cb_free_leaf(c->leaf_allocator, (void *)k->to_be_freed);
293305
}
294306

295307
utils_atomic_store_release_ptr((void **)&k->value, c->deleted_leaf);
@@ -334,8 +346,11 @@ int critnib_insert(struct critnib *c, word key, void *value, int update) {
334346

335347
utils_annotate_memory_no_check(k, sizeof(struct critnib_leaf));
336348

349+
utils_atomic_store_release_ptr(&k->to_be_freed, 0);
337350
utils_atomic_store_release_ptr((void **)&k->key, (void *)key);
338351
utils_atomic_store_release_ptr((void **)&k->value, value);
352+
// mark the leaf as valid (ref_count == 1)
353+
utils_atomic_store_release_u64(&k->ref_count, 1ULL);
339354

340355
struct critnib_node *kn = (void *)((word)k | 1);
341356

@@ -370,9 +385,9 @@ int critnib_insert(struct critnib *c, word key, void *value, int update) {
370385
word at = path ^ key;
371386
if (!at) {
372387
ASSERT(is_leaf(n));
373-
if (to_leaf(kn)->value == value) {
388+
if (to_leaf(kn)->to_be_freed == value) {
374389
// do not free the value
375-
to_leaf(kn)->value = NULL;
390+
to_leaf(kn)->to_be_freed = NULL;
376391
}
377392
free_leaf(c, to_leaf(kn));
378393

@@ -418,19 +433,31 @@ int critnib_insert(struct critnib *c, word key, void *value, int update) {
418433
/*
419434
* critnib_remove -- delete a key from the critnib structure, return its value
420435
*/
421-
void *critnib_remove(struct critnib *c, word key) {
436+
void *critnib_remove(struct critnib *c, word key, void **ref) {
422437
struct critnib_leaf *k;
423438
void *value = NULL;
424439

440+
if (!ref) {
441+
return NULL;
442+
}
443+
425444
utils_mutex_lock(&c->mutex);
426445

427446
struct critnib_node *n = c->root;
428447
if (!n) {
429448
goto not_found;
430449
}
431450

432-
word del =
433-
(utils_atomic_increment_u64(&c->remove_count) - 1) % DELETED_LIFE;
451+
word del;
452+
int i_del = 0;
453+
do {
454+
del = (utils_atomic_increment_u64(&c->remove_count) - 1) % DELETED_LIFE;
455+
k = c->pending_del_leaves[del];
456+
if (i_del++ == DELETED_LIFE) {
457+
break;
458+
}
459+
} while (k && (k->ref_count > 0));
460+
434461
free_node(c, c->pending_del_nodes[del]);
435462
free_leaf(c, c->pending_del_leaves[del]);
436463
c->pending_del_nodes[del] = NULL;
@@ -491,13 +518,40 @@ void *critnib_remove(struct critnib *c, word key) {
491518

492519
del_leaf:
493520
value = k->value;
521+
*ref = k;
522+
utils_atomic_store_release_ptr(&k->to_be_freed, value);
523+
utils_atomic_store_release_ptr((void **)&k->value, NULL);
494524
c->pending_del_leaves[del] = k;
495525

496526
not_found:
497527
utils_mutex_unlock(&c->mutex);
498528
return value;
499529
}
500530

531+
/*
532+
* critnib_release -- release a reference to a key
533+
*/
534+
int critnib_release(struct critnib *c, void *ref) {
535+
if (!c || !ref) {
536+
return -1;
537+
}
538+
539+
struct critnib_leaf *k = (struct critnib_leaf *)ref;
540+
541+
/* decrement the reference count */
542+
if (k->ref_count && (utils_atomic_decrement_u64(&k->ref_count) == 0) &&
543+
k->to_be_freed) {
544+
void *value = k->to_be_freed;
545+
utils_atomic_store_release_ptr(&k->to_be_freed, NULL);
546+
utils_atomic_store_release_u64(&k->key, 0);
547+
if (value && c->cb_free_leaf) {
548+
c->cb_free_leaf(c->leaf_allocator, value);
549+
}
550+
}
551+
552+
return 0;
553+
}
554+
501555
/*
502556
* critnib_get -- query for a key ("==" match), returns value or NULL
503557
*
@@ -508,13 +562,17 @@ void *critnib_remove(struct critnib *c, word key) {
508562
* Counterintuitively, it's pointless to return the most current answer,
509563
* we need only one that was valid at any point after the call started.
510564
*/
511-
void *critnib_get(struct critnib *c, word key) {
565+
void *critnib_get(struct critnib *c, word key, void **ref) {
566+
struct critnib_leaf *k;
567+
struct critnib_node *n;
512568
uint64_t wrs1, wrs2;
513-
void *res;
569+
void *res = NULL;
514570

515-
do {
516-
struct critnib_node *n;
571+
if (!ref) {
572+
return NULL;
573+
}
517574

575+
do {
518576
utils_atomic_load_acquire_u64(&c->remove_count, &wrs1);
519577
utils_atomic_load_acquire_ptr((void **)&c->root, (void **)&n);
520578

@@ -529,11 +587,25 @@ void *critnib_get(struct critnib *c, word key) {
529587
}
530588

531589
/* ... as we check it at the end. */
532-
struct critnib_leaf *k = to_leaf(n);
590+
k = to_leaf(n);
533591
res = (n && k->key == key) ? k->value : NULL;
534592
utils_atomic_load_acquire_u64(&c->remove_count, &wrs2);
535593
} while (wrs1 + DELETED_LIFE <= wrs2);
536594

595+
if (res) {
596+
uint64_t ref_count;
597+
utils_atomic_load_acquire_u64(&k->ref_count, &ref_count);
598+
if (ref_count == 0) {
599+
return NULL;
600+
}
601+
if (utils_atomic_increment_u64(&k->ref_count) == 1) {
602+
utils_atomic_decrement_u64(&k->ref_count);
603+
return NULL;
604+
}
605+
606+
*ref = k;
607+
}
608+
537609
return res;
538610
}
539611

@@ -645,19 +717,38 @@ static struct critnib_leaf *find_le(struct critnib_node *__restrict n,
645717
*
646718
* Same guarantees as critnib_get().
647719
*/
648-
void *critnib_find_le(struct critnib *c, word key) {
720+
void *critnib_find_le(struct critnib *c, word key, void **ref) {
721+
struct critnib_leaf *k;
649722
uint64_t wrs1, wrs2;
650723
void *res;
651724

725+
if (!ref) {
726+
return NULL;
727+
}
728+
652729
do {
653730
utils_atomic_load_acquire_u64(&c->remove_count, &wrs1);
654731
struct critnib_node *n; /* avoid a subtle TOCTOU */
655732
utils_atomic_load_acquire_ptr((void **)&c->root, (void **)&n);
656-
struct critnib_leaf *k = n ? find_le(n, key) : NULL;
733+
k = n ? find_le(n, key) : NULL;
657734
res = k ? k->value : NULL;
658735
utils_atomic_load_acquire_u64(&c->remove_count, &wrs2);
659736
} while (wrs1 + DELETED_LIFE <= wrs2);
660737

738+
if (res) {
739+
uint64_t ref_count;
740+
utils_atomic_load_acquire_u64(&k->ref_count, &ref_count);
741+
if (ref_count == 0) {
742+
return NULL;
743+
}
744+
if (utils_atomic_increment_u64(&k->ref_count) == 1) {
745+
utils_atomic_decrement_u64(&k->ref_count);
746+
return NULL;
747+
}
748+
749+
*ref = k;
750+
}
751+
661752
return res;
662753
}
663754

@@ -743,12 +834,16 @@ static struct critnib_leaf *find_ge(struct critnib_node *__restrict n,
743834
* critnib_find -- parametrized query, returns 1 if found
744835
*/
745836
int critnib_find(struct critnib *c, uintptr_t key, enum find_dir_t dir,
746-
uintptr_t *rkey, void **rvalue) {
837+
uintptr_t *rkey, void **rvalue, void **ref) {
747838
uint64_t wrs1, wrs2;
748839
struct critnib_leaf *k;
749840
uintptr_t _rkey = (uintptr_t)0x0;
750841
void **_rvalue = NULL;
751842

843+
if (!ref) {
844+
return 0;
845+
}
846+
752847
/* <42 ≡ ≤41 */
753848
if (dir < -1) {
754849
if (!key) {
@@ -790,6 +885,18 @@ int critnib_find(struct critnib *c, uintptr_t key, enum find_dir_t dir,
790885
} while (wrs1 + DELETED_LIFE <= wrs2);
791886

792887
if (k) {
888+
uint64_t ref_count;
889+
utils_atomic_load_acquire_u64(&k->ref_count, &ref_count);
890+
if (ref_count == 0) {
891+
return 0;
892+
}
893+
if (utils_atomic_increment_u64(&k->ref_count) == 1) {
894+
utils_atomic_decrement_u64(&k->ref_count);
895+
return 0;
896+
}
897+
898+
*ref = k;
899+
793900
if (rkey) {
794901
*rkey = _rkey;
795902
}

src/critnib/critnib.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,15 @@ critnib *critnib_new(free_leaf_t cb_free_leaf, void *leaf_allocator);
3232
void critnib_delete(critnib *c);
3333

3434
int critnib_insert(critnib *c, uintptr_t key, void *value, int update);
35-
void *critnib_remove(critnib *c, uintptr_t key);
36-
void *critnib_get(critnib *c, uintptr_t key);
37-
void *critnib_find_le(critnib *c, uintptr_t key);
35+
void *critnib_remove(critnib *c, uintptr_t key, void **ref);
36+
void *critnib_get(critnib *c, uintptr_t key, void **ref);
37+
void *critnib_find_le(critnib *c, uintptr_t key, void **ref);
3838
int critnib_find(critnib *c, uintptr_t key, enum find_dir_t dir,
39-
uintptr_t *rkey, void **rvalue);
39+
uintptr_t *rkey, void **rvalue, void **ref);
4040
void critnib_iter(critnib *c, uintptr_t min, uintptr_t max,
4141
int (*func)(uintptr_t key, void *value, void *privdata),
4242
void *privdata);
43+
int critnib_release(struct critnib *c, void *ref);
4344

4445
#ifdef __cplusplus
4546
}

src/pool/pool_disjoint.c

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,11 @@ static umf_result_t pool_unregister_slab(disjoint_pool_t *pool, slab_t *slab) {
231231
// TODO ASSERT_IS_ALIGNED((uintptr_t)slab_addr, bucket->size);
232232
LOG_DEBUG("slab: %p, start: %p", (void *)slab, slab_addr);
233233

234-
critnib_remove(slabs, (uintptr_t)slab_addr);
234+
void *ref_slabs = NULL;
235+
critnib_remove(slabs, (uintptr_t)slab_addr, &ref_slabs);
236+
if (ref_slabs) {
237+
critnib_release(slabs, ref_slabs);
238+
}
235239

236240
return UMF_RESULT_SUCCESS;
237241
}
@@ -812,8 +816,9 @@ size_t disjoint_pool_malloc_usable_size(void *pool, const void *ptr) {
812816
}
813817

814818
// check if given pointer is allocated inside any Disjoint Pool slab
815-
slab_t *slab =
816-
(slab_t *)critnib_find_le(disjoint_pool->known_slabs, (uintptr_t)ptr);
819+
void *ref_slab = NULL;
820+
slab_t *slab = (slab_t *)critnib_find_le(disjoint_pool->known_slabs,
821+
(uintptr_t)ptr, &ref_slab);
817822
if (slab == NULL || ptr >= slab_get_end(slab)) {
818823
// memory comes directly from the provider
819824
umf_alloc_info_t allocInfo = {NULL, 0, NULL};
@@ -831,7 +836,12 @@ size_t disjoint_pool_malloc_usable_size(void *pool, const void *ptr) {
831836

832837
ptrdiff_t diff = (ptrdiff_t)ptr - (ptrdiff_t)unaligned_ptr;
833838

834-
return slab->bucket->size - diff;
839+
size_t size = slab->bucket->size - diff;
840+
841+
assert(ref_slab);
842+
critnib_release(disjoint_pool->known_slabs, ref_slab);
843+
844+
return size;
835845
}
836846

837847
umf_result_t disjoint_pool_free(void *pool, void *ptr) {
@@ -841,8 +851,9 @@ umf_result_t disjoint_pool_free(void *pool, void *ptr) {
841851
}
842852

843853
// check if given pointer is allocated inside any Disjoint Pool slab
844-
slab_t *slab =
845-
(slab_t *)critnib_find_le(disjoint_pool->known_slabs, (uintptr_t)ptr);
854+
void *ref_slab = NULL;
855+
slab_t *slab = (slab_t *)critnib_find_le(disjoint_pool->known_slabs,
856+
(uintptr_t)ptr, &ref_slab);
846857

847858
if (slab == NULL || ptr >= slab_get_end(slab)) {
848859

@@ -889,6 +900,9 @@ umf_result_t disjoint_pool_free(void *pool, void *ptr) {
889900
utils_annotate_memory_inaccessible(unaligned_ptr, bucket->size);
890901
bucket_free_chunk(bucket, unaligned_ptr, slab, &to_pool);
891902

903+
assert(ref_slab);
904+
critnib_release(disjoint_pool->known_slabs, ref_slab);
905+
892906
if (disjoint_pool->params.pool_trace > 1) {
893907
bucket->free_count++;
894908
}

0 commit comments

Comments
 (0)