Skip to content

Commit 6c334bf

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

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) {
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

@@ -486,6 +494,11 @@ void *critnib_remove(struct critnib *c, word key) {
486494
c->pending_del_nodes[del] = n;
487495

488496
del_leaf:
497+
uint64_t ref_count = utils_atomic_decrement_u64(&k->ref_count);
498+
fprintf(stderr,
499+
"critnib_remove(): k->ref_count = %llu of k->key = %p\n",
500+
(unsigned long long)ref_count, (void *)k->key);
501+
489502
value = k->value;
490503
c->pending_del_leaves[del] = k;
491504

@@ -494,6 +507,28 @@ void *critnib_remove(struct critnib *c, word key) {
494507
return value;
495508
}
496509

510+
/*
511+
* critnib_release -- release a reference to a key
512+
*/
513+
int critnib_release(struct critnib *c, void *ref) {
514+
if (!c || !ref) {
515+
return -1;
516+
}
517+
518+
struct critnib_leaf *k = (struct critnib_leaf *)ref;
519+
520+
// (TODO HERE...)
521+
522+
/* decrement the reference count */
523+
if (utils_atomic_decrement_u64(&k->ref_count) == 0) {
524+
fprintf(stderr, "critnib_release(): k->ref_count = %llu of k->key = %p\n",
525+
(unsigned long long)k->ref_count, (void *)k->key);
526+
free_leaf(c, k);
527+
}
528+
529+
return 0;
530+
}
531+
497532
/*
498533
* critnib_get -- query for a key ("==" match), returns value or NULL
499534
*
@@ -504,13 +539,17 @@ void *critnib_remove(struct critnib *c, word key) {
504539
* Counterintuitively, it's pointless to return the most current answer,
505540
* we need only one that was valid at any point after the call started.
506541
*/
507-
void *critnib_get(struct critnib *c, word key) {
542+
void *critnib_get(struct critnib *c, word key, void **ref) {
543+
struct critnib_leaf *k;
544+
struct critnib_node *n;
508545
uint64_t wrs1, wrs2;
509-
void *res;
546+
void *res = NULL;
510547

511-
do {
512-
struct critnib_node *n;
548+
if (!ref) {
549+
return NULL;
550+
}
513551

552+
do {
514553
utils_atomic_load_acquire_u64(&c->remove_count, &wrs1);
515554
utils_atomic_load_acquire_ptr((void **)&c->root, (void **)&n);
516555

@@ -525,11 +564,16 @@ void *critnib_get(struct critnib *c, word key) {
525564
}
526565

527566
/* ... as we check it at the end. */
528-
struct critnib_leaf *k = to_leaf(n);
567+
k = to_leaf(n);
529568
res = (n && k->key == key) ? k->value : NULL;
530569
utils_atomic_load_acquire_u64(&c->remove_count, &wrs2);
531570
} while (wrs1 + DELETED_LIFE <= wrs2);
532571

572+
if (res) {
573+
utils_atomic_increment_u64(&k->ref_count);
574+
*ref = k;
575+
}
576+
533577
return res;
534578
}
535579

@@ -641,19 +685,29 @@ static struct critnib_leaf *find_le(struct critnib_node *__restrict n,
641685
*
642686
* Same guarantees as critnib_get().
643687
*/
644-
void *critnib_find_le(struct critnib *c, word key) {
688+
void *critnib_find_le(struct critnib *c, word key, void **ref) {
689+
struct critnib_leaf *k;
645690
uint64_t wrs1, wrs2;
646691
void *res;
647692

693+
if (!ref) {
694+
return NULL;
695+
}
696+
648697
do {
649698
utils_atomic_load_acquire_u64(&c->remove_count, &wrs1);
650699
struct critnib_node *n; /* avoid a subtle TOCTOU */
651700
utils_atomic_load_acquire_ptr((void **)&c->root, (void **)&n);
652-
struct critnib_leaf *k = n ? find_le(n, key) : NULL;
701+
k = n ? find_le(n, key) : NULL;
653702
res = k ? k->value : NULL;
654703
utils_atomic_load_acquire_u64(&c->remove_count, &wrs2);
655704
} while (wrs1 + DELETED_LIFE <= wrs2);
656705

706+
if (res) {
707+
utils_atomic_increment_u64(&k->ref_count);
708+
*ref = k;
709+
}
710+
657711
return res;
658712
}
659713

@@ -739,12 +793,16 @@ static struct critnib_leaf *find_ge(struct critnib_node *__restrict n,
739793
* critnib_find -- parametrized query, returns 1 if found
740794
*/
741795
int critnib_find(struct critnib *c, uintptr_t key, enum find_dir_t dir,
742-
uintptr_t *rkey, void **rvalue) {
796+
uintptr_t *rkey, void **rvalue, void **ref) {
743797
uint64_t wrs1, wrs2;
744798
struct critnib_leaf *k;
745799
uintptr_t _rkey = (uintptr_t)0x0;
746800
void **_rvalue = NULL;
747801

802+
if (!ref) {
803+
return 0;
804+
}
805+
748806
/* <42 ≡ ≤41 */
749807
if (dir < -1) {
750808
if (!key) {
@@ -786,6 +844,9 @@ int critnib_find(struct critnib *c, uintptr_t key, enum find_dir_t dir,
786844
} while (wrs1 + DELETED_LIFE <= wrs2);
787845

788846
if (k) {
847+
utils_atomic_increment_u64(&k->ref_count);
848+
*ref = k;
849+
789850
if (rkey) {
790851
*rkey = _rkey;
791852
}

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)