X-Git-Url: https://git.liburcu.org/?p=urcu.git;a=blobdiff_plain;f=urcu%2Frcuwfstack.h;h=4bbe7c507679a07a6350ab65b8ea06f8107247c7;hp=f2906cead9058af10f133e349734866bc1202111;hb=4a2f213c83ca73f35073b1460d3df683f0b9043c;hpb=bf4b1620f85f3b539a06da5facab8c603686fe7a diff --git a/urcu/rcuwfstack.h b/urcu/rcuwfstack.h index f2906ce..4bbe7c5 100644 --- a/urcu/rcuwfstack.h +++ b/urcu/rcuwfstack.h @@ -20,17 +20,20 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include + #if (!defined(_GNU_SOURCE) && !defined(_LGPL_SOURCE)) #error "Dynamic loader LGPL wrappers not implemented yet" #endif +#define RCU_WF_STACK_END ((void *)0x1UL) + struct rcu_wfs_node { struct rcu_wfs_node *next; }; struct rcu_wfs_stack { struct rcu_wfs_node *head; - struct rcu_wfs_node end; }; void rcu_wfs_node_init(struct rcu_wfs_node *node) @@ -40,14 +43,14 @@ void rcu_wfs_node_init(struct rcu_wfs_node *node) void rcu_wfs_init(struct rcu_wfs_stack *s) { - s->head = &s->end; - rcu_wfs_node_init(&s->end); + s->head = RCU_WF_STACK_END; } void rcu_wfs_push(struct rcu_wfs_stack *s, struct rcu_wfs_node *node) { struct rcu_wfs_node *old_head; + assert(node->next == NULL); /* * uatomic_xchg() implicit memory barrier orders earlier stores to node * (setting it to NULL) before publication. @@ -61,7 +64,12 @@ void rcu_wfs_push(struct rcu_wfs_stack *s, struct rcu_wfs_node *node) } /* - * The caller must wait for a grace period before freeing the returned node. + * The caller must wait for a grace period before: + * - freeing the returned node. + * - modifying the ->next pointer of the returned node. (be careful with unions) + * - passing the returned node back to push() on the same stack they got it + * from. + * * Returns NULL if stack is empty. * * cmpxchg is protected from ABA races by holding a RCU read lock between @@ -74,22 +82,25 @@ void rcu_wfs_push(struct rcu_wfs_stack *s, struct rcu_wfs_node *node) struct rcu_wfs_node * rcu_wfs_pop(struct rcu_wfs_stack *s) { - rcu_read_lock(); for (;;) { - struct rcu_wfs_node *head = rcu_dereference(s->head); + struct rcu_wfs_node *head; - if (head != &s->end) { + rcu_read_lock(); + head = rcu_dereference(s->head); + if (head != RCU_WF_STACK_END) { struct rcu_wfs_node *next = rcu_dereference(head->next); /* Retry while head is being set by push(). */ - if (!next) + if (!next) { + rcu_read_unlock(); continue; - + } if (uatomic_cmpxchg(&s->head, head, next) == head) { rcu_read_unlock(); return head; } else { /* Concurrent modification. Retry. */ + rcu_read_unlock(); continue; } } else {