projects
/
urcu.git
/ blobdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
|
inline
| side by side
rculfhash: merge dummy into next ptr
[urcu.git]
/
rculfhash.c
diff --git
a/rculfhash.c
b/rculfhash.c
index da04b9dce7ced2659a0b89ee6fd806d3dc97c439..55f56ceb6bc54a248032d3e2ce94e2db1bfeb82b 100644
(file)
--- a/
rculfhash.c
+++ b/
rculfhash.c
@@
-54,7
+54,8
@@
#endif
#define REMOVED_FLAG (1UL << 0)
#endif
#define REMOVED_FLAG (1UL << 0)
-#define FLAGS_MASK ((1UL << 1) - 1)
+#define DUMMY_FLAG (1UL << 1)
+#define FLAGS_MASK ((1UL << 2) - 1)
struct rcu_table {
unsigned long size; /* always a power of 2 */
struct rcu_table {
unsigned long size; /* always a power of 2 */
@@
-194,6
+195,18
@@
struct rcu_ht_node *flag_removed(struct rcu_ht_node *node)
return (struct rcu_ht_node *) (((unsigned long) node) | REMOVED_FLAG);
}
return (struct rcu_ht_node *) (((unsigned long) node) | REMOVED_FLAG);
}
+static
+int is_dummy(struct rcu_ht_node *node)
+{
+ return ((unsigned long) node) & DUMMY_FLAG;
+}
+
+static
+struct rcu_ht_node *flag_dummy(struct rcu_ht_node *node)
+{
+ return (struct rcu_ht_node *) (((unsigned long) node) | DUMMY_FLAG);
+}
+
static
unsigned long _uatomic_max(unsigned long *ptr, unsigned long v)
{
static
unsigned long _uatomic_max(unsigned long *ptr, unsigned long v)
{
@@
-214,7
+227,7
@@
unsigned long _uatomic_max(unsigned long *ptr, unsigned long v)
static
void _ht_gc_bucket(struct rcu_ht_node *dummy, struct rcu_ht_node *node)
{
static
void _ht_gc_bucket(struct rcu_ht_node *dummy, struct rcu_ht_node *node)
{
- struct rcu_ht_node *iter_prev, *iter, *next;
+ struct rcu_ht_node *iter_prev, *iter, *next
, *new_next
;
for (;;) {
iter_prev = dummy;
for (;;) {
iter_prev = dummy;
@@
-233,19
+246,25
@@
void _ht_gc_bucket(struct rcu_ht_node *dummy, struct rcu_ht_node *node)
iter = next;
}
assert(!is_removed(iter));
iter = next;
}
assert(!is_removed(iter));
- (void) uatomic_cmpxchg(&iter_prev->p.next, iter, clear_flag(next));
+ if (is_dummy(iter))
+ new_next = flag_dummy(clear_flag(next));
+ else
+ new_next = clear_flag(next);
+ (void) uatomic_cmpxchg(&iter_prev->p.next, iter, new_next);
}
}
static
struct rcu_ht_node *_ht_add(struct rcu_ht *ht, struct rcu_table *t,
}
}
static
struct rcu_ht_node *_ht_add(struct rcu_ht *ht, struct rcu_table *t,
- struct rcu_ht_node *node, int unique)
+ struct rcu_ht_node *node, int unique
, int dummy
)
{
{
- struct rcu_ht_node *iter_prev, *dummy, *iter, *next;
+ struct rcu_ht_node *iter_prev, *iter, *next, *new_node, *new_next,
+ *dummy_node;
unsigned long hash;
if (!t->size) {
unsigned long hash;
if (!t->size) {
- assert(node->p.dummy);
+ assert(dummy);
+ node->p.next = flag_dummy(NULL);
return node; /* Initial first add (head) */
}
hash = bit_reverse_ulong(node->p.reverse_hash);
return node; /* Initial first add (head) */
}
hash = bit_reverse_ulong(node->p.reverse_hash);
@@
-269,7
+288,7
@@
struct rcu_ht_node *_ht_add(struct rcu_ht *ht, struct rcu_table *t,
if (is_removed(next))
goto gc_node;
if (unique
if (is_removed(next))
goto gc_node;
if (unique
- && !
clear_flag(iter)->p.dummy
+ && !
is_dummy(next)
&& !ht->compare_fct(node->key, node->key_len,
clear_flag(iter)->key,
clear_flag(iter)->key_len))
&& !ht->compare_fct(node->key, node->key_len,
clear_flag(iter)->key,
clear_flag(iter)->key_len))
@@
-284,21
+303,32
@@
struct rcu_ht_node *_ht_add(struct rcu_ht *ht, struct rcu_table *t,
assert(node != clear_flag(iter));
assert(!is_removed(iter_prev));
assert(iter_prev != node);
assert(node != clear_flag(iter));
assert(!is_removed(iter_prev));
assert(iter_prev != node);
- node->p.next = iter;
+ if (!dummy)
+ node->p.next = clear_flag(iter);
+ else
+ node->p.next = flag_dummy(clear_flag(iter));
+ if (is_dummy(iter))
+ new_node = flag_dummy(node);
+ else
+ new_node = node;
if (uatomic_cmpxchg(&iter_prev->p.next, iter,
if (uatomic_cmpxchg(&iter_prev->p.next, iter,
- node) != iter)
+ n
ew_n
ode) != iter)
continue; /* retry */
else
goto gc_end;
gc_node:
assert(!is_removed(iter));
continue; /* retry */
else
goto gc_end;
gc_node:
assert(!is_removed(iter));
- (void) uatomic_cmpxchg(&iter_prev->p.next, iter, clear_flag(next));
+ if (is_dummy(iter))
+ new_next = flag_dummy(clear_flag(next));
+ else
+ new_next = clear_flag(next);
+ (void) uatomic_cmpxchg(&iter_prev->p.next, iter, new_next);
/* retry */
}
gc_end:
/* Garbage collect logically removed nodes in the bucket */
/* retry */
}
gc_end:
/* Garbage collect logically removed nodes in the bucket */
- dummy = rcu_dereference(t->tbl[hash & (t->size - 1)]);
- _ht_gc_bucket(dummy, node);
+ dummy
_node
= rcu_dereference(t->tbl[hash & (t->size - 1)]);
+ _ht_gc_bucket(dummy
_node
, node);
return node;
}
return node;
}
@@
-315,7
+345,7
@@
int _ht_remove(struct rcu_ht *ht, struct rcu_table *t, struct rcu_ht_node *node)
next = old;
if (is_removed(next))
goto end;
next = old;
if (is_removed(next))
goto end;
- assert(!
node->p.dummy
);
+ assert(!
is_dummy(next)
);
old = uatomic_cmpxchg(&node->p.next, next,
flag_removed(next));
} while (old != next);
old = uatomic_cmpxchg(&node->p.next, next,
flag_removed(next));
} while (old != next);
@@
-355,9
+385,8
@@
void init_table(struct rcu_ht *ht, struct rcu_table *t,
if (i != 0 && !(i & (i - 1)))
t->size = i;
t->tbl[i] = calloc(1, sizeof(struct _rcu_ht_node));
if (i != 0 && !(i & (i - 1)))
t->size = i;
t->tbl[i] = calloc(1, sizeof(struct _rcu_ht_node));
- t->tbl[i]->p.dummy = 1;
t->tbl[i]->p.reverse_hash = bit_reverse_ulong(i);
t->tbl[i]->p.reverse_hash = bit_reverse_ulong(i);
- (void) _ht_add(ht, t, t->tbl[i], 0);
+ (void) _ht_add(ht, t, t->tbl[i], 0
, 1
);
}
t->resize_target = t->size = end;
t->resize_initiated = 0;
}
t->resize_target = t->size = end;
t->resize_initiated = 0;
@@
-392,7
+421,7
@@
struct rcu_ht *ht_new(ht_hash_fct hash_fct,
struct rcu_ht_node *ht_lookup(struct rcu_ht *ht, void *key, size_t key_len)
{
struct rcu_table *t;
struct rcu_ht_node *ht_lookup(struct rcu_ht *ht, void *key, size_t key_len)
{
struct rcu_table *t;
- struct rcu_ht_node *node;
+ struct rcu_ht_node *node
, *next
;
unsigned long hash, reverse_hash;
hash = ht->hash_fct(key, key_len, ht->hash_seed);
unsigned long hash, reverse_hash;
hash = ht->hash_fct(key, key_len, ht->hash_seed);
@@
-407,14
+436,15
@@
struct rcu_ht_node *ht_lookup(struct rcu_ht *ht, void *key, size_t key_len)
node = NULL;
break;
}
node = NULL;
break;
}
- if (likely(!is_removed(rcu_dereference(node->p.next)))
- && !node->p.dummy
+ next = rcu_dereference(node->p.next);
+ if (likely(!is_removed(next))
+ && !is_dummy(next)
&& likely(!ht->compare_fct(node->key, node->key_len, key, key_len))) {
break;
}
&& likely(!ht->compare_fct(node->key, node->key_len, key, key_len))) {
break;
}
- node = clear_flag(
rcu_dereference(node->p.next)
);
+ node = clear_flag(
next
);
}
}
- assert(!node || !
node->p.dummy
);
+ assert(!node || !
is_dummy(rcu_dereference(node->p.next))
);
return node;
}
return node;
}
@@
-427,7
+457,7
@@
void ht_add(struct rcu_ht *ht, struct rcu_ht_node *node)
node->p.reverse_hash = bit_reverse_ulong((unsigned long) hash);
t = rcu_dereference(ht->t);
node->p.reverse_hash = bit_reverse_ulong((unsigned long) hash);
t = rcu_dereference(ht->t);
- (void) _ht_add(ht, t, node, 0);
+ (void) _ht_add(ht, t, node, 0
, 0
);
}
struct rcu_ht_node *ht_add_unique(struct rcu_ht *ht, struct rcu_ht_node *node)
}
struct rcu_ht_node *ht_add_unique(struct rcu_ht *ht, struct rcu_ht_node *node)
@@
-439,7
+469,7
@@
struct rcu_ht_node *ht_add_unique(struct rcu_ht *ht, struct rcu_ht_node *node)
node->p.reverse_hash = bit_reverse_ulong((unsigned long) hash);
t = rcu_dereference(ht->t);
node->p.reverse_hash = bit_reverse_ulong((unsigned long) hash);
t = rcu_dereference(ht->t);
- return _ht_add(ht, t, node, 1);
+ return _ht_add(ht, t, node, 1
, 0
);
}
int ht_remove(struct rcu_ht *ht, struct rcu_ht_node *node)
}
int ht_remove(struct rcu_ht *ht, struct rcu_ht_node *node)
@@
-461,14
+491,14
@@
int ht_delete_dummy(struct rcu_ht *ht)
/* Check that the table is empty */
node = t->tbl[0];
do {
/* Check that the table is empty */
node = t->tbl[0];
do {
- if (!node->p.dummy)
+ node = clear_flag(node)->p.next;
+ if (!is_dummy(node))
return -EPERM;
return -EPERM;
- node = node->p.next;
assert(!is_removed(node));
} while (clear_flag(node));
/* Internal sanity check: all nodes left should be dummy */
for (i = 0; i < t->size; i++) {
assert(!is_removed(node));
} while (clear_flag(node));
/* Internal sanity check: all nodes left should be dummy */
for (i = 0; i < t->size; i++) {
- assert(
t->tbl[i]->p.dummy
);
+ assert(
is_dummy(t->tbl[i]->p.next)
);
free(t->tbl[i]);
}
return 0;
free(t->tbl[i]);
}
return 0;
@@
-509,9
+539,9
@@
void ht_count_nodes(struct rcu_ht *ht,
do {
next = rcu_dereference(node->p.next);
if (is_removed(next)) {
do {
next = rcu_dereference(node->p.next);
if (is_removed(next)) {
- assert(!
node->p.dummy
);
+ assert(!
is_dummy(next)
);
(*removed)++;
(*removed)++;
- } else if (!
node->p.dummy
)
+ } else if (!
is_dummy(next)
)
(*count)++;
node = clear_flag(next);
} while (node);
(*count)++;
node = clear_flag(next);
} while (node);
This page took
0.026701 seconds
and
4
git commands to generate.