X-Git-Url: https://git.liburcu.org/?p=urcu.git;a=blobdiff_plain;f=urcu%2Frculfqueue.h;h=f229cc77ca8d8a741a516dc4f3bbcae2cd67a90e;hp=f9b14fe93657343c5e1917ab77afcab4dc087a0d;hb=3d02c34dba0edc4a3554a3862a2ae96d77b3b4e8;hpb=453629a9317adef5b96c3d55e4dcd98db680997a diff --git a/urcu/rculfqueue.h b/urcu/rculfqueue.h index f9b14fe..f229cc7 100644 --- a/urcu/rculfqueue.h +++ b/urcu/rculfqueue.h @@ -1,3 +1,6 @@ +#ifndef _URCU_RCULFQUEUE_H +#define _URCU_RCULFQUEUE_H + /* * rculfqueue.h * @@ -23,8 +26,8 @@ #include #include -#if (!defined(_GNU_SOURCE) && !defined(_LGPL_SOURCE)) -#error "Dynamic loader LGPL wrappers not implemented yet" +#ifdef __cplusplus +extern "C" { #endif /* @@ -37,8 +40,6 @@ * which point their reference count will be decremented. */ -#define URCU_LFQ_PERMANENT_REF 128 - struct rcu_lfq_node { struct rcu_lfq_node *next; struct urcu_ref ref; @@ -49,88 +50,38 @@ struct rcu_lfq_queue { struct rcu_lfq_node init; /* Dummy initialization node */ }; -void rcu_lfq_node_init(struct rcu_lfq_node *node) -{ - node->next = NULL; - urcu_ref_init(&node->ref); -} +#ifdef _LGPL_SOURCE -void rcu_lfq_init(struct rcu_lfq_queue *q) -{ - rcu_lfq_node_init(&q->init); - /* Make sure the initial node is never freed. */ - urcu_ref_set(&q->init.ref, URCU_LFQ_PERMANENT_REF); - q->head = q->tail = &q->init; -} +#include -void rcu_lfq_enqueue(struct rcu_lfq_queue *q, struct rcu_lfq_node *node) -{ - urcu_ref_get(&node->ref); +#define rcu_lfq_node_init _rcu_lfq_node_init +#define rcu_lfq_init _rcu_lfq_init +#define rcu_lfq_enqueue _rcu_lfq_enqueue +#define rcu_lfq_dequeue _rcu_lfq_dequeue - /* - * uatomic_cmpxchg() implicit memory barrier orders earlier stores to - * node before publication. - */ +#else /* !_LGPL_SOURCE */ - rcu_read_lock(); - for (;;) { - struct rcu_lfq_node *tail = rcu_dereference(q->tail); - struct rcu_lfq_node *next; - - /* - * Typically expect tail to be NULL. - */ - next = uatomic_cmpxchg(&tail->next, NULL, node); - if (next == NULL) { - /* - * Tail was at the end of queue, we successfully - * appended to it. - * Now move tail (another enqueue might beat - * us to it, that's fine). - */ - uatomic_cmpxchg(&q->tail, tail, node); - rcu_read_unlock(); - return; - } else { - /* - * Failure to append to current tail. Help moving tail - * further and retry. - */ - uatomic_cmpxchg(&q->tail, tail, next); - continue; - } - } -} +extern void rcu_lfq_node_init(struct rcu_lfq_node *node); +extern void rcu_lfq_init(struct rcu_lfq_queue *q); +extern void rcu_lfq_enqueue(struct rcu_lfq_queue *q, struct rcu_lfq_node *node); /* * The entry returned by dequeue must be taken care of by doing a urcu_ref_put, * which calls the release primitive when the reference count drops to zero. A - * grace period must be waited before performing the actual memory reclamation - * in the release primitive. - * The entry lfq node returned by dequeue must no be re-used before the - * reference count reaches zero. + * grace period must be waited after execution of the release callback before + * performing the actual memory reclamation or modifying the rcu_lfq_node + * structure. + * In other words, the entry lfq node returned by dequeue must not be + * modified/re-used/freed until the reference count reaches zero and a grace + * period has elapsed (after the refcount reached 0). */ -struct rcu_lfq_node * -rcu_lfq_dequeue(struct rcu_lfq_queue *q, void (*release)(struct urcu_ref *)) -{ - rcu_read_lock(); - for (;;) { - struct rcu_lfq_node *head = rcu_dereference(q->head); - struct rcu_lfq_node *next = rcu_dereference(head->next); +extern struct rcu_lfq_node * +rcu_lfq_dequeue(struct rcu_lfq_queue *q, void (*release)(struct urcu_ref *)); + +#endif /* !_LGPL_SOURCE */ - if (next) { - if (uatomic_cmpxchg(&q->head, head, next) == head) { - rcu_read_unlock(); - urcu_ref_put(&head->ref, release); - return next; - } else { - /* Concurrently pushed, retry */ - continue; - } - } else { - /* Empty */ - rcu_read_unlock(); - return NULL; - } - } +#ifdef __cplusplus } +#endif + +#endif /* _URCU_RCULFQUEUE_H */