The pop side needs to hold the RCU read lock to deal with ABA problem.
The push side does not need to hold the RCU read lock because even if the next
item is changed to the same value initially read, the stack will still be
consistent.
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
struct rcu_lfs_node *
_rcu_lfs_pop(struct rcu_lfs_stack *s)
{
- struct rcu_lfs_node *head = NULL;
-
for (;;) {
- struct rcu_lfs_node *old_head = head;
- struct rcu_lfs_node *next;
+ struct rcu_lfs_node *head;
- if (head)
- next = head->next;
- else
- next = NULL;
+ rcu_read_lock();
+ head = rcu_dereference(s->head);
+ if (head) {
+ struct rcu_lfs_node *next = rcu_dereference(head->next);
- head = uatomic_cmpxchg(&s->head, old_head, next);
- if (old_head == head)
- break;
+ if (uatomic_cmpxchg(&s->head, head, next) == head) {
+ rcu_read_unlock();
+ return head;
+ } else {
+ /* Concurrent modification. Retry. */
+ rcu_read_unlock();
+ continue;
+ }
+ } else {
+ /* Empty stack */
+ rcu_read_unlock();
+ return NULL;
+ }
}
- return head;
}
#ifdef __cplusplus