@@ -116,6 +116,7 @@ struct critnib_node {
116
116
struct critnib_leaf {
117
117
word key ;
118
118
void * value ;
119
+ uint64_t ref_count ;
119
120
};
120
121
121
122
struct critnib {
@@ -336,6 +337,8 @@ int critnib_insert(struct critnib *c, word key, void *value, int update) {
336
337
337
338
utils_atomic_store_release_ptr ((void * * )& k -> key , (void * )key );
338
339
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 );
339
342
340
343
struct critnib_node * kn = (void * )((word )k | 1 );
341
344
@@ -486,6 +489,8 @@ void *critnib_remove(struct critnib *c, word key) {
486
489
c -> pending_del_nodes [del ] = n ;
487
490
488
491
del_leaf :
492
+ // clear the most significant bit of the ref_count
493
+ utils_atomic_and_u64 (& k -> ref_count , (1ULL << 63 ) - 1 );
489
494
value = k -> value ;
490
495
c -> pending_del_leaves [del ] = k ;
491
496
@@ -505,12 +510,14 @@ void *critnib_remove(struct critnib *c, word key) {
505
510
* we need only one that was valid at any point after the call started.
506
511
*/
507
512
void * critnib_get (struct critnib * c , word key ) {
513
+ struct critnib_leaf * k ;
514
+ struct critnib_node * n ;
508
515
uint64_t wrs1 , wrs2 ;
509
516
void * res ;
510
517
511
- do {
512
- struct critnib_node * n ;
518
+ int value_read = 0 ;
513
519
520
+ do {
514
521
utils_atomic_load_acquire_u64 (& c -> remove_count , & wrs1 );
515
522
utils_atomic_load_acquire_ptr ((void * * )& c -> root , (void * * )& n );
516
523
@@ -525,11 +532,31 @@ void *critnib_get(struct critnib *c, word key) {
525
532
}
526
533
527
534
/* ... 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
+ }
530
542
utils_atomic_load_acquire_u64 (& c -> remove_count , & wrs2 );
531
543
} while (wrs1 + DELETED_LIFE <= wrs2 );
532
544
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
+
533
560
return res ;
534
561
}
535
562
@@ -786,6 +813,17 @@ int critnib_find(struct critnib *c, uintptr_t key, enum find_dir_t dir,
786
813
} while (wrs1 + DELETED_LIFE <= wrs2 );
787
814
788
815
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
+
789
827
if (rkey ) {
790
828
* rkey = _rkey ;
791
829
}
0 commit comments