Skip to content

Commit dfc62fd

Browse files
committed
[WIP!] critnib: add refcount WIP!
Signed-off-by: Lukasz Dorau <[email protected]>
1 parent a7f1d83 commit dfc62fd

File tree

6 files changed

+254
-79
lines changed

6 files changed

+254
-79
lines changed

src/critnib/critnib.c

Lines changed: 69 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ struct critnib_node {
116116
struct critnib_leaf {
117117
word key;
118118
void *value;
119+
uint64_t ref_count;
119120
};
120121

121122
struct critnib {
@@ -289,6 +290,11 @@ static void free_leaf(struct critnib *__restrict c,
289290
}
290291

291292
if (c->cb_free_leaf && k && k->value) {
293+
if (k->ref_count > 0) {
294+
fprintf(stderr, "free_leaf(): k->ref_count = %llu of k->key = %p\n",
295+
(unsigned long long)k->ref_count, (void *)k->key);
296+
}
297+
assert(k->ref_count == 0); // TODO: check ref_count
292298
c->cb_free_leaf(c->leaf_allocator, (void *)k->value);
293299
}
294300

@@ -336,6 +342,8 @@ int critnib_insert(struct critnib *c, word key, void *value, int update) {
336342

337343
utils_atomic_store_release_ptr((void **)&k->key, (void *)key);
338344
utils_atomic_store_release_ptr((void **)&k->value, value);
345+
// mark the leaf as valid (ref_count == 1)
346+
utils_atomic_store_release_u64(&k->ref_count, 1ULL);
339347

340348
struct critnib_node *kn = (void *)((word)k | 1);
341349

@@ -490,6 +498,11 @@ void *critnib_remove(struct critnib *c, word key) {
490498
c->pending_del_nodes[del] = n;
491499

492500
del_leaf:
501+
uint64_t ref_count = utils_atomic_decrement_u64(&k->ref_count);
502+
fprintf(stderr,
503+
"critnib_remove(): k->ref_count = %llu of k->key = %p\n",
504+
(unsigned long long)ref_count, (void *)k->key);
505+
493506
value = k->value;
494507
c->pending_del_leaves[del] = k;
495508

@@ -498,6 +511,28 @@ void *critnib_remove(struct critnib *c, word key) {
498511
return value;
499512
}
500513

514+
/*
515+
* critnib_release -- release a reference to a key
516+
*/
517+
int critnib_release(struct critnib *c, void *ref) {
518+
if (!c || !ref) {
519+
return -1;
520+
}
521+
522+
struct critnib_leaf *k = (struct critnib_leaf *)ref;
523+
524+
// (TODO HERE...)
525+
526+
/* decrement the reference count */
527+
if (utils_atomic_decrement_u64(&k->ref_count) == 0) {
528+
fprintf(stderr, "critnib_release(): k->ref_count = %llu of k->key = %p\n",
529+
(unsigned long long)k->ref_count, (void *)k->key);
530+
free_leaf(c, k);
531+
}
532+
533+
return 0;
534+
}
535+
501536
/*
502537
* critnib_get -- query for a key ("==" match), returns value or NULL
503538
*
@@ -508,13 +543,17 @@ void *critnib_remove(struct critnib *c, word key) {
508543
* Counterintuitively, it's pointless to return the most current answer,
509544
* we need only one that was valid at any point after the call started.
510545
*/
511-
void *critnib_get(struct critnib *c, word key) {
546+
void *critnib_get(struct critnib *c, word key, void **ref) {
547+
struct critnib_leaf *k;
548+
struct critnib_node *n;
512549
uint64_t wrs1, wrs2;
513-
void *res;
550+
void *res = NULL;
514551

515-
do {
516-
struct critnib_node *n;
552+
if (!ref) {
553+
return NULL;
554+
}
517555

556+
do {
518557
utils_atomic_load_acquire_u64(&c->remove_count, &wrs1);
519558
utils_atomic_load_acquire_ptr((void **)&c->root, (void **)&n);
520559

@@ -529,11 +568,16 @@ void *critnib_get(struct critnib *c, word key) {
529568
}
530569

531570
/* ... as we check it at the end. */
532-
struct critnib_leaf *k = to_leaf(n);
571+
k = to_leaf(n);
533572
res = (n && k->key == key) ? k->value : NULL;
534573
utils_atomic_load_acquire_u64(&c->remove_count, &wrs2);
535574
} while (wrs1 + DELETED_LIFE <= wrs2);
536575

576+
if (res) {
577+
utils_atomic_increment_u64(&k->ref_count);
578+
*ref = k;
579+
}
580+
537581
return res;
538582
}
539583

@@ -645,19 +689,29 @@ static struct critnib_leaf *find_le(struct critnib_node *__restrict n,
645689
*
646690
* Same guarantees as critnib_get().
647691
*/
648-
void *critnib_find_le(struct critnib *c, word key) {
692+
void *critnib_find_le(struct critnib *c, word key, void **ref) {
693+
struct critnib_leaf *k;
649694
uint64_t wrs1, wrs2;
650695
void *res;
651696

697+
if (!ref) {
698+
return NULL;
699+
}
700+
652701
do {
653702
utils_atomic_load_acquire_u64(&c->remove_count, &wrs1);
654703
struct critnib_node *n; /* avoid a subtle TOCTOU */
655704
utils_atomic_load_acquire_ptr((void **)&c->root, (void **)&n);
656-
struct critnib_leaf *k = n ? find_le(n, key) : NULL;
705+
k = n ? find_le(n, key) : NULL;
657706
res = k ? k->value : NULL;
658707
utils_atomic_load_acquire_u64(&c->remove_count, &wrs2);
659708
} while (wrs1 + DELETED_LIFE <= wrs2);
660709

710+
if (res) {
711+
utils_atomic_increment_u64(&k->ref_count);
712+
*ref = k;
713+
}
714+
661715
return res;
662716
}
663717

@@ -743,12 +797,16 @@ static struct critnib_leaf *find_ge(struct critnib_node *__restrict n,
743797
* critnib_find -- parametrized query, returns 1 if found
744798
*/
745799
int critnib_find(struct critnib *c, uintptr_t key, enum find_dir_t dir,
746-
uintptr_t *rkey, void **rvalue) {
800+
uintptr_t *rkey, void **rvalue, void **ref) {
747801
uint64_t wrs1, wrs2;
748802
struct critnib_leaf *k;
749803
uintptr_t _rkey = (uintptr_t)0x0;
750804
void **_rvalue = NULL;
751805

806+
if (!ref) {
807+
return 0;
808+
}
809+
752810
/* <42 ≡ ≤41 */
753811
if (dir < -1) {
754812
if (!key) {
@@ -790,6 +848,9 @@ int critnib_find(struct critnib *c, uintptr_t key, enum find_dir_t dir,
790848
} while (wrs1 + DELETED_LIFE <= wrs2);
791849

792850
if (k) {
851+
utils_atomic_increment_u64(&k->ref_count);
852+
*ref = k;
853+
793854
if (rkey) {
794855
*rkey = _rkey;
795856
}

src/critnib/critnib.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,14 @@ void critnib_delete(critnib *c);
3333

3434
int critnib_insert(critnib *c, uintptr_t key, void *value, int update);
3535
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);
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: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -812,8 +812,9 @@ size_t disjoint_pool_malloc_usable_size(void *pool, const void *ptr) {
812812
}
813813

814814
// 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);
815+
void *ref_slab = NULL;
816+
slab_t *slab = (slab_t *)critnib_find_le(disjoint_pool->known_slabs,
817+
(uintptr_t)ptr, &ref_slab);
817818
if (slab == NULL || ptr >= slab_get_end(slab)) {
818819
// memory comes directly from the provider
819820
umf_alloc_info_t allocInfo = {NULL, 0, NULL};
@@ -831,7 +832,12 @@ size_t disjoint_pool_malloc_usable_size(void *pool, const void *ptr) {
831832

832833
ptrdiff_t diff = (ptrdiff_t)ptr - (ptrdiff_t)unaligned_ptr;
833834

834-
return slab->bucket->size - diff;
835+
size_t size = slab->bucket->size - diff;
836+
837+
assert(ref_slab);
838+
critnib_release(disjoint_pool->known_slabs, ref_slab);
839+
840+
return size;
835841
}
836842

837843
umf_result_t disjoint_pool_free(void *pool, void *ptr) {
@@ -841,8 +847,9 @@ umf_result_t disjoint_pool_free(void *pool, void *ptr) {
841847
}
842848

843849
// 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);
850+
void *ref_slab = NULL;
851+
slab_t *slab = (slab_t *)critnib_find_le(disjoint_pool->known_slabs,
852+
(uintptr_t)ptr, &ref_slab);
846853

847854
if (slab == NULL || ptr >= slab_get_end(slab)) {
848855

@@ -889,6 +896,9 @@ umf_result_t disjoint_pool_free(void *pool, void *ptr) {
889896
utils_annotate_memory_inaccessible(unaligned_ptr, bucket->size);
890897
bucket_free_chunk(bucket, unaligned_ptr, slab, &to_pool);
891898

899+
assert(ref_slab);
900+
critnib_release(disjoint_pool->known_slabs, ref_slab);
901+
892902
if (disjoint_pool->params.pool_trace > 1) {
893903
bucket->free_count++;
894904
}

src/provider/provider_file_memory.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -311,9 +311,11 @@ static void file_finalize(void *provider) {
311311
uintptr_t key = 0;
312312
uintptr_t rkey = 0;
313313
void *rvalue = NULL;
314-
while (1 ==
315-
critnib_find(file_provider->mmaps, key, FIND_G, &rkey, &rvalue)) {
314+
void *ref = NULL;
315+
while (1 == critnib_find(file_provider->mmaps, key, FIND_G, &rkey, &rvalue,
316+
&ref)) {
316317
utils_munmap((void *)rkey, (size_t)rvalue);
318+
critnib_release(file_provider->mmaps, ref);
317319
critnib_remove(file_provider->mmaps, rkey);
318320
key = rkey;
319321
}
@@ -644,7 +646,9 @@ static umf_result_t file_allocation_split_cb(void *provider, void *ptr,
644646
return UMF_RESULT_SUCCESS;
645647
}
646648

647-
void *value = critnib_get(file_provider->fd_offset_map, (uintptr_t)ptr);
649+
void *ref_value = NULL;
650+
void *value =
651+
critnib_get(file_provider->fd_offset_map, (uintptr_t)ptr, &ref_value);
648652
if (value == NULL) {
649653
LOG_ERR("getting a value from the file descriptor offset map failed "
650654
"(addr=%p)",
@@ -658,6 +662,7 @@ static umf_result_t file_allocation_split_cb(void *provider, void *ptr,
658662

659663
uintptr_t new_key = (uintptr_t)ptr + firstSize;
660664
void *new_value = (void *)((uintptr_t)value + firstSize);
665+
critnib_release(file_provider->fd_offset_map, ref_value);
661666
int ret = critnib_insert(file_provider->fd_offset_map, new_key, new_value,
662667
0 /* update */);
663668
if (ret) {
@@ -734,14 +739,17 @@ static umf_result_t file_get_ipc_handle(void *provider, const void *ptr,
734739
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
735740
}
736741

737-
void *value = critnib_get(file_provider->fd_offset_map, (uintptr_t)ptr);
742+
void *ref_value = NULL;
743+
void *value =
744+
critnib_get(file_provider->fd_offset_map, (uintptr_t)ptr, &ref_value);
738745
if (value == NULL) {
739746
LOG_ERR("getting a value from the IPC cache failed (addr=%p)", ptr);
740747
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
741748
}
742749

743750
file_ipc_data_t *file_ipc_data = (file_ipc_data_t *)providerIpcData;
744751
file_ipc_data->offset_fd = (size_t)value - 1;
752+
critnib_release(file_provider->fd_offset_map, ref_value);
745753
file_ipc_data->size = size;
746754
strncpy(file_ipc_data->path, file_provider->path, PATH_MAX - 1);
747755
file_ipc_data->path[PATH_MAX - 1] = '\0';

src/provider/provider_os_memory.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1245,7 +1245,9 @@ static umf_result_t os_allocation_split(void *provider, void *ptr,
12451245
return UMF_RESULT_SUCCESS;
12461246
}
12471247

1248-
void *value = critnib_get(os_provider->fd_offset_map, (uintptr_t)ptr);
1248+
void *ref_value = NULL;
1249+
void *value =
1250+
critnib_get(os_provider->fd_offset_map, (uintptr_t)ptr, &ref_value);
12491251
if (value == NULL) {
12501252
LOG_ERR("os_allocation_split(): getting a value from the file "
12511253
"descriptor offset map failed (addr=%p)",
@@ -1255,6 +1257,7 @@ static umf_result_t os_allocation_split(void *provider, void *ptr,
12551257

12561258
uintptr_t new_key = (uintptr_t)ptr + firstSize;
12571259
void *new_value = (void *)((uintptr_t)value + firstSize);
1260+
critnib_release(os_provider->fd_offset_map, ref_value);
12581261
int ret = critnib_insert(os_provider->fd_offset_map, new_key, new_value,
12591262
0 /* update */);
12601263
if (ret) {
@@ -1324,7 +1327,9 @@ static umf_result_t os_get_ipc_handle(void *provider, const void *ptr,
13241327
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
13251328
}
13261329

1327-
void *value = critnib_get(os_provider->fd_offset_map, (uintptr_t)ptr);
1330+
void *ref_value = NULL;
1331+
void *value =
1332+
critnib_get(os_provider->fd_offset_map, (uintptr_t)ptr, &ref_value);
13281333
if (value == NULL) {
13291334
LOG_ERR("getting a value from the IPC cache failed (addr=%p)", ptr);
13301335
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
@@ -1333,6 +1338,7 @@ static umf_result_t os_get_ipc_handle(void *provider, const void *ptr,
13331338
os_ipc_data_t *os_ipc_data = (os_ipc_data_t *)providerIpcData;
13341339
os_ipc_data->pid = utils_getpid();
13351340
os_ipc_data->fd_offset = (size_t)value - 1;
1341+
critnib_release(os_provider->fd_offset_map, ref_value);
13361342
os_ipc_data->size = size;
13371343
os_ipc_data->protection = os_provider->protection;
13381344
os_ipc_data->visibility = os_provider->visibility;

0 commit comments

Comments
 (0)