X-Git-Url: https://git.liburcu.org/?a=blobdiff_plain;f=urcu%2Frcuwfstack.h;h=300c95e3280b47c809b51a433d08844421f79525;hb=05dd4b94f48c1717c18e0dcee88830394a5f171c;hp=f2906cead9058af10f133e349734866bc1202111;hpb=a5eb5ffcbd3f901c8e56ab3649fd06056b27536f;p=urcu.git diff --git a/urcu/rcuwfstack.h b/urcu/rcuwfstack.h index f2906ce..300c95e 100644 --- a/urcu/rcuwfstack.h +++ b/urcu/rcuwfstack.h @@ -1,3 +1,6 @@ +#ifndef _URCU_RCUWFSTACK_H +#define _URCU_RCUWFSTACK_H + /* * rcuwfstack.h * @@ -20,17 +23,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 +46,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 +67,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 @@ -72,24 +83,27 @@ void rcu_wfs_push(struct rcu_wfs_stack *s, struct rcu_wfs_node *node) * loops. Better for UP. */ struct rcu_wfs_node * -rcu_wfs_pop(struct rcu_wfs_stack *s) +rcu_wfs_pop_blocking(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 { @@ -99,3 +113,5 @@ rcu_wfs_pop(struct rcu_wfs_stack *s) } } } + +#endif /* _URCU_RCUWFSTACK_H */