projects
/
urcu.git
/ blobdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
|
inline
| side by side
urcu: move busy-wait code and name it ___cds_wfq_node_sync_next()
[urcu.git]
/
rculfhash.c
diff --git
a/rculfhash.c
b/rculfhash.c
index b26a69085c35cbbf86d173193920c9e51f3b9e68..3ad3618aa7297ee5403d176d5c7f0e02be504def 100644
(file)
--- a/
rculfhash.c
+++ b/
rculfhash.c
@@
-734,12
+734,6
@@
int is_removed(struct cds_lfht_node *node)
return ((unsigned long) node) & REMOVED_FLAG;
}
return ((unsigned long) node) & REMOVED_FLAG;
}
-static
-struct cds_lfht_node *flag_removed(struct cds_lfht_node *node)
-{
- return (struct cds_lfht_node *) (((unsigned long) node) | REMOVED_FLAG);
-}
-
static
int is_bucket(struct cds_lfht_node *node)
{
static
int is_bucket(struct cds_lfht_node *node)
{
@@
-764,6
+758,12
@@
struct cds_lfht_node *flag_removal_owner(struct cds_lfht_node *node)
return (struct cds_lfht_node *) (((unsigned long) node) | REMOVAL_OWNER_FLAG);
}
return (struct cds_lfht_node *) (((unsigned long) node) | REMOVAL_OWNER_FLAG);
}
+static
+struct cds_lfht_node *flag_removed_or_removal_owner(struct cds_lfht_node *node)
+{
+ return (struct cds_lfht_node *) (((unsigned long) node) | REMOVED_FLAG | REMOVAL_OWNER_FLAG);
+}
+
static
struct cds_lfht_node *get_end(void)
{
static
struct cds_lfht_node *get_end(void)
{
@@
-894,6
+894,12
@@
int _cds_lfht_replace(struct cds_lfht *ht, unsigned long size,
}
assert(old_next == clear_flag(old_next));
assert(new_node != old_next);
}
assert(old_next == clear_flag(old_next));
assert(new_node != old_next);
+ /*
+ * REMOVAL_OWNER flag is _NEVER_ set before the REMOVED
+ * flag. It is either set atomically at the same time
+ * (replace) or after (del).
+ */
+ assert(!is_removal_owner(old_next));
new_node->next = old_next;
/*
* Here is the whole trick for lock-free replace: we add
new_node->next = old_next;
/*
* Here is the whole trick for lock-free replace: we add
@@
-906,10
+912,12
@@
int _cds_lfht_replace(struct cds_lfht *ht, unsigned long size,
* the old node, but will not see the new one.
* This is a replacement of a node with another node
* that has the same value: we are therefore not
* the old node, but will not see the new one.
* This is a replacement of a node with another node
* that has the same value: we are therefore not
- * removing a value from the hash table.
+ * removing a value from the hash table. We set both the
+ * REMOVED and REMOVAL_OWNER flags atomically so we own
+ * the node after successful cmpxchg.
*/
ret_next = uatomic_cmpxchg(&old_node->next,
*/
ret_next = uatomic_cmpxchg(&old_node->next,
-
old_next, flag_removed
(new_node));
+
old_next, flag_removed_or_removal_owner
(new_node));
if (ret_next == old_next)
break; /* We performed the replacement. */
old_next = ret_next;
if (ret_next == old_next)
break; /* We performed the replacement. */
old_next = ret_next;
@@
-1065,6
+1073,11
@@
int _cds_lfht_del(struct cds_lfht *ht, unsigned long size,
if (caa_unlikely(is_removed(next)))
return -ENOENT;
assert(!is_bucket(next));
if (caa_unlikely(is_removed(next)))
return -ENOENT;
assert(!is_bucket(next));
+ /*
+ * The del operation semantic guarantees a full memory barrier
+ * before the uatomic_or atomic commit of the deletion flag.
+ */
+ cmm_smp_mb__before_uatomic_or();
/*
* We set the REMOVED_FLAG unconditionally. Note that there may
* be more than one concurrent thread setting this flag.
/*
* We set the REMOVED_FLAG unconditionally. Note that there may
* be more than one concurrent thread setting this flag.
This page took
0.034624 seconds
and
4
git commands to generate.