ptr->next = NULL;
}
- /* Get typed element from list at a given position. */
- #define cds_hlist_entry(ptr, type, member) \
+ #define CDS_HLIST_HEAD(name) \
+ struct cds_hlist_head name = { NULL }
+
+ #define CDS_HLIST_HEAD_INIT(name) \
+ { .next = NULL }
+
+ /* Get typed element from list at a given position. */
+ #define cds_hlist_entry(ptr, type, member) \
((type *) ((char *) (ptr) - (unsigned long) (&((type *) 0)->member)))
- static inline int cds_hlist_empty(struct cds_hlist_head *head)
+/* Get first entry from a list. Assumes the hlist is not empty. */
+#define cds_hlist_first_entry(ptr, type, member) \
+ cds_list_entry((ptr)->next, type, member)
+
- /* Add new element at the head of the list. */
- static inline void cds_hlist_add_head (struct cds_hlist_node *newp,
- struct cds_hlist_head *head)
++static inline
++int cds_hlist_empty(struct cds_hlist_head *head)
+{
+ return !head->next;
+}
+
+ /* Add new element at the head of the list. */
+ static inline
+ void cds_hlist_add_head(struct cds_hlist_node *newp,
+ struct cds_hlist_head *head)
{
if (head->next)
head->next->prev = newp;
{
if (elem->next)
elem->next->prev = elem->prev;
- elem->prev->next = elem->next;
+ CMM_STORE_SHARED(elem->prev->next, elem->next);
}
- #define cds_hlist_first_rcu(ptr, type) \
+/*
+ * Get first element from a RCU hlist. Assumes the hlist is not empty.
+ * This must be done while rcu_read_lock() is held.
+ */
- #define cds_hlist_first_entry_rcu(ptr, type, member) \
++#define cds_hlist_first_rcu(ptr, type) \
+ rcu_dereference((ptr)->next)
+
+/*
+ * Get first entry from a RCU hlist. Assumes the hlist is not empty.
+ * This must be done while rcu_read_lock() is held.
+ */
++#define cds_hlist_first_entry_rcu(ptr, type, member) \
+ cds_hlist_entry(rcu_dereference((ptr)->next), type, member)
+
/*
- * Iterate through nodes of the list.
+ * Iterate through elements of the list.
* This must be done while rcu_read_lock() is held.
*/
-
- #define cds_hlist_for_each_rcu(pos, head) \
- for (pos = rcu_dereference((head)->next); \
- pos != NULL; \
- pos = rcu_dereference((pos)->next))
+ #define cds_hlist_for_each_rcu(pos, head) \
+ for (pos = rcu_dereference((head)->next); pos != NULL; \
+ pos = rcu_dereference(pos->next))
/*
- * Iterate through elements of the list.
- * This must be done while rcu_read_lock() is held.
+ * cds_hlist_for_each_entry_rcu takes 4 arguments, while the Linux
+ * kernel API only takes 3.
+ * We implement cds_hlist_for_each_entry_rcu_2() to follow the Linux
+ * kernel APIs.
*/
+ #define cds_hlist_for_each_entry_rcu(entry, pos, head, member) \
+ for (pos = rcu_dereference((head)->next), \
+ entry = cds_hlist_entry(pos, __typeof__(*entry), member); \
+ pos != NULL; \
+ pos = rcu_dereference(pos->next), \
+ entry = cds_hlist_entry(pos, __typeof__(*entry), member))
- #define cds_hlist_for_each_entry_rcu(entry, pos, head, member) \
- for (pos = rcu_dereference((head)->next), \
- entry = cds_hlist_entry(pos, __typeof__(*entry), member); \
- pos != NULL; \
- pos = rcu_dereference(pos->next), \
- entry = cds_hlist_entry(pos, __typeof__(*entry), member))
+ #define cds_hlist_for_each_entry_rcu_2(entry, head, member) \
+ for (entry = cds_hlist_entry(rcu_dereference((head)->next), \
+ __typeof__(*entry), member); \
+ &entry->member != NULL; \
+ entry = cds_hlist_entry(rcu_dereference(entry->member.next), \
+ __typeof__(*entry), member))
#endif /* _URCU_RCUHLIST_H */
#include <urcu/arch.h>
#include <urcu-pointer.h>
- /* Add new element at the head of the list.
- */
- static inline void cds_list_add_rcu(struct cds_list_head *newp, struct cds_list_head *head)
+ /* Add new element at the head of the list. */
+ static inline
+ void cds_list_add_rcu(struct cds_list_head *newp, struct cds_list_head *head)
{
- newp->next = head->next;
+ struct cds_list_head *first = head->next;
+
+ newp->next = first;
newp->prev = head;
+ head->next->prev = newp;
rcu_assign_pointer(head->next, newp);
- first->prev = newp;
}
- /* replace an old entry atomically.
+ /* Add new element at the tail of the list. */
+ static inline
+ void cds_list_add_tail_rcu(struct cds_list_head *newp,
+ struct cds_list_head *head)
+ {
+ newp->next = head;
+ newp->prev = head->prev;
+ rcu_assign_pointer(head->prev->next, newp);
+ head->prev = newp;
+ }
+
+ /*
+ * Replace an old entry atomically with respect to concurrent RCU
+ * traversal. Mutual exclusion against concurrent updates is required
+ * though.
*/
- static inline void cds_list_replace_rcu(struct cds_list_head *old, struct cds_list_head *_new)
+ static inline
+ void cds_list_replace_rcu(struct cds_list_head *old, struct cds_list_head *_new)
{
_new->next = old->next;
_new->prev = old->prev;