@@ -116,6 +116,7 @@ struct critnib_node {
116116struct critnib_leaf {
117117 word key ;
118118 void * value ;
119+ uint64_t ref_count ;
119120};
120121
121122struct critnib {
@@ -336,6 +337,8 @@ int critnib_insert(struct critnib *c, word key, void *value, int update) {
336337
337338 utils_atomic_store_release_ptr ((void * * )& k -> key , (void * )key );
338339 utils_atomic_store_release_ptr ((void * * )& k -> value , value );
340+ // set the most significant bit of the ref_count
341+ utils_atomic_store_release_u64 (& k -> ref_count , 1ULL << 63 );
339342
340343 struct critnib_node * kn = (void * )((word )k | 1 );
341344
@@ -486,6 +489,8 @@ void *critnib_remove(struct critnib *c, word key) {
486489 c -> pending_del_nodes [del ] = n ;
487490
488491del_leaf :
492+ // clear the most significant bit of the ref_count
493+ utils_atomic_and_u64 (& k -> ref_count , (1ULL << 63 ) - 1 );
489494 value = k -> value ;
490495 c -> pending_del_leaves [del ] = k ;
491496
@@ -505,12 +510,14 @@ void *critnib_remove(struct critnib *c, word key) {
505510 * we need only one that was valid at any point after the call started.
506511 */
507512void * critnib_get (struct critnib * c , word key ) {
513+ struct critnib_leaf * k ;
514+ struct critnib_node * n ;
508515 uint64_t wrs1 , wrs2 ;
509516 void * res ;
510517
511- do {
512- struct critnib_node * n ;
518+ int value_read = 0 ;
513519
520+ do {
514521 utils_atomic_load_acquire_u64 (& c -> remove_count , & wrs1 );
515522 utils_atomic_load_acquire_ptr ((void * * )& c -> root , (void * * )& n );
516523
@@ -525,11 +532,31 @@ void *critnib_get(struct critnib *c, word key) {
525532 }
526533
527534 /* ... as we check it at the end. */
528- struct critnib_leaf * k = to_leaf (n );
529- res = (n && k -> key == key ) ? k -> value : NULL ;
535+ k = to_leaf (n );
536+ if (n && k -> key == key ) {
537+ res = k -> value ;
538+ value_read = 1 ;
539+ } else {
540+ res = NULL ;
541+ }
530542 utils_atomic_load_acquire_u64 (& c -> remove_count , & wrs2 );
531543 } while (wrs1 + DELETED_LIFE <= wrs2 );
532544
545+ if (!value_read ) {
546+ return res ;
547+ }
548+
549+ // test the most significant bit of the ref_count
550+ uint64_t ref_count ;
551+ utils_atomic_load_acquire_u64 (& k -> ref_count , & ref_count );
552+ if ((ref_count & (1ULL << 63 )) == 0 ) {
553+ // the leaf was already removed
554+ return NULL ;
555+ }
556+
557+ // the leaf is still in use, increment the refcount and return the value
558+ utils_atomic_increment_u64 (& k -> ref_count );
559+
533560 return res ;
534561}
535562
@@ -786,6 +813,17 @@ int critnib_find(struct critnib *c, uintptr_t key, enum find_dir_t dir,
786813 } while (wrs1 + DELETED_LIFE <= wrs2 );
787814
788815 if (k ) {
816+ // test the most significant bit of the ref_count
817+ uint64_t ref_count ;
818+ utils_atomic_load_acquire_u64 (& k -> ref_count , & ref_count );
819+ if ((ref_count & (1ULL << 63 )) == 0 ) {
820+ // the leaf was already removed
821+ return 0 ;
822+ }
823+
824+ // the leaf is still in use, increment the refcount and return the value
825+ utils_atomic_increment_u64 (& k -> ref_count );
826+
789827 if (rkey ) {
790828 * rkey = _rkey ;
791829 }
0 commit comments