11/*
22 *
3- * Copyright (C) 2023-2024 Intel Corporation
3+ * Copyright (C) 2023-2025 Intel Corporation
44 *
55 * Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
66 * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
@@ -110,6 +110,7 @@ struct critnib_node {
110110 struct critnib_node * child [SLNODES ];
111111 word path ;
112112 sh_t shift ;
113+ size_t a ;
113114};
114115
115116struct critnib_leaf {
@@ -118,7 +119,8 @@ struct critnib_leaf {
118119};
119120
120121struct critnib {
121- struct critnib_node * root ;
122+ CACHE_ALIGNED struct critnib_node * root ;
123+ CACHE_ALIGNED uint64_t remove_count ;
122124
123125 /* pool of freed nodes: singly linked list, next at child[0] */
124126 struct critnib_node * deleted_node ;
@@ -128,29 +130,10 @@ struct critnib {
128130 struct critnib_node * pending_del_nodes [DELETED_LIFE ];
129131 struct critnib_leaf * pending_del_leaves [DELETED_LIFE ];
130132
131- uint64_t remove_count ;
132133
133134 struct utils_mutex_t mutex ; /* writes/removes */
134135};
135136
136- /*
137- * atomic load
138- */
139- static void load (void * src , void * dst ) {
140- utils_atomic_load_acquire ((word * )src , (word * )dst );
141- }
142-
143- static void load64 (uint64_t * src , uint64_t * dst ) {
144- utils_atomic_load_acquire (src , dst );
145- }
146-
147- /*
148- * atomic store
149- */
150- static void store (void * dst , void * src ) {
151- utils_atomic_store_release ((word * )dst , (word )src );
152- }
153-
154137/*
155138 * internal: is_leaf -- check tagged pointer for leafness
156139 */
@@ -180,7 +163,7 @@ static inline unsigned slice_index(word key, sh_t shift) {
180163 * critnib_new -- allocates a new critnib structure
181164 */
182165struct critnib * critnib_new (void ) {
183- struct critnib * c = umf_ba_global_alloc (sizeof (struct critnib ));
166+ struct critnib * c = umf_ba_global_aligned_alloc (sizeof (struct critnib ), 64 );
184167 if (!c ) {
185168 return NULL ;
186169 }
@@ -272,7 +255,7 @@ static void free_node(struct critnib *__restrict c,
272255 */
273256static struct critnib_node * alloc_node (struct critnib * __restrict c ) {
274257 if (!c -> deleted_node ) {
275- return umf_ba_global_alloc (sizeof (struct critnib_node ));
258+ return umf_ba_global_aligned_alloc (sizeof (struct critnib_node ), 64 );
276259 }
277260
278261 struct critnib_node * n = c -> deleted_node ;
@@ -303,7 +286,7 @@ static void free_leaf(struct critnib *__restrict c,
303286 */
304287static struct critnib_leaf * alloc_leaf (struct critnib * __restrict c ) {
305288 if (!c -> deleted_leaf ) {
306- return umf_ba_global_alloc (sizeof (struct critnib_leaf ));
289+ return umf_ba_global_aligned_alloc (sizeof (struct critnib_leaf ), 64 );
307290 }
308291
309292 struct critnib_leaf * k = c -> deleted_leaf ;
@@ -339,18 +322,16 @@ int critnib_insert(struct critnib *c, word key, void *value, int update) {
339322 k -> key = key ;
340323 k -> value = value ;
341324
342- struct critnib_node * kn = (void * )((word )k | 1 );
325+ CACHE_ALIGNED struct critnib_node * kn = (void * )((word )k | 1 );
343326
344327 struct critnib_node * n = c -> root ;
345328 if (!n ) {
346- store (& c -> root , kn );
347-
329+ utils_atomic_store_release_ptr (& c -> root , kn );
348330 utils_mutex_unlock (& c -> mutex );
349-
350331 return 0 ;
351332 }
352333
353- struct critnib_node * * parent = & c -> root ;
334+ CACHE_ALIGNED struct critnib_node * * parent = & c -> root ;
354335 struct critnib_node * prev = c -> root ;
355336
356337 while (n && !is_leaf (n ) && (key & path_mask (n -> shift )) == n -> path ) {
@@ -361,7 +342,8 @@ int critnib_insert(struct critnib *c, word key, void *value, int update) {
361342
362343 if (!n ) {
363344 n = prev ;
364- store (& n -> child [slice_index (key , n -> shift )], kn );
345+ utils_atomic_store_release_ptr (& n -> child [slice_index (key , n -> shift )],
346+ kn );
365347
366348 utils_mutex_unlock (& c -> mutex );
367349
@@ -406,7 +388,7 @@ int critnib_insert(struct critnib *c, word key, void *value, int update) {
406388 m -> child [slice_index (path , sh )] = n ;
407389 m -> shift = sh ;
408390 m -> path = key & path_mask (sh );
409- store (parent , m );
391+ utils_atomic_store_release_ptr (parent , m );
410392
411393 utils_mutex_unlock (& c -> mutex );
412394
@@ -427,7 +409,8 @@ void *critnib_remove(struct critnib *c, word key) {
427409 goto not_found ;
428410 }
429411
430- word del = (utils_atomic_increment (& c -> remove_count ) - 1 ) % DELETED_LIFE ;
412+ word del =
413+ (utils_atomic_increment_u64 (& c -> remove_count ) - 1 ) % DELETED_LIFE ;
431414 free_node (c , c -> pending_del_nodes [del ]);
432415 free_leaf (c , c -> pending_del_leaves [del ]);
433416 c -> pending_del_nodes [del ] = NULL ;
@@ -436,7 +419,7 @@ void *critnib_remove(struct critnib *c, word key) {
436419 if (is_leaf (n )) {
437420 k = to_leaf (n );
438421 if (k -> key == key ) {
439- store (& c -> root , NULL );
422+ utils_atomic_store_release_ptr (& c -> root , NULL );
440423 goto del_leaf ;
441424 }
442425
@@ -466,7 +449,7 @@ void *critnib_remove(struct critnib *c, word key) {
466449 goto not_found ;
467450 }
468451
469- store (& n -> child [slice_index (key , n -> shift )], NULL );
452+ utils_atomic_store_release_ptr (& n -> child [slice_index (key , n -> shift )], NULL );
470453
471454 /* Remove the node if there's only one remaining child. */
472455 int ochild = -1 ;
@@ -482,7 +465,7 @@ void *critnib_remove(struct critnib *c, word key) {
482465
483466 ASSERTne (ochild , -1 );
484467
485- store (n_parent , n -> child [ochild ]);
468+ utils_atomic_store_release_ptr (n_parent , n -> child [ochild ]);
486469 c -> pending_del_nodes [del ] = n ;
487470
488471del_leaf :
@@ -511,22 +494,23 @@ void *critnib_get(struct critnib *c, word key) {
511494 do {
512495 struct critnib_node * n ;
513496
514- load64 (& c -> remove_count , & wrs1 );
515- load (& c -> root , & n );
497+ utils_atomic_load_acquire_u64 (& c -> remove_count , & wrs1 );
498+ utils_atomic_load_acquire_ptr (& c -> root , ( void * * ) & n );
516499
517500 /*
518501 * critbit algorithm: dive into the tree, looking at nothing but
519502 * each node's critical bit^H^H^Hnibble. This means we risk
520503 * going wrong way if our path is missing, but that's ok...
521504 */
522505 while (n && !is_leaf (n )) {
523- load (& n -> child [slice_index (key , n -> shift )], & n );
506+ utils_atomic_load_acquire_ptr (& n -> child [slice_index (key , n -> shift )],
507+ (void * * )& n );
524508 }
525509
526510 /* ... as we check it at the end. */
527511 struct critnib_leaf * k = to_leaf (n );
528512 res = (n && k -> key == key ) ? k -> value : NULL ;
529- load64 (& c -> remove_count , & wrs2 );
513+ utils_atomic_load_acquire_u64 (& c -> remove_count , & wrs2 );
530514 } while (wrs1 + DELETED_LIFE <= wrs2 );
531515
532516 return res ;
@@ -597,7 +581,7 @@ static struct critnib_leaf *find_le(struct critnib_node *__restrict n,
597581 /* recursive call: follow the path */
598582 {
599583 struct critnib_node * m ;
600- load (& n -> child [nib ], & m );
584+ utils_atomic_load_acquire_ptr (& n -> child [nib ], ( void * * ) & m );
601585 struct critnib_leaf * k = find_le (m , key );
602586 if (k ) {
603587 return k ;
@@ -611,7 +595,7 @@ static struct critnib_leaf *find_le(struct critnib_node *__restrict n,
611595 */
612596 for (; nib > 0 ; nib -- ) {
613597 struct critnib_node * m ;
614- load (& n -> child [nib - 1 ], & m );
598+ utils_atomic_load_acquire_ptr (& n -> child [nib - 1 ], ( void * * ) & m );
615599 if (m ) {
616600 n = m ;
617601 if (is_leaf (n )) {
@@ -635,12 +619,12 @@ void *critnib_find_le(struct critnib *c, word key) {
635619 void * res ;
636620
637621 do {
638- load64 (& c -> remove_count , & wrs1 );
622+ utils_atomic_load_acquire_u64 (& c -> remove_count , & wrs1 );
639623 struct critnib_node * n ; /* avoid a subtle TOCTOU */
640- load (& c -> root , & n );
624+ utils_atomic_load_acquire_ptr (& c -> root , ( void * * ) & n );
641625 struct critnib_leaf * k = n ? find_le (n , key ) : NULL ;
642626 res = k ? k -> value : NULL ;
643- load64 (& c -> remove_count , & wrs2 );
627+ utils_atomic_load_acquire_u64 (& c -> remove_count , & wrs2 );
644628 } while (wrs1 + DELETED_LIFE <= wrs2 );
645629
646630 return res ;
@@ -694,7 +678,7 @@ static struct critnib_leaf *find_ge(struct critnib_node *__restrict n,
694678 unsigned nib = slice_index (key , n -> shift );
695679 {
696680 struct critnib_node * m ;
697- load (& n -> child [nib ], & m );
681+ utils_atomic_load_acquire_ptr (& n -> child [nib ], ( void * * ) & m );
698682 struct critnib_leaf * k = find_ge (m , key );
699683 if (k ) {
700684 return k ;
@@ -703,7 +687,7 @@ static struct critnib_leaf *find_ge(struct critnib_node *__restrict n,
703687
704688 for (; nib < NIB ; nib ++ ) {
705689 struct critnib_node * m ;
706- load (& n -> child [nib + 1 ], & m );
690+ utils_atomic_load_acquire_ptr (& n -> child [nib + 1 ], ( void * * ) & m );
707691 if (m ) {
708692 n = m ;
709693 if (is_leaf (n )) {
@@ -741,17 +725,18 @@ int critnib_find(struct critnib *c, uintptr_t key, enum find_dir_t dir,
741725 }
742726
743727 do {
744- load64 (& c -> remove_count , & wrs1 );
745- struct critnib_node * n ;
746- load (& c -> root , & n );
728+ utils_atomic_load_acquire_u64 (& c -> remove_count , & wrs1 );
729+ CACHE_ALIGNED struct critnib_node * n ;
730+ utils_atomic_load_acquire_ptr (& c -> root , ( void * * ) & n );
747731
748732 if (dir < 0 ) {
749733 k = find_le (n , key );
750734 } else if (dir > 0 ) {
751735 k = find_ge (n , key );
752736 } else {
753737 while (n && !is_leaf (n )) {
754- load (& n -> child [slice_index (key , n -> shift )], & n );
738+ utils_atomic_load_acquire_ptr (
739+ & n -> child [slice_index (key , n -> shift )], (void * * )& n );
755740 }
756741
757742 struct critnib_leaf * kk = to_leaf (n );
@@ -761,7 +746,7 @@ int critnib_find(struct critnib *c, uintptr_t key, enum find_dir_t dir,
761746 _rkey = k -> key ;
762747 _rvalue = k -> value ;
763748 }
764- load64 (& c -> remove_count , & wrs2 );
749+ utils_atomic_load_acquire_u64 (& c -> remove_count , & wrs2 );
765750 } while (wrs1 + DELETED_LIFE <= wrs2 );
766751
767752 if (k ) {
0 commit comments