From: Mathieu Desnoyers Date: Thu, 1 Oct 2009 13:48:35 +0000 (-0400) Subject: urcu-pointer: create specific objects and headers to deal with RCU pointers X-Git-Tag: v0.2~1 X-Git-Url: https://git.liburcu.org/?p=urcu.git;a=commitdiff_plain;h=7e30abe3df0e83eeb741bfc18d07cb016af804a1 urcu-pointer: create specific objects and headers to deal with RCU pointers Signed-off-by: Mathieu Desnoyers --- diff --git a/Makefile.inc b/Makefile.inc index 3fc3a6c..5743c83 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -26,6 +26,9 @@ urcu.h: urcu/arch.h urcu/arch_uatomic.h urcu-qsbr.h: urcu/arch.h urcu/arch_uatomic.h +urcu-pointer.o: urcu-pointer.c urcu-pointer.h urcu-pointer-static.h + $(CC) -fPIC ${CFLAGS} -c -o $@ $(SRC_DEP) + urcu.o: urcu.c urcu.h $(CC) -fPIC ${CFLAGS} -c -o $@ $(SRC_DEP) @@ -38,13 +41,13 @@ urcu-qsbr.o: urcu-qsbr.c urcu-qsbr.h urcu-defer.o: urcu-defer.c urcu-defer.h $(CC) -fPIC ${CFLAGS} -c -o $@ $(SRC_DEP) -liburcu.so: urcu.o +liburcu.so: urcu.o urcu-pointer.o $(CC) ${LDFLAGS} -fPIC -shared -o $@ $< -liburcu-qsbr.so: urcu-qsbr.o +liburcu-qsbr.so: urcu-qsbr.o urcu-pointer.o $(CC) ${LDFLAGS} -fPIC -shared -o $@ $< -liburcu-mb.so: urcu-mb.o +liburcu-mb.so: urcu-mb.o urcu-pointer.o $(CC) ${LDFLAGS} -fPIC -shared -o $@ $< liburcu-defer.so: urcu-defer.o @@ -68,6 +71,7 @@ install: liburcu.so cp -f urcu.h urcu-static.h \ urcu-qsbr.h urcu-qsbr-static.h \ urcu-defer.h urcu-defer-static.h \ + urcu-pointer.h urcu-pointer-static.h \ /usr/include/ clean: diff --git a/tests/Makefile.inc b/tests/Makefile.inc index 78a6092..92d619e 100644 --- a/tests/Makefile.inc +++ b/tests/Makefile.inc @@ -11,11 +11,11 @@ LIBDIR=.. CFLAGS+=-I${LIBDIR} -URCU_SIGNAL=${LIBDIR}/urcu.o ${LIBDIR}/urcu.h -URCU_SIGNAL_YIELD=${LIBDIR}/urcu-yield.o ${LIBDIR}/urcu.h -URCU_MB=${LIBDIR}/urcu-mb.o ${LIBDIR}/urcu.h -URCU_QSBR=${LIBDIR}/urcu-qsbr.o ${LIBDIR}/urcu-qsbr.h -URCU_MB_DEFER=${LIBDIR}/urcu-mb.o ${LIBDIR}/urcu-defer.o ${LIBDIR}/urcu.h +URCU_SIGNAL=${LIBDIR}/urcu.o ${LIBDIR}/urcu-pointer.o ${LIBDIR}/urcu.h +URCU_SIGNAL_YIELD=${LIBDIR}/urcu-yield.o ${LIBDIR}/urcu-pointer.o ${LIBDIR}/urcu.h +URCU_MB=${LIBDIR}/urcu-mb.o ${LIBDIR}/urcu-pointer.o ${LIBDIR}/urcu.h +URCU_QSBR=${LIBDIR}/urcu-qsbr.o ${LIBDIR}/urcu-pointer.o ${LIBDIR}/urcu-qsbr.h +URCU_MB_DEFER=${LIBDIR}/urcu-mb.o ${LIBDIR}/urcu-defer.o ${LIBDIR}/urcu-pointer.o ${LIBDIR}/urcu.h all: test_urcu test_urcu_dynamic_link test_urcu_timing \ test_rwlock_timing test_rwlock test_perthreadlock_timing \ diff --git a/urcu-pointer-static.h b/urcu-pointer-static.h new file mode 100644 index 0000000..c2ba800 --- /dev/null +++ b/urcu-pointer-static.h @@ -0,0 +1,133 @@ +#ifndef _URCU_POINTER_STATIC_H +#define _URCU_POINTER_STATIC_H + +/* + * urcu-pointer-static.h + * + * Userspace RCU header. Operations on pointers. + * + * TO BE INCLUDED ONLY IN LGPL-COMPATIBLE CODE. See urcu-pointer.h for + * linking dynamically with the userspace rcu library. + * + * Copyright (c) 2009 Mathieu Desnoyers + * Copyright (c) 2009 Paul E. McKenney, IBM Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * 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, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * IBM's contributions to this file may be relicensed under LGPLv2 or later. + */ + +#include +#include +#include +#include + +/** + * _rcu_dereference - reads (copy) a RCU-protected pointer to a local variable + * into a RCU read-side critical section. The pointer can later be safely + * dereferenced within the critical section. + * + * This ensures that the pointer copy is invariant thorough the whole critical + * section. + * + * Inserts memory barriers on architectures that require them (currently only + * Alpha) and documents which pointers are protected by RCU. + * + * The compiler memory barrier in LOAD_SHARED() ensures that value-speculative + * optimizations (e.g. VSS: Value Speculation Scheduling) does not perform the + * data read before the pointer read by speculating the value of the pointer. + * Correct ordering is ensured because the pointer is read as a volatile access. + * This acts as a global side-effect operation, which forbids reordering of + * dependent memory operations. Note that such concern about dependency-breaking + * optimizations will eventually be taken care of by the "memory_order_consume" + * addition to forthcoming C++ standard. + * + * Should match rcu_assign_pointer() or rcu_xchg_pointer(). + */ + +#define _rcu_dereference(p) ({ \ + typeof(p) _________p1 = LOAD_SHARED(p); \ + smp_read_barrier_depends(); \ + (_________p1); \ + }) + +/** + * _rcu_cmpxchg_pointer - same as rcu_assign_pointer, but tests if the pointer + * is as expected by "old". If succeeds, returns the previous pointer to the + * data structure, which can be safely freed after waiting for a quiescent state + * using synchronize_rcu(). If fails (unexpected value), returns old (which + * should not be freed !). + */ + +#define _rcu_cmpxchg_pointer(p, old, _new) \ + ({ \ + if (!__builtin_constant_p(_new) || \ + ((_new) != NULL)) \ + wmb(); \ + uatomic_cmpxchg(p, old, _new); \ + }) + +/** + * _rcu_xchg_pointer - same as rcu_assign_pointer, but returns the previous + * pointer to the data structure, which can be safely freed after waiting for a + * quiescent state using synchronize_rcu(). + */ + +#define _rcu_xchg_pointer(p, v) \ + ({ \ + if (!__builtin_constant_p(v) || \ + ((v) != NULL)) \ + wmb(); \ + uatomic_xchg(p, v); \ + }) + + +#define _rcu_set_pointer(p, v) \ + ({ \ + if (!__builtin_constant_p(v) || \ + ((v) != NULL)) \ + wmb(); \ + STORE_SHARED(*(p), v); \ + }) + +/* + * _rcu_publish_content - Exchanges the pointer and waits for quiescent state. + * + * The pointer returned can be freed. + */ +#define _rcu_publish_content(p, v) \ + ({ \ + void *oldptr; \ + oldptr = _rcu_xchg_pointer(p, v); \ + synchronize_rcu(); \ + oldptr; \ + }) + +/** + * _rcu_assign_pointer - assign (publicize) a pointer to a new data structure + * meant to be read by RCU read-side critical sections. Returns the assigned + * value. + * + * Documents which pointers will be dereferenced by RCU read-side critical + * sections and adds the required memory barriers on architectures requiring + * them. It also makes sure the compiler does not reorder code initializing the + * data structure before its publication. + * + * Should match rcu_dereference_pointer(). + */ + +#define _rcu_assign_pointer(p, v) _rcu_set_pointer(&(p), v) + +#endif /* _URCU_POINTER_STATIC_H */ diff --git a/urcu-pointer.c b/urcu-pointer.c new file mode 100644 index 0000000..1461c60 --- /dev/null +++ b/urcu-pointer.c @@ -0,0 +1,63 @@ + +/* + * urcu-pointer.c + * + * library wrappers to be used by non-LGPL compatible source code. + * + * Copyright (c) 2009 Mathieu Desnoyers + * Copyright (c) 2009 Paul E. McKenney, IBM Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * 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, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * IBM's contributions to this file may be relicensed under LGPLv2 or later. + */ + +#include "urcu-pointer-static.h" +/* Do not #define _LGPL_SOURCE to ensure we can emit the wrapper symbols */ +#include "urcu-pointer.h" + +extern void synchronize_rcu(void); + +void *rcu_dereference(void *p) +{ + return _rcu_dereference(p); +} + +void *rcu_set_pointer_sym(void **p, void *v) +{ + wmb(); + return STORE_SHARED(*p, v); +} + +void *rcu_xchg_pointer_sym(void **p, void *v) +{ + wmb(); + return uatomic_xchg(p, v); +} + +void *rcu_cmpxchg_pointer_sym(void **p, void *old, void *_new) +{ + wmb(); + return uatomic_cmpxchg(p, old, _new); +} + +void *rcu_publish_content_sym(void **p, void *v) +{ + void *oldptr; + + oldptr = _rcu_xchg_pointer(p, v); + synchronize_rcu(); + return oldptr; +} diff --git a/urcu-pointer.h b/urcu-pointer.h new file mode 100644 index 0000000..748a37a --- /dev/null +++ b/urcu-pointer.h @@ -0,0 +1,106 @@ +#ifndef _URCU_POINTER_H +#define _URCU_POINTER_H + +/* + * urcu-pointer.h + * + * Userspace RCU header. Operations on pointers. + * + * Copyright (c) 2009 Mathieu Desnoyers + * Copyright (c) 2009 Paul E. McKenney, IBM Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * 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, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * IBM's contributions to this file may be relicensed under LGPLv2 or later. + */ + +#include +#include +#include + +#ifdef _LGPL_SOURCE + +#include + +/* + * rcu_dereference(ptr) + * + * Fetch a RCU-protected pointer. Typically used to copy the variable ptr to a + * local variable. + */ +#define rcu_dereference _rcu_dereference + +/* + * rcu_cmpxchg_pointer(type **ptr, type *new, type *old) + * type *rcu_xchg_pointer(type **ptr, type *new) + * type *rcu_set_pointer(type **ptr, type *new) + * + * RCU pointer updates. + * @ptr: address of the pointer to modify + * @new: new pointer value + * @old: old pointer value (expected) + * + * return: old pointer value + */ +#define rcu_cmpxchg_pointer _rcu_cmpxchg_pointer +#define rcu_xchg_pointer _rcu_xchg_pointer +#define rcu_set_pointer _rcu_set_pointer + +/* + * type *rcu_publish_content(type **ptr, type *new) + * + * Exchanges the pointer and waits for quiescent state. The pointer returned + * can be freed. You are encouraged to use either + * - rcu_cmpxchg_pointer + * - rcu_xchg_pointer + * - rcu_set_pointer + * with call_rcu(free, ptr) instead to deal with reclamation more efficiently. + */ +#define rcu_publish_content _rcu_publish_content + +#else /* !_LGPL_SOURCE */ + +extern void *rcu_dereference(void *p); + +extern void *rcu_cmpxchg_pointer_sym(void **p, void *old, void *_new); +#define rcu_cmpxchg_pointer(p, old, _new) \ + rcu_cmpxchg_pointer_sym((void **)(p), (old), (_new)) + +extern void *rcu_xchg_pointer_sym(void **p, void *v); +#define rcu_xchg_pointer(p, v) \ + rcu_xchg_pointer_sym((void **)(p), (v)) + +extern void *rcu_set_pointer_sym(void **p, void *v); +#define rcu_set_pointer(p, v) \ + rcu_set_pointer_sym((void **)(p), (v)) + +extern void *rcu_publish_content_sym(void **p, void *v); +#define rcu_publish_content(p, v) \ + rcu_publish_content_sym((void **)(p), (v)) + +extern void *rcu_assign_pointer_sym(void **p, void *v); + +#endif /* !_LGPL_SOURCE */ + +/* + * rcu_assign_pointer(type *ptr, type *new) + * + * 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 kernel + * RCU semantic. + */ +#define rcu_assign_pointer(p, v) rcu_set_pointer((&p), (v)) + +#endif /* _URCU_POINTER_H */ diff --git a/urcu-qsbr-static.h b/urcu-qsbr-static.h index d53a1f4..d4cb6a9 100644 --- a/urcu-qsbr-static.h +++ b/urcu-qsbr-static.h @@ -38,59 +38,10 @@ #include #include +#include #include #include -/* - * Identify a shared load. A smp_rmc() or smp_mc() should come before the load. - */ -#define _LOAD_SHARED(p) ACCESS_ONCE(p) - -/* - * Load a data from shared memory, doing a cache flush if required. - */ -#define LOAD_SHARED(p) \ - ({ \ - smp_rmc(); \ - _LOAD_SHARED(p); \ - }) - -/* - * Identify a shared store. A smp_wmc() or smp_mc() should follow the store. - */ -#define _STORE_SHARED(x, v) ({ ACCESS_ONCE(x) = (v); }) - -/* - * Store v into x, where x is located in shared memory. Performs the required - * cache flush after writing. Returns v. - */ -#define STORE_SHARED(x, v) \ - ({ \ - _STORE_SHARED(x, v); \ - smp_wmc(); \ - (v); \ - }) - -/** - * _rcu_dereference - reads (copy) a RCU-protected pointer to a local variable - * into a RCU read-side critical section. The pointer can later be safely - * dereferenced within the critical section. - * - * This ensures that the pointer copy is invariant thorough the whole critical - * section. - * - * Inserts memory barriers on architectures that require them (currently only - * Alpha) and documents which pointers are protected by RCU. - * - * Should match rcu_assign_pointer() or rcu_xchg_pointer(). - */ - -#define _rcu_dereference(p) ({ \ - typeof(p) _________p1 = LOAD_SHARED(p); \ - smp_read_barrier_depends(); \ - (_________p1); \ - }) - #define futex(...) syscall(__NR_futex, __VA_ARGS__) #define FUTEX_WAIT 0 #define FUTEX_WAKE 1 @@ -262,67 +213,4 @@ static inline void _rcu_thread_online(void) smp_mb(); } -/** - * _rcu_assign_pointer - assign (publicize) a pointer to a new data structure - * meant to be read by RCU read-side critical sections. Returns the assigned - * value. - * - * Documents which pointers will be dereferenced by RCU read-side critical - * sections and adds the required memory barriers on architectures requiring - * them. It also makes sure the compiler does not reorder code initializing the - * data structure before its publication. - * - * Should match rcu_dereference_pointer(). - */ - -#define _rcu_assign_pointer(p, v) \ - ({ \ - if (!__builtin_constant_p(v) || \ - ((v) != NULL)) \ - wmb(); \ - STORE_SHARED(p, v); \ - }) - -/** - * _rcu_cmpxchg_pointer - same as rcu_assign_pointer, but tests if the pointer - * is as expected by "old". If succeeds, returns the previous pointer to the - * data structure, which can be safely freed after waiting for a quiescent state - * using synchronize_rcu(). If fails (unexpected value), returns old (which - * should not be freed !). - */ - -#define _rcu_cmpxchg_pointer(p, old, _new) \ - ({ \ - if (!__builtin_constant_p(_new) || \ - ((_new) != NULL)) \ - wmb(); \ - uatomic_cmpxchg(p, old, _new); \ - }) - -/** - * _rcu_xchg_pointer - same as rcu_assign_pointer, but returns the previous - * pointer to the data structure, which can be safely freed after waiting for a - * quiescent state using synchronize_rcu(). - */ - -#define _rcu_xchg_pointer(p, v) \ - ({ \ - if (!__builtin_constant_p(v) || \ - ((v) != NULL)) \ - wmb(); \ - uatomic_xchg(p, v); \ - }) - -/* - * Exchanges the pointer and waits for quiescent state. - * The pointer returned can be freed. - */ -#define _rcu_publish_content(p, v) \ - ({ \ - void *oldptr; \ - oldptr = _rcu_xchg_pointer(p, v); \ - synchronize_rcu(); \ - oldptr; \ - }) - #endif /* _URCU_QSBR_STATIC_H */ diff --git a/urcu-qsbr.c b/urcu-qsbr.c index bb98a19..56d86f9 100644 --- a/urcu-qsbr.c +++ b/urcu-qsbr.c @@ -278,38 +278,6 @@ void rcu_read_unlock(void) _rcu_read_unlock(); } -void *rcu_dereference(void *p) -{ - return _rcu_dereference(p); -} - -void *rcu_assign_pointer_sym(void **p, void *v) -{ - wmb(); - return STORE_SHARED(*p, v); -} - -void *rcu_cmpxchg_pointer_sym(void **p, void *old, void *_new) -{ - wmb(); - return uatomic_cmpxchg(p, old, _new); -} - -void *rcu_xchg_pointer_sym(void **p, void *v) -{ - wmb(); - return uatomic_xchg(p, v); -} - -void *rcu_publish_content_sym(void **p, void *v) -{ - void *oldptr; - - oldptr = _rcu_xchg_pointer(p, v); - synchronize_rcu(); - return oldptr; -} - void rcu_quiescent_state(void) { _rcu_quiescent_state(); diff --git a/urcu-qsbr.h b/urcu-qsbr.h index 6eebdc7..21c2a2e 100644 --- a/urcu-qsbr.h +++ b/urcu-qsbr.h @@ -31,6 +31,11 @@ #include #include +/* + * See urcu-pointer.h and urcu-pointer-static.h for pointer publication headers. + */ +#include + /* * Important ! * @@ -48,18 +53,20 @@ * Should only be used in LGPL-compatible code. */ -#define rcu_dereference _rcu_dereference -#define rcu_read_lock _rcu_read_lock -#define rcu_read_unlock _rcu_read_unlock - -#define rcu_quiescent_state _rcu_quiescent_state -#define rcu_thread_offline _rcu_thread_offline -#define rcu_thread_online _rcu_thread_online +/* + * rcu_read_lock() + * rcu_read_unlock() + * + * Mark the beginning and end of a read-side critical section. + * DON'T FORGET TO USE RCU_REGISTER/UNREGISTER_THREAD() FOR EACH THREAD WITH + * READ-SIDE CRITICAL SECTION. + */ +#define rcu_read_lock() _rcu_read_lock() +#define rcu_read_unlock() _rcu_read_unlock() -#define rcu_assign_pointer _rcu_assign_pointer -#define rcu_cmpxchg_pointer _rcu_cmpxchg_pointer -#define rcu_xchg_pointer _rcu_xchg_pointer -#define rcu_publish_content _rcu_publish_content +#define rcu_quiescent_state() _rcu_quiescent_state() +#define rcu_thread_offline() _rcu_thread_offline() +#define rcu_thread_online() _rcu_thread_online() #else /* !_LGPL_SOURCE */ @@ -93,29 +100,10 @@ extern void rcu_read_unlock(void); #endif /* !URCU_DEBUG */ -extern void *rcu_dereference(void *p); - extern void rcu_quiescent_state(void); extern void rcu_thread_offline(void); extern void rcu_thread_online(void); -extern void *rcu_assign_pointer_sym(void **p, void *v); - -#define rcu_assign_pointer(p, v) \ - rcu_assign_pointer_sym((void **)(&(p)), (v)) - -extern void *rcu_cmpxchg_pointer_sym(void **p, void *old, void *_new); -#define rcu_cmpxchg_pointer(p, old, _new) \ - rcu_cmpxchg_pointer_sym((void **)(p), (old), (_new)) - -extern void *rcu_xchg_pointer_sym(void **p, void *v); -#define rcu_xchg_pointer(p, v) \ - rcu_xchg_pointer_sym((void **)(p), (v)) - -extern void *rcu_publish_content_sym(void **p, void *v); -#define rcu_publish_content(p, v) \ - rcu_publish_content_sym((void **)(p), (v)) - #endif /* !_LGPL_SOURCE */ extern void synchronize_rcu(void); diff --git a/urcu-static.h b/urcu-static.h index 7d6d7ac..30bd7fd 100644 --- a/urcu-static.h +++ b/urcu-static.h @@ -36,68 +36,10 @@ #include #include +#include #include #include -/* - * Identify a shared load. A smp_rmc() or smp_mc() should come before the load. - */ -#define _LOAD_SHARED(p) ACCESS_ONCE(p) - -/* - * Load a data from shared memory, doing a cache flush if required. - */ -#define LOAD_SHARED(p) \ - ({ \ - smp_rmc(); \ - _LOAD_SHARED(p); \ - }) - -/* - * Identify a shared store. A smp_wmc() or smp_mc() should follow the store. - */ -#define _STORE_SHARED(x, v) ({ ACCESS_ONCE(x) = (v); }) - -/* - * Store v into x, where x is located in shared memory. Performs the required - * cache flush after writing. Returns v. - */ -#define STORE_SHARED(x, v) \ - ({ \ - _STORE_SHARED(x, v); \ - smp_wmc(); \ - (v); \ - }) - -/** - * _rcu_dereference - reads (copy) a RCU-protected pointer to a local variable - * into a RCU read-side critical section. The pointer can later be safely - * dereferenced within the critical section. - * - * This ensures that the pointer copy is invariant thorough the whole critical - * section. - * - * Inserts memory barriers on architectures that require them (currently only - * Alpha) and documents which pointers are protected by RCU. - * - * The compiler memory barrier in LOAD_SHARED() ensures that value-speculative - * optimizations (e.g. VSS: Value Speculation Scheduling) does not perform the - * data read before the pointer read by speculating the value of the pointer. - * Correct ordering is ensured because the pointer is read as a volatile access. - * This acts as a global side-effect operation, which forbids reordering of - * dependent memory operations. Note that such concern about dependency-breaking - * optimizations will eventually be taken care of by the "memory_order_consume" - * addition to forthcoming C++ standard. - * - * Should match rcu_assign_pointer() or rcu_xchg_pointer(). - */ - -#define _rcu_dereference(p) ({ \ - typeof(p) _________p1 = LOAD_SHARED(p); \ - smp_read_barrier_depends(); \ - (_________p1); \ - }) - #define futex(...) syscall(__NR_futex, __VA_ARGS__) #define FUTEX_WAIT 0 #define FUTEX_WAKE 1 @@ -298,67 +240,4 @@ static inline void _rcu_read_unlock(void) } } -/** - * _rcu_assign_pointer - assign (publicize) a pointer to a new data structure - * meant to be read by RCU read-side critical sections. Returns the assigned - * value. - * - * Documents which pointers will be dereferenced by RCU read-side critical - * sections and adds the required memory barriers on architectures requiring - * them. It also makes sure the compiler does not reorder code initializing the - * data structure before its publication. - * - * Should match rcu_dereference_pointer(). - */ - -#define _rcu_assign_pointer(p, v) \ - ({ \ - if (!__builtin_constant_p(v) || \ - ((v) != NULL)) \ - wmb(); \ - STORE_SHARED(p, v); \ - }) - -/** - * _rcu_cmpxchg_pointer - same as rcu_assign_pointer, but tests if the pointer - * is as expected by "old". If succeeds, returns the previous pointer to the - * data structure, which can be safely freed after waiting for a quiescent state - * using synchronize_rcu(). If fails (unexpected value), returns old (which - * should not be freed !). - */ - -#define _rcu_cmpxchg_pointer(p, old, _new) \ - ({ \ - if (!__builtin_constant_p(_new) || \ - ((_new) != NULL)) \ - wmb(); \ - uatomic_cmpxchg(p, old, _new); \ - }) - -/** - * _rcu_xchg_pointer - same as rcu_assign_pointer, but returns the previous - * pointer to the data structure, which can be safely freed after waiting for a - * quiescent state using synchronize_rcu(). - */ - -#define _rcu_xchg_pointer(p, v) \ - ({ \ - if (!__builtin_constant_p(v) || \ - ((v) != NULL)) \ - wmb(); \ - uatomic_xchg(p, v); \ - }) - -/* - * Exchanges the pointer and waits for quiescent state. - * The pointer returned can be freed. - */ -#define _rcu_publish_content(p, v) \ - ({ \ - void *oldptr; \ - oldptr = _rcu_xchg_pointer(p, v); \ - synchronize_rcu(); \ - oldptr; \ - }) - #endif /* _URCU_STATIC_H */ diff --git a/urcu.c b/urcu.c index c13ad63..8ff39db 100644 --- a/urcu.c +++ b/urcu.c @@ -372,38 +372,6 @@ void rcu_read_unlock(void) _rcu_read_unlock(); } -void *rcu_dereference(void *p) -{ - return _rcu_dereference(p); -} - -void *rcu_assign_pointer_sym(void **p, void *v) -{ - wmb(); - return STORE_SHARED(*p, v); -} - -void *rcu_xchg_pointer_sym(void **p, void *v) -{ - wmb(); - return uatomic_xchg(p, v); -} - -void *rcu_cmpxchg_pointer_sym(void **p, void *old, void *_new) -{ - wmb(); - return uatomic_cmpxchg(p, old, _new); -} - -void *rcu_publish_content_sym(void **p, void *v) -{ - void *oldptr; - - oldptr = _rcu_xchg_pointer(p, v); - synchronize_rcu(); - return oldptr; -} - void rcu_register_thread(void) { urcu_reader.tid = pthread_self(); diff --git a/urcu.h b/urcu.h index a0aac21..69c06e4 100644 --- a/urcu.h +++ b/urcu.h @@ -34,6 +34,11 @@ #include #include +/* + * See urcu-pointer.h and urcu-pointer-static.h for pointer publication headers. + */ +#include + /* * Important ! * @@ -51,43 +56,27 @@ * Should only be used in LGPL-compatible code. */ -#define rcu_dereference _rcu_dereference -#define rcu_read_lock _rcu_read_lock -#define rcu_read_unlock _rcu_read_unlock - -#define rcu_assign_pointer _rcu_assign_pointer -#define rcu_cmpxchg_pointer _rcu_cmpxchg_pointer -#define rcu_xchg_pointer _rcu_xchg_pointer -#define rcu_publish_content _rcu_publish_content +/* + * rcu_read_lock() + * rcu_read_unlock() + * + * Mark the beginning and end of a read-side critical section. + * DON'T FORGET TO USE RCU_REGISTER/UNREGISTER_THREAD() FOR EACH THREAD WITH + * READ-SIDE CRITICAL SECTION. + */ +#define rcu_read_lock() _rcu_read_lock() +#define rcu_read_unlock() _rcu_read_unlock() #else /* !_LGPL_SOURCE */ /* * library wrappers to be used by non-LGPL compatible source code. + * See LGPL-only urcu-pointer-static.h for documentation. */ extern void rcu_read_lock(void); extern void rcu_read_unlock(void); -extern void *rcu_dereference(void *p); - -extern void *rcu_assign_pointer_sym(void **p, void *v); - -#define rcu_assign_pointer(p, v) \ - rcu_assign_pointer_sym((void **)(&(p)), (v)) - -extern void *rcu_cmpxchg_pointer_sym(void **p, void *old, void *_new); -#define rcu_cmpxchg_pointer(p, old, _new) \ - rcu_cmpxchg_pointer_sym((void **)(p), (old), (_new)) - -extern void *rcu_xchg_pointer_sym(void **p, void *v); -#define rcu_xchg_pointer(p, v) \ - rcu_xchg_pointer_sym((void **)(p), (v)) - -extern void *rcu_publish_content_sym(void **p, void *v); -#define rcu_publish_content(p, v) \ - rcu_publish_content_sym((void **)(p), (v)) - #endif /* !_LGPL_SOURCE */ extern void synchronize_rcu(void); diff --git a/urcu/system.h b/urcu/system.h new file mode 100644 index 0000000..e36a13b --- /dev/null +++ b/urcu/system.h @@ -0,0 +1,54 @@ +#ifndef _URCU_SYSTEM_H +#define _URCU_SYSTEM_H + +/* + * system.h + * + * System definitions. + * + * Copyright (c) 2009 Mathieu Desnoyers + * + * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED + * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + * + * Permission is hereby granted to use or copy this program + * for any purpose, provided the above notices are retained on all copies. + * Permission to modify the code and to distribute modified code is granted, + * provided the above notices are retained, and a notice that the code was + * modified is included with the above copyright notice. + */ + +#include +#include + +/* + * Identify a shared load. A smp_rmc() or smp_mc() should come before the load. + */ +#define _LOAD_SHARED(p) ACCESS_ONCE(p) + +/* + * Load a data from shared memory, doing a cache flush if required. + */ +#define LOAD_SHARED(p) \ + ({ \ + smp_rmc(); \ + _LOAD_SHARED(p); \ + }) + +/* + * Identify a shared store. A smp_wmc() or smp_mc() should follow the store. + */ +#define _STORE_SHARED(x, v) ({ ACCESS_ONCE(x) = (v); }) + +/* + * Store v into x, where x is located in shared memory. Performs the required + * cache flush after writing. Returns v. + */ +#define STORE_SHARED(x, v) \ + ({ \ + _STORE_SHARED(x, v); \ + smp_wmc(); \ + (v); \ + }) + +#endif /* _URCU_SYSTEM_H */