arch.h   arch.h 
skipping to change at line 63 skipping to change at line 63
* kernels should think twice before enabling this", but for now let's * kernels should think twice before enabling this", but for now let's
* be conservative and leave the full barrier on 32-bit processors. Also, * be conservative and leave the full barrier on 32-bit processors. Also,
* IDT WinChip supports weak store ordering, and the kernel may enable it * IDT WinChip supports weak store ordering, and the kernel may enable it
* under our feet; cmm_smp_wmb() ceases to be a nop for these processors. * under our feet; cmm_smp_wmb() ceases to be a nop for these processors.
*/ */
#define cmm_mb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)":::"memor y") #define cmm_mb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)":::"memor y")
#define cmm_rmb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)":::"memor y") #define cmm_rmb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)":::"memor y")
#define cmm_wmb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)"::: "memo ry") #define cmm_wmb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)"::: "memo ry")
#endif #endif
#define caa_cpu_relax() __asm__ __volatile__ ("rep; nop" : : : "memo ry") #define caa_cpu_relax() __asm__ __volatile__ ("rep; nop" : : : "memo ry");
#define rdtscll(val) \ #define rdtscll(val) \
do { \ do { \
unsigned int __a, __d; \ unsigned int __a, __d; \
__asm__ __volatile__ ("rdtsc" : "=a" (__a), "=d" (__d)); \ __asm__ __volatile__ ("rdtsc" : "=a" (__a), "=d" (__d)); \
(val) = ((unsigned long long)__a) \ (val) = ((unsigned long long)__a) \
| (((unsigned long long)__d) << 32); \ | (((unsigned long long)__d) << 32); \
} while(0) } while(0)
typedef unsigned long long cycles_t; typedef unsigned long long cycles_t;
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 cds.h   cds.h 
skipping to change at line 34 skipping to change at line 34
*/ */
#include <urcu/hlist.h> #include <urcu/hlist.h>
#include <urcu/list.h> #include <urcu/list.h>
#include <urcu/rcuhlist.h> #include <urcu/rcuhlist.h>
#include <urcu/rculist.h> #include <urcu/rculist.h>
#include <urcu/rculfqueue.h> #include <urcu/rculfqueue.h>
#include <urcu/rculfstack.h> #include <urcu/rculfstack.h>
#include <urcu/rculfhash.h> #include <urcu/rculfhash.h>
#include <urcu/wfqueue.h> #include <urcu/wfqueue.h>
#include <urcu/wfcqueue.h>
#include <urcu/wfstack.h> #include <urcu/wfstack.h>
#include <urcu/lfstack.h>
#endif /* _URCU_CDS_H */ #endif /* _URCU_CDS_H */
 End of changes. 2 change blocks. 
0 lines changed or deleted 2 lines changed or added


 compiler.h   compiler.h 
skipping to change at line 67 skipping to change at line 67
#endif #endif
/* /*
* caa_container_of - Get the address of an object containing a field. * caa_container_of - Get the address of an object containing a field.
* *
* @ptr: pointer to the field. * @ptr: pointer to the field.
* @type: type of the object. * @type: type of the object.
* @member: name of the field within the object. * @member: name of the field within the object.
*/ */
#define caa_container_of(ptr, type, member) \ #define caa_container_of(ptr, type, member) \
__extension__ \
({ \ ({ \
const __typeof__(((type *) NULL)->member) * __ptr = (ptr); \ const __typeof__(((type *) NULL)->member) * __ptr = (ptr); \
(type *)((char *)__ptr - offsetof(type, member)); \ (type *)((char *)__ptr - offsetof(type, member)); \
}) })
#define CAA_BUILD_BUG_ON_ZERO(cond) (sizeof(struct { int:-!!(cond); })) #define CAA_BUILD_BUG_ON_ZERO(cond) (sizeof(struct { int:-!!(cond); }))
#define CAA_BUILD_BUG_ON(cond) ((void)CAA_BUILD_BUG_ON_ZERO(cond)) #define CAA_BUILD_BUG_ON(cond) ((void)CAA_BUILD_BUG_ON_ZERO(cond))
/* /*
* __rcu is an annotation that documents RCU pointer accesses that need * __rcu is an annotation that documents RCU pointer accesses that need
skipping to change at line 90 skipping to change at line 89
* usage. * usage.
*/ */
#define __rcu #define __rcu
#ifdef __cplusplus #ifdef __cplusplus
#define URCU_FORCE_CAST(type, arg) (reinterpret_cast<type>(arg)) #define URCU_FORCE_CAST(type, arg) (reinterpret_cast<type>(arg))
#else #else
#define URCU_FORCE_CAST(type, arg) ((type) (arg)) #define URCU_FORCE_CAST(type, arg) ((type) (arg))
#endif #endif
#define caa_is_signed_type(type) ((type) -1 < (type) 0) #define caa_is_signed_type(type) (((type) (-1)) < 0)
/* #define caa_cast_long_keep_sign(v) \
* Cast to unsigned long, sign-extending if @v is signed. (caa_is_signed_type(__typeof__(v)) ? (long) (v) : (unsigned long) (v
* Note: casting to a larger type or to same type size keeps the sign of ))
* the expression being cast (see C99 6.3.1.3).
*/
#define caa_cast_long_keep_sign(v) ((unsigned long) (v))
/*
* Don't allow compiling with buggy compiler.
*/
#ifdef __GNUC__ #if defined (__GNUC__) \
# define URCU_GCC_VERSION (__GNUC__ * 10000 \ && ((__GNUC_MAJOR__ == 4) && (__GNUC_MINOR__ >= 5) \
+ __GNUC_MINOR__ * 100 \ || __GNUC_MAJOR__ >= 5)
+ __GNUC_PATCHLEVEL__) #define CDS_DEPRECATED(msg) \
__attribute__((deprecated(msg)))
/* #else
* http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58854 #define CDS_DEPRECATED(msg) \
*/ __attribute__((deprecated))
# ifdef __ARMEL__
# if URCU_GCC_VERSION >= 40800 && URCU_GCC_VERSION <= 40802
# error Your gcc version produces clobbered frame accesses
# endif
# endif
#endif #endif
#define CAA_ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#endif /* _URCU_COMPILER_H */ #endif /* _URCU_COMPILER_H */
 End of changes. 5 change blocks. 
25 lines changed or deleted 14 lines changed or added


 futex.h   futex.h 
skipping to change at line 48 skipping to change at line 48
* Use *only* *either of* futex_noasync OR futex_async on a given address. * Use *only* *either of* futex_noasync OR futex_async on a given address.
* *
* futex_noasync cannot be executed in signal handlers, but ensures that * futex_noasync cannot be executed in signal handlers, but ensures that
* it will be put in a wait queue even in compatibility mode. * it will be put in a wait queue even in compatibility mode.
* *
* futex_async is signal-handler safe for the wakeup. It uses polling * futex_async is signal-handler safe for the wakeup. It uses polling
* on the wait-side in compatibility mode. * on the wait-side in compatibility mode.
*/ */
#ifdef CONFIG_RCU_HAVE_FUTEX #ifdef CONFIG_RCU_HAVE_FUTEX
#include <sys/syscall.h> #include <syscall.h>
#define futex(...) syscall(__NR_futex, __VA_ARGS__) #define futex(...) syscall(__NR_futex, __VA_ARGS__)
#define futex_noasync(uaddr, op, val, timeout, uaddr2, val3) \ #define futex_noasync(uaddr, op, val, timeout, uaddr2, val3) \
futex(uaddr, op, val, timeout, uaddr2, val3) futex(uaddr, op, val, timeout, uaddr2, val3)
#define futex_async(uaddr, op, val, timeout, uaddr2, val3) \ #define futex_async(uaddr, op, val, timeout, uaddr2, val3) \
futex(uaddr, op, val, timeout, uaddr2, val3) futex(uaddr, op, val, timeout, uaddr2, val3)
#else #else
extern int compat_futex_noasync(int32_t *uaddr, int op, int32_t val, extern int compat_futex_noasync(int32_t *uaddr, int op, int32_t val,
const struct timespec *timeout, int32_t *uaddr2, int32_t val3); const struct timespec *timeout, int32_t *uaddr2, int32_t val3);
#define futex_noasync(uaddr, op, val, timeout, uaddr2, val3) \ #define futex_noasync(uaddr, op, val, timeout, uaddr2, val3) \
compat_futex_noasync(uaddr, op, val, timeout, uaddr2, val3) compat_futex_noasync(uaddr, op, val, timeout, uaddr2, val3)
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 hlist.h   hlist.h 
skipping to change at line 12 skipping to change at line 12
#define _KCOMPAT_HLIST_H #define _KCOMPAT_HLIST_H
/* /*
* Kernel sourcecode compatible lightweight single pointer list head useful * Kernel sourcecode compatible lightweight single pointer list head useful
* for implementing hash tables * for implementing hash tables
* *
* Copyright (C) 2009 Novell Inc. * Copyright (C) 2009 Novell Inc.
* *
* Author: Jan Blunck <jblunck@suse.de> * Author: Jan Blunck <jblunck@suse.de>
* *
* Copyright (C) 2010 Mathieu Desnoyers <mathieu.desnoyers@efficios.com> * Copyright (C) 2010-2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.co m>
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License version 2.1 as * under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <stddef.h> #include <stddef.h>
struct cds_hlist_head struct cds_hlist_head {
{
struct cds_hlist_node *next; struct cds_hlist_node *next;
}; };
struct cds_hlist_node struct cds_hlist_node {
{ struct cds_hlist_node *next, *prev;
struct cds_hlist_node *next;
struct cds_hlist_node *prev;
}; };
/* Initialize a new list head. */ /* Initialize a new list head. */
static inline void CDS_INIT_HLIST_HEAD(struct cds_hlist_head *ptr) static inline
void CDS_INIT_HLIST_HEAD(struct cds_hlist_head *ptr)
{ {
ptr->next = NULL; ptr->next = NULL;
} }
/* Get typed element from list at a given position. */ #define CDS_HLIST_HEAD(name) \
#define cds_hlist_entry(ptr, type, member) 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)) ) ((type *) ((char *) (ptr) - (unsigned long) (&((type *) 0)->member)) )
/* Add new element at the head of the list. */ /* Add new element at the head of the list. */
static inline void cds_hlist_add_head (struct cds_hlist_node *newp, static inline
struct cds_hlist_head *head) void cds_hlist_add_head(struct cds_hlist_node *newp,
struct cds_hlist_head *head)
{ {
if (head->next) if (head->next)
head->next->prev = newp; head->next->prev = newp;
newp->next = head->next; newp->next = head->next;
newp->prev = (struct cds_hlist_node *)head; newp->prev = (struct cds_hlist_node *) head;
head->next = newp; head->next = newp;
} }
/* Remove element from list. */ /* Remove element from list. */
static inline void cds_hlist_del (struct cds_hlist_node *elem) static inline
void cds_hlist_del(struct cds_hlist_node *elem)
{ {
if (elem->next) if (elem->next)
elem->next->prev = elem->prev; elem->next->prev = elem->prev;
elem->prev->next = elem->next; elem->prev->next = elem->next;
} }
#define cds_hlist_for_each_entry(entry, pos, head, member) #define cds_hlist_for_each(pos, head) \
\ for (pos = (head)->next; pos != NULL; pos = pos->next)
for (pos = (head)->next, \
entry = cds_hlist_entry(pos, __typeof__(*entry), member #define cds_hlist_for_each_safe(pos, p, head) \
); \ for (pos = (head)->next; \
pos != NULL; \ (pos != NULL) && (p = pos->next, 1); \
pos = pos->next, \ pos = p)
entry = cds_hlist_entry(pos, __typeof__(*entry), member
)) /*
* cds_hlist_for_each_entry and cds_hlist_for_each_entry_safe take
#define cds_hlist_for_each_entry_safe(entry, pos, p, head, member) * respectively 4 and 5 arguments, while the Linux kernel APIs take 3,
\ * and 4. We implement cds_hlist_for_each_entry_2() and
for (pos = (head)->next, \ * cds_hlist_for_each_entry_safe_2() to follow the Linux kernel APIs.
entry = cds_hlist_entry(pos, __typeof__(*entry), member */
); \ #define cds_hlist_for_each_entry(entry, pos, head, member) \
(pos != NULL) && ({ p = pos->next; 1;}); \ for (pos = (head)->next, \
pos = p, \ entry = cds_hlist_entry(pos, __typeof__(*entry), mem
entry = cds_hlist_entry(pos, __typeof__(*entry), member ber); \
)) pos != NULL; \
pos = pos->next, \
entry = cds_hlist_entry(pos, __typeof__(*entry), mem
ber))
#define cds_hlist_for_each_entry_safe(entry, pos, p, head, member) \
for (pos = (head)->next, \
entry = cds_hlist_entry(pos, __typeof__(*entry), mem
ber); \
(pos != NULL) && (p = pos->next, 1); \
pos = p, \
entry = cds_hlist_entry(pos, __typeof__(*entry), mem
ber))
#define cds_hlist_for_each_entry_2(entry, head, member) \
for (entry = cds_hlist_entry((head)->next, __typeof__(*entry), membe
r); \
&entry->member != NULL; \
entry = cds_hlist_entry(entry->member.next, __typeof__(*entr
y), member))
#define cds_hlist_for_each_entry_safe_2(entry, e, head, member) \
for (entry = cds_hlist_entry((head)->next, __typeof__(*entry), membe
r); \
(&entry->member != NULL) && (e = cds_hlist_entry(entry->memb
er.next, \
__typeof__(*entry), member),
1); \
entry = e)
#endif /* _KCOMPAT_HLIST_H */ #endif /* _KCOMPAT_HLIST_H */
 End of changes. 11 change blocks. 
39 lines changed or deleted 70 lines changed or added


 list.h   list.h 
skipping to change at line 28 skipping to change at line 28
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#ifndef _CDS_LIST_H #ifndef _CDS_LIST_H
#define _CDS_LIST_H 1 #define _CDS_LIST_H 1
/* The definitions of this file are adopted from those which can be /*
found in the Linux kernel headers to enable people familiar with * The definitions of this file are adopted from those which can be
the latter find their way in these sources as well. */ * found in the Linux kernel headers to enable people familiar with the
* latter find their way in these sources as well.
*/
/* Basic type for the double-link list. */ /* Basic type for the double-link list. */
struct cds_list_head struct cds_list_head {
{ struct cds_list_head *next, *prev;
struct cds_list_head *next;
struct cds_list_head *prev;
}; };
/* Define a variable with the head and tail of the list. */ /* Define a variable with the head and tail of the list. */
#define CDS_LIST_HEAD(name) \ #define CDS_LIST_HEAD(name) \
struct cds_list_head name = { &(name), &(name) } struct cds_list_head name = { &(name), &(name) }
/* Initialize a new list head. */ /* Initialize a new list head. */
#define CDS_INIT_LIST_HEAD(ptr) \ #define CDS_INIT_LIST_HEAD(ptr) \
(ptr)->next = (ptr)->prev = (ptr) (ptr)->next = (ptr)->prev = (ptr)
#define CDS_LIST_HEAD_INIT(name) { .prev = &(name), .next = &(name) } #define CDS_LIST_HEAD_INIT(name) { .prev = &(name), .next = &(name) }
/* Add new element at the head of the list. */ /* Add new element at the head of the list. */
static inline void static inline
cds_list_add (struct cds_list_head *newp, struct cds_list_head *head) void cds_list_add(struct cds_list_head *newp, struct cds_list_head *head)
{ {
head->next->prev = newp; head->next->prev = newp;
newp->next = head->next; newp->next = head->next;
newp->prev = head; newp->prev = head;
head->next = newp; head->next = newp;
} }
/* Add new element at the tail of the list. */ /* Add new element at the tail of the list. */
static inline void static inline
cds_list_add_tail (struct cds_list_head *newp, struct cds_list_head *head) void cds_list_add_tail(struct cds_list_head *newp, struct cds_list_head *he
ad)
{ {
head->prev->next = newp; head->prev->next = newp;
newp->next = head; newp->next = head;
newp->prev = head->prev; newp->prev = head->prev;
head->prev = newp; head->prev = newp;
} }
/* Remove element from list. */ /* Remove element from list. */
static inline void static inline
__cds_list_del (struct cds_list_head *prev, struct cds_list_head *next) void __cds_list_del(struct cds_list_head *prev, struct cds_list_head *next)
{ {
next->prev = prev; next->prev = prev;
prev->next = next; prev->next = next;
} }
/* Remove element from list. */ /* Remove element from list. */
static inline void static inline
cds_list_del (struct cds_list_head *elem) void cds_list_del(struct cds_list_head *elem)
{ {
__cds_list_del (elem->prev, elem->next); __cds_list_del(elem->prev, elem->next);
} }
/* Remove element from list, initializing the element's list pointers. */ /* Remove element from list, initializing the element's list pointers. */
static inline void static inline
cds_list_del_init (struct cds_list_head *elem) void cds_list_del_init(struct cds_list_head *elem)
{ {
cds_list_del(elem); cds_list_del(elem);
CDS_INIT_LIST_HEAD(elem); CDS_INIT_LIST_HEAD(elem);
} }
/* delete from list, add to another list as head */ /* Delete from list, add to another list as head. */
static inline void static inline
cds_list_move (struct cds_list_head *elem, struct cds_list_head *head) void cds_list_move(struct cds_list_head *elem, struct cds_list_head *head)
{ {
__cds_list_del (elem->prev, elem->next); __cds_list_del(elem->prev, elem->next);
cds_list_add (elem, head); cds_list_add(elem, head);
} }
/* replace an old entry. /* Replace an old entry. */
*/ static inline
static inline void void cds_list_replace(struct cds_list_head *old, struct cds_list_head *_new
cds_list_replace(struct cds_list_head *old, struct cds_list_head *_new) )
{ {
_new->next = old->next; _new->next = old->next;
_new->prev = old->prev; _new->prev = old->prev;
_new->prev->next = _new; _new->prev->next = _new;
_new->next->prev = _new; _new->next->prev = _new;
} }
/* Join two lists. */ /* Join two lists. */
static inline void static inline
cds_list_splice (struct cds_list_head *add, struct cds_list_head *head) void cds_list_splice(struct cds_list_head *add, struct cds_list_head *head)
{ {
/* Do nothing if the list which gets added is empty. */ /* Do nothing if the list which gets added is empty. */
if (add != add->next) if (add != add->next) {
{ add->next->prev = head;
add->next->prev = head; add->prev->next = head->next;
add->prev->next = head->next; head->next->prev = add->prev;
head->next->prev = add->prev; head->next = add->next;
head->next = add->next; }
}
} }
/* Get typed element from list at a given position. */ /* Get typed element from list at a given position. */
#define cds_list_entry(ptr, type, member) \ #define cds_list_entry(ptr, type, member) \
((type *) ((char *) (ptr) - (unsigned long) (&((type *) 0)->member))) ((type *) ((char *) (ptr) - (unsigned long) (&((type *) 0)->member)) )
/* Get first entry from a list. */ /* Get first entry from a list. */
#define cds_list_first_entry(ptr, type, member) \ #define cds_list_first_entry(ptr, type, member) \
cds_list_entry((ptr)->next, type, member) cds_list_entry((ptr)->next, type, member)
/* Iterate forward over the elements of the list. */ /* Iterate forward over the elements of the list. */
#define cds_list_for_each(pos, head) \ #define cds_list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next) for (pos = (head)->next; pos != (head); pos = pos->next)
/* Iterate forward over the elements of the list. */ /*
* Iterate forward over the elements list. The list elements can be
* removed from the list while doing this.
*/
#define cds_list_for_each_safe(pos, p, head) \
for (pos = (head)->next, p = pos->next; \
pos != (head); \
pos = p, p = pos->next)
/* Iterate backward over the elements of the list. */
#define cds_list_for_each_prev(pos, head) \ #define cds_list_for_each_prev(pos, head) \
for (pos = (head)->prev; pos != (head); pos = pos->prev) for (pos = (head)->prev; pos != (head); pos = pos->prev)
/* Iterate backwards over the elements list. The list elements can be /*
removed from the list while doing this. */ * Iterate backwards over the elements list. The list elements can be
* removed from the list while doing this.
*/
#define cds_list_for_each_prev_safe(pos, p, head) \ #define cds_list_for_each_prev_safe(pos, p, head) \
for (pos = (head)->prev, p = pos->prev; \ for (pos = (head)->prev, p = pos->prev; \
pos != (head); \ pos != (head); \
pos = p, p = pos->prev) pos = p, p = pos->prev)
#define cds_list_for_each_entry(pos, head, member) \ #define cds_list_for_each_entry(pos, head, member) \
for (pos = cds_list_entry((head)->next, __typeof__(*pos), member); \ for (pos = cds_list_entry((head)->next, __typeof__(*pos), member); \
&pos->member != (head); \ &pos->member != (head); \
pos = cds_list_entry(pos->member.next, __typeof__(*pos), member pos = cds_list_entry(pos->member.next, __typeof__(*pos), mem
)) ber))
#define cds_list_for_each_entry_reverse(pos, head, member) \ #define cds_list_for_each_entry_reverse(pos, head, member) \
for (pos = cds_list_entry((head)->prev, __typeof__(*pos), member); \ for (pos = cds_list_entry((head)->prev, __typeof__(*pos), member); \
&pos->member != (head); \ &pos->member != (head); \
pos = cds_list_entry(pos->member.prev, __typeof__(*pos), member pos = cds_list_entry(pos->member.prev, __typeof__(*pos), mem
)) ber))
#define cds_list_for_each_entry_safe(pos, p, head, member) \ #define cds_list_for_each_entry_safe(pos, p, head, member) \
for (pos = cds_list_entry((head)->next, __typeof__(*pos), member), \ for (pos = cds_list_entry((head)->next, __typeof__(*pos), member), \
p = cds_list_entry(pos->member.next, __typeof__(*pos), p = cds_list_entry(pos->member.next, __typeof__(*pos
member); \ ), member); \
&pos->member != (head); \ &pos->member != (head); \
pos = p, p = cds_list_entry(pos->member.next, __typeof__(*pos), pos = p, p = cds_list_entry(pos->member.next, __typeof__(*po
member)) s), member))
static inline int cds_list_empty(struct cds_list_head *head) static inline
int cds_list_empty(struct cds_list_head *head)
{ {
return head == head->next; return head == head->next;
} }
static inline void cds_list_replace_init(struct cds_list_head *old, static inline
struct cds_list_head *_new) void cds_list_replace_init(struct cds_list_head *old,
struct cds_list_head *_new)
{ {
struct cds_list_head *head = old->next; struct cds_list_head *head = old->next;
cds_list_del(old); cds_list_del(old);
cds_list_add_tail(_new, head); cds_list_add_tail(_new, head);
CDS_INIT_LIST_HEAD(old); CDS_INIT_LIST_HEAD(old);
} }
#endif /* _CDS_LIST_H */ #endif /* _CDS_LIST_H */
 End of changes. 36 change blocks. 
86 lines changed or deleted 100 lines changed or added


 rcuhlist.h   rcuhlist.h 
skipping to change at line 32 skipping to change at line 32
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#ifndef _URCU_RCUHLIST_H #ifndef _URCU_RCUHLIST_H
#define _URCU_RCUHLIST_H #define _URCU_RCUHLIST_H
#include <urcu/hlist.h> #include <urcu/hlist.h>
#include <urcu/arch.h> #include <urcu/arch.h>
#include <urcu-pointer.h> #include <urcu-pointer.h>
/* Add new element at the head of the list. /* Add new element at the head of the list. */
*/ static inline
static inline void cds_hlist_add_head_rcu(struct cds_hlist_node *newp, void cds_hlist_add_head_rcu(struct cds_hlist_node *newp,
struct cds_hlist_head *head) struct cds_hlist_head *head)
{ {
newp->next = head->next; newp->next = head->next;
newp->prev = (struct cds_hlist_node *)head; newp->prev = (struct cds_hlist_node *)head;
cmm_smp_wmb();
if (head->next) if (head->next)
head->next->prev = newp; head->next->prev = newp;
head->next = newp; rcu_assign_pointer(head->next, newp);
} }
/* Remove element from list. */ /* Remove element from list. */
static inline void cds_hlist_del_rcu(struct cds_hlist_node *elem) static inline
void cds_hlist_del_rcu(struct cds_hlist_node *elem)
{ {
if (elem->next) if (elem->next)
elem->next->prev = elem->prev; elem->next->prev = elem->prev;
elem->prev->next = elem->next; CMM_STORE_SHARED(elem->prev->next, elem->next);
} }
/* Iterate through elements of the list. /*
* Iterate through elements of the list.
* This must be done while rcu_read_lock() is held. * This must be done while rcu_read_lock() is held.
*/ */
#define cds_hlist_for_each_rcu(pos, head) \
#define cds_hlist_for_each_entry_rcu(entry, pos, head, member) \ for (pos = rcu_dereference((head)->next); pos != NULL; \
for (pos = rcu_dereference((head)->next), \ pos = rcu_dereference(pos->next))
entry = cds_hlist_entry(pos, __typeof__(*entry), member
); \ /*
pos != NULL; \ * cds_hlist_for_each_entry_rcu takes 4 arguments, while the Linux
pos = rcu_dereference(pos->next), \ * kernel API only takes 3.
entry = cds_hlist_entry(pos, __typeof__(*entry), member * 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), mem
ber); \
pos != NULL; \
pos = rcu_dereference(pos->next), \
entry = cds_hlist_entry(pos, __typeof__(*entry), mem
ber))
#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 */ #endif /* _URCU_RCUHLIST_H */
 End of changes. 7 change blocks. 
18 lines changed or deleted 36 lines changed or added


 rculfhash.h   rculfhash.h 
skipping to change at line 121 skipping to change at line 121
unsigned long index); unsigned long index);
}; };
extern const struct cds_lfht_mm_type cds_lfht_mm_order; extern const struct cds_lfht_mm_type cds_lfht_mm_order;
extern const struct cds_lfht_mm_type cds_lfht_mm_chunk; extern const struct cds_lfht_mm_type cds_lfht_mm_chunk;
extern const struct cds_lfht_mm_type cds_lfht_mm_mmap; extern const struct cds_lfht_mm_type cds_lfht_mm_mmap;
/* /*
* _cds_lfht_new - API used by cds_lfht_new wrapper. Do not use directly. * _cds_lfht_new - API used by cds_lfht_new wrapper. Do not use directly.
*/ */
extern
struct cds_lfht *_cds_lfht_new(unsigned long init_size, struct cds_lfht *_cds_lfht_new(unsigned long init_size,
unsigned long min_nr_alloc_buckets, unsigned long min_nr_alloc_buckets,
unsigned long max_nr_buckets, unsigned long max_nr_buckets,
int flags, int flags,
const struct cds_lfht_mm_type *mm, const struct cds_lfht_mm_type *mm,
const struct rcu_flavor_struct *flavor, const struct rcu_flavor_struct *flavor,
pthread_attr_t *attr); pthread_attr_t *attr);
/* /*
* cds_lfht_new - allocate a hash table. * cds_lfht_new - allocate a hash table.
* @init_size: number of buckets to allocate initially. Must be power of tw o. * @init_size: number of buckets to allocate initially. Must be power of tw o.
* @min_nr_alloc_buckets: the minimum number of allocated buckets. * @min_nr_alloc_buckets: the minimum number of allocated buckets.
* (must be power of two) * (must be power of two)
* @max_nr_buckets: the maximum number of hash table buckets allowed. * @max_nr_buckets: the maximum number of hash table buckets allowed.
* (must be power of two, 0 is accepted, means * (must be power of two)
* "infinite")
* @flags: hash table creation flags (can be combined with bitwise or: '|') . * @flags: hash table creation flags (can be combined with bitwise or: '|') .
* 0: no flags. * 0: no flags.
* CDS_LFHT_AUTO_RESIZE: automatically resize hash table. * CDS_LFHT_AUTO_RESIZE: automatically resize hash table.
* CDS_LFHT_ACCOUNTING: count the number of node addition * CDS_LFHT_ACCOUNTING: count the number of node addition
* and removal in the table * and removal in the table
* @attr: optional resize worker thread attributes. NULL for default. * @attr: optional resize worker thread attributes. NULL for default.
* *
* Return NULL on error. * Return NULL on error.
* Note: the RCU flavor must be already included before the hash table head er. * Note: the RCU flavor must be already included before the hash table head er.
* *
skipping to change at line 180 skipping to change at line 180
* cds_lfht_destroy - destroy a hash table. * cds_lfht_destroy - destroy a hash table.
* @ht: the hash table to destroy. * @ht: the hash table to destroy.
* @attr: (output) resize worker thread attributes, as received by cds_lfht _new. * @attr: (output) resize worker thread attributes, as received by cds_lfht _new.
* The caller will typically want to free this pointer if dynamicall y * The caller will typically want to free this pointer if dynamicall y
* allocated. The attr point can be NULL if the caller does not * allocated. The attr point can be NULL if the caller does not
* need to be informed of the value passed to cds_lfht_new(). * need to be informed of the value passed to cds_lfht_new().
* *
* Return 0 on success, negative error value on error. * Return 0 on success, negative error value on error.
* Threads calling this API need to be registered RCU read-side threads. * Threads calling this API need to be registered RCU read-side threads.
* cds_lfht_destroy should *not* be called from a RCU read-side critical * cds_lfht_destroy should *not* be called from a RCU read-side critical
* section. It should *not* be called from call_rcu thread context * section. It should *not* be called from a call_rcu thread context
* neither. * neither.
* In userspace RCU 0.7.x, for QSBR RCU flavor, cds_lfht_destroy() has a
* side-effect: it puts the caller thread in "online" state. This will
* be fixed in userspace RCU 0.8.x.
*/ */
extern
int cds_lfht_destroy(struct cds_lfht *ht, pthread_attr_t **attr); int cds_lfht_destroy(struct cds_lfht *ht, pthread_attr_t **attr);
/* /*
* cds_lfht_count_nodes - count the number of nodes in the hash table. * cds_lfht_count_nodes - count the number of nodes in the hash table.
* @ht: the hash table. * @ht: the hash table.
* @split_count_before: sample the node count split-counter before traversa l. * @split_count_before: sample the node count split-counter before traversa l.
* @count: traverse the hash table, count the number of nodes observed. * @count: traverse the hash table, count the number of nodes observed.
* @split_count_after: sample the node count split-counter after traversal. * @split_count_after: sample the node count split-counter after traversal.
* *
* Call with rcu_read_lock held. * Call with rcu_read_lock held.
* Threads calling this API need to be registered RCU read-side threads. * Threads calling this API need to be registered RCU read-side threads.
*/ */
extern
void cds_lfht_count_nodes(struct cds_lfht *ht, void cds_lfht_count_nodes(struct cds_lfht *ht,
long *split_count_before, long *split_count_before,
unsigned long *count, unsigned long *count,
long *split_count_after); long *split_count_after);
/* /*
* cds_lfht_lookup - lookup a node by key. * cds_lfht_lookup - lookup a node by key.
* @ht: the hash table. * @ht: the hash table.
* @hash: the key hash. * @hash: the key hash.
* @match: the key match function. * @match: the key match function.
* @key: the current node key. * @key: the current node key.
* @iter: node, if found (output). *iter->node set to NULL if not found. * @iter: node, if found (output). *iter->node set to NULL if not found.
* *
* Call with rcu_read_lock held. * Call with rcu_read_lock held.
* Threads calling this API need to be registered RCU read-side threads. * Threads calling this API need to be registered RCU read-side threads.
* This function acts as a rcu_dereference() to read the node pointer. * This function acts as a rcu_dereference() to read the node pointer.
*/ */
extern
void cds_lfht_lookup(struct cds_lfht *ht, unsigned long hash, void cds_lfht_lookup(struct cds_lfht *ht, unsigned long hash,
cds_lfht_match_fct match, const void *key, cds_lfht_match_fct match, const void *key,
struct cds_lfht_iter *iter); struct cds_lfht_iter *iter);
/* /*
* cds_lfht_next_duplicate - get the next item with same key, after iterato r. * cds_lfht_next_duplicate - get the next item with same key, after iterato r.
* @ht: the hash table. * @ht: the hash table.
* @match: the key match function. * @match: the key match function.
* @key: the current node key. * @key: the current node key.
* @iter: input: current iterator. * @iter: input: current iterator.
skipping to change at line 239 skipping to change at line 239
* cds_lfht_next_duplicate. * cds_lfht_next_duplicate.
* Sets *iter-node to the following node with same key. * Sets *iter-node to the following node with same key.
* Sets *iter->node to NULL if no following node exists with same key. * Sets *iter->node to NULL if no following node exists with same key.
* RCU read-side lock must be held across cds_lfht_lookup and * RCU read-side lock must be held across cds_lfht_lookup and
* cds_lfht_next calls, and also between cds_lfht_next calls using the * cds_lfht_next calls, and also between cds_lfht_next calls using the
* node returned by a previous cds_lfht_next. * node returned by a previous cds_lfht_next.
* Call with rcu_read_lock held. * Call with rcu_read_lock held.
* Threads calling this API need to be registered RCU read-side threads. * Threads calling this API need to be registered RCU read-side threads.
* This function acts as a rcu_dereference() to read the node pointer. * This function acts as a rcu_dereference() to read the node pointer.
*/ */
extern
void cds_lfht_next_duplicate(struct cds_lfht *ht, void cds_lfht_next_duplicate(struct cds_lfht *ht,
cds_lfht_match_fct match, const void *key, cds_lfht_match_fct match, const void *key,
struct cds_lfht_iter *iter); struct cds_lfht_iter *iter);
/* /*
* cds_lfht_first - get the first node in the table. * cds_lfht_first - get the first node in the table.
* @ht: the hash table. * @ht: the hash table.
* @iter: First node, if exists (output). *iter->node set to NULL if not fo und. * @iter: First node, if exists (output). *iter->node set to NULL if not fo und.
* *
* Output in "*iter". *iter->node set to NULL if table is empty. * Output in "*iter". *iter->node set to NULL if table is empty.
* Call with rcu_read_lock held. * Call with rcu_read_lock held.
* Threads calling this API need to be registered RCU read-side threads. * Threads calling this API need to be registered RCU read-side threads.
* This function acts as a rcu_dereference() to read the node pointer. * This function acts as a rcu_dereference() to read the node pointer.
*/ */
extern
void cds_lfht_first(struct cds_lfht *ht, struct cds_lfht_iter *iter); void cds_lfht_first(struct cds_lfht *ht, struct cds_lfht_iter *iter);
/* /*
* cds_lfht_next - get the next node in the table. * cds_lfht_next - get the next node in the table.
* @ht: the hash table. * @ht: the hash table.
* @iter: input: current iterator. * @iter: input: current iterator.
* output: next node, if exists. *iter->node set to NULL if not foun d. * output: next node, if exists. *iter->node set to NULL if not foun d.
* *
* Input/Output in "*iter". *iter->node set to NULL if *iter was * Input/Output in "*iter". *iter->node set to NULL if *iter was
* pointing to the last table node. * pointing to the last table node.
* Call with rcu_read_lock held. * Call with rcu_read_lock held.
* Threads calling this API need to be registered RCU read-side threads. * Threads calling this API need to be registered RCU read-side threads.
* This function acts as a rcu_dereference() to read the node pointer. * This function acts as a rcu_dereference() to read the node pointer.
*/ */
extern
void cds_lfht_next(struct cds_lfht *ht, struct cds_lfht_iter *iter); void cds_lfht_next(struct cds_lfht *ht, struct cds_lfht_iter *iter);
/* /*
* cds_lfht_add - add a node to the hash table. * cds_lfht_add - add a node to the hash table.
* @ht: the hash table. * @ht: the hash table.
* @hash: the key hash. * @hash: the key hash.
* @node: the node to add. * @node: the node to add.
* *
* This function supports adding redundant keys into the table. * This function supports adding redundant keys into the table.
* Call with rcu_read_lock held. * Call with rcu_read_lock held.
* Threads calling this API need to be registered RCU read-side threads. * Threads calling this API need to be registered RCU read-side threads.
* This function issues a full memory barrier before and after its * This function issues a full memory barrier before and after its
* atomic commit. * atomic commit.
*/ */
extern
void cds_lfht_add(struct cds_lfht *ht, unsigned long hash, void cds_lfht_add(struct cds_lfht *ht, unsigned long hash,
struct cds_lfht_node *node); struct cds_lfht_node *node);
/* /*
* cds_lfht_add_unique - add a node to hash table, if key is not present. * cds_lfht_add_unique - add a node to hash table, if key is not present.
* @ht: the hash table. * @ht: the hash table.
* @hash: the node's hash. * @hash: the node's hash.
* @match: the key match function. * @match: the key match function.
* @key: the node's key. * @key: the node's key.
* @node: the node to try adding. * @node: the node to try adding.
skipping to change at line 311 skipping to change at line 315
* to add keys into the table, no duplicated keys should ever be * to add keys into the table, no duplicated keys should ever be
* observable in the table. The same guarantee apply for combination of * observable in the table. The same guarantee apply for combination of
* add_unique and add_replace (see below). * add_unique and add_replace (see below).
* *
* Upon success, this function issues a full memory barrier before and * Upon success, this function issues a full memory barrier before and
* after its atomic commit. Upon failure, this function acts like a * after its atomic commit. Upon failure, this function acts like a
* simple lookup operation: it acts as a rcu_dereference() to read the * simple lookup operation: it acts as a rcu_dereference() to read the
* node pointer. The failure case does not guarantee any other memory * node pointer. The failure case does not guarantee any other memory
* barrier. * barrier.
*/ */
extern
struct cds_lfht_node *cds_lfht_add_unique(struct cds_lfht *ht, struct cds_lfht_node *cds_lfht_add_unique(struct cds_lfht *ht,
unsigned long hash, unsigned long hash,
cds_lfht_match_fct match, cds_lfht_match_fct match,
const void *key, const void *key,
struct cds_lfht_node *node); struct cds_lfht_node *node);
/* /*
* cds_lfht_add_replace - replace or add a node within hash table. * cds_lfht_add_replace - replace or add a node within hash table.
* @ht: the hash table. * @ht: the hash table.
* @hash: the node's hash. * @hash: the node's hash.
skipping to change at line 347 skipping to change at line 352
* replaced concurrently with the lookups. * replaced concurrently with the lookups.
* *
* Providing this semantic allows us to ensure that replacement-only * Providing this semantic allows us to ensure that replacement-only
* schemes will never generate duplicated keys. It also allows us to * schemes will never generate duplicated keys. It also allows us to
* guarantee that a combination of add_replace and add_unique updates * guarantee that a combination of add_replace and add_unique updates
* will never generate duplicated keys. * will never generate duplicated keys.
* *
* This function issues a full memory barrier before and after its * This function issues a full memory barrier before and after its
* atomic commit. * atomic commit.
*/ */
extern
struct cds_lfht_node *cds_lfht_add_replace(struct cds_lfht *ht, struct cds_lfht_node *cds_lfht_add_replace(struct cds_lfht *ht,
unsigned long hash, unsigned long hash,
cds_lfht_match_fct match, cds_lfht_match_fct match,
const void *key, const void *key,
struct cds_lfht_node *node); struct cds_lfht_node *node);
/* /*
* cds_lfht_replace - replace a node pointed to by iter within hash table. * cds_lfht_replace - replace a node pointed to by iter within hash table.
* @ht: the hash table. * @ht: the hash table.
* @old_iter: the iterator position of the node to replace. * @old_iter: the iterator position of the node to replace.
skipping to change at line 382 skipping to change at line 388
* freeing the memory reserved for the old node (which can be accessed * freeing the memory reserved for the old node (which can be accessed
* with cds_lfht_iter_get_node). * with cds_lfht_iter_get_node).
* *
* The semantic of replacement vs lookups is the same as * The semantic of replacement vs lookups is the same as
* cds_lfht_add_replace(). * cds_lfht_add_replace().
* *
* Upon success, this function issues a full memory barrier before and * Upon success, this function issues a full memory barrier before and
* after its atomic commit. Upon failure, this function does not issue * after its atomic commit. Upon failure, this function does not issue
* any memory barrier. * any memory barrier.
*/ */
extern
int cds_lfht_replace(struct cds_lfht *ht, int cds_lfht_replace(struct cds_lfht *ht,
struct cds_lfht_iter *old_iter, struct cds_lfht_iter *old_iter,
unsigned long hash, unsigned long hash,
cds_lfht_match_fct match, cds_lfht_match_fct match,
const void *key, const void *key,
struct cds_lfht_node *new_node); struct cds_lfht_node *new_node);
/* /*
* cds_lfht_del - remove node pointed to by iterator from hash table. * cds_lfht_del - remove node pointed to by iterator from hash table.
* @ht: the hash table. * @ht: the hash table.
skipping to change at line 410 skipping to change at line 417
* RCU read-side lock must be held between lookup and removal. * RCU read-side lock must be held between lookup and removal.
* Call with rcu_read_lock held. * Call with rcu_read_lock held.
* Threads calling this API need to be registered RCU read-side threads. * Threads calling this API need to be registered RCU read-side threads.
* After successful removal, a grace period must be waited for before * After successful removal, a grace period must be waited for before
* freeing the memory reserved for old node (which can be accessed with * freeing the memory reserved for old node (which can be accessed with
* cds_lfht_iter_get_node). * cds_lfht_iter_get_node).
* Upon success, this function issues a full memory barrier before and * Upon success, this function issues a full memory barrier before and
* after its atomic commit. Upon failure, this function does not issue * after its atomic commit. Upon failure, this function does not issue
* any memory barrier. * any memory barrier.
*/ */
extern
int cds_lfht_del(struct cds_lfht *ht, struct cds_lfht_node *node); int cds_lfht_del(struct cds_lfht *ht, struct cds_lfht_node *node);
/* /*
* cds_lfht_is_node_deleted - query whether a node is removed from hash tab le. * cds_lfht_is_node_deleted - query whether a node is removed from hash tab le.
* *
* Return non-zero if the node is deleted from the hash table, 0 * Return non-zero if the node is deleted from the hash table, 0
* otherwise. * otherwise.
* Node can be looked up with cds_lfht_lookup and cds_lfht_next, * Node can be looked up with cds_lfht_lookup and cds_lfht_next,
* followed by use of cds_lfht_iter_get_node. * followed by use of cds_lfht_iter_get_node.
* RCU read-side lock must be held between lookup and call to this * RCU read-side lock must be held between lookup and call to this
* function. * function.
* Call with rcu_read_lock held. * Call with rcu_read_lock held.
* Threads calling this API need to be registered RCU read-side threads. * Threads calling this API need to be registered RCU read-side threads.
* This function does not issue any memory barrier. * This function does not issue any memory barrier.
*/ */
extern
int cds_lfht_is_node_deleted(struct cds_lfht_node *node); int cds_lfht_is_node_deleted(struct cds_lfht_node *node);
/* /*
* cds_lfht_resize - Force a hash table resize * cds_lfht_resize - Force a hash table resize
* @ht: the hash table. * @ht: the hash table.
* @new_size: update to this hash table size. * @new_size: update to this hash table size.
* *
* Threads calling this API need to be registered RCU read-side threads. * Threads calling this API need to be registered RCU read-side threads.
* This function does not (necessarily) issue memory barriers. * This function does not (necessarily) issue memory barriers.
* cds_lfht_resize should *not* be called from a RCU read-side critical * cds_lfht_resize should *not* be called from a RCU read-side critical
* section. * section.
* In userspace RCU 0.7.x, for QSBR RCU flavor, cds_lfht_resize() has a
* side-effect: it puts the caller thread in "online" state. This will
* be fixed in userspace RCU 0.8.x.
*/ */
extern
void cds_lfht_resize(struct cds_lfht *ht, unsigned long new_size); void cds_lfht_resize(struct cds_lfht *ht, unsigned long new_size);
/* /*
* Note: it is safe to perform element removal (del), replacement, or * Note: it is safe to perform element removal (del), replacement, or
* any hash table update operation during any of the following hash * any hash table update operation during any of the following hash
* table traversals. * table traversals.
* These functions act as rcu_dereference() to read the node pointers. * These functions act as rcu_dereference() to read the node pointers.
*/ */
#define cds_lfht_for_each(ht, iter, node) \ #define cds_lfht_for_each(ht, iter, node) \
for (cds_lfht_first(ht, iter), \ for (cds_lfht_first(ht, iter), \
skipping to change at line 466 skipping to change at line 473
for (cds_lfht_lookup(ht, hash, match, key, iter), \ for (cds_lfht_lookup(ht, hash, match, key, iter), \
node = cds_lfht_iter_get_node(iter); \ node = cds_lfht_iter_get_node(iter); \
node != NULL; \ node != NULL; \
cds_lfht_next_duplicate(ht, match, key, iter), \ cds_lfht_next_duplicate(ht, match, key, iter), \
node = cds_lfht_iter_get_node(iter)) node = cds_lfht_iter_get_node(iter))
#define cds_lfht_for_each_entry(ht, iter, pos, member) \ #define cds_lfht_for_each_entry(ht, iter, pos, member) \
for (cds_lfht_first(ht, iter), \ for (cds_lfht_first(ht, iter), \
pos = caa_container_of(cds_lfht_iter_get_node(iter), \ pos = caa_container_of(cds_lfht_iter_get_node(iter), \
__typeof__(*(pos)), member); \ __typeof__(*(pos)), member); \
cds_lfht_iter_get_node(iter) != NULL; \ &(pos)->member != NULL; \
cds_lfht_next(ht, iter), \ cds_lfht_next(ht, iter), \
pos = caa_container_of(cds_lfht_iter_get_node(iter), \ pos = caa_container_of(cds_lfht_iter_get_node(iter), \
__typeof__(*(pos)), member)) __typeof__(*(pos)), member))
#define cds_lfht_for_each_entry_duplicate(ht, hash, match, key, \ #define cds_lfht_for_each_entry_duplicate(ht, hash, match, key, \
iter, pos, member) \ iter, pos, member) \
for (cds_lfht_lookup(ht, hash, match, key, iter), \ for (cds_lfht_lookup(ht, hash, match, key, iter), \
pos = caa_container_of(cds_lfht_iter_get_node(iter), \ pos = caa_container_of(cds_lfht_iter_get_node(iter), \
__typeof__(*(pos)), member); \ __typeof__(*(pos)), member); \
cds_lfht_iter_get_node(iter) != NULL; \ &(pos)->member != NULL; \
cds_lfht_next_duplicate(ht, match, key, iter), \ cds_lfht_next_duplicate(ht, match, key, iter), \
pos = caa_container_of(cds_lfht_iter_get_node(iter), \ pos = caa_container_of(cds_lfht_iter_get_node(iter), \
__typeof__(*(pos)), member)) __typeof__(*(pos)), member))
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* _URCU_RCULFHASH_H */ #endif /* _URCU_RCULFHASH_H */
 End of changes. 20 change blocks. 
11 lines changed or deleted 18 lines changed or added


 rculfstack.h   rculfstack.h 
skipping to change at line 26 skipping to change at line 26
* This library is distributed in the hope that it will be useful, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include <urcu/compiler.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#ifndef CDS_LFS_RCU_DEPRECATED
#define CDS_LFS_RCU_DEPRECATED \
CDS_DEPRECATED("urcu/rculfstack.h is deprecated. Please use urcu/lfs
tack.h instead.")
#endif
struct cds_lfs_node_rcu { struct cds_lfs_node_rcu {
struct cds_lfs_node_rcu *next; struct cds_lfs_node_rcu *next;
}; };
struct cds_lfs_stack_rcu { struct cds_lfs_stack_rcu {
struct cds_lfs_node_rcu *head; struct cds_lfs_node_rcu *head;
}; };
#ifdef _LGPL_SOURCE #ifdef _LGPL_SOURCE
#include <urcu/static/rculfstack.h> #include <urcu/static/rculfstack.h>
#define cds_lfs_node_init_rcu _cds_lfs_node_init_rcu static inline CDS_LFS_RCU_DEPRECATED
#define cds_lfs_init_rcu _cds_lfs_init_rcu void cds_lfs_node_init_rcu(struct cds_lfs_node_rcu *node)
#define cds_lfs_push_rcu _cds_lfs_push_rcu {
#define cds_lfs_pop_rcu _cds_lfs_pop_rcu _cds_lfs_node_init_rcu(node);
}
static inline
void cds_lfs_init_rcu(struct cds_lfs_stack_rcu *s)
{
_cds_lfs_init_rcu(s);
}
static inline CDS_LFS_RCU_DEPRECATED
int cds_lfs_push_rcu(struct cds_lfs_stack_rcu *s,
struct cds_lfs_node_rcu *node)
{
return _cds_lfs_push_rcu(s, node);
}
static inline CDS_LFS_RCU_DEPRECATED
struct cds_lfs_node_rcu *cds_lfs_pop_rcu(struct cds_lfs_stack_rcu *s)
{
return _cds_lfs_pop_rcu(s);
}
#else /* !_LGPL_SOURCE */ #else /* !_LGPL_SOURCE */
extern void cds_lfs_node_init_rcu(struct cds_lfs_node_rcu *node); extern CDS_LFS_RCU_DEPRECATED
extern void cds_lfs_init_rcu(struct cds_lfs_stack_rcu *s); void cds_lfs_node_init_rcu(struct cds_lfs_node_rcu *node);
extern int cds_lfs_push_rcu(struct cds_lfs_stack_rcu *s, extern CDS_LFS_RCU_DEPRECATED
void cds_lfs_init_rcu(struct cds_lfs_stack_rcu *s);
extern CDS_LFS_RCU_DEPRECATED
int cds_lfs_push_rcu(struct cds_lfs_stack_rcu *s,
struct cds_lfs_node_rcu *node); struct cds_lfs_node_rcu *node);
/* /*
* Should be called under rcu read lock critical section. * Should be called under rcu read lock critical section.
* *
* The caller must wait for a grace period to pass before freeing the retur ned * The caller must wait for a grace period to pass before freeing the retur ned
* node or modifying the cds_lfs_node_rcu structure. * node or modifying the cds_lfs_node_rcu structure.
* Returns NULL if stack is empty. * Returns NULL if stack is empty.
*/ */
extern struct cds_lfs_node_rcu *cds_lfs_pop_rcu(struct cds_lfs_stack_rcu *s extern CDS_LFS_RCU_DEPRECATED
); struct cds_lfs_node_rcu *cds_lfs_pop_rcu(struct cds_lfs_stack_rcu *s);
#endif /* !_LGPL_SOURCE */ #endif /* !_LGPL_SOURCE */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* _URCU_RCULFSTACK_H */ #endif /* _URCU_RCULFSTACK_H */
 End of changes. 5 change blocks. 
9 lines changed or deleted 40 lines changed or added


 rculist.h   rculist.h 
skipping to change at line 32 skipping to change at line 32
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#ifndef _URCU_RCULIST_H #ifndef _URCU_RCULIST_H
#define _URCU_RCULIST_H #define _URCU_RCULIST_H
#include <urcu/list.h> #include <urcu/list.h>
#include <urcu/arch.h> #include <urcu/arch.h>
#include <urcu-pointer.h> #include <urcu-pointer.h>
/* Add new element at the head of the list. /* Add new element at the head of the list. */
*/ static inline
static inline void cds_list_add_rcu(struct cds_list_head *newp, struct cds_ void cds_list_add_rcu(struct cds_list_head *newp, struct cds_list_head *hea
list_head *head) d)
{ {
newp->next = head->next; newp->next = head->next;
newp->prev = head; newp->prev = head;
cmm_smp_wmb();
head->next->prev = newp; head->next->prev = newp;
head->next = newp; rcu_assign_pointer(head->next, newp);
}
/* 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. /*
* 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 c static inline
ds_list_head *_new) void cds_list_replace_rcu(struct cds_list_head *old, struct cds_list_head *
_new)
{ {
_new->next = old->next; _new->next = old->next;
_new->prev = old->prev; _new->prev = old->prev;
rcu_assign_pointer(_new->prev->next, _new); rcu_assign_pointer(_new->prev->next, _new);
_new->next->prev = _new; _new->next->prev = _new;
} }
/* Remove element from list. */ /* Remove element from list. */
static inline void cds_list_del_rcu(struct cds_list_head *elem) static inline
void cds_list_del_rcu(struct cds_list_head *elem)
{ {
elem->next->prev = elem->prev; elem->next->prev = elem->prev;
elem->prev->next = elem->next; CMM_STORE_SHARED(elem->prev->next, elem->next);
} }
/* /*
* Iteration through all elements of the list must be done while rcu_read_l ock() * Iteration through all elements of the list must be done while rcu_read_l ock()
* is held. * is held.
*/ */
/* Iterate forward over the elements of the list. */ /* Iterate forward over the elements of the list. */
#define cds_list_for_each_rcu(pos, head) \ #define cds_list_for_each_rcu(pos, head) \
for (pos = rcu_dereference((head)->next); pos != (head); \ for (pos = rcu_dereference((head)->next); pos != (head); \
pos = rcu_dereference(pos->next)) pos = rcu_dereference(pos->next))
/* Iterate through elements of the list. /* Iterate through elements of the list. */
*/ #define cds_list_for_each_entry_rcu(pos, head, member) \
#define cds_list_for_each_entry_rcu(pos, head, member) for (pos = cds_list_entry(rcu_dereference((head)->next), __typeof__(
\ *pos), member); \
for (pos = cds_list_entry(rcu_dereference((head)->next), __typeof__( &pos->member != (head); \
*pos), member); \ pos = cds_list_entry(rcu_dereference(pos->member.next), __ty
&pos->member != (head); \ peof__(*pos), member))
pos = cds_list_entry(rcu_dereference(pos->member.next), __typeo
f__(*pos), member))
#endif /* _URCU_RCULIST_H */ #endif /* _URCU_RCULIST_H */
 End of changes. 9 change blocks. 
22 lines changed or deleted 35 lines changed or added


 system.h   system.h 
skipping to change at line 35 skipping to change at line 35
/* /*
* Identify a shared load. A cmm_smp_rmc() or cmm_smp_mc() should come * Identify a shared load. A cmm_smp_rmc() or cmm_smp_mc() should come
* before the load. * before the load.
*/ */
#define _CMM_LOAD_SHARED(p) CMM_ACCESS_ONCE(p) #define _CMM_LOAD_SHARED(p) CMM_ACCESS_ONCE(p)
/* /*
* Load a data from shared memory, doing a cache flush if required. * Load a data from shared memory, doing a cache flush if required.
*/ */
#define CMM_LOAD_SHARED(p) \ #define CMM_LOAD_SHARED(p) \
__extension__ \
({ \ ({ \
cmm_smp_rmc(); \ cmm_smp_rmc(); \
_CMM_LOAD_SHARED(p); \ _CMM_LOAD_SHARED(p); \
}) })
/* /*
* Identify a shared store. A cmm_smp_wmc() or cmm_smp_mc() should * Identify a shared store. A cmm_smp_wmc() or cmm_smp_mc() should
* follow the store. * follow the store.
*/ */
#define _CMM_STORE_SHARED(x, v) __extension__ ({ CMM_ACCESS_ONCE(x) = (v); }) #define _CMM_STORE_SHARED(x, v) ({ CMM_ACCESS_ONCE(x) = (v); })
/* /*
* Store v into x, where x is located in shared memory. Performs the * Store v into x, where x is located in shared memory. Performs the
* required cache flush after writing. Returns v. * required cache flush after writing. Returns v.
*/ */
#define CMM_STORE_SHARED(x, v) \ #define CMM_STORE_SHARED(x, v) \
__extension__ \
({ \ ({ \
__typeof__(x) _v = _CMM_STORE_SHARED(x, v); \ __typeof__(x) _v = _CMM_STORE_SHARED(x, v); \
cmm_smp_wmc(); \ cmm_smp_wmc(); \
_v = _v; /* Work around clang "unused result" */ \ _v = _v; /* Work around clang "unused result" */ \
}) })
#endif /* _URCU_SYSTEM_H */ #endif /* _URCU_SYSTEM_H */
 End of changes. 3 change blocks. 
3 lines changed or deleted 1 lines changed or added


 tls-compat.h   tls-compat.h 
skipping to change at line 47 skipping to change at line 47
/* /*
* Hint: How to define/declare TLS variables of compound types * Hint: How to define/declare TLS variables of compound types
* such as array or function pointers? * such as array or function pointers?
* *
* Answer: Use typedef to assign a type_name to the compound type. * Answer: Use typedef to assign a type_name to the compound type.
* Example: Define a TLS variable which is an int array with len=4: * Example: Define a TLS variable which is an int array with len=4:
* *
* typedef int my_int_array_type[4]; * typedef int my_int_array_type[4];
* DEFINE_URCU_TLS(my_int_array_type, var_name); * DEFINE_URCU_TLS(my_int_array_type, var_name);
* *
* Another exmaple: * Another example:
* typedef void (*call_rcu_flavor)(struct rcu_head *, XXXX); * typedef void (*call_rcu_flavor)(struct rcu_head *, XXXX);
* DECLARE_URCU_TLS(call_rcu_flavor, p_call_rcu); * DECLARE_URCU_TLS(call_rcu_flavor, p_call_rcu);
* *
* NOTE: URCU_TLS() is NOT async-signal-safe, you can't use it * NOTE: URCU_TLS() is NOT async-signal-safe, you can't use it
* inside any function which can be called from signal handler. * inside any function which can be called from signal handler.
* *
* But if pthread_getspecific() is async-signal-safe in your * But if pthread_getspecific() is async-signal-safe in your
* platform, you can make URCU_TLS() async-signal-safe via: * platform, you can make URCU_TLS() async-signal-safe via:
* ensuring the first call to URCU_TLS() of a given TLS variable of * ensuring the first call to URCU_TLS() of a given TLS variable of
* all threads is called earliest from a non-signal handler function. * all threads is called earliest from a non-signal handler function.
skipping to change at line 73 skipping to change at line 73
* Moreover, URCU_TLS variables should not be touched from signal * Moreover, URCU_TLS variables should not be touched from signal
* handlers setup with with sigaltstack(2). * handlers setup with with sigaltstack(2).
*/ */
# define DECLARE_URCU_TLS(type, name) \ # define DECLARE_URCU_TLS(type, name) \
CONFIG_RCU_TLS type name CONFIG_RCU_TLS type name
# define DEFINE_URCU_TLS(type, name) \ # define DEFINE_URCU_TLS(type, name) \
CONFIG_RCU_TLS type name CONFIG_RCU_TLS type name
# define __DEFINE_URCU_TLS_GLOBAL(type, name) \
CONFIG_RCU_TLS type name
# define URCU_TLS(name) (name) # define URCU_TLS(name) (name)
#else /* #ifndef CONFIG_RCU_TLS */ #else /* #ifndef CONFIG_RCU_TLS */
/*
* The *_1() macros ensure macro parameters are expanded.
*
* __DEFINE_URCU_TLS_GLOBAL and __URCU_TLS_CALL exist for the sole
* purpose of notifying applications compiled against non-fixed 0.7 and
* 0.8 userspace RCU headers and using multiple flavors concurrently to
* recompile against fixed userspace RCU headers.
*/
# include <pthread.h> # include <pthread.h>
struct urcu_tls { struct urcu_tls {
pthread_key_t key; pthread_key_t key;
pthread_mutex_t init_mutex; pthread_mutex_t init_mutex;
int init_done; int init_done;
}; };
# define DECLARE_URCU_TLS_1(type, name) \
type *__tls_access2_ ## name(void)
# define DECLARE_URCU_TLS(type, name) \ # define DECLARE_URCU_TLS(type, name) \
DECLARE_URCU_TLS_1(type, name) type *__tls_access_ ## name(void)
/* /*
* Note: we don't free memory at process exit, since it will be dealt * Note: we don't free memory at process exit, since it will be dealt
* with by the OS. * with by the OS.
*/ */
# define __URCU_TLS_CALL_1(name) \ # define DEFINE_URCU_TLS(type, name) \
__tls_access2_ ## name type *__tls_access_ ## name(void) \
# define __URCU_TLS_CALL(name) \
__URCU_TLS_CALL_1(name)
# define DEFINE_URCU_TLS_1(type, name) \
type *__tls_access2_ ## name(void) \
{ \ { \
static struct urcu_tls __tls_ ## name = { \ static struct urcu_tls __tls_ ## name = { \
.init_mutex = PTHREAD_MUTEX_INITIALIZER,\ .init_mutex = PTHREAD_MUTEX_INITIALIZER,\
.init_done = 0, \ .init_done = 0, \
}; \ }; \
void *__tls_p; \ void *__tls_p; \
if (!__tls_ ## name.init_done) { \ if (!__tls_ ## name.init_done) { \
/* Mutex to protect concurrent init */ \ /* Mutex to protect concurrent init */ \
pthread_mutex_lock(&__tls_ ## name.init_mutex); \ pthread_mutex_lock(&__tls_ ## name.init_mutex); \
if (!__tls_ ## name.init_done) { \ if (!__tls_ ## name.init_done) { \
skipping to change at line 142 skipping to change at line 121
cmm_smp_rmb(); /* read init_done before getting key */ \ cmm_smp_rmb(); /* read init_done before getting key */ \
__tls_p = pthread_getspecific(__tls_ ## name.key); \ __tls_p = pthread_getspecific(__tls_ ## name.key); \
if (caa_unlikely(__tls_p == NULL)) { \ if (caa_unlikely(__tls_p == NULL)) { \
__tls_p = calloc(1, sizeof(type)); \ __tls_p = calloc(1, sizeof(type)); \
(void) pthread_setspecific(__tls_ ## name.key, \ (void) pthread_setspecific(__tls_ ## name.key, \
__tls_p); \ __tls_p); \
} \ } \
return __tls_p; \ return __tls_p; \
} }
/* # define URCU_TLS(name) (*__tls_access_ ## name())
* Define with and without macro expansion to handle erroneous callers.
* Trigger an abort() if the caller application uses the clashing symbol
* if a weak symbol is overridden.
*/
# define __DEFINE_URCU_TLS_GLOBAL(type, name) \
DEFINE_URCU_TLS_1(type, name) \
int __urcu_tls_symbol_refcount_ ## name __attribute__((weak)); \
static __attribute__((constructor)) \
void __urcu_tls_inc_refcount_ ## name(void) \
{ \
__urcu_tls_symbol_refcount_ ## name++; \
} \
type *__tls_access_ ## name(void) \
{ \
if (__urcu_tls_symbol_refcount_ ## name > 1) { \
fprintf(stderr, "Error: Userspace RCU symbol clash f
or multiple concurrent flavors. Please upgrade liburcu libraries and header
s, then recompile your application.\n"); \
abort(); \
} \
return __URCU_TLS_CALL(name)(); \
}
# define DEFINE_URCU_TLS(type, name) \
DEFINE_URCU_TLS_1(type, name)
# define URCU_TLS_1(name) (*__tls_access2_ ## name())
# define URCU_TLS(name) URCU_TLS_1(name)
#endif /* #else #ifndef CONFIG_RCU_TLS */ #endif /* #else #ifndef CONFIG_RCU_TLS */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* _URCU_TLS_COMPAT_H */ #endif /* _URCU_TLS_COMPAT_H */
 End of changes. 7 change blocks. 
55 lines changed or deleted 5 lines changed or added


 urcu-bp.h   urcu-bp.h 
skipping to change at line 77 skipping to change at line 77
*/ */
/* /*
* rcu_read_lock() * rcu_read_lock()
* rcu_read_unlock() * rcu_read_unlock()
* *
* Mark the beginning and end of a read-side critical section. * Mark the beginning and end of a read-side critical section.
*/ */
#define rcu_read_lock_bp _rcu_read_lock #define rcu_read_lock_bp _rcu_read_lock
#define rcu_read_unlock_bp _rcu_read_unlock #define rcu_read_unlock_bp _rcu_read_unlock
#define rcu_read_ongoing_bp _rcu_read_ongoing
#define rcu_dereference_bp rcu_dereference #define rcu_dereference_bp rcu_dereference
#define rcu_cmpxchg_pointer_bp rcu_cmpxchg_pointer #define rcu_cmpxchg_pointer_bp rcu_cmpxchg_pointer
#define rcu_xchg_pointer_bp rcu_xchg_pointer #define rcu_xchg_pointer_bp rcu_xchg_pointer
#define rcu_set_pointer_bp rcu_set_pointer #define rcu_set_pointer_bp rcu_set_pointer
#else /* !_LGPL_SOURCE */ #else /* !_LGPL_SOURCE */
/* /*
* library wrappers to be used by non-LGPL compatible source code. * library wrappers to be used by non-LGPL compatible source code.
* See LGPL-only urcu/static/urcu-pointer.h for documentation. * See LGPL-only urcu/static/urcu-pointer.h for documentation.
*/ */
extern void rcu_read_lock(void); extern void rcu_read_lock(void);
extern void rcu_read_unlock(void); extern void rcu_read_unlock(void);
extern int rcu_read_ongoing(void);
extern void *rcu_dereference_sym_bp(void *p); extern void *rcu_dereference_sym_bp(void *p);
#define rcu_dereference_bp(p) \ #define rcu_dereference_bp(p) \
__extension__ \
({ \ ({ \
__typeof__(p) _________p1 = URCU_FORCE_CAST(__typeof__(p), \ __typeof__(p) _________p1 = URCU_FORCE_CAST(__typeof__(p), \
rcu_dereference_sym_bp(URCU_FORCE_CAST(void *, p))); \ rcu_dereference_sym_bp(URCU_FORCE_CAST(void *, p))); \
(_________p1); \ (_________p1); \
}) })
extern void *rcu_cmpxchg_pointer_sym_bp(void **p, void *old, void *_new); extern void *rcu_cmpxchg_pointer_sym_bp(void **p, void *old, void *_new);
#define rcu_cmpxchg_pointer_bp(p, old, _new) \ #define rcu_cmpxchg_pointer_bp(p, old, _new) \
__extension__ \
({ \ ({ \
__typeof__(*(p)) _________pold = (old); \ __typeof__(*(p)) _________pold = (old); \
__typeof__(*(p)) _________pnew = (_new); \ __typeof__(*(p)) _________pnew = (_new); \
__typeof__(*(p)) _________p1 = URCU_FORCE_CAST(__typeof__(*( p)), \ __typeof__(*(p)) _________p1 = URCU_FORCE_CAST(__typeof__(*( p)), \
rcu_cmpxchg_pointer_sym_bp(URCU_FORCE_CAST(void **, p), \ rcu_cmpxchg_pointer_sym_bp(URCU_FORCE_CAST(void **, p), \
_________pold, \ _________pold, \
_________pnew)); \ _________pnew)); \
(_________p1); \ (_________p1); \
}) })
extern void *rcu_xchg_pointer_sym_bp(void **p, void *v); extern void *rcu_xchg_pointer_sym_bp(void **p, void *v);
#define rcu_xchg_pointer_bp(p, v) \ #define rcu_xchg_pointer_bp(p, v) \
__extension__ \
({ \ ({ \
__typeof__(*(p)) _________pv = (v); \ __typeof__(*(p)) _________pv = (v); \
__typeof__(*(p)) _________p1 = URCU_FORCE_CAST(__typeof__(*( p)),\ __typeof__(*(p)) _________p1 = URCU_FORCE_CAST(__typeof__(*( p)),\
rcu_xchg_pointer_sym_bp(URCU_FORCE_CAST(void **, p), \ rcu_xchg_pointer_sym_bp(URCU_FORCE_CAST(void **, p), \
_________pv)); \ _________pv)); \
(_________p1); \ (_________p1); \
}) })
extern void *rcu_set_pointer_sym_bp(void **p, void *v); extern void *rcu_set_pointer_sym_bp(void **p, void *v);
#define rcu_set_pointer_bp(p, v) \ #define rcu_set_pointer_bp(p, v) \
__extension__ \
({ \ ({ \
__typeof__(*(p)) _________pv = (v); \ __typeof__(*(p)) _________pv = (v); \
__typeof__(*(p)) _________p1 = URCU_FORCE_CAST(__typeof__(*( p)), \ __typeof__(*(p)) _________p1 = URCU_FORCE_CAST(__typeof__(*( p)), \
rcu_set_pointer_sym_bp(URCU_FORCE_CAST(void **, p), \ rcu_set_pointer_sym_bp(URCU_FORCE_CAST(void **, p), \
_________pv)); \ _________pv)); \
(_________p1); \ (_________p1); \
}) })
#endif /* !_LGPL_SOURCE */ #endif /* !_LGPL_SOURCE */
 End of changes. 6 change blocks. 
4 lines changed or deleted 2 lines changed or added


 urcu-call-rcu.h   urcu-call-rcu.h 
skipping to change at line 35 skipping to change at line 35
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include <stdlib.h> #include <stdlib.h>
#include <pthread.h> #include <pthread.h>
#include <urcu/wfqueue.h> #include <urcu/wfcqueue.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
/* Note that struct call_rcu_data is opaque to callers. */ /* Note that struct call_rcu_data is opaque to callers. */
struct call_rcu_data; struct call_rcu_data;
/* Flag values. */ /* Flag values. */
skipping to change at line 60 skipping to change at line 60
#define URCU_CALL_RCU_STOPPED (1U << 3) #define URCU_CALL_RCU_STOPPED (1U << 3)
#define URCU_CALL_RCU_PAUSE (1U << 4) #define URCU_CALL_RCU_PAUSE (1U << 4)
#define URCU_CALL_RCU_PAUSED (1U << 5) #define URCU_CALL_RCU_PAUSED (1U << 5)
/* /*
* The rcu_head data structure is placed in the structure to be freed * The rcu_head data structure is placed in the structure to be freed
* via call_rcu(). * via call_rcu().
*/ */
struct rcu_head { struct rcu_head {
struct cds_wfq_node next; struct cds_wfcq_node next;
void (*func)(struct rcu_head *head); void (*func)(struct rcu_head *head);
}; };
/* /*
* Exported functions * Exported functions
* *
* Important: see rcu-api.txt in userspace-rcu documentation for * Important: see rcu-api.txt in userspace-rcu documentation for
* call_rcu family of functions usage detail, including the surrounding * call_rcu family of functions usage detail, including the surrounding
* RCU usage required when using these primitives. * RCU usage required when using these primitives.
*/ */
skipping to change at line 95 skipping to change at line 95
void set_thread_call_rcu_data(struct call_rcu_data *crdp); void set_thread_call_rcu_data(struct call_rcu_data *crdp);
int set_cpu_call_rcu_data(int cpu, struct call_rcu_data *crdp); int set_cpu_call_rcu_data(int cpu, struct call_rcu_data *crdp);
int create_all_cpu_call_rcu_data(unsigned long flags); int create_all_cpu_call_rcu_data(unsigned long flags);
void free_all_cpu_call_rcu_data(void); void free_all_cpu_call_rcu_data(void);
void call_rcu_before_fork(void); void call_rcu_before_fork(void);
void call_rcu_after_fork_parent(void); void call_rcu_after_fork_parent(void);
void call_rcu_after_fork_child(void); void call_rcu_after_fork_child(void);
void rcu_barrier(void);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* _URCU_CALL_RCU_H */ #endif /* _URCU_CALL_RCU_H */
 End of changes. 3 change blocks. 
2 lines changed or deleted 4 lines changed or added


 urcu-flavor.h   urcu-flavor.h 
skipping to change at line 33 skipping to change at line 33
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
struct rcu_flavor_struct { struct rcu_flavor_struct {
void (*read_lock)(void); void (*read_lock)(void);
void (*read_unlock)(void); void (*read_unlock)(void);
int (*read_ongoing)(void);
void (*read_quiescent_state)(void); void (*read_quiescent_state)(void);
void (*update_call_rcu)(struct rcu_head *head, void (*update_call_rcu)(struct rcu_head *head,
void (*func)(struct rcu_head *head)); void (*func)(struct rcu_head *head));
void (*update_synchronize_rcu)(void); void (*update_synchronize_rcu)(void);
void (*update_defer_rcu)(void (*fct)(void *p), void *p); void (*update_defer_rcu)(void (*fct)(void *p), void *p);
void (*thread_offline)(void); void (*thread_offline)(void);
void (*thread_online)(void); void (*thread_online)(void);
void (*register_thread)(void); void (*register_thread)(void);
void (*unregister_thread)(void); void (*unregister_thread)(void);
void (*barrier)(void);
}; };
#define DEFINE_RCU_FLAVOR(x) \ #define DEFINE_RCU_FLAVOR(x) \
const struct rcu_flavor_struct x = { \ const struct rcu_flavor_struct x = { \
.read_lock = rcu_read_lock, \ .read_lock = rcu_read_lock, \
.read_unlock = rcu_read_unlock, \ .read_unlock = rcu_read_unlock, \
.read_ongoing = rcu_read_ongoing, \
.read_quiescent_state = rcu_quiescent_state, \ .read_quiescent_state = rcu_quiescent_state, \
.update_call_rcu = call_rcu, \ .update_call_rcu = call_rcu, \
.update_synchronize_rcu = synchronize_rcu, \ .update_synchronize_rcu = synchronize_rcu, \
.update_defer_rcu = defer_rcu, \ .update_defer_rcu = defer_rcu, \
.thread_offline = rcu_thread_offline, \ .thread_offline = rcu_thread_offline, \
.thread_online = rcu_thread_online, \ .thread_online = rcu_thread_online, \
.register_thread = rcu_register_thread, \ .register_thread = rcu_register_thread, \
.unregister_thread = rcu_unregister_thread,\ .unregister_thread = rcu_unregister_thread,\
.barrier = rcu_barrier, \
} }
extern const struct rcu_flavor_struct rcu_flavor; extern const struct rcu_flavor_struct rcu_flavor;
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* _URCU_FLAVOR_H */ #endif /* _URCU_FLAVOR_H */
 End of changes. 4 change blocks. 
0 lines changed or deleted 5 lines changed or added


 urcu-pointer.h   urcu-pointer.h 
skipping to change at line 37 skipping to change at line 37
*/ */
#include <urcu/compiler.h> #include <urcu/compiler.h>
#include <urcu/arch.h> #include <urcu/arch.h>
#include <urcu/uatomic.h> #include <urcu/uatomic.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#ifdef _LGPL_SOURCE #if defined(_LGPL_SOURCE) || defined(URCU_INLINE_SMALL_FUNCTIONS)
#include <urcu/static/urcu-pointer.h> #include <urcu/static/urcu-pointer.h>
/* /*
* rcu_dereference(ptr) * rcu_dereference(ptr)
* *
* Fetch a RCU-protected pointer. Typically used to copy the variable ptr t o a * Fetch a RCU-protected pointer. Typically used to copy the variable ptr t o a
* local variable. * local variable.
*/ */
#define rcu_dereference _rcu_dereference #define rcu_dereference _rcu_dereference
skipping to change at line 65 skipping to change at line 65
* @ptr: address of the pointer to modify * @ptr: address of the pointer to modify
* @new: new pointer value * @new: new pointer value
* @old: old pointer value (expected) * @old: old pointer value (expected)
* *
* return: old pointer value * return: old pointer value
*/ */
#define rcu_cmpxchg_pointer _rcu_cmpxchg_pointer #define rcu_cmpxchg_pointer _rcu_cmpxchg_pointer
#define rcu_xchg_pointer _rcu_xchg_pointer #define rcu_xchg_pointer _rcu_xchg_pointer
#define rcu_set_pointer _rcu_set_pointer #define rcu_set_pointer _rcu_set_pointer
#else /* !_LGPL_SOURCE */ #else /* !(defined(_LGPL_SOURCE) || defined(URCU_INLINE_SMALL_FUNCTIONS)) * /
extern void *rcu_dereference_sym(void *p); extern void *rcu_dereference_sym(void *p);
#define rcu_dereference(p) \ #define rcu_dereference(p) \
__extension__ \
({ \ ({ \
__typeof__(p) _________p1 = URCU_FORCE_CAST(__typeof__(p ), \ __typeof__(p) _________p1 = URCU_FORCE_CAST(__typeof__(p ), \
rcu_dereference_sym(URCU_FORCE_CAST(void *, p))); \ rcu_dereference_sym(URCU_FORCE_CAST(void *, p))); \
(_________p1); \ (_________p1); \
}) })
extern void *rcu_cmpxchg_pointer_sym(void **p, void *old, void *_new); extern void *rcu_cmpxchg_pointer_sym(void **p, void *old, void *_new);
#define rcu_cmpxchg_pointer(p, old, _new) \ #define rcu_cmpxchg_pointer(p, old, _new) \
__extension__ \
({ \ ({ \
__typeof__(*(p)) _________pold = (old); \ __typeof__(*(p)) _________pold = (old); \
__typeof__(*(p)) _________pnew = (_new); \ __typeof__(*(p)) _________pnew = (_new); \
__typeof__(*(p)) _________p1 = URCU_FORCE_CAST(__typeof__(*( p)), \ __typeof__(*(p)) _________p1 = URCU_FORCE_CAST(__typeof__(*( p)), \
rcu_cmpxchg_pointer_sym(URCU_FORCE_CAST(void **, p), \ rcu_cmpxchg_pointer_sym(URCU_FORCE_CAST(void **, p), \
_________pold, \ _________pold, \
_________pnew)); \ _________pnew)); \
(_________p1); \ (_________p1); \
}) })
extern void *rcu_xchg_pointer_sym(void **p, void *v); extern void *rcu_xchg_pointer_sym(void **p, void *v);
#define rcu_xchg_pointer(p, v) \ #define rcu_xchg_pointer(p, v) \
__extension__ \
({ \ ({ \
__typeof__(*(p)) _________pv = (v); \ __typeof__(*(p)) _________pv = (v); \
__typeof__(*(p)) _________p1 = URCU_FORCE_CAST(__typeof__(*( p)), \ __typeof__(*(p)) _________p1 = URCU_FORCE_CAST(__typeof__(*( p)), \
rcu_xchg_pointer_sym(URCU_FORCE_CAST(void **, p), \ rcu_xchg_pointer_sym(URCU_FORCE_CAST(void **, p), \
_________pv)); \ _________pv)); \
(_________p1); \ (_________p1); \
}) })
/* /*
* Note: rcu_set_pointer_sym returns @v because we don't want to break * Note: rcu_set_pointer_sym returns @v because we don't want to break
skipping to change at line 114 skipping to change at line 111
* error. * error.
*/ */
extern void *rcu_set_pointer_sym(void **p, void *v); extern void *rcu_set_pointer_sym(void **p, void *v);
#define rcu_set_pointer(p, v) \ #define rcu_set_pointer(p, v) \
do { \ do { \
__typeof__(*(p)) _________pv = (v); \ __typeof__(*(p)) _________pv = (v); \
(void) rcu_set_pointer_sym(URCU_FORCE_CAST(void **, p), \ (void) rcu_set_pointer_sym(URCU_FORCE_CAST(void **, p), \
_________pv); \ _________pv); \
} while (0) } while (0)
#endif /* !_LGPL_SOURCE */ #endif /* !(defined(_LGPL_SOURCE) || defined(URCU_INLINE_SMALL_FUNCTIONS)) */
/* /*
* void rcu_assign_pointer(type *ptr, type *new) * void rcu_assign_pointer(type *ptr, type *new)
* *
* Same as rcu_set_pointer, but takes the pointer to assign to rather than its * Same as rcu_set_pointer, but takes the pointer to assign to rather than its
* address as first parameter. Provided for compatibility with the Linux ke rnel * address as first parameter. Provided for compatibility with the Linux ke rnel
* RCU semantic. * RCU semantic.
*/ */
#define rcu_assign_pointer(p, v) rcu_set_pointer((&p), (v)) #define rcu_assign_pointer(p, v) rcu_set_pointer((&p), (v))
 End of changes. 6 change blocks. 
6 lines changed or deleted 3 lines changed or added


 urcu-qsbr.h   urcu-qsbr.h 
skipping to change at line 46 skipping to change at line 46
* publication headers. * publication headers.
*/ */
#include <urcu-pointer.h> #include <urcu-pointer.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#include <urcu/map/urcu-qsbr.h> #include <urcu/map/urcu-qsbr.h>
#ifdef RCU_DEBUG /* For backward compatibility */
#define DEBUG_RCU
#endif
/* /*
* Important ! * Important !
* *
* Each thread containing read-side critical sections must be registered * Each thread containing read-side critical sections must be registered
* with rcu_register_thread() before calling rcu_read_lock(). * with rcu_register_thread() before calling rcu_read_lock().
* rcu_unregister_thread() should be called before the thread exits. * rcu_unregister_thread() should be called before the thread exits.
*/ */
#ifdef _LGPL_SOURCE #ifdef _LGPL_SOURCE
skipping to change at line 77 skipping to change at line 73
/* /*
* rcu_read_lock() * rcu_read_lock()
* rcu_read_unlock() * rcu_read_unlock()
* *
* Mark the beginning and end of a read-side critical section. * Mark the beginning and end of a read-side critical section.
* DON'T FORGET TO USE rcu_register_thread/rcu_unregister_thread() * DON'T FORGET TO USE rcu_register_thread/rcu_unregister_thread()
* FOR EACH THREAD WITH READ-SIDE CRITICAL SECTION. * FOR EACH THREAD WITH READ-SIDE CRITICAL SECTION.
*/ */
#define rcu_read_lock_qsbr _rcu_read_lock #define rcu_read_lock_qsbr _rcu_read_lock
#define rcu_read_unlock_qsbr _rcu_read_unlock #define rcu_read_unlock_qsbr _rcu_read_unlock
#define rcu_read_ongoing_qsbr _rcu_read_ongoing
#define rcu_quiescent_state_qsbr _rcu_quiescent_state #define rcu_quiescent_state_qsbr _rcu_quiescent_state
#define rcu_thread_offline_qsbr _rcu_thread_offline #define rcu_thread_offline_qsbr _rcu_thread_offline
#define rcu_thread_online_qsbr _rcu_thread_online #define rcu_thread_online_qsbr _rcu_thread_online
#else /* !_LGPL_SOURCE */ #else /* !_LGPL_SOURCE */
/* /*
* library wrappers to be used by non-LGPL compatible source code. * library wrappers to be used by non-LGPL compatible source code.
*/ */
/* /*
* QSBR read lock/unlock are guaranteed to be no-ops. Therefore, we expose them * QSBR read lock/unlock are guaranteed to be no-ops. Therefore, we expose them
* in the LGPL header for any code to use. However, the debug version is no t * in the LGPL header for any code to use. However, the debug version is no t
* nops and may contain sanity checks. To activate it, applications must be * nops and may contain sanity checks. To activate it, applications must be
* recompiled with -DDEBUG_RCU (even non-LGPL/GPL applications). This is th e * recompiled with -DRCU_DEBUG (even non-LGPL/GPL applications). This is th e
* best trade-off between license/performance/code triviality and * best trade-off between license/performance/code triviality and
* library debugging & tracing features we could come up with. * library debugging & tracing features we could come up with.
*/ */
#if (!defined(BUILD_QSBR_LIB) && !defined(DEBUG_RCU)) #if (!defined(BUILD_QSBR_LIB) && defined(RCU_DEBUG))
static inline void rcu_read_lock(void) static inline void rcu_read_lock(void)
{ {
} }
static inline void rcu_read_unlock(void) static inline void rcu_read_unlock(void)
{ {
} }
#else /* !DEBUG_RCU */ #else /* !RCU_DEBUG */
extern void rcu_read_lock(void); extern void rcu_read_lock(void);
extern void rcu_read_unlock(void); extern void rcu_read_unlock(void);
#endif /* !DEBUG_RCU */ #endif /* !RCU_DEBUG */
extern int rcu_read_ongoing(void);
extern void rcu_quiescent_state(void); extern void rcu_quiescent_state(void);
extern void rcu_thread_offline(void); extern void rcu_thread_offline(void);
extern void rcu_thread_online(void); extern void rcu_thread_online(void);
#endif /* !_LGPL_SOURCE */ #endif /* !_LGPL_SOURCE */
extern void synchronize_rcu(void); extern void synchronize_rcu(void);
/* /*
* Reader thread registration. * Reader thread registration.
 End of changes. 7 change blocks. 
8 lines changed or deleted 6 lines changed or added


 urcu.h   urcu.h 
skipping to change at line 77 skipping to change at line 77
* rcu_read_lock() * rcu_read_lock()
* rcu_read_unlock() * rcu_read_unlock()
* *
* Mark the beginning and end of a read-side critical section. * Mark the beginning and end of a read-side critical section.
* DON'T FORGET TO USE RCU_REGISTER/UNREGISTER_THREAD() FOR EACH THREAD WIT H * DON'T FORGET TO USE RCU_REGISTER/UNREGISTER_THREAD() FOR EACH THREAD WIT H
* READ-SIDE CRITICAL SECTION. * READ-SIDE CRITICAL SECTION.
*/ */
#ifdef RCU_MEMBARRIER #ifdef RCU_MEMBARRIER
#define rcu_read_lock_memb _rcu_read_lock #define rcu_read_lock_memb _rcu_read_lock
#define rcu_read_unlock_memb _rcu_read_unlock #define rcu_read_unlock_memb _rcu_read_unlock
#define rcu_read_ongoing_memb _rcu_read_ongoing
#elif defined(RCU_SIGNAL) #elif defined(RCU_SIGNAL)
#define rcu_read_lock_sig _rcu_read_lock #define rcu_read_lock_sig _rcu_read_lock
#define rcu_read_unlock_sig _rcu_read_unlock #define rcu_read_unlock_sig _rcu_read_unlock
#define rcu_read_ongoing_sig _rcu_read_ongoing
#elif defined(RCU_MB) #elif defined(RCU_MB)
#define rcu_read_lock_mb _rcu_read_lock #define rcu_read_lock_mb _rcu_read_lock
#define rcu_read_unlock_mb _rcu_read_unlock #define rcu_read_unlock_mb _rcu_read_unlock
#define rcu_read_ongoing_mb _rcu_read_ongoing
#endif #endif
#else /* !_LGPL_SOURCE */ #else /* !_LGPL_SOURCE */
/* /*
* library wrappers to be used by non-LGPL compatible source code. * library wrappers to be used by non-LGPL compatible source code.
* See LGPL-only urcu/static/urcu-pointer.h for documentation. * See LGPL-only urcu/static/urcu-pointer.h for documentation.
*/ */
extern void rcu_read_lock(void); extern void rcu_read_lock(void);
extern void rcu_read_unlock(void); extern void rcu_read_unlock(void);
extern int rcu_read_ongoing(void);
#endif /* !_LGPL_SOURCE */ #endif /* !_LGPL_SOURCE */
extern void synchronize_rcu(void); extern void synchronize_rcu(void);
/* /*
* Reader thread registration. * Reader thread registration.
*/ */
extern void rcu_register_thread(void); extern void rcu_register_thread(void);
extern void rcu_unregister_thread(void); extern void rcu_unregister_thread(void);
 End of changes. 4 change blocks. 
0 lines changed or deleted 4 lines changed or added


 wfqueue.h   wfqueue.h 
skipping to change at line 34 skipping to change at line 34
*/ */
#include <pthread.h> #include <pthread.h>
#include <assert.h> #include <assert.h>
#include <urcu/compiler.h> #include <urcu/compiler.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#ifndef CDS_WFQ_DEPRECATED
#define CDS_WFQ_DEPRECATED \
CDS_DEPRECATED("urcu/wfqueue.h is deprecated. Please use urcu/wfcque
ue.h instead.")
#endif
/* /*
* Queue with wait-free enqueue/blocking dequeue. * Queue with wait-free enqueue/blocking dequeue.
* This implementation adds a dummy head node when the queue is empty to en sure * This implementation adds a dummy head node when the queue is empty to en sure
* we can always update the queue locklessly. * we can always update the queue locklessly.
* *
* Inspired from half-wait-free/half-blocking queue implementation done by * Inspired from half-wait-free/half-blocking queue implementation done by
* Paul E. McKenney. * Paul E. McKenney.
*/ */
struct cds_wfq_node { struct cds_wfq_node {
skipping to change at line 57 skipping to change at line 62
struct cds_wfq_queue { struct cds_wfq_queue {
struct cds_wfq_node *head, **tail; struct cds_wfq_node *head, **tail;
struct cds_wfq_node dummy; /* Dummy node */ struct cds_wfq_node dummy; /* Dummy node */
pthread_mutex_t lock; pthread_mutex_t lock;
}; };
#ifdef _LGPL_SOURCE #ifdef _LGPL_SOURCE
#include <urcu/static/wfqueue.h> #include <urcu/static/wfqueue.h>
#define cds_wfq_node_init _cds_wfq_node_init static inline CDS_WFQ_DEPRECATED
#define cds_wfq_init _cds_wfq_init void cds_wfq_node_init(struct cds_wfq_node *node)
#define cds_wfq_enqueue _cds_wfq_enqueue {
#define __cds_wfq_dequeue_blocking ___cds_wfq_dequeue_blocking _cds_wfq_node_init(node);
#define cds_wfq_dequeue_blocking _cds_wfq_dequeue_blocking }
static inline CDS_WFQ_DEPRECATED
void cds_wfq_init(struct cds_wfq_queue *q)
{
_cds_wfq_init(q);
}
static inline CDS_WFQ_DEPRECATED
void cds_wfq_enqueue(struct cds_wfq_queue *q, struct cds_wfq_node *node)
{
_cds_wfq_enqueue(q, node);
}
static inline CDS_WFQ_DEPRECATED
struct cds_wfq_node *__cds_wfq_dequeue_blocking(struct cds_wfq_queue *q)
{
return ___cds_wfq_dequeue_blocking(q);
}
static inline CDS_WFQ_DEPRECATED
struct cds_wfq_node *cds_wfq_dequeue_blocking(struct cds_wfq_queue *q)
{
return _cds_wfq_dequeue_blocking(q);
}
#else /* !_LGPL_SOURCE */ #else /* !_LGPL_SOURCE */
extern void cds_wfq_node_init(struct cds_wfq_node *node); extern CDS_WFQ_DEPRECATED
extern void cds_wfq_init(struct cds_wfq_queue *q); void cds_wfq_node_init(struct cds_wfq_node *node);
extern void cds_wfq_enqueue(struct cds_wfq_queue *q, struct cds_wfq_node *n
ode); extern CDS_WFQ_DEPRECATED
void cds_wfq_init(struct cds_wfq_queue *q);
extern CDS_WFQ_DEPRECATED
void cds_wfq_enqueue(struct cds_wfq_queue *q, struct cds_wfq_node *node);
/* __cds_wfq_dequeue_blocking: caller ensures mutual exclusion between dequ eues */ /* __cds_wfq_dequeue_blocking: caller ensures mutual exclusion between dequ eues */
extern struct cds_wfq_node *__cds_wfq_dequeue_blocking(struct cds_wfq_queue extern CDS_WFQ_DEPRECATED
*q); struct cds_wfq_node *__cds_wfq_dequeue_blocking(struct cds_wfq_queue *q);
extern struct cds_wfq_node *cds_wfq_dequeue_blocking(struct cds_wfq_queue *
q); extern CDS_WFQ_DEPRECATED
struct cds_wfq_node *cds_wfq_dequeue_blocking(struct cds_wfq_queue *q);
#endif /* !_LGPL_SOURCE */ #endif /* !_LGPL_SOURCE */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* _URCU_WFQUEUE_H */ #endif /* _URCU_WFQUEUE_H */
 End of changes. 4 change blocks. 
13 lines changed or deleted 49 lines changed or added


 wfstack.h   wfstack.h 
#ifndef _URCU_WFSTACK_H #ifndef _URCU_WFSTACK_H
#define _URCU_WFSTACK_H #define _URCU_WFSTACK_H
/* /*
* wfstack.h * urcu/wfstack.h
* *
* Userspace RCU library - Stack with Wait-Free push, Blocking pop. * Userspace RCU library - Stack with wait-free push, blocking traversal.
* *
* Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com> * Copyright 2010-2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version. * version 2.1 of the License, or (at your option) any later version.
* *
* This library is distributed in the hope that it will be useful, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include <pthread.h> #include <pthread.h>
#include <assert.h> #include <assert.h>
#include <stdbool.h>
#include <urcu/compiler.h> #include <urcu/compiler.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
/*
* Stack with wait-free push, blocking traversal.
*
* Stack implementing push, pop, pop_all operations, as well as iterator
* on the stack head returned by pop_all.
*
* Wait-free operations: cds_wfs_push, __cds_wfs_pop_all, cds_wfs_empty,
* cds_wfs_first.
* Blocking operations: cds_wfs_pop, cds_wfs_pop_all, cds_wfs_next,
* iteration on stack head returned by pop_all.
*
* Synchronization table:
*
* External synchronization techniques described in the API below is
* required between pairs marked with "X". No external synchronization
* required between pairs marked with "-".
*
* cds_wfs_push __cds_wfs_pop __cds_wfs_pop_all
* cds_wfs_push - - -
* __cds_wfs_pop - X X
* __cds_wfs_pop_all - X -
*
* cds_wfs_pop and cds_wfs_pop_all use an internal mutex to provide
* synchronization.
*/
#define CDS_WFS_WOULDBLOCK ((void *) -1UL)
enum cds_wfs_state {
CDS_WFS_STATE_LAST = (1U << 0),
};
/*
* struct cds_wfs_node is returned by __cds_wfs_pop, and also used as
* iterator on stack. It is not safe to dereference the node next
* pointer when returned by __cds_wfs_pop_blocking.
*/
struct cds_wfs_node { struct cds_wfs_node {
struct cds_wfs_node *next; struct cds_wfs_node *next;
}; };
/*
* struct cds_wfs_head is returned by __cds_wfs_pop_all, and can be used
* to begin iteration on the stack. "node" needs to be the first field of
* cds_wfs_head, so the end-of-stack pointer value can be used for both
* types.
*/
struct cds_wfs_head {
struct cds_wfs_node node;
};
struct cds_wfs_stack { struct cds_wfs_stack {
struct cds_wfs_node *head; struct cds_wfs_head *head;
pthread_mutex_t lock; pthread_mutex_t lock;
}; };
#ifdef _LGPL_SOURCE #ifdef _LGPL_SOURCE
#include <urcu/static/wfstack.h> #include <urcu/static/wfstack.h>
#define cds_wfs_node_init _cds_wfs_node_init #define cds_wfs_node_init _cds_wfs_node_init
#define cds_wfs_init _cds_wfs_init #define cds_wfs_init _cds_wfs_init
#define cds_wfs_push _cds_wfs_push #define cds_wfs_empty _cds_wfs_empty
#define __cds_wfs_pop_blocking ___cds_wfs_pop_blocking #define cds_wfs_push _cds_wfs_push
#define cds_wfs_pop_blocking _cds_wfs_pop_blocking
/* Locking performed internally */
#define cds_wfs_pop_blocking _cds_wfs_pop_blocking
#define cds_wfs_pop_with_state_blocking _cds_wfs_pop_with_state_bloc
king
#define cds_wfs_pop_all_blocking _cds_wfs_pop_all_blocking
/*
* For iteration on cds_wfs_head returned by __cds_wfs_pop_all or
* cds_wfs_pop_all_blocking.
*/
#define cds_wfs_first _cds_wfs_first
#define cds_wfs_next_blocking _cds_wfs_next_blocking
#define cds_wfs_next_nonblocking _cds_wfs_next_nonblocking
/* Pop locking with internal mutex */
#define cds_wfs_pop_lock _cds_wfs_pop_lock
#define cds_wfs_pop_unlock _cds_wfs_pop_unlock
/* Synchronization ensured by the caller. See synchronization table. */
#define __cds_wfs_pop_blocking ___cds_wfs_pop_blocking
#define __cds_wfs_pop_with_state_blocking \
___cds_wfs_pop_with_state_blocking
#define __cds_wfs_pop_nonblocking ___cds_wfs_pop_nonblocking
#define __cds_wfs_pop_with_state_nonblocking \
___cds_wfs_pop_with_state_nonblockin
g
#define __cds_wfs_pop_all ___cds_wfs_pop_all
#else /* !_LGPL_SOURCE */ #else /* !_LGPL_SOURCE */
/*
* cds_wfs_node_init: initialize wait-free stack node.
*/
extern void cds_wfs_node_init(struct cds_wfs_node *node); extern void cds_wfs_node_init(struct cds_wfs_node *node);
/*
* cds_wfs_init: initialize wait-free stack.
*/
extern void cds_wfs_init(struct cds_wfs_stack *s); extern void cds_wfs_init(struct cds_wfs_stack *s);
/*
* cds_wfs_empty: return whether wait-free stack is empty.
*
* No memory barrier is issued. No mutual exclusion is required.
*/
extern bool cds_wfs_empty(struct cds_wfs_stack *s);
/*
* cds_wfs_push: push a node into the stack.
*
* Issues a full memory barrier before push. No mutual exclusion is
* required.
*
* Returns 0 if the stack was empty prior to adding the node.
* Returns non-zero otherwise.
*/
extern int cds_wfs_push(struct cds_wfs_stack *s, struct cds_wfs_node *node) ; extern int cds_wfs_push(struct cds_wfs_stack *s, struct cds_wfs_node *node) ;
/* __cds_wfs_pop_blocking: caller ensures mutual exclusion between pops */
extern struct cds_wfs_node *__cds_wfs_pop_blocking(struct cds_wfs_stack *s) /*
; * cds_wfs_pop_blocking: pop a node from the stack.
*
* Calls __cds_wfs_pop_blocking with an internal pop mutex held.
*/
extern struct cds_wfs_node *cds_wfs_pop_blocking(struct cds_wfs_stack *s); extern struct cds_wfs_node *cds_wfs_pop_blocking(struct cds_wfs_stack *s);
/*
* cds_wfs_pop_with_state_blocking: pop a node from the stack, with state.
*
* Same as cds_wfs_pop_blocking, but stores whether the stack was
* empty into state (CDS_WFS_STATE_LAST).
*/
extern struct cds_wfs_node *
cds_wfs_pop_with_state_blocking(struct cds_wfs_stack *s, int *state)
;
/*
* cds_wfs_pop_all_blocking: pop all nodes from a stack.
*
* Calls __cds_wfs_pop_all with an internal pop mutex held.
*/
extern struct cds_wfs_head *cds_wfs_pop_all_blocking(struct cds_wfs_stack *
s);
/*
* cds_wfs_first: get first node of a popped stack.
*
* Content written into the node before enqueue is guaranteed to be
* consistent, but no other memory ordering is ensured.
*
* Used by for-like iteration macros in urcu/wfstack.h:
* cds_wfs_for_each_blocking()
* cds_wfs_for_each_blocking_safe()
*
* Returns NULL if popped stack is empty, top stack node otherwise.
*/
extern struct cds_wfs_node *cds_wfs_first(struct cds_wfs_head *head);
/*
* cds_wfs_next_blocking: get next node of a popped stack.
*
* Content written into the node before enqueue is guaranteed to be
* consistent, but no other memory ordering is ensured.
*
* Used by for-like iteration macros in urcu/wfstack.h:
* cds_wfs_for_each_blocking()
* cds_wfs_for_each_blocking_safe()
*
* Returns NULL if reached end of popped stack, non-NULL next stack
* node otherwise.
*/
extern struct cds_wfs_node *cds_wfs_next_blocking(struct cds_wfs_node *node
);
/*
* cds_wfs_next_nonblocking: get next node of a popped stack.
*
* Same as cds_wfs_next_blocking, but returns CDS_WFS_WOULDBLOCK if it
* needs to block.
*/
extern struct cds_wfs_node *cds_wfs_next_nonblocking(struct cds_wfs_node *n
ode);
/*
* cds_wfs_pop_lock: lock stack pop-protection mutex.
*/
extern void cds_wfs_pop_lock(struct cds_wfs_stack *s);
/*
* cds_wfs_pop_unlock: unlock stack pop-protection mutex.
*/
extern void cds_wfs_pop_unlock(struct cds_wfs_stack *s);
/*
* __cds_wfs_pop_blocking: pop a node from the stack.
*
* Returns NULL if stack is empty.
*
* __cds_wfs_pop_blocking needs to be synchronized using one of the
* following techniques:
*
* 1) Calling __cds_wfs_pop_blocking under rcu read lock critical
* section. The caller must wait for a grace period to pass before
* freeing the returned node or modifying the cds_wfs_node structure.
* 2) Using mutual exclusion (e.g. mutexes) to protect
* __cds_wfs_pop_blocking and __cds_wfs_pop_all callers.
* 3) Ensuring that only ONE thread can call __cds_wfs_pop_blocking()
* and __cds_wfs_pop_all(). (multi-provider/single-consumer scheme).
*/
extern struct cds_wfs_node *__cds_wfs_pop_blocking(struct cds_wfs_stack *s)
;
/*
* __cds_wfs_pop_with_state_blocking: pop a node from the stack, with state
.
*
* Same as __cds_wfs_pop_blocking, but stores whether the stack was
* empty into state (CDS_WFS_STATE_LAST).
*/
extern struct cds_wfs_node *
__cds_wfs_pop_with_state_blocking(struct cds_wfs_stack *s, int *stat
e);
/*
* __cds_wfs_pop_nonblocking: pop a node from the stack.
*
* Same as __cds_wfs_pop_blocking, but returns CDS_WFS_WOULDBLOCK if
* it needs to block.
*/
extern struct cds_wfs_node *__cds_wfs_pop_nonblocking(struct cds_wfs_stack
*s);
/*
* __cds_wfs_pop_with_state_nonblocking: pop a node from the stack, with st
ate.
*
* Same as __cds_wfs_pop_nonblocking, but stores whether the stack was
* empty into state (CDS_WFS_STATE_LAST).
*/
extern struct cds_wfs_node *
__cds_wfs_pop_with_state_nonblocking(struct cds_wfs_stack *s,
int *state);
/*
* __cds_wfs_pop_all: pop all nodes from a stack.
*
* __cds_wfs_pop_all does not require any synchronization with other
* push, nor with other __cds_wfs_pop_all, but requires synchronization
* matching the technique used to synchronize __cds_wfs_pop_blocking:
*
* 1) If __cds_wfs_pop_blocking is called under rcu read lock critical
* section, both __cds_wfs_pop_blocking and cds_wfs_pop_all callers
* must wait for a grace period to pass before freeing the returned
* node or modifying the cds_wfs_node structure. However, no RCU
* read-side critical section is needed around __cds_wfs_pop_all.
* 2) Using mutual exclusion (e.g. mutexes) to protect
* __cds_wfs_pop_blocking and __cds_wfs_pop_all callers.
* 3) Ensuring that only ONE thread can call __cds_wfs_pop_blocking()
* and __cds_wfs_pop_all(). (multi-provider/single-consumer scheme).
*/
extern struct cds_wfs_head *__cds_wfs_pop_all(struct cds_wfs_stack *s);
#endif /* !_LGPL_SOURCE */ #endif /* !_LGPL_SOURCE */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
/*
* cds_wfs_for_each_blocking: Iterate over all nodes returned by
* __cds_wfs_pop_all().
* @head: head of the queue (struct cds_wfs_head pointer).
* @node: iterator (struct cds_wfs_node pointer).
*
* Content written into each node before enqueue is guaranteed to be
* consistent, but no other memory ordering is ensured.
*/
#define cds_wfs_for_each_blocking(head, node) \
for (node = cds_wfs_first(head); \
node != NULL; \
node = cds_wfs_next_blocking(node))
/*
* cds_wfs_for_each_blocking_safe: Iterate over all nodes returned by
* __cds_wfs_pop_all(). Safe against deletion.
* @head: head of the queue (struct cds_wfs_head pointer).
* @node: iterator (struct cds_wfs_node pointer).
* @n: struct cds_wfs_node pointer holding the next pointer (used
* internally).
*
* Content written into each node before enqueue is guaranteed to be
* consistent, but no other memory ordering is ensured.
*/
#define cds_wfs_for_each_blocking_safe(head, node, n) \
for (node = cds_wfs_first(head), \
n = (node ? cds_wfs_next_blocking(node) : NULL); \
node != NULL; \
node = n, n = (node ? cds_wfs_next_blocking(node) : NULL))
#endif /* _URCU_WFSTACK_H */ #endif /* _URCU_WFSTACK_H */
 End of changes. 14 change blocks. 
11 lines changed or deleted 280 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/