From: Mathieu Desnoyers Date: Wed, 28 Nov 2018 17:07:09 +0000 (-0500) Subject: Refactor liburcu to support many flavors per compile unit X-Git-Tag: v0.11.0~29 X-Git-Url: https://git.lttng.org./?a=commitdiff_plain;h=4477a87021ffbfbfdb2a2084d05a084171343d36;p=userspace-rcu.git Refactor liburcu to support many flavors per compile unit This refactoring keeps the prior use of liburcu "map" APIs unchanged. However, it introduces the following new APIs: Each urcu flavor is now available as its own header: include/urcu/urcu-memb.h include/urcu/urcu-mb.h include/urcu/urcu-signal.h include/urcu/urcu-bp.h include/urcu/urcu-qsbr.h The installed urcu headers that were not under the urcu/ subdirectory are moved there: include/urcu-call-rcu.h -> include/urcu/call-rcu.h include/urcu-defer.h -> include/urcu/defer.h include/urcu-flavor.h -> include/urcu/flavor.h include/urcu-pointer.h -> include/urcu/pointer.h include/urcu-bp.h -> include/urcu/urcu-bp.h include/urcu.h -> include/urcu/urcu.h include/urcu-qsbr.h -> include/urcu/urcu-qsbr.h The liburcu "map" API is now only available for use when URCU_API_MAP is defined before including the liburcu flavor headers. The old headers are now placeholders defining URCU_API_MAP and including the new headers for backward compatibility: include/urcu-bp.h include/urcu-call-rcu.h include/urcu-defer.h include/urcu-flavor.h include/urcu-pointer.h include/urcu-qsbr.h include/urcu.h The header include/urcu/urcu.h now includes the right header between the memb, signal, or mb flavors based on the compiler defines. The symbol names of liburcu flavors are cleaned up, favoring the following hierarchy: urcu__... This is an ABI-breaking change, however the previous symbols name were kept as aliases to maintain backward compatibility. They will be removed when the next SONAME bump occurs. The new liburcu-memb.so shared object is introduced, properly namespacing this flavor. It is a duplicate of the previous liburcu.so, which is kept around for backward compatibility. The new URCU_API_MAP macro is introduced, controlling whether the urcu API "mapping" should stay defined after inclusion of the flavor headers. Users wishing to use the prior urcu API should either explicitly define URCU_API_MAP before including the urcu/urcu*.h flavor headers, or include the flavor header files from the include toplevel directory, which are placeholders for backward compatibility. Use of many urcu flavors within the same _LGPL_SOURCE compile unit should not use the "map" APIs. Internally, the "map" header files are split into one header per flavor. The include guards are removed, so their effect can be applied more than once. A new include/urcu/map/clear.h header is introduced, which undefines the mappings at the end of the flavor header if URCU_API_MAP is not set. The new APIs namespaced for each urcu flavor is the recommended way to use liburcu. We can expect the prior APIs to eventually become deprecated over time. Signed-off-by: Mathieu Desnoyers --- diff --git a/configure.ac b/configure.ac index 9145081..8e7ff4c 100644 --- a/configure.ac +++ b/configure.ac @@ -508,6 +508,8 @@ PPRINT_PROP_BOOL([Require membarrier], $value) test "x$enable_rcu_debug" = "xyes" && value=1 || value=0 PPRINT_PROP_BOOL([Internal debugging], $value) +PPRINT_PROP_BOOL([Multi-flavor support], 1) + report_bindir="`eval eval echo $bindir`" report_libdir="`eval eval echo $libdir`" diff --git a/include/Makefile.am b/include/Makefile.am index 36667b4..a567f91 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -6,12 +6,21 @@ nobase_dist_include_HEADERS = urcu/compiler.h urcu/hlist.h urcu/list.h \ urcu/uatomic_arch.h urcu/rculfhash.h urcu/wfcqueue.h \ urcu/lfstack.h urcu/syscall-compat.h \ urcu/map/urcu-bp.h urcu/map/urcu.h urcu/map/urcu-qsbr.h \ + urcu/map/clear.h urcu/map/urcu-mb.h urcu/map/urcu-memb.h \ + urcu/map/urcu-signal.h \ urcu/static/lfstack.h urcu/static/rculfqueue.h \ urcu/static/rculfstack.h urcu/static/urcu-bp.h \ urcu/static/urcu.h urcu/static/urcu-pointer.h \ urcu/static/urcu-qsbr.h urcu/static/wfcqueue.h \ urcu/static/wfqueue.h urcu/static/wfstack.h \ - urcu/tls-compat.h urcu/debug.h + urcu/static/urcu-mb.h urcu/static/urcu-memb.h \ + urcu/static/urcu-signal.h urcu/static/urcu-common.h \ + urcu/tls-compat.h urcu/debug.h urcu/urcu.h urcu/urcu-bp.h \ + urcu/call-rcu.h urcu/defer.h \ + urcu/pointer.h urcu/urcu-qsbr.h urcu/flavor.h \ + urcu/urcu-mb.h urcu/urcu-memb.h urcu/urcu-signal.h \ + urcu.h urcu-bp.h urcu-call-rcu.h urcu-defer.h \ + urcu-pointer.h urcu-qsbr.h urcu-flavor.h # Don't distribute generated headers nobase_nodist_include_HEADERS = urcu/arch.h urcu/uatomic.h urcu/config.h diff --git a/include/urcu-bp.h b/include/urcu-bp.h new file mode 100644 index 0000000..acafee2 --- /dev/null +++ b/include/urcu-bp.h @@ -0,0 +1,2 @@ +#define URCU_API_MAP +#include diff --git a/include/urcu-call-rcu.h b/include/urcu-call-rcu.h new file mode 100644 index 0000000..162bc56 --- /dev/null +++ b/include/urcu-call-rcu.h @@ -0,0 +1 @@ +#include diff --git a/include/urcu-defer.h b/include/urcu-defer.h new file mode 100644 index 0000000..e097d45 --- /dev/null +++ b/include/urcu-defer.h @@ -0,0 +1 @@ +#include diff --git a/include/urcu-flavor.h b/include/urcu-flavor.h new file mode 100644 index 0000000..aca264d --- /dev/null +++ b/include/urcu-flavor.h @@ -0,0 +1 @@ +#include diff --git a/include/urcu-pointer.h b/include/urcu-pointer.h new file mode 100644 index 0000000..97aed98 --- /dev/null +++ b/include/urcu-pointer.h @@ -0,0 +1 @@ +#include diff --git a/include/urcu-qsbr.h b/include/urcu-qsbr.h new file mode 100644 index 0000000..43d95a9 --- /dev/null +++ b/include/urcu-qsbr.h @@ -0,0 +1,2 @@ +#define URCU_API_MAP +#include diff --git a/include/urcu.h b/include/urcu.h new file mode 100644 index 0000000..5599961 --- /dev/null +++ b/include/urcu.h @@ -0,0 +1,2 @@ +#define URCU_API_MAP +#include diff --git a/include/urcu/call-rcu.h b/include/urcu/call-rcu.h new file mode 100644 index 0000000..339ebac --- /dev/null +++ b/include/urcu/call-rcu.h @@ -0,0 +1,101 @@ +#ifndef _URCU_CALL_RCU_H +#define _URCU_CALL_RCU_H + +/* + * urcu-call-rcu.h + * + * Userspace RCU header - deferred execution + * + * Copyright (c) 2009 Mathieu Desnoyers + * Copyright (c) 2009 Paul E. McKenney, IBM Corporation. + * + * LGPL-compatible code should include this header with : + * + * #define _LGPL_SOURCE + * #include + * + * 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 + */ + +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Note that struct call_rcu_data is opaque to callers. */ + +struct call_rcu_data; + +/* Flag values. */ + +#define URCU_CALL_RCU_RT (1U << 0) +#define URCU_CALL_RCU_RUNNING (1U << 1) +#define URCU_CALL_RCU_STOP (1U << 2) +#define URCU_CALL_RCU_STOPPED (1U << 3) +#define URCU_CALL_RCU_PAUSE (1U << 4) +#define URCU_CALL_RCU_PAUSED (1U << 5) + +/* + * The rcu_head data structure is placed in the structure to be freed + * via call_rcu(). + */ + +struct rcu_head { + struct cds_wfcq_node next; + void (*func)(struct rcu_head *head); +}; + +/* + * Exported functions + * + * Important: see rcu-api.md in userspace-rcu documentation for + * call_rcu family of functions usage detail, including the surrounding + * RCU usage required when using these primitives. + */ + +void call_rcu(struct rcu_head *head, + void (*func)(struct rcu_head *head)); + +struct call_rcu_data *create_call_rcu_data(unsigned long flags, + int cpu_affinity); +void call_rcu_data_free(struct call_rcu_data *crdp); + +struct call_rcu_data *get_default_call_rcu_data(void); +struct call_rcu_data *get_cpu_call_rcu_data(int cpu); +struct call_rcu_data *get_thread_call_rcu_data(void); +struct call_rcu_data *get_call_rcu_data(void); +pthread_t get_call_rcu_thread(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 create_all_cpu_call_rcu_data(unsigned long flags); +void free_all_cpu_call_rcu_data(void); + +void call_rcu_before_fork(void); +void call_rcu_after_fork_parent(void); +void call_rcu_after_fork_child(void); + +void rcu_barrier(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _URCU_CALL_RCU_H */ diff --git a/include/urcu/config.h.in b/include/urcu/config.h.in index 9ed0454..9f2aa99 100644 --- a/include/urcu/config.h.in +++ b/include/urcu/config.h.in @@ -30,3 +30,6 @@ /* Enable internal debugging self-checks. Introduce performance penalty. */ #undef CONFIG_RCU_DEBUG + +/* Expose multi-flavor support */ +#define CONFIG_RCU_MULTIFLAVOR 1 diff --git a/include/urcu/defer.h b/include/urcu/defer.h new file mode 100644 index 0000000..43eca34 --- /dev/null +++ b/include/urcu/defer.h @@ -0,0 +1,67 @@ +#ifndef _URCU_BATCH_H +#define _URCU_BATCH_H + +/* + * urcu-defer.h + * + * Userspace RCU header - deferred execution + * + * Copyright (c) 2009 Mathieu Desnoyers + * Copyright (c) 2009 Paul E. McKenney, IBM Corporation. + * + * LGPL-compatible code should include this header with : + * + * #define _LGPL_SOURCE + * #include + * + * 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 + */ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Note: the defer_rcu() API is currently EXPERIMENTAL. It may change in the + * future. + * + * Important ! + * + * Each thread queuing memory reclamation must be registered with + * rcu_defer_register_thread(). rcu_defer_unregister_thread() should be + * called before the thread exits. + * + * *NEVER* use defer_rcu() within a RCU read-side critical section, because this + * primitive need to call synchronize_rcu() if the thread queue is full. + */ + +extern void defer_rcu(void (*fct)(void *p), void *p); + +/* + * Thread registration for reclamation. + */ +extern int rcu_defer_register_thread(void); +extern void rcu_defer_unregister_thread(void); +extern void rcu_defer_barrier(void); +extern void rcu_defer_barrier_thread(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _URCU_BATCH_H */ diff --git a/include/urcu/flavor.h b/include/urcu/flavor.h new file mode 100644 index 0000000..411fefb --- /dev/null +++ b/include/urcu/flavor.h @@ -0,0 +1,90 @@ +#ifndef _URCU_FLAVOR_H +#define _URCU_FLAVOR_H + +/* + * urcu-flavor.h + * + * Userspace RCU header - rcu flavor declarations + * + * Copyright (c) 2011 Lai Jiangshan + * + * 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 + */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct urcu_atfork { + void (*before_fork)(void *priv); + void (*after_fork_parent)(void *priv); + void (*after_fork_child)(void *priv); + void *priv; +}; + +void urcu_register_rculfhash_atfork(struct urcu_atfork *atfork); +void urcu_unregister_rculfhash_atfork(struct urcu_atfork *atfork); + +struct rcu_flavor_struct { + void (*read_lock)(void); + void (*read_unlock)(void); + int (*read_ongoing)(void); + void (*read_quiescent_state)(void); + void (*update_call_rcu)(struct rcu_head *head, + void (*func)(struct rcu_head *head)); + void (*update_synchronize_rcu)(void); + void (*update_defer_rcu)(void (*fct)(void *p), void *p); + + void (*thread_offline)(void); + void (*thread_online)(void); + void (*register_thread)(void); + void (*unregister_thread)(void); + + void (*barrier)(void); + + void (*register_rculfhash_atfork)(struct urcu_atfork *atfork); + void (*unregister_rculfhash_atfork)(struct urcu_atfork *atfork); +}; + +#define DEFINE_RCU_FLAVOR(x) \ +const struct rcu_flavor_struct x = { \ + .read_lock = rcu_read_lock, \ + .read_unlock = rcu_read_unlock, \ + .read_ongoing = rcu_read_ongoing, \ + .read_quiescent_state = rcu_quiescent_state, \ + .update_call_rcu = call_rcu, \ + .update_synchronize_rcu = synchronize_rcu, \ + .update_defer_rcu = defer_rcu, \ + .thread_offline = rcu_thread_offline, \ + .thread_online = rcu_thread_online, \ + .register_thread = rcu_register_thread, \ + .unregister_thread = rcu_unregister_thread,\ + .barrier = rcu_barrier, \ + .register_rculfhash_atfork = urcu_register_rculfhash_atfork, \ + .unregister_rculfhash_atfork = urcu_unregister_rculfhash_atfork,\ +} + +#define DEFINE_RCU_FLAVOR_ALIAS(x, y) _DEFINE_RCU_FLAVOR_ALIAS(x, y) +#define _DEFINE_RCU_FLAVOR_ALIAS(x, y) \ +__attribute__((alias(#x))) \ +extern const struct rcu_flavor_struct y; + +extern const struct rcu_flavor_struct rcu_flavor; + +#ifdef __cplusplus +} +#endif + +#endif /* _URCU_FLAVOR_H */ diff --git a/include/urcu/map/clear.h b/include/urcu/map/clear.h new file mode 100644 index 0000000..76d5464 --- /dev/null +++ b/include/urcu/map/clear.h @@ -0,0 +1,123 @@ +/* + * map/urcu-clear.h + * + * Userspace RCU header -- name mapping to allow multiple flavors to be + * used in the same executable. + * + * Copyright (c) 2009 Mathieu Desnoyers + * Copyright (c) 2009 Paul E. McKenney, IBM Corporation. + * + * LGPL-compatible code should include this header with : + * + * #undef _LGPL_SOURCE + * #include + * + * 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. + */ + +#undef rcu_read_lock +#undef _rcu_read_lock +#undef rcu_read_unlock +#undef _rcu_read_unlock +#undef rcu_read_ongoing +#undef _rcu_read_ongoing +#undef rcu_quiescent_state +#undef _rcu_quiescent_state +#undef rcu_thread_offline +#undef rcu_thread_online +#undef rcu_register_thread +#undef rcu_unregister_thread +#undef rcu_init +#undef rcu_exit +#undef synchronize_rcu +#undef rcu_reader +#undef rcu_gp + +#undef get_cpu_call_rcu_data +#undef get_call_rcu_thread +#undef create_call_rcu_data +#undef set_cpu_call_rcu_data +#undef get_default_call_rcu_data +#undef get_call_rcu_data +#undef get_thread_call_rcu_data +#undef set_thread_call_rcu_data +#undef create_all_cpu_call_rcu_data +#undef free_all_cpu_call_rcu_data +#undef call_rcu +#undef call_rcu_data_free +#undef call_rcu_before_fork +#undef call_rcu_after_fork_parent +#undef call_rcu_after_fork_child +#undef rcu_barrier + +#undef defer_rcu +#undef rcu_defer_register_thread +#undef rcu_defer_unregister_thread +#undef rcu_defer_barrier + +#undef rcu_defer_barrier_thread +#undef rcu_defer_exit + +#undef rcu_flavor + +#undef urcu_register_rculfhash_atfork +#undef urcu_unregister_rculfhash_atfork + +/* Aliases for ABI(6) compat */ + +#undef alias_rcu_flavor + +/* src/urcu.c */ +#undef alias_rcu_read_lock +#undef alias_rcu_read_unlock +#undef alias_rcu_read_ongoing +#undef alias_rcu_register_thread +#undef alias_rcu_unregister_thread +#undef alias_rcu_init +#undef alias_rcu_exit +#undef alias_synchronize_rcu +#undef alias_rcu_reader +#undef alias_rcu_gp + +/* src/urcu-call-rcu-impl.h */ +#undef alias_get_cpu_call_rcu_data +#undef alias_get_call_rcu_thread +#undef alias_create_call_rcu_data +#undef alias_set_cpu_call_rcu_data +#undef alias_get_default_call_rcu_data +#undef alias_get_call_rcu_data +#undef alias_get_thread_call_rcu_data +#undef alias_set_thread_call_rcu_data +#undef alias_create_all_cpu_call_rcu_data +#undef alias_free_all_cpu_call_rcu_data +#undef alias_call_rcu +#undef alias_call_rcu_data_free +#undef alias_call_rcu_before_fork +#undef alias_call_rcu_after_fork_parent +#undef alias_call_rcu_after_fork_child +#undef alias_rcu_barrier + +#undef alias_urcu_register_rculfhash_atfork +#undef alias_urcu_unregister_rculfhash_atfork + +/* src/urcu-defer-impl.h */ +#undef alias_defer_rcu +#undef alias_rcu_defer_register_thread +#undef alias_rcu_defer_unregister_thread +#undef alias_rcu_defer_barrier +#undef alias_rcu_defer_barrier_thread +#undef alias_rcu_defer_exit diff --git a/include/urcu/map/urcu-bp.h b/include/urcu/map/urcu-bp.h index 1476924..ed73ab2 100644 --- a/include/urcu/map/urcu-bp.h +++ b/include/urcu/map/urcu-bp.h @@ -1,8 +1,5 @@ -#ifndef _URCU_BP_MAP_H -#define _URCU_BP_MAP_H - /* - * urcu-map.h + * urcu/map/urcu-bp.h * * Userspace RCU header -- name mapping to allow multiple flavors to be * used in the same executable. @@ -34,52 +31,92 @@ /* Mapping macros to allow multiple flavors in a single binary. */ -#define rcu_read_lock rcu_read_lock_bp -#define _rcu_read_lock _rcu_read_lock_bp -#define rcu_read_unlock rcu_read_unlock_bp -#define _rcu_read_unlock _rcu_read_unlock_bp -#define rcu_read_ongoing rcu_read_ongoing_bp -#define _rcu_read_ongoing _rcu_read_ongoing_bp -#define rcu_register_thread rcu_register_thread_bp -#define rcu_unregister_thread rcu_unregister_thread_bp -#define rcu_init rcu_init_bp -#define rcu_exit rcu_exit_bp -#define synchronize_rcu synchronize_rcu_bp -#define rcu_reader rcu_reader_bp -#define rcu_gp rcu_gp_bp +#define rcu_read_lock urcu_bp_read_lock +#define _rcu_read_lock _urcu_bp_read_lock +#define rcu_read_unlock urcu_bp_read_unlock +#define _rcu_read_unlock _urcu_bp_read_unlock +#define rcu_read_ongoing urcu_bp_read_ongoing +#define _rcu_read_ongoing _urcu_bp_read_ongoing +#define rcu_quiescent_state urcu_bp_quiescent_state +#define _rcu_quiescent_state _urcu_bp_quiescent_state +#define rcu_thread_offline urcu_bp_thread_offline +#define rcu_thread_online urcu_bp_thread_online +#define rcu_register_thread urcu_bp_register_thread +#define rcu_unregister_thread urcu_bp_unregister_thread +#define rcu_init urcu_bp_init +#define rcu_exit urcu_bp_exit +#define synchronize_rcu urcu_bp_synchronize_rcu +#define rcu_reader urcu_bp_reader +#define rcu_gp urcu_bp_gp -#define get_cpu_call_rcu_data get_cpu_call_rcu_data_bp -#define get_call_rcu_thread get_call_rcu_thread_bp -#define create_call_rcu_data create_call_rcu_data_bp -#define set_cpu_call_rcu_data set_cpu_call_rcu_data_bp -#define get_default_call_rcu_data get_default_call_rcu_data_bp -#define get_call_rcu_data get_call_rcu_data_bp -#define get_thread_call_rcu_data get_thread_call_rcu_data_bp -#define set_thread_call_rcu_data set_thread_call_rcu_data_bp -#define create_all_cpu_call_rcu_data create_all_cpu_call_rcu_data_bp -#define free_all_cpu_call_rcu_data free_all_cpu_call_rcu_data_bp -#define call_rcu call_rcu_bp -#define call_rcu_data_free call_rcu_data_free_bp -#define call_rcu_before_fork call_rcu_before_fork_bp -#define call_rcu_after_fork_parent call_rcu_after_fork_parent_bp -#define call_rcu_after_fork_child call_rcu_after_fork_child_bp -#define rcu_barrier rcu_barrier_bp +#define get_cpu_call_rcu_data urcu_bp_get_cpu_call_rcu_data +#define get_call_rcu_thread urcu_bp_get_call_rcu_thread +#define create_call_rcu_data urcu_bp_create_call_rcu_data +#define set_cpu_call_rcu_data urcu_bp_set_cpu_call_rcu_data +#define get_default_call_rcu_data urcu_bp_get_default_call_rcu_data +#define get_call_rcu_data urcu_bp_get_call_rcu_data +#define get_thread_call_rcu_data urcu_bp_get_thread_call_rcu_data +#define set_thread_call_rcu_data urcu_bp_set_thread_call_rcu_data +#define create_all_cpu_call_rcu_data urcu_bp_create_all_cpu_call_rcu_data +#define free_all_cpu_call_rcu_data urcu_bp_free_all_cpu_call_rcu_data +#define call_rcu urcu_bp_call_rcu +#define call_rcu_data_free urcu_bp_call_rcu_data_free +#define call_rcu_before_fork urcu_bp_call_rcu_before_fork +#define call_rcu_after_fork_parent urcu_bp_call_rcu_after_fork_parent +#define call_rcu_after_fork_child urcu_bp_call_rcu_after_fork_child +#define rcu_barrier urcu_bp_barrier -#define defer_rcu defer_rcu_bp -#define rcu_defer_register_thread rcu_defer_register_thread_bp -#define rcu_defer_unregister_thread rcu_defer_unregister_thread_bp -#define rcu_defer_barrier rcu_defer_barrier_bp -#define rcu_defer_barrier_thread rcu_defer_barrier_thread_bp -#define rcu_defer_exit rcu_defer_exit_bp +#define defer_rcu urcu_bp_defer_rcu +#define rcu_defer_register_thread urcu_bp_defer_register_thread +#define rcu_defer_unregister_thread urcu_bp_defer_unregister_thread +#define rcu_defer_barrier urcu_bp_defer_barrier +#define rcu_defer_barrier_thread urcu_bp_defer_barrier_thread +#define rcu_defer_exit urcu_bp_defer_exit -#define rcu_flavor rcu_flavor_bp +#define rcu_flavor urcu_bp_flavor -#define rcu_yield_active rcu_yield_active_bp -#define rcu_rand_yield rcu_rand_yield_bp +#define rcu_yield_active urcu_bp_yield_active +#define rcu_rand_yield urcu_bp_rand_yield #define urcu_register_rculfhash_atfork \ - urcu_register_rculfhash_atfork_bp + urcu_bp_register_rculfhash_atfork #define urcu_unregister_rculfhash_atfork \ - urcu_unregister_rculfhash_atfork_bp + urcu_bp_unregister_rculfhash_atfork + + +/* Aliases for ABI(6) compat */ -#endif /* _URCU_BP_MAP_H */ +#define alias_rcu_flavor rcu_flavor_bp + +#define alias_get_cpu_call_rcu_data get_cpu_call_rcu_data_bp +#define alias_get_call_rcu_thread get_call_rcu_thread_bp +#define alias_create_call_rcu_data create_call_rcu_data_bp +#define alias_set_cpu_call_rcu_data set_cpu_call_rcu_data_bp +#define alias_get_default_call_rcu_data get_default_call_rcu_data_bp +#define alias_get_call_rcu_data get_call_rcu_data_bp +#define alias_get_thread_call_rcu_data get_thread_call_rcu_data_bp +#define alias_set_thread_call_rcu_data set_thread_call_rcu_data_bp +#define alias_create_all_cpu_call_rcu_data \ + create_all_cpu_call_rcu_data_bp +#define alias_free_all_cpu_call_rcu_data \ + free_all_cpu_call_rcu_data_bp +#define alias_call_rcu call_rcu_bp +#define alias_call_rcu_data_free call_rcu_data_free_bp +#define alias_call_rcu_before_fork call_rcu_before_fork_bp +#define alias_call_rcu_after_fork_parent \ + call_rcu_after_fork_parent_bp +#define alias_call_rcu_after_fork_child call_rcu_after_fork_child_bp +#define alias_rcu_barrier rcu_barrier_bp + +#define alias_defer_rcu defer_rcu_bp +#define alias_rcu_defer_register_thread rcu_defer_register_thread_bp +#define alias_rcu_defer_unregister_thread \ + rcu_defer_unregister_thread_bp +#define alias_rcu_defer_barrier rcu_defer_barrier_bp +#define alias_rcu_defer_barrier_thread rcu_defer_barrier_thread_bp +#define alias_rcu_defer_exit rcu_defer_exit_bp + +#define alias_urcu_register_rculfhash_atfork \ + urcu_register_rculfhash_atfork_bp +#define alias_urcu_unregister_rculfhash_atfork \ + urcu_unregister_rculfhash_atfork_bp diff --git a/include/urcu/map/urcu-mb.h b/include/urcu/map/urcu-mb.h new file mode 100644 index 0000000..fa77a1a --- /dev/null +++ b/include/urcu/map/urcu-mb.h @@ -0,0 +1,130 @@ +/* + * urcu/map/urcu-mb.h + * + * Userspace RCU header -- name mapping to allow multiple flavors to be + * used in the same executable. + * + * Copyright (c) 2009 Mathieu Desnoyers + * Copyright (c) 2009 Paul E. McKenney, IBM Corporation. + * + * LGPL-compatible code should include this header with : + * + * #define _LGPL_SOURCE + * #include + * + * 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. + */ + +#define rcu_read_lock urcu_mb_read_lock +#define _rcu_read_lock _urcu_mb_read_lock +#define rcu_read_unlock urcu_mb_read_unlock +#define _rcu_read_unlock _urcu_mb_read_unlock +#define rcu_read_ongoing urcu_mb_read_ongoing +#define _rcu_read_ongoing _urcu_mb_read_ongoing +#define rcu_quiescent_state urcu_mb_quiescent_state +#define _rcu_quiescent_state _urcu_mb_quiescent_state +#define rcu_thread_offline urcu_mb_thread_offline +#define rcu_thread_online urcu_mb_thread_online +#define rcu_register_thread urcu_mb_register_thread +#define rcu_unregister_thread urcu_mb_unregister_thread +#define rcu_init urcu_mb_init +#define rcu_exit urcu_mb_exit +#define synchronize_rcu urcu_mb_synchronize_rcu +#define rcu_reader urcu_mb_reader +#define rcu_gp urcu_mb_gp + +#define get_cpu_call_rcu_data urcu_mb_get_cpu_call_rcu_data +#define get_call_rcu_thread urcu_mb_get_call_rcu_thread +#define create_call_rcu_data urcu_mb_create_call_rcu_data +#define set_cpu_call_rcu_data urcu_mb_set_cpu_call_rcu_data +#define get_default_call_rcu_data urcu_mb_get_default_call_rcu_data +#define get_call_rcu_data urcu_mb_get_call_rcu_data +#define get_thread_call_rcu_data urcu_mb_get_thread_call_rcu_data +#define set_thread_call_rcu_data urcu_mb_set_thread_call_rcu_data +#define create_all_cpu_call_rcu_data urcu_mb_create_all_cpu_call_rcu_data +#define free_all_cpu_call_rcu_data urcu_mb_free_all_cpu_call_rcu_data +#define call_rcu urcu_mb_call_rcu +#define call_rcu_data_free urcu_mb_call_rcu_data_free +#define call_rcu_before_fork urcu_mb_call_rcu_before_fork +#define call_rcu_after_fork_parent urcu_mb_call_rcu_after_fork_parent +#define call_rcu_after_fork_child urcu_mb_call_rcu_after_fork_child +#define rcu_barrier urcu_mb_barrier + +#define defer_rcu urcu_mb_defer_rcu +#define rcu_defer_register_thread urcu_mb_defer_register_thread +#define rcu_defer_unregister_thread urcu_mb_defer_unregister_thread +#define rcu_defer_barrier urcu_mb_defer_barrier +#define rcu_defer_barrier_thread urcu_mb_defer_barrier_thread +#define rcu_defer_exit urcu_mb_defer_exit + +#define rcu_flavor urcu_mb_flavor + +#define urcu_register_rculfhash_atfork \ + urcu_mb_register_rculfhash_atfork +#define urcu_unregister_rculfhash_atfork \ + urcu_mb_unregister_rculfhash_atfork + + +/* Aliases for ABI(6) compat */ + +#define alias_rcu_flavor rcu_flavor_mb + +/* src/urcu.c */ +#define alias_rcu_read_lock rcu_read_lock_mb +#define alias_rcu_read_unlock rcu_read_unlock_mb +#define alias_rcu_read_ongoing rcu_read_ongoing_mb +#define alias_rcu_register_thread rcu_register_thread_mb +#define alias_rcu_unregister_thread rcu_unregister_thread_mb +#define alias_rcu_init rcu_init_mb +#define alias_synchronize_rcu synchronize_rcu_mb +#define alias_rcu_reader rcu_reader_mb +#define alias_rcu_gp rcu_gp_mb + +/* src/urcu-call-rcu-impl.h */ +#define alias_get_cpu_call_rcu_data get_cpu_call_rcu_data_mb +#define alias_get_call_rcu_thread get_call_rcu_thread_mb +#define alias_create_call_rcu_data create_call_rcu_data_mb +#define alias_set_cpu_call_rcu_data set_cpu_call_rcu_data_mb +#define alias_get_default_call_rcu_data get_default_call_rcu_data_mb +#define alias_get_call_rcu_data get_call_rcu_data_mb +#define alias_get_thread_call_rcu_data get_thread_call_rcu_data_mb +#define alias_set_thread_call_rcu_data set_thread_call_rcu_data_mb +#define alias_create_all_cpu_call_rcu_data \ + create_all_cpu_call_rcu_data_mb +#define alias_free_all_cpu_call_rcu_data \ + free_all_cpu_call_rcu_data_mb +#define alias_call_rcu call_rcu_mb +#define alias_call_rcu_data_free call_rcu_data_free_mb +#define alias_call_rcu_before_fork call_rcu_before_fork_mb +#define alias_call_rcu_after_fork_parent \ + call_rcu_after_fork_parent_mb +#define alias_call_rcu_after_fork_child call_rcu_after_fork_child_mb +#define alias_rcu_barrier rcu_barrier_mb + +#define alias_urcu_register_rculfhash_atfork \ + urcu_register_rculfhash_atfork_mb +#define alias_urcu_unregister_rculfhash_atfork \ + urcu_unregister_rculfhash_atfork_mb + +/* src/urcu-defer-impl.h */ +#define alias_defer_rcu defer_rcu_mb +#define alias_rcu_defer_register_thread rcu_defer_register_thread_mb +#define alias_rcu_defer_unregister_thread \ + rcu_defer_unregister_thread_mb +#define alias_rcu_defer_barrier rcu_defer_barrier_mb +#define alias_rcu_defer_barrier_thread rcu_defer_barrier_thread_mb +#define alias_rcu_defer_exit rcu_defer_exit_mb diff --git a/include/urcu/map/urcu-memb.h b/include/urcu/map/urcu-memb.h new file mode 100644 index 0000000..33f9a9b --- /dev/null +++ b/include/urcu/map/urcu-memb.h @@ -0,0 +1,130 @@ +/* + * urcu/map/urcu-memb.h + * + * Userspace RCU header -- name mapping to allow multiple flavors to be + * used in the same executable. + * + * Copyright (c) 2009 Mathieu Desnoyers + * Copyright (c) 2009 Paul E. McKenney, IBM Corporation. + * + * LGPL-compatible code should include this header with : + * + * #define _LGPL_SOURCE + * #include + * + * 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. + */ + +#define rcu_read_lock urcu_memb_read_lock +#define _rcu_read_lock _urcu_memb_read_lock +#define rcu_read_unlock urcu_memb_read_unlock +#define _rcu_read_unlock _urcu_memb_read_unlock +#define rcu_read_ongoing urcu_memb_read_ongoing +#define _rcu_read_ongoing _urcu_memb_read_ongoing +#define rcu_quiescent_state urcu_memb_quiescent_state +#define _rcu_quiescent_state _urcu_memb_quiescent_state +#define rcu_thread_offline urcu_memb_thread_offline +#define rcu_thread_online urcu_memb_thread_online +#define rcu_register_thread urcu_memb_register_thread +#define rcu_unregister_thread urcu_memb_unregister_thread +#define rcu_init urcu_memb_init +#define rcu_exit urcu_memb_exit +#define synchronize_rcu urcu_memb_synchronize_rcu +#define rcu_reader urcu_memb_reader +#define rcu_gp urcu_memb_gp + +#define get_cpu_call_rcu_data urcu_memb_get_cpu_call_rcu_data +#define get_call_rcu_thread urcu_memb_get_call_rcu_thread +#define create_call_rcu_data urcu_memb_create_call_rcu_data +#define set_cpu_call_rcu_data urcu_memb_set_cpu_call_rcu_data +#define get_default_call_rcu_data urcu_memb_get_default_call_rcu_data +#define get_call_rcu_data urcu_memb_get_call_rcu_data +#define get_thread_call_rcu_data urcu_memb_get_thread_call_rcu_data +#define set_thread_call_rcu_data urcu_memb_set_thread_call_rcu_data +#define create_all_cpu_call_rcu_data urcu_memb_create_all_cpu_call_rcu_data +#define free_all_cpu_call_rcu_data urcu_memb_free_all_cpu_call_rcu_data +#define call_rcu urcu_memb_call_rcu +#define call_rcu_data_free urcu_memb_call_rcu_data_free +#define call_rcu_before_fork urcu_memb_call_rcu_before_fork +#define call_rcu_after_fork_parent urcu_memb_call_rcu_after_fork_parent +#define call_rcu_after_fork_child urcu_memb_call_rcu_after_fork_child +#define rcu_barrier urcu_memb_barrier + +#define defer_rcu urcu_memb_defer_rcu +#define rcu_defer_register_thread urcu_memb_defer_register_thread +#define rcu_defer_unregister_thread urcu_memb_defer_unregister_thread +#define rcu_defer_barrier urcu_memb_defer_barrier +#define rcu_defer_barrier_thread urcu_memb_defer_barrier_thread +#define rcu_defer_exit urcu_memb_defer_exit + +#define rcu_flavor urcu_memb_flavor + +#define urcu_register_rculfhash_atfork \ + urcu_memb_register_rculfhash_atfork +#define urcu_unregister_rculfhash_atfork \ + urcu_memb_unregister_rculfhash_atfork + + +/* Aliases for ABI(6) compat */ + +#define alias_rcu_flavor rcu_flavor_memb + +/* src/urcu.c */ +#define alias_rcu_read_lock rcu_read_lock_memb +#define alias_rcu_read_unlock rcu_read_unlock_memb +#define alias_rcu_read_ongoing rcu_read_ongoing_memb +#define alias_rcu_register_thread rcu_register_thread_memb +#define alias_rcu_unregister_thread rcu_unregister_thread_memb +#define alias_rcu_init rcu_init_memb +#define alias_synchronize_rcu synchronize_rcu_memb +#define alias_rcu_reader rcu_reader_memb +#define alias_rcu_gp rcu_gp_memb + +/* src/urcu-call-rcu-impl.h */ +#define alias_get_cpu_call_rcu_data get_cpu_call_rcu_data_memb +#define alias_get_call_rcu_thread get_call_rcu_thread_memb +#define alias_create_call_rcu_data create_call_rcu_data_memb +#define alias_set_cpu_call_rcu_data set_cpu_call_rcu_data_memb +#define alias_get_default_call_rcu_data get_default_call_rcu_data_memb +#define alias_get_call_rcu_data get_call_rcu_data_memb +#define alias_get_thread_call_rcu_data get_thread_call_rcu_data_memb +#define alias_set_thread_call_rcu_data set_thread_call_rcu_data_memb +#define alias_create_all_cpu_call_rcu_data \ + create_all_cpu_call_rcu_data_memb +#define alias_free_all_cpu_call_rcu_data \ + free_all_cpu_call_rcu_data_memb +#define alias_call_rcu call_rcu_memb +#define alias_call_rcu_data_free call_rcu_data_free_memb +#define alias_call_rcu_before_fork call_rcu_before_fork_memb +#define alias_call_rcu_after_fork_parent \ + call_rcu_after_fork_parent_memb +#define alias_call_rcu_after_fork_child call_rcu_after_fork_child_memb +#define alias_rcu_barrier rcu_barrier_memb + +#define alias_urcu_register_rculfhash_atfork \ + urcu_register_rculfhash_atfork_memb +#define alias_urcu_unregister_rculfhash_atfork \ + urcu_unregister_rculfhash_atfork_memb + +/* src/urcu-defer-impl.h */ +#define alias_defer_rcu defer_rcu_memb +#define alias_rcu_defer_register_thread rcu_defer_register_thread_memb +#define alias_rcu_defer_unregister_thread \ + rcu_defer_unregister_thread_memb +#define alias_rcu_defer_barrier rcu_defer_barrier_memb +#define alias_rcu_defer_barrier_thread rcu_defer_barrier_thread_memb +#define alias_rcu_defer_exit rcu_defer_exit_memb diff --git a/include/urcu/map/urcu-qsbr.h b/include/urcu/map/urcu-qsbr.h index bf38c82..2b4d861 100644 --- a/include/urcu/map/urcu-qsbr.h +++ b/include/urcu/map/urcu-qsbr.h @@ -1,8 +1,5 @@ -#ifndef _URCU_QSBR_MAP_H -#define _URCU_QSBR_MAP_H - /* - * urcu-map.h + * urcu/map/urcu-qsbr.h * * Userspace RCU header -- name mapping to allow multiple flavors to be * used in the same executable. @@ -32,53 +29,100 @@ * IBM's contributions to this file may be relicensed under LGPLv2 or later. */ -/* Mapping macros to allow multiple flavors in a single binary. */ - -#define rcu_read_lock rcu_read_lock_qsbr -#define _rcu_read_lock _rcu_read_lock_qsbr -#define rcu_read_unlock rcu_read_unlock_qsbr -#define _rcu_read_unlock _rcu_read_unlock_qsbr -#define rcu_read_ongoing rcu_read_ongoing_qsbr -#define _rcu_read_ongoing _rcu_read_ongoing_qsbr -#define rcu_quiescent_state rcu_quiescent_state_qsbr -#define _rcu_quiescent_state _rcu_quiescent_state_qsbr -#define rcu_thread_offline rcu_thread_offline_qsbr -#define rcu_thread_online rcu_thread_online_qsbr -#define rcu_register_thread rcu_register_thread_qsbr -#define rcu_unregister_thread rcu_unregister_thread_qsbr -#define rcu_exit rcu_exit_qsbr -#define synchronize_rcu synchronize_rcu_qsbr -#define rcu_reader rcu_reader_qsbr -#define rcu_gp rcu_gp_qsbr +#define rcu_read_lock urcu_qsbr_read_lock +#define _rcu_read_lock _urcu_qsbr_read_lock +#define rcu_read_unlock urcu_qsbr_read_unlock +#define _rcu_read_unlock _urcu_qsbr_read_unlock +#define rcu_read_ongoing urcu_qsbr_read_ongoing +#define _rcu_read_ongoing _urcu_qsbr_read_ongoing +#define rcu_quiescent_state urcu_qsbr_quiescent_state +#define _rcu_quiescent_state _urcu_qsbr_quiescent_state +#define rcu_thread_offline urcu_qsbr_thread_offline +#define rcu_thread_online urcu_qsbr_thread_online +#define rcu_register_thread urcu_qsbr_register_thread +#define rcu_unregister_thread urcu_qsbr_unregister_thread +#define rcu_exit urcu_qsbr_exit +#define synchronize_rcu urcu_qsbr_synchronize_rcu +#define rcu_reader urcu_qsbr_reader +#define rcu_gp urcu_qsbr_gp -#define get_cpu_call_rcu_data get_cpu_call_rcu_data_qsbr -#define get_call_rcu_thread get_call_rcu_thread_qsbr -#define create_call_rcu_data create_call_rcu_data_qsbr -#define set_cpu_call_rcu_data set_cpu_call_rcu_data_qsbr -#define get_default_call_rcu_data get_default_call_rcu_data_qsbr -#define get_call_rcu_data get_call_rcu_data_qsbr -#define get_thread_call_rcu_data get_thread_call_rcu_data_qsbr -#define set_thread_call_rcu_data set_thread_call_rcu_data_qsbr -#define create_all_cpu_call_rcu_data create_all_cpu_call_rcu_data_qsbr -#define call_rcu call_rcu_qsbr -#define call_rcu_data_free call_rcu_data_free_qsbr -#define call_rcu_before_fork call_rcu_before_fork_qsbr -#define call_rcu_after_fork_parent call_rcu_after_fork_parent_qsbr -#define call_rcu_after_fork_child call_rcu_after_fork_child_qsbr -#define rcu_barrier rcu_barrier_qsbr +#define get_cpu_call_rcu_data urcu_qsbr_get_cpu_call_rcu_data +#define get_call_rcu_thread urcu_qsbr_get_call_rcu_thread +#define create_call_rcu_data urcu_qsbr_create_call_rcu_data +#define set_cpu_call_rcu_data urcu_qsbr_set_cpu_call_rcu_data +#define get_default_call_rcu_data urcu_qsbr_get_default_call_rcu_data +#define get_call_rcu_data urcu_qsbr_get_call_rcu_data +#define get_thread_call_rcu_data urcu_qsbr_get_thread_call_rcu_data +#define set_thread_call_rcu_data urcu_qsbr_set_thread_call_rcu_data +#define create_all_cpu_call_rcu_data urcu_qsbr_create_all_cpu_call_rcu_data +#define free_all_cpu_call_rcu_data urcu_qsbr_free_all_cpu_call_rcu_data +#define call_rcu urcu_qsbr_call_rcu +#define call_rcu_data_free urcu_qsbr_call_rcu_data_free +#define call_rcu_before_fork urcu_qsbr_call_rcu_before_fork +#define call_rcu_after_fork_parent urcu_qsbr_call_rcu_after_fork_parent +#define call_rcu_after_fork_child urcu_qsbr_call_rcu_after_fork_child +#define rcu_barrier urcu_qsbr_barrier -#define defer_rcu defer_rcu_qsbr -#define rcu_defer_register_thread rcu_defer_register_thread_qsbr -#define rcu_defer_unregister_thread rcu_defer_unregister_thread_qsbr -#define rcu_defer_barrier rcu_defer_barrier_qsbr -#define rcu_defer_barrier_thread rcu_defer_barrier_thread_qsbr -#define rcu_defer_exit rcu_defer_exit_qsbr +#define defer_rcu urcu_qsbr_defer_rcu +#define rcu_defer_register_thread urcu_qsbr_defer_register_thread +#define rcu_defer_unregister_thread urcu_qsbr_defer_unregister_thread +#define rcu_defer_barrier urcu_qsbr_defer_barrier +#define rcu_defer_barrier_thread urcu_qsbr_defer_barrier_thread +#define rcu_defer_exit urcu_qsbr_defer_exit -#define rcu_flavor rcu_flavor_qsbr +#define rcu_flavor urcu_qsbr_flavor #define urcu_register_rculfhash_atfork \ - urcu_register_rculfhash_atfork_qsbr + urcu_qsbr_register_rculfhash_atfork #define urcu_unregister_rculfhash_atfork \ + urcu_qsbr_unregister_rculfhash_atfork + +/* Aliases for ABI(6) compat */ + +#define alias_rcu_flavor rcu_flavor_qsbr + +/* src/urcu.c */ +#define alias_rcu_read_lock rcu_read_lock_qsbr +#define alias_rcu_read_unlock rcu_read_unlock_qsbr +#define alias_rcu_read_ongoing rcu_read_ongoing_qsbr +#define alias_rcu_register_thread rcu_register_thread_qsbr +#define alias_rcu_unregister_thread rcu_unregister_thread_qsbr +#define alias_rcu_init rcu_init_qsbr +#define alias_synchronize_rcu synchronize_rcu_qsbr +#define alias_rcu_reader rcu_reader_qsbr +#define alias_rcu_gp rcu_gp_qsbr + +/* src/urcu-call-rcu-impl.h */ +#define alias_get_cpu_call_rcu_data get_cpu_call_rcu_data_qsbr +#define alias_get_call_rcu_thread get_call_rcu_thread_qsbr +#define alias_create_call_rcu_data create_call_rcu_data_qsbr +#define alias_set_cpu_call_rcu_data set_cpu_call_rcu_data_qsbr +#define alias_get_default_call_rcu_data get_default_call_rcu_data_qsbr +#define alias_get_call_rcu_data get_call_rcu_data_qsbr +#define alias_get_thread_call_rcu_data get_thread_call_rcu_data_qsbr +#define alias_set_thread_call_rcu_data set_thread_call_rcu_data_qsbr +#define alias_create_all_cpu_call_rcu_data \ + create_all_cpu_call_rcu_data_qsbr +#define alias_free_all_cpu_call_rcu_data \ + free_all_cpu_call_rcu_data_qsbr +#define alias_call_rcu call_rcu_qsbr +#define alias_call_rcu_data_free call_rcu_data_free_qsbr +#define alias_call_rcu_before_fork call_rcu_before_fork_qsbr +#define alias_call_rcu_after_fork_parent \ + call_rcu_after_fork_parent_qsbr +#define alias_call_rcu_after_fork_child call_rcu_after_fork_child_qsbr +#define alias_rcu_barrier rcu_barrier_qsbr + +#define alias_urcu_register_rculfhash_atfork \ + urcu_register_rculfhash_atfork_qsbr +#define alias_urcu_unregister_rculfhash_atfork \ urcu_unregister_rculfhash_atfork_qsbr -#endif /* _URCU_QSBR_MAP_H */ +/* src/urcu-defer-impl.h */ +#define alias_defer_rcu defer_rcu_qsbr +#define alias_rcu_defer_register_thread rcu_defer_register_thread_qsbr +#define alias_rcu_defer_unregister_thread \ + rcu_defer_unregister_thread_qsbr +#define alias_rcu_defer_barrier rcu_defer_barrier_qsbr +#define alias_rcu_defer_barrier_thread rcu_defer_barrier_thread_qsbr +#define alias_rcu_defer_exit rcu_defer_exit_qsbr diff --git a/include/urcu/map/urcu-signal.h b/include/urcu/map/urcu-signal.h new file mode 100644 index 0000000..842a14f --- /dev/null +++ b/include/urcu/map/urcu-signal.h @@ -0,0 +1,131 @@ +/* + * urcu/map/urcu-signal.h + * + * Userspace RCU header -- name mapping to allow multiple flavors to be + * used in the same executable. + * + * Copyright (c) 2009 Mathieu Desnoyers + * Copyright (c) 2009 Paul E. McKenney, IBM Corporation. + * + * LGPL-compatible code should include this header with : + * + * #define _LGPL_SOURCE + * #include + * + * 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. + */ + +#define rcu_read_lock urcu_signal_read_lock +#define _rcu_read_lock _urcu_signal_read_lock +#define rcu_read_unlock urcu_signal_read_unlock +#define _rcu_read_unlock _urcu_signal_read_unlock +#define rcu_read_ongoing urcu_signal_read_ongoing +#define _rcu_read_ongoing _urcu_signal_read_ongoing +#define rcu_quiescent_state urcu_signal_quiescent_state +#define _rcu_quiescent_state _urcu_signal_quiescent_state +#define rcu_thread_offline urcu_signal_thread_offline +#define rcu_thread_online urcu_signal_thread_online +#define rcu_register_thread urcu_signal_register_thread +#define rcu_unregister_thread urcu_signal_unregister_thread +#define rcu_init urcu_signal_init +#define rcu_exit urcu_signal_exit +#define synchronize_rcu urcu_signal_synchronize_rcu +#define rcu_reader urcu_signal_reader +#define rcu_gp urcu_signal_gp + +#define get_cpu_call_rcu_data urcu_signal_get_cpu_call_rcu_data +#define get_call_rcu_thread urcu_signal_get_call_rcu_thread +#define create_call_rcu_data urcu_signal_create_call_rcu_data +#define set_cpu_call_rcu_data urcu_signal_set_cpu_call_rcu_data +#define get_default_call_rcu_data urcu_signal_get_default_call_rcu_data +#define get_call_rcu_data urcu_signal_get_call_rcu_data +#define get_thread_call_rcu_data urcu_signal_get_thread_call_rcu_data +#define set_thread_call_rcu_data urcu_signal_set_thread_call_rcu_data +#define create_all_cpu_call_rcu_data urcu_signal_create_all_cpu_call_rcu_data +#define free_all_cpu_call_rcu_data urcu_signal_free_all_cpu_call_rcu_data +#define call_rcu urcu_signal_call_rcu +#define call_rcu_data_free urcu_signal_call_rcu_data_free +#define call_rcu_before_fork urcu_signal_call_rcu_before_fork +#define call_rcu_after_fork_parent urcu_signal_call_rcu_after_fork_parent +#define call_rcu_after_fork_child urcu_signal_call_rcu_after_fork_child +#define rcu_barrier urcu_signal_barrier + +#define defer_rcu urcu_signal_defer_rcu +#define rcu_defer_register_thread urcu_signal_defer_register_thread +#define rcu_defer_unregister_thread urcu_signal_defer_unregister_thread +#define rcu_defer_barrier urcu_signal_defer_barrier +#define rcu_defer_barrier_thread urcu_signal_defer_barrier_thread +#define rcu_defer_exit urcu_signal_defer_exit + +#define rcu_flavor urcu_signal_flavor + +#define urcu_register_rculfhash_atfork \ + urcu_signal_register_rculfhash_atfork +#define urcu_unregister_rculfhash_atfork \ + urcu_signal_unregister_rculfhash_atfork + + +/* Aliases for ABI(6) compat */ + +#define alias_rcu_flavor rcu_flavor_sig + +/* src/urcu.c */ +#define alias_rcu_read_lock rcu_read_lock_sig +#define alias_rcu_read_unlock rcu_read_unlock_sig +#define alias_rcu_read_ongoing rcu_read_ongoing_sig +#define alias_rcu_register_thread rcu_register_thread_sig +#define alias_rcu_unregister_thread rcu_unregister_thread_sig +#define alias_rcu_init rcu_init_sig +#define alias_rcu_exit rcu_exit_sig +#define alias_synchronize_rcu synchronize_rcu_sig +#define alias_rcu_reader rcu_reader_sig +#define alias_rcu_gp rcu_gp_sig + +/* src/urcu-call-rcu-impl.h */ +#define alias_get_cpu_call_rcu_data get_cpu_call_rcu_data_sig +#define alias_get_call_rcu_thread get_call_rcu_thread_sig +#define alias_create_call_rcu_data create_call_rcu_data_sig +#define alias_set_cpu_call_rcu_data set_cpu_call_rcu_data_sig +#define alias_get_default_call_rcu_data get_default_call_rcu_data_sig +#define alias_get_call_rcu_data get_call_rcu_data_sig +#define alias_get_thread_call_rcu_data get_thread_call_rcu_data_sig +#define alias_set_thread_call_rcu_data set_thread_call_rcu_data_sig +#define alias_create_all_cpu_call_rcu_data \ + create_all_cpu_call_rcu_data_sig +#define alias_free_all_cpu_call_rcu_data \ + free_all_cpu_call_rcu_data_sig +#define alias_call_rcu call_rcu_sig +#define alias_call_rcu_data_free call_rcu_data_free_sig +#define alias_call_rcu_before_fork call_rcu_before_fork_sig +#define alias_call_rcu_after_fork_parent \ + call_rcu_after_fork_parent_sig +#define alias_call_rcu_after_fork_child call_rcu_after_fork_child_sig +#define alias_rcu_barrier rcu_barrier_sig + +#define alias_urcu_register_rculfhash_atfork \ + urcu_register_rculfhash_atfork_sig +#define alias_urcu_unregister_rculfhash_atfork \ + urcu_unregister_rculfhash_atfork_sig + +/* src/urcu-defer-impl.h */ +#define alias_defer_rcu defer_rcu_sig +#define alias_rcu_defer_register_thread rcu_defer_register_thread_sig +#define alias_rcu_defer_unregister_thread \ + rcu_defer_unregister_thread_sig +#define alias_rcu_defer_barrier rcu_defer_barrier_sig +#define alias_rcu_defer_barrier_thread rcu_defer_barrier_thread_sig +#define alias_rcu_defer_exit rcu_defer_exit_sig diff --git a/include/urcu/map/urcu.h b/include/urcu/map/urcu.h index b12fa74..a2fb7c8 100644 --- a/include/urcu/map/urcu.h +++ b/include/urcu/map/urcu.h @@ -1,6 +1,3 @@ -#ifndef _URCU_MAP_H -#define _URCU_MAP_H - /* * urcu-map.h * @@ -32,157 +29,12 @@ * IBM's contributions to this file may be relicensed under LGPLv2 or later. */ -/* Mapping macros to allow multiple flavors in a single binary. */ - -#if !defined(RCU_MEMBARRIER) && !defined(RCU_SIGNAL) && !defined(RCU_MB) -#define RCU_MEMBARRIER -#endif - #ifdef RCU_MEMBARRIER - -#define rcu_read_lock rcu_read_lock_memb -#define _rcu_read_lock _rcu_read_lock_memb -#define rcu_read_unlock rcu_read_unlock_memb -#define _rcu_read_unlock _rcu_read_unlock_memb -#define rcu_read_ongoing rcu_read_ongoing_memb -#define _rcu_read_ongoing _rcu_read_ongoing_memb -#define rcu_register_thread rcu_register_thread_memb -#define rcu_unregister_thread rcu_unregister_thread_memb -#define rcu_init rcu_init_memb -#define rcu_exit rcu_exit_memb -#define synchronize_rcu synchronize_rcu_memb -#define rcu_reader rcu_reader_memb -#define rcu_gp rcu_gp_memb - -#define get_cpu_call_rcu_data get_cpu_call_rcu_data_memb -#define get_call_rcu_thread get_call_rcu_thread_memb -#define create_call_rcu_data create_call_rcu_data_memb -#define set_cpu_call_rcu_data set_cpu_call_rcu_data_memb -#define get_default_call_rcu_data get_default_call_rcu_data_memb -#define get_call_rcu_data get_call_rcu_data_memb -#define get_thread_call_rcu_data get_thread_call_rcu_data_memb -#define set_thread_call_rcu_data set_thread_call_rcu_data_memb -#define create_all_cpu_call_rcu_data create_all_cpu_call_rcu_data_memb -#define free_all_cpu_call_rcu_data free_all_cpu_call_rcu_data_memb -#define call_rcu call_rcu_memb -#define call_rcu_data_free call_rcu_data_free_memb -#define call_rcu_before_fork call_rcu_before_fork_memb -#define call_rcu_after_fork_parent call_rcu_after_fork_parent_memb -#define call_rcu_after_fork_child call_rcu_after_fork_child_memb -#define rcu_barrier rcu_barrier_memb - -#define defer_rcu defer_rcu_memb -#define rcu_defer_register_thread rcu_defer_register_thread_memb -#define rcu_defer_unregister_thread rcu_defer_unregister_thread_memb -#define rcu_defer_barrier rcu_defer_barrier_memb -#define rcu_defer_barrier_thread rcu_defer_barrier_thread_memb -#define rcu_defer_exit rcu_defer_exit_memb - -#define rcu_flavor rcu_flavor_memb - -#define urcu_register_rculfhash_atfork \ - urcu_register_rculfhash_atfork_memb -#define urcu_unregister_rculfhash_atfork \ - urcu_unregister_rculfhash_atfork_memb - +#include #elif defined(RCU_SIGNAL) - -#define rcu_read_lock rcu_read_lock_sig -#define _rcu_read_lock _rcu_read_lock_sig -#define rcu_read_unlock rcu_read_unlock_sig -#define _rcu_read_unlock _rcu_read_unlock_sig -#define rcu_read_ongoing rcu_read_ongoing_sig -#define _rcu_read_ongoing _rcu_read_ongoing_sig -#define rcu_register_thread rcu_register_thread_sig -#define rcu_unregister_thread rcu_unregister_thread_sig -#define rcu_init rcu_init_sig -#define rcu_exit rcu_exit_sig -#define synchronize_rcu synchronize_rcu_sig -#define rcu_reader rcu_reader_sig -#define rcu_gp rcu_gp_sig - -#define get_cpu_call_rcu_data get_cpu_call_rcu_data_sig -#define get_call_rcu_thread get_call_rcu_thread_sig -#define create_call_rcu_data create_call_rcu_data_sig -#define set_cpu_call_rcu_data set_cpu_call_rcu_data_sig -#define get_default_call_rcu_data get_default_call_rcu_data_sig -#define get_call_rcu_data get_call_rcu_data_sig -#define get_thread_call_rcu_data get_thread_call_rcu_data_sig -#define set_thread_call_rcu_data set_thread_call_rcu_data_sig -#define create_all_cpu_call_rcu_data create_all_cpu_call_rcu_data_sig -#define free_all_cpu_call_rcu_data free_all_cpu_call_rcu_data_sig -#define call_rcu call_rcu_sig -#define call_rcu_data_free call_rcu_data_free_sig -#define call_rcu_before_fork call_rcu_before_fork_sig -#define call_rcu_after_fork_parent call_rcu_after_fork_parent_sig -#define call_rcu_after_fork_child call_rcu_after_fork_child_sig -#define rcu_barrier rcu_barrier_sig - -#define defer_rcu defer_rcu_sig -#define rcu_defer_register_thread rcu_defer_register_thread_sig -#define rcu_defer_unregister_thread rcu_defer_unregister_thread_sig -#define rcu_defer_barrier rcu_defer_barrier_sig -#define rcu_defer_barrier_thread rcu_defer_barrier_thread_sig -#define rcu_defer_exit rcu_defer_exit_sig - -#define rcu_flavor rcu_flavor_sig - -#define urcu_register_rculfhash_atfork \ - urcu_register_rculfhash_atfork_sig -#define urcu_unregister_rculfhash_atfork \ - urcu_unregister_rculfhash_atfork_sig - +#include #elif defined(RCU_MB) - -#define rcu_read_lock rcu_read_lock_mb -#define _rcu_read_lock _rcu_read_lock_mb -#define rcu_read_unlock rcu_read_unlock_mb -#define _rcu_read_unlock _rcu_read_unlock_mb -#define rcu_read_ongoing rcu_read_ongoing_mb -#define _rcu_read_ongoing _rcu_read_ongoing_mb -#define rcu_register_thread rcu_register_thread_mb -#define rcu_unregister_thread rcu_unregister_thread_mb -#define rcu_init rcu_init_mb -#define rcu_exit rcu_exit_mb -#define synchronize_rcu synchronize_rcu_mb -#define rcu_reader rcu_reader_mb -#define rcu_gp rcu_gp_mb - -#define get_cpu_call_rcu_data get_cpu_call_rcu_data_mb -#define get_call_rcu_thread get_call_rcu_thread_mb -#define create_call_rcu_data create_call_rcu_data_mb -#define set_cpu_call_rcu_data set_cpu_call_rcu_data_mb -#define get_default_call_rcu_data get_default_call_rcu_data_mb -#define get_call_rcu_data get_call_rcu_data_mb -#define get_thread_call_rcu_data get_thread_call_rcu_data_mb -#define set_thread_call_rcu_data set_thread_call_rcu_data_mb -#define create_all_cpu_call_rcu_data create_all_cpu_call_rcu_data_mb -#define free_all_cpu_call_rcu_data free_all_cpu_call_rcu_data_mb -#define call_rcu call_rcu_mb -#define call_rcu_data_free call_rcu_data_free_mb -#define call_rcu_before_fork call_rcu_before_fork_mb -#define call_rcu_after_fork_parent call_rcu_after_fork_parent_mb -#define call_rcu_after_fork_child call_rcu_after_fork_child_mb -#define rcu_barrier rcu_barrier_mb - -#define defer_rcu defer_rcu_mb -#define rcu_defer_register_thread rcu_defer_register_thread_mb -#define rcu_defer_unregister_thread rcu_defer_unregister_thread_mb -#define rcu_defer_barrier rcu_defer_barrier_mb -#define rcu_defer_barrier_thread rcu_defer_barrier_thread_mb -#define rcu_defer_exit rcu_defer_exit_mb - -#define rcu_flavor rcu_flavor_mb - -#define urcu_register_rculfhash_atfork \ - urcu_register_rculfhash_atfork_mb -#define urcu_unregister_rculfhash_atfork \ - urcu_unregister_rculfhash_atfork_mb - +#include #else - #error "Undefined selection" - #endif - -#endif /* _URCU_MAP_H */ diff --git a/include/urcu/pointer.h b/include/urcu/pointer.h new file mode 100644 index 0000000..dc1a0da --- /dev/null +++ b/include/urcu/pointer.h @@ -0,0 +1,129 @@ +#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 __cplusplus +extern "C" { +#endif + +#if defined(_LGPL_SOURCE) || defined(URCU_INLINE_SMALL_FUNCTIONS) + +#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 + +/* + * type *rcu_cmpxchg_pointer(type **ptr, type *new, type *old) + * type *rcu_xchg_pointer(type **ptr, type *new) + * void 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 + +#else /* !(defined(_LGPL_SOURCE) || defined(URCU_INLINE_SMALL_FUNCTIONS)) */ + +extern void *rcu_dereference_sym(void *p); +#define rcu_dereference(p) \ + __extension__ \ + ({ \ + __typeof__(p) _________p1 = URCU_FORCE_CAST(__typeof__(p), \ + rcu_dereference_sym(URCU_FORCE_CAST(void *, p))); \ + (_________p1); \ + }) + +extern void *rcu_cmpxchg_pointer_sym(void **p, void *old, void *_new); +#define rcu_cmpxchg_pointer(p, old, _new) \ + __extension__ \ + ({ \ + __typeof__(*(p)) _________pold = (old); \ + __typeof__(*(p)) _________pnew = (_new); \ + __typeof__(*(p)) _________p1 = URCU_FORCE_CAST(__typeof__(*(p)), \ + rcu_cmpxchg_pointer_sym(URCU_FORCE_CAST(void **, p), \ + _________pold, \ + _________pnew)); \ + (_________p1); \ + }) + +extern void *rcu_xchg_pointer_sym(void **p, void *v); +#define rcu_xchg_pointer(p, v) \ + __extension__ \ + ({ \ + __typeof__(*(p)) _________pv = (v); \ + __typeof__(*(p)) _________p1 = URCU_FORCE_CAST(__typeof__(*(p)), \ + rcu_xchg_pointer_sym(URCU_FORCE_CAST(void **, p), \ + _________pv)); \ + (_________p1); \ + }) + +/* + * Note: rcu_set_pointer_sym returns @v because we don't want to break + * the ABI. At the API level, rcu_set_pointer() now returns void. Use of + * the return value is therefore deprecated, and will cause a build + * error. + */ +extern void *rcu_set_pointer_sym(void **p, void *v); +#define rcu_set_pointer(p, v) \ + do { \ + __typeof__(*(p)) _________pv = (v); \ + (void) rcu_set_pointer_sym(URCU_FORCE_CAST(void **, p), \ + _________pv); \ + } while (0) + +#endif /* !(defined(_LGPL_SOURCE) || defined(URCU_INLINE_SMALL_FUNCTIONS)) */ + +/* + * void 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)) + +#ifdef __cplusplus +} +#endif + +#endif /* _URCU_POINTER_H */ diff --git a/include/urcu/static/urcu-bp.h b/include/urcu/static/urcu-bp.h index 6bcfab4..8614d68 100644 --- a/include/urcu/static/urcu-bp.h +++ b/include/urcu/static/urcu-bp.h @@ -54,41 +54,41 @@ extern "C" { #endif -enum rcu_state { - RCU_READER_ACTIVE_CURRENT, - RCU_READER_ACTIVE_OLD, - RCU_READER_INACTIVE, +enum urcu_bp_state { + URCU_BP_READER_ACTIVE_CURRENT, + URCU_BP_READER_ACTIVE_OLD, + URCU_BP_READER_INACTIVE, }; /* - * The trick here is that RCU_GP_CTR_PHASE must be a multiple of 8 so we can use a + * The trick here is that URCU_BP_GP_CTR_PHASE must be a multiple of 8 so we can use a * full 8-bits, 16-bits or 32-bits bitmask for the lower order bits. */ -#define RCU_GP_COUNT (1UL << 0) +#define URCU_BP_GP_COUNT (1UL << 0) /* Use the amount of bits equal to half of the architecture long size */ -#define RCU_GP_CTR_PHASE (1UL << (sizeof(long) << 2)) -#define RCU_GP_CTR_NEST_MASK (RCU_GP_CTR_PHASE - 1) +#define URCU_BP_GP_CTR_PHASE (1UL << (sizeof(long) << 2)) +#define URCU_BP_GP_CTR_NEST_MASK (URCU_BP_GP_CTR_PHASE - 1) /* - * Used internally by _rcu_read_lock. + * Used internally by _urcu_bp_read_lock. */ -extern void rcu_bp_register(void); +extern void urcu_bp_register(void); -struct rcu_gp { +struct urcu_bp_gp { /* * Global grace period counter. - * Contains the current RCU_GP_CTR_PHASE. - * Also has a RCU_GP_COUNT of 1, to accelerate the reader fast path. + * Contains the current URCU_BP_GP_CTR_PHASE. + * Also has a URCU_BP_GP_COUNT of 1, to accelerate the reader fast path. * Written to only by writer with mutex taken. * Read by both writer and readers. */ unsigned long ctr; } __attribute__((aligned(CAA_CACHE_LINE_SIZE))); -extern struct rcu_gp rcu_gp; +extern struct urcu_bp_gp urcu_bp_gp; -struct rcu_reader { - /* Data used by both reader and synchronize_rcu() */ +struct urcu_bp_reader { + /* Data used by both reader and urcu_bp_synchronize_rcu() */ unsigned long ctr; /* Data used for registry */ struct cds_list_head node __attribute__((aligned(CAA_CACHE_LINE_SIZE))); @@ -101,7 +101,7 @@ struct rcu_reader { * Adds a pointer dereference on the read-side, but won't require to unregister * the reader thread. */ -extern DECLARE_URCU_TLS(struct rcu_reader *, rcu_reader); +extern DECLARE_URCU_TLS(struct urcu_bp_reader *, urcu_bp_reader); #ifdef CONFIG_RCU_FORCE_SYS_MEMBARRIER #define urcu_bp_has_sys_membarrier 1 @@ -117,60 +117,60 @@ static inline void urcu_bp_smp_mb_slave(void) cmm_smp_mb(); } -static inline enum rcu_state rcu_reader_state(unsigned long *ctr) +static inline enum urcu_bp_state urcu_bp_reader_state(unsigned long *ctr) { unsigned long v; if (ctr == NULL) - return RCU_READER_INACTIVE; + return URCU_BP_READER_INACTIVE; /* * Make sure both tests below are done on the same version of *value * to insure consistency. */ v = CMM_LOAD_SHARED(*ctr); - if (!(v & RCU_GP_CTR_NEST_MASK)) - return RCU_READER_INACTIVE; - if (!((v ^ rcu_gp.ctr) & RCU_GP_CTR_PHASE)) - return RCU_READER_ACTIVE_CURRENT; - return RCU_READER_ACTIVE_OLD; + if (!(v & URCU_BP_GP_CTR_NEST_MASK)) + return URCU_BP_READER_INACTIVE; + if (!((v ^ urcu_bp_gp.ctr) & URCU_BP_GP_CTR_PHASE)) + return URCU_BP_READER_ACTIVE_CURRENT; + return URCU_BP_READER_ACTIVE_OLD; } /* - * Helper for _rcu_read_lock(). The format of rcu_gp.ctr (as well as + * Helper for _urcu_bp_read_lock(). The format of urcu_bp_gp.ctr (as well as * the per-thread rcu_reader.ctr) has the upper bits containing a count of - * _rcu_read_lock() nesting, and a lower-order bit that contains either zero - * or RCU_GP_CTR_PHASE. The smp_mb_slave() ensures that the accesses in - * _rcu_read_lock() happen before the subsequent read-side critical section. + * _urcu_bp_read_lock() nesting, and a lower-order bit that contains either zero + * or URCU_BP_GP_CTR_PHASE. The smp_mb_slave() ensures that the accesses in + * _urcu_bp_read_lock() happen before the subsequent read-side critical section. */ -static inline void _rcu_read_lock_update(unsigned long tmp) +static inline void _urcu_bp_read_lock_update(unsigned long tmp) { - if (caa_likely(!(tmp & RCU_GP_CTR_NEST_MASK))) { - _CMM_STORE_SHARED(URCU_TLS(rcu_reader)->ctr, _CMM_LOAD_SHARED(rcu_gp.ctr)); + if (caa_likely(!(tmp & URCU_BP_GP_CTR_NEST_MASK))) { + _CMM_STORE_SHARED(URCU_TLS(urcu_bp_reader)->ctr, _CMM_LOAD_SHARED(urcu_bp_gp.ctr)); urcu_bp_smp_mb_slave(); } else - _CMM_STORE_SHARED(URCU_TLS(rcu_reader)->ctr, tmp + RCU_GP_COUNT); + _CMM_STORE_SHARED(URCU_TLS(urcu_bp_reader)->ctr, tmp + URCU_BP_GP_COUNT); } /* * Enter an RCU read-side critical section. * * The first cmm_barrier() call ensures that the compiler does not reorder - * the body of _rcu_read_lock() with a mutex. + * the body of _urcu_bp_read_lock() with a mutex. * * This function and its helper are both less than 10 lines long. The * intent is that this function meets the 10-line criterion in LGPL, * allowing this function to be invoked directly from non-LGPL code. */ -static inline void _rcu_read_lock(void) +static inline void _urcu_bp_read_lock(void) { unsigned long tmp; - if (caa_unlikely(!URCU_TLS(rcu_reader))) - rcu_bp_register(); /* If not yet registered. */ + if (caa_unlikely(!URCU_TLS(urcu_bp_reader))) + urcu_bp_register(); /* If not yet registered. */ cmm_barrier(); /* Ensure the compiler does not reorder us with mutex */ - tmp = URCU_TLS(rcu_reader)->ctr; - urcu_assert((tmp & RCU_GP_CTR_NEST_MASK) != RCU_GP_CTR_NEST_MASK); - _rcu_read_lock_update(tmp); + tmp = URCU_TLS(urcu_bp_reader)->ctr; + urcu_assert((tmp & URCU_BP_GP_CTR_NEST_MASK) != URCU_BP_GP_CTR_NEST_MASK); + _urcu_bp_read_lock_update(tmp); } /* @@ -178,15 +178,15 @@ static inline void _rcu_read_lock(void) * 10 lines of code, and is intended to be usable by non-LGPL code, as * called out in LGPL. */ -static inline void _rcu_read_unlock(void) +static inline void _urcu_bp_read_unlock(void) { unsigned long tmp; - tmp = URCU_TLS(rcu_reader)->ctr; - urcu_assert(tmp & RCU_GP_CTR_NEST_MASK); + tmp = URCU_TLS(urcu_bp_reader)->ctr; + urcu_assert(tmp & URCU_BP_GP_CTR_NEST_MASK); /* Finish using rcu before decrementing the pointer. */ urcu_bp_smp_mb_slave(); - _CMM_STORE_SHARED(URCU_TLS(rcu_reader)->ctr, tmp - RCU_GP_COUNT); + _CMM_STORE_SHARED(URCU_TLS(urcu_bp_reader)->ctr, tmp - URCU_BP_GP_COUNT); cmm_barrier(); /* Ensure the compiler does not reorder us with mutex */ } @@ -197,11 +197,11 @@ static inline void _rcu_read_unlock(void) * function meets the 10-line criterion for LGPL, allowing this function * to be invoked directly from non-LGPL code. */ -static inline int _rcu_read_ongoing(void) +static inline int _urcu_bp_read_ongoing(void) { - if (caa_unlikely(!URCU_TLS(rcu_reader))) - rcu_bp_register(); /* If not yet registered. */ - return URCU_TLS(rcu_reader)->ctr & RCU_GP_CTR_NEST_MASK; + if (caa_unlikely(!URCU_TLS(urcu_bp_reader))) + urcu_bp_register(); /* If not yet registered. */ + return URCU_TLS(urcu_bp_reader)->ctr & URCU_BP_GP_CTR_NEST_MASK; } #ifdef __cplusplus diff --git a/include/urcu/static/urcu-common.h b/include/urcu/static/urcu-common.h new file mode 100644 index 0000000..28d3160 --- /dev/null +++ b/include/urcu/static/urcu-common.h @@ -0,0 +1,129 @@ +#ifndef _URCU_COMMON_STATIC_H +#define _URCU_COMMON_STATIC_H + +/* + * urcu-common-static.h + * + * Userspace RCU header. + * + * TO BE INCLUDED ONLY IN CODE THAT IS TO BE RECOMPILED ON EACH LIBURCU + * RELEASE. See urcu.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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +enum urcu_state { + URCU_READER_ACTIVE_CURRENT, + URCU_READER_ACTIVE_OLD, + URCU_READER_INACTIVE, +}; + +/* + * The trick here is that URCU_GP_CTR_PHASE must be a multiple of 8 so + * we can use a full 8-bits, 16-bits or 32-bits bitmask for the lower + * order bits. + */ +#define URCU_GP_COUNT (1UL << 0) +/* Use the amount of bits equal to half of the architecture long size */ +#define URCU_GP_CTR_PHASE (1UL << (sizeof(unsigned long) << 2)) +#define URCU_GP_CTR_NEST_MASK (URCU_GP_CTR_PHASE - 1) + +struct urcu_gp { + /* + * Global grace period counter. + * Contains the current URCU_GP_CTR_PHASE. + * Also has a URCU_GP_COUNT of 1, to accelerate the reader fast path. + * Written to only by writer with mutex taken. + * Read by both writer and readers. + */ + unsigned long ctr; + + int32_t futex; +} __attribute__((aligned(CAA_CACHE_LINE_SIZE))); + +struct urcu_reader { + /* Data used by both reader and synchronize_rcu() */ + unsigned long ctr; + char need_mb; + /* Data used for registry */ + struct cds_list_head node __attribute__((aligned(CAA_CACHE_LINE_SIZE))); + pthread_t tid; + /* Reader registered flag, for internal checks. */ + unsigned int registered:1; +}; + +/* + * Wake-up waiting synchronize_rcu(). Called from many concurrent threads. + */ +static inline void urcu_common_wake_up_gp(struct urcu_gp *gp) +{ + if (caa_unlikely(uatomic_read(&gp->futex) == -1)) { + uatomic_set(&gp->futex, 0); + /* + * Ignoring return value until we can make this function + * return something (because urcu_die() is not publicly + * exposed). + */ + (void) futex_async(&gp->futex, FUTEX_WAKE, 1, + NULL, NULL, 0); + } +} + +static inline enum urcu_state urcu_common_reader_state(struct urcu_gp *gp, + unsigned long *ctr) +{ + unsigned long v; + + /* + * Make sure both tests below are done on the same version of *value + * to insure consistency. + */ + v = CMM_LOAD_SHARED(*ctr); + if (!(v & URCU_GP_CTR_NEST_MASK)) + return URCU_READER_INACTIVE; + if (!((v ^ gp->ctr) & URCU_GP_CTR_PHASE)) + return URCU_READER_ACTIVE_CURRENT; + return URCU_READER_ACTIVE_OLD; +} + +#ifdef __cplusplus +} +#endif + +#endif /* _URCU_COMMON_STATIC_H */ diff --git a/include/urcu/static/urcu-mb.h b/include/urcu/static/urcu-mb.h new file mode 100644 index 0000000..0dd7d42 --- /dev/null +++ b/include/urcu/static/urcu-mb.h @@ -0,0 +1,152 @@ +#ifndef _URCU_MB_STATIC_H +#define _URCU_MB_STATIC_H + +/* + * urcu-mb-static.h + * + * Userspace RCU header. + * + * TO BE INCLUDED ONLY IN CODE THAT IS TO BE RECOMPILED ON EACH LIBURCU + * RELEASE. See urcu.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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This code section can only be included in LGPL 2.1 compatible source code. + * See below for the function call wrappers which can be used in code meant to + * be only linked with the Userspace RCU library. This comes with a small + * performance degradation on the read-side due to the added function calls. + * This is required to permit relinking with newer versions of the library. + */ + +extern struct urcu_gp urcu_mb_gp; + +extern DECLARE_URCU_TLS(struct urcu_reader, urcu_mb_reader); + +/* + * Helper for _urcu_mb_read_lock(). The format of urcu_mb_gp.ctr (as well as + * the per-thread rcu_reader.ctr) has the upper bits containing a count of + * _urcu_mb_read_lock() nesting, and a lower-order bit that contains either zero + * or URCU_GP_CTR_PHASE. The cmm_smp_mb() ensures that the accesses in + * _urcu_mb_read_lock() happen before the subsequent read-side critical section. + */ +static inline void _urcu_mb_read_lock_update(unsigned long tmp) +{ + if (caa_likely(!(tmp & URCU_GP_CTR_NEST_MASK))) { + _CMM_STORE_SHARED(URCU_TLS(urcu_mb_reader).ctr, _CMM_LOAD_SHARED(urcu_mb_gp.ctr)); + cmm_smp_mb(); + } else + _CMM_STORE_SHARED(URCU_TLS(urcu_mb_reader).ctr, tmp + URCU_GP_COUNT); +} + +/* + * Enter an RCU read-side critical section. + * + * The first cmm_barrier() call ensures that the compiler does not reorder + * the body of _urcu_mb_read_lock() with a mutex. + * + * This function and its helper are both less than 10 lines long. The + * intent is that this function meets the 10-line criterion in LGPL, + * allowing this function to be invoked directly from non-LGPL code. + */ +static inline void _urcu_mb_read_lock(void) +{ + unsigned long tmp; + + urcu_assert(URCU_TLS(urcu_mb_reader).registered); + cmm_barrier(); + tmp = URCU_TLS(urcu_mb_reader).ctr; + urcu_assert((tmp & URCU_GP_CTR_NEST_MASK) != URCU_GP_CTR_NEST_MASK); + _urcu_mb_read_lock_update(tmp); +} + +/* + * This is a helper function for _urcu_mb_read_unlock(). + * + * The first cmm_smp_mb() call ensures that the critical section is + * seen to precede the store to rcu_reader.ctr. + * The second cmm_smp_mb() call ensures that we write to rcu_reader.ctr + * before reading the update-side futex. + */ +static inline void _urcu_mb_read_unlock_update_and_wakeup(unsigned long tmp) +{ + if (caa_likely((tmp & URCU_GP_CTR_NEST_MASK) == URCU_GP_COUNT)) { + cmm_smp_mb(); + _CMM_STORE_SHARED(URCU_TLS(urcu_mb_reader).ctr, tmp - URCU_GP_COUNT); + cmm_smp_mb(); + urcu_common_wake_up_gp(&urcu_mb_gp); + } else + _CMM_STORE_SHARED(URCU_TLS(urcu_mb_reader).ctr, tmp - URCU_GP_COUNT); +} + +/* + * Exit an RCU read-side crtical section. Both this function and its + * helper are smaller than 10 lines of code, and are intended to be + * usable by non-LGPL code, as called out in LGPL. + */ +static inline void _urcu_mb_read_unlock(void) +{ + unsigned long tmp; + + urcu_assert(URCU_TLS(urcu_mb_reader).registered); + tmp = URCU_TLS(urcu_mb_reader).ctr; + urcu_assert(tmp & URCU_GP_CTR_NEST_MASK); + _urcu_mb_read_unlock_update_and_wakeup(tmp); + cmm_barrier(); /* Ensure the compiler does not reorder us with mutex */ +} + +/* + * Returns whether within a RCU read-side critical section. + * + * This function is less than 10 lines long. The intent is that this + * function meets the 10-line criterion for LGPL, allowing this function + * to be invoked directly from non-LGPL code. + */ +static inline int _urcu_mb_read_ongoing(void) +{ + return URCU_TLS(urcu_mb_reader).ctr & URCU_GP_CTR_NEST_MASK; +} + +#ifdef __cplusplus +} +#endif + +#endif /* _URCU_MB_STATIC_H */ diff --git a/include/urcu/static/urcu-memb.h b/include/urcu/static/urcu-memb.h new file mode 100644 index 0000000..a64efee --- /dev/null +++ b/include/urcu/static/urcu-memb.h @@ -0,0 +1,175 @@ +#ifndef _URCU_MEMB_STATIC_H +#define _URCU_MEMB_STATIC_H + +/* + * urcu-memb-static.h + * + * Userspace RCU header. + * + * TO BE INCLUDED ONLY IN CODE THAT IS TO BE RECOMPILED ON EACH LIBURCU + * RELEASE. See urcu.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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This code section can only be included in LGPL 2.1 compatible source code. + * See below for the function call wrappers which can be used in code meant to + * be only linked with the Userspace RCU library. This comes with a small + * performance degradation on the read-side due to the added function calls. + * This is required to permit relinking with newer versions of the library. + */ + +/* + * Slave barriers are only guaranteed to be ordered wrt master barriers. + * + * The pair ordering is detailed as (O: ordered, X: not ordered) : + * slave master + * slave X O + * master O O + */ + +#ifdef CONFIG_RCU_FORCE_SYS_MEMBARRIER +#define urcu_memb_has_sys_membarrier 1 +#else +extern int urcu_memb_has_sys_membarrier; +#endif + +static inline void urcu_memb_smp_mb_slave(void) +{ + if (caa_likely(urcu_memb_has_sys_membarrier)) + cmm_barrier(); + else + cmm_smp_mb(); +} + +extern struct urcu_gp urcu_memb_gp; + +extern DECLARE_URCU_TLS(struct urcu_reader, urcu_memb_reader); + +/* + * Helper for _rcu_read_lock(). The format of urcu_memb_gp.ctr (as well as + * the per-thread rcu_reader.ctr) has the upper bits containing a count of + * _rcu_read_lock() nesting, and a lower-order bit that contains either zero + * or URCU_GP_CTR_PHASE. The smp_mb_slave() ensures that the accesses in + * _rcu_read_lock() happen before the subsequent read-side critical section. + */ +static inline void _urcu_memb_read_lock_update(unsigned long tmp) +{ + if (caa_likely(!(tmp & URCU_GP_CTR_NEST_MASK))) { + _CMM_STORE_SHARED(URCU_TLS(urcu_memb_reader).ctr, _CMM_LOAD_SHARED(urcu_memb_gp.ctr)); + urcu_memb_smp_mb_slave(); + } else + _CMM_STORE_SHARED(URCU_TLS(urcu_memb_reader).ctr, tmp + URCU_GP_COUNT); +} + +/* + * Enter an RCU read-side critical section. + * + * The first cmm_barrier() call ensures that the compiler does not reorder + * the body of _rcu_read_lock() with a mutex. + * + * This function and its helper are both less than 10 lines long. The + * intent is that this function meets the 10-line criterion in LGPL, + * allowing this function to be invoked directly from non-LGPL code. + */ +static inline void _urcu_memb_read_lock(void) +{ + unsigned long tmp; + + urcu_assert(URCU_TLS(urcu_memb_reader).registered); + cmm_barrier(); + tmp = URCU_TLS(urcu_memb_reader).ctr; + urcu_assert((tmp & URCU_GP_CTR_NEST_MASK) != URCU_GP_CTR_NEST_MASK); + _urcu_memb_read_lock_update(tmp); +} + +/* + * This is a helper function for _rcu_read_unlock(). + * + * The first smp_mb_slave() call ensures that the critical section is + * seen to precede the store to rcu_reader.ctr. + * The second smp_mb_slave() call ensures that we write to rcu_reader.ctr + * before reading the update-side futex. + */ +static inline void _urcu_memb_read_unlock_update_and_wakeup(unsigned long tmp) +{ + if (caa_likely((tmp & URCU_GP_CTR_NEST_MASK) == URCU_GP_COUNT)) { + urcu_memb_smp_mb_slave(); + _CMM_STORE_SHARED(URCU_TLS(urcu_memb_reader).ctr, tmp - URCU_GP_COUNT); + urcu_memb_smp_mb_slave(); + urcu_common_wake_up_gp(&urcu_memb_gp); + } else + _CMM_STORE_SHARED(URCU_TLS(urcu_memb_reader).ctr, tmp - URCU_GP_COUNT); +} + +/* + * Exit an RCU read-side crtical section. Both this function and its + * helper are smaller than 10 lines of code, and are intended to be + * usable by non-LGPL code, as called out in LGPL. + */ +static inline void _urcu_memb_read_unlock(void) +{ + unsigned long tmp; + + urcu_assert(URCU_TLS(urcu_memb_reader).registered); + tmp = URCU_TLS(urcu_memb_reader).ctr; + urcu_assert(tmp & URCU_GP_CTR_NEST_MASK); + _urcu_memb_read_unlock_update_and_wakeup(tmp); + cmm_barrier(); /* Ensure the compiler does not reorder us with mutex */ +} + +/* + * Returns whether within a RCU read-side critical section. + * + * This function is less than 10 lines long. The intent is that this + * function meets the 10-line criterion for LGPL, allowing this function + * to be invoked directly from non-LGPL code. + */ +static inline int _urcu_memb_read_ongoing(void) +{ + return URCU_TLS(urcu_memb_reader).ctr & URCU_GP_CTR_NEST_MASK; +} + +#ifdef __cplusplus +} +#endif + +#endif /* _URCU_MEMB_STATIC_H */ diff --git a/include/urcu/static/urcu-qsbr.h b/include/urcu/static/urcu-qsbr.h index 8d5fd03..a6063e2 100644 --- a/include/urcu/static/urcu-qsbr.h +++ b/include/urcu/static/urcu-qsbr.h @@ -43,6 +43,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -56,29 +57,12 @@ extern "C" { * This is required to permit relinking with newer versions of the library. */ -enum rcu_state { - RCU_READER_ACTIVE_CURRENT, - RCU_READER_ACTIVE_OLD, - RCU_READER_INACTIVE, -}; - -#define RCU_GP_ONLINE (1UL << 0) -#define RCU_GP_CTR (1UL << 1) - -struct rcu_gp { - /* - * Global quiescent period counter with low-order bits unused. - * Using a int rather than a char to eliminate false register - * dependencies causing stalls on some architectures. - */ - unsigned long ctr; - - int32_t futex; -} __attribute__((aligned(CAA_CACHE_LINE_SIZE))); +#define URCU_QSBR_GP_ONLINE (1UL << 0) +#define URCU_QSBR_GP_CTR (1UL << 1) -extern struct rcu_gp rcu_gp; +extern struct urcu_gp urcu_qsbr_gp; -struct rcu_reader { +struct urcu_qsbr_reader { /* Data used by both reader and synchronize_rcu() */ unsigned long ctr; /* Data used for registry */ @@ -89,39 +73,39 @@ struct rcu_reader { unsigned int registered:1; }; -extern DECLARE_URCU_TLS(struct rcu_reader, rcu_reader); +extern DECLARE_URCU_TLS(struct urcu_qsbr_reader, urcu_qsbr_reader); /* * Wake-up waiting synchronize_rcu(). Called from many concurrent threads. */ -static inline void wake_up_gp(void) +static inline void urcu_qsbr_wake_up_gp(void) { - if (caa_unlikely(_CMM_LOAD_SHARED(URCU_TLS(rcu_reader).waiting))) { - _CMM_STORE_SHARED(URCU_TLS(rcu_reader).waiting, 0); + if (caa_unlikely(_CMM_LOAD_SHARED(URCU_TLS(urcu_qsbr_reader).waiting))) { + _CMM_STORE_SHARED(URCU_TLS(urcu_qsbr_reader).waiting, 0); cmm_smp_mb(); - if (uatomic_read(&rcu_gp.futex) != -1) + if (uatomic_read(&urcu_qsbr_gp.futex) != -1) return; - uatomic_set(&rcu_gp.futex, 0); + uatomic_set(&urcu_qsbr_gp.futex, 0); /* * Ignoring return value until we can make this function * return something (because urcu_die() is not publicly * exposed). */ - (void) futex_noasync(&rcu_gp.futex, FUTEX_WAKE, 1, + (void) futex_noasync(&urcu_qsbr_gp.futex, FUTEX_WAKE, 1, NULL, NULL, 0); } } -static inline enum rcu_state rcu_reader_state(unsigned long *ctr) +static inline enum urcu_state urcu_qsbr_reader_state(unsigned long *ctr) { unsigned long v; v = CMM_LOAD_SHARED(*ctr); if (!v) - return RCU_READER_INACTIVE; - if (v == rcu_gp.ctr) - return RCU_READER_ACTIVE_CURRENT; - return RCU_READER_ACTIVE_OLD; + return URCU_READER_INACTIVE; + if (v == urcu_qsbr_gp.ctr) + return URCU_READER_ACTIVE_CURRENT; + return URCU_READER_ACTIVE_OLD; } /* @@ -131,9 +115,9 @@ static inline enum rcu_state rcu_reader_state(unsigned long *ctr) * function meets the 10-line criterion for LGPL, allowing this function * to be invoked directly from non-LGPL code. */ -static inline void _rcu_read_lock(void) +static inline void _urcu_qsbr_read_lock(void) { - urcu_assert(URCU_TLS(rcu_reader).ctr); + urcu_assert(URCU_TLS(urcu_qsbr_reader).ctr); } /* @@ -143,9 +127,9 @@ static inline void _rcu_read_lock(void) * function meets the 10-line criterion for LGPL, allowing this function * to be invoked directly from non-LGPL code. */ -static inline void _rcu_read_unlock(void) +static inline void _urcu_qsbr_read_unlock(void) { - urcu_assert(URCU_TLS(rcu_reader).ctr); + urcu_assert(URCU_TLS(urcu_qsbr_reader).ctr); } /* @@ -155,26 +139,26 @@ static inline void _rcu_read_unlock(void) * function meets the 10-line criterion for LGPL, allowing this function * to be invoked directly from non-LGPL code. */ -static inline int _rcu_read_ongoing(void) +static inline int _urcu_qsbr_read_ongoing(void) { - return URCU_TLS(rcu_reader).ctr; + return URCU_TLS(urcu_qsbr_reader).ctr; } /* * This is a helper function for _rcu_quiescent_state(). * The first cmm_smp_mb() ensures memory accesses in the prior read-side * critical sections are not reordered with store to - * URCU_TLS(rcu_reader).ctr, and ensures that mutexes held within an + * URCU_TLS(urcu_qsbr_reader).ctr, and ensures that mutexes held within an * offline section that would happen to end with this - * rcu_quiescent_state() call are not reordered with - * store to URCU_TLS(rcu_reader).ctr. + * urcu_qsbr_quiescent_state() call are not reordered with + * store to URCU_TLS(urcu_qsbr_reader).ctr. */ -static inline void _rcu_quiescent_state_update_and_wakeup(unsigned long gp_ctr) +static inline void _urcu_qsbr_quiescent_state_update_and_wakeup(unsigned long gp_ctr) { cmm_smp_mb(); - _CMM_STORE_SHARED(URCU_TLS(rcu_reader).ctr, gp_ctr); - cmm_smp_mb(); /* write URCU_TLS(rcu_reader).ctr before read futex */ - wake_up_gp(); + _CMM_STORE_SHARED(URCU_TLS(urcu_qsbr_reader).ctr, gp_ctr); + cmm_smp_mb(); /* write URCU_TLS(urcu_qsbr_reader).ctr before read futex */ + urcu_qsbr_wake_up_gp(); cmm_smp_mb(); } @@ -186,18 +170,18 @@ static inline void _rcu_quiescent_state_update_and_wakeup(unsigned long gp_ctr) * to be invoked directly from non-LGPL code. * * We skip the memory barriers and gp store if our local ctr already - * matches the global rcu_gp.ctr value: this is OK because a prior + * matches the global urcu_qsbr_gp.ctr value: this is OK because a prior * _rcu_quiescent_state() or _rcu_thread_online() already updated it * within our thread, so we have no quiescent state to report. */ -static inline void _rcu_quiescent_state(void) +static inline void _urcu_qsbr_quiescent_state(void) { unsigned long gp_ctr; - urcu_assert(URCU_TLS(rcu_reader).registered); - if ((gp_ctr = CMM_LOAD_SHARED(rcu_gp.ctr)) == URCU_TLS(rcu_reader).ctr) + urcu_assert(URCU_TLS(urcu_qsbr_reader).registered); + if ((gp_ctr = CMM_LOAD_SHARED(urcu_qsbr_gp.ctr)) == URCU_TLS(urcu_qsbr_reader).ctr) return; - _rcu_quiescent_state_update_and_wakeup(gp_ctr); + _urcu_qsbr_quiescent_state_update_and_wakeup(gp_ctr); } /* @@ -208,13 +192,13 @@ static inline void _rcu_quiescent_state(void) * function meets the 10-line criterion for LGPL, allowing this function * to be invoked directly from non-LGPL code. */ -static inline void _rcu_thread_offline(void) +static inline void _urcu_qsbr_thread_offline(void) { - urcu_assert(URCU_TLS(rcu_reader).registered); + urcu_assert(URCU_TLS(urcu_qsbr_reader).registered); cmm_smp_mb(); - CMM_STORE_SHARED(URCU_TLS(rcu_reader).ctr, 0); - cmm_smp_mb(); /* write URCU_TLS(rcu_reader).ctr before read futex */ - wake_up_gp(); + CMM_STORE_SHARED(URCU_TLS(urcu_qsbr_reader).ctr, 0); + cmm_smp_mb(); /* write URCU_TLS(urcu_qsbr_reader).ctr before read futex */ + urcu_qsbr_wake_up_gp(); cmm_barrier(); /* Ensure the compiler does not reorder us with mutex */ } @@ -226,11 +210,11 @@ static inline void _rcu_thread_offline(void) * function meets the 10-line criterion for LGPL, allowing this function * to be invoked directly from non-LGPL code. */ -static inline void _rcu_thread_online(void) +static inline void _urcu_qsbr_thread_online(void) { - urcu_assert(URCU_TLS(rcu_reader).registered); + urcu_assert(URCU_TLS(urcu_qsbr_reader).registered); cmm_barrier(); /* Ensure the compiler does not reorder us with mutex */ - _CMM_STORE_SHARED(URCU_TLS(rcu_reader).ctr, CMM_LOAD_SHARED(rcu_gp.ctr)); + _CMM_STORE_SHARED(URCU_TLS(urcu_qsbr_reader).ctr, CMM_LOAD_SHARED(urcu_qsbr_gp.ctr)); cmm_smp_mb(); } diff --git a/include/urcu/static/urcu-signal.h b/include/urcu/static/urcu-signal.h new file mode 100644 index 0000000..385e6f5 --- /dev/null +++ b/include/urcu/static/urcu-signal.h @@ -0,0 +1,165 @@ +#ifndef _URCU_SIGNAL_STATIC_H +#define _URCU_SIGNAL_STATIC_H + +/* + * urcu-signal-static.h + * + * Userspace RCU header. + * + * TO BE INCLUDED ONLY IN CODE THAT IS TO BE RECOMPILED ON EACH LIBURCU + * RELEASE. See urcu.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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This code section can only be included in LGPL 2.1 compatible source code. + * See below for the function call wrappers which can be used in code meant to + * be only linked with the Userspace RCU library. This comes with a small + * performance degradation on the read-side due to the added function calls. + * This is required to permit relinking with newer versions of the library. + */ + +/* + * The signal number used by the RCU library can be overridden with + * -DSIGRCU= when compiling the library. + * Provide backward compatibility for liburcu 0.3.x SIGURCU. + */ +#ifdef SIGURCU +#define SIGRCU SIGURCU +#endif + +#ifndef SIGRCU +#define SIGRCU SIGUSR1 +#endif + +extern struct urcu_gp urcu_signal_gp; + +extern DECLARE_URCU_TLS(struct urcu_reader, urcu_signal_reader); + +/* + * Helper for _rcu_read_lock(). The format of urcu_signal_gp.ctr (as well as + * the per-thread rcu_reader.ctr) has the upper bits containing a count of + * _rcu_read_lock() nesting, and a lower-order bit that contains either zero + * or URCU_GP_CTR_PHASE. The cmm_barrier() ensures that the accesses in + * _rcu_read_lock() happen before the subsequent read-side critical section. + */ +static inline void _urcu_signal_read_lock_update(unsigned long tmp) +{ + if (caa_likely(!(tmp & URCU_GP_CTR_NEST_MASK))) { + _CMM_STORE_SHARED(URCU_TLS(urcu_signal_reader).ctr, _CMM_LOAD_SHARED(urcu_signal_gp.ctr)); + cmm_barrier(); + } else + _CMM_STORE_SHARED(URCU_TLS(urcu_signal_reader).ctr, tmp + URCU_GP_COUNT); +} + +/* + * Enter an RCU read-side critical section. + * + * The first cmm_barrier() call ensures that the compiler does not reorder + * the body of _rcu_read_lock() with a mutex. + * + * This function and its helper are both less than 10 lines long. The + * intent is that this function meets the 10-line criterion in LGPL, + * allowing this function to be invoked directly from non-LGPL code. + */ +static inline void _urcu_signal_read_lock(void) +{ + unsigned long tmp; + + urcu_assert(URCU_TLS(urcu_signal_reader).registered); + cmm_barrier(); + tmp = URCU_TLS(urcu_signal_reader).ctr; + urcu_assert((tmp & URCU_GP_CTR_NEST_MASK) != URCU_GP_CTR_NEST_MASK); + _urcu_signal_read_lock_update(tmp); +} + +/* + * This is a helper function for _rcu_read_unlock(). + * + * The first cmm_barrier() call ensures that the critical section is + * seen to precede the store to rcu_reader.ctr. + * The second cmm_barrier() call ensures that we write to rcu_reader.ctr + * before reading the update-side futex. + */ +static inline void _urcu_signal_read_unlock_update_and_wakeup(unsigned long tmp) +{ + if (caa_likely((tmp & URCU_GP_CTR_NEST_MASK) == URCU_GP_COUNT)) { + cmm_barrier(); + _CMM_STORE_SHARED(URCU_TLS(urcu_signal_reader).ctr, tmp - URCU_GP_COUNT); + cmm_barrier(); + urcu_common_wake_up_gp(&urcu_signal_gp); + } else + _CMM_STORE_SHARED(URCU_TLS(urcu_signal_reader).ctr, tmp - URCU_GP_COUNT); +} + +/* + * Exit an RCU read-side crtical section. Both this function and its + * helper are smaller than 10 lines of code, and are intended to be + * usable by non-LGPL code, as called out in LGPL. + */ +static inline void _urcu_signal_read_unlock(void) +{ + unsigned long tmp; + + urcu_assert(URCU_TLS(urcu_signal_reader).registered); + tmp = URCU_TLS(urcu_signal_reader).ctr; + urcu_assert(tmp & URCU_GP_CTR_NEST_MASK); + _urcu_signal_read_unlock_update_and_wakeup(tmp); + cmm_barrier(); /* Ensure the compiler does not reorder us with mutex */ +} + +/* + * Returns whether within a RCU read-side critical section. + * + * This function is less than 10 lines long. The intent is that this + * function meets the 10-line criterion for LGPL, allowing this function + * to be invoked directly from non-LGPL code. + */ +static inline int _urcu_signal_read_ongoing(void) +{ + return URCU_TLS(urcu_signal_reader).ctr & URCU_GP_CTR_NEST_MASK; +} + +#ifdef __cplusplus +} +#endif + +#endif /* _URCU_SIGNAL_STATIC_H */ diff --git a/include/urcu/static/urcu.h b/include/urcu/static/urcu.h index 20fc864..b83e72b 100644 --- a/include/urcu/static/urcu.h +++ b/include/urcu/static/urcu.h @@ -29,252 +29,21 @@ * IBM's contributions to this file may be relicensed under LGPLv2 or later. */ -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - /* Default is RCU_MEMBARRIER */ #if !defined(RCU_MEMBARRIER) && !defined(RCU_MB) && !defined(RCU_SIGNAL) #define RCU_MEMBARRIER #endif -/* - * This code section can only be included in LGPL 2.1 compatible source code. - * See below for the function call wrappers which can be used in code meant to - * be only linked with the Userspace RCU library. This comes with a small - * performance degradation on the read-side due to the added function calls. - * This is required to permit relinking with newer versions of the library. - */ - -/* - * The signal number used by the RCU library can be overridden with - * -DSIGRCU= when compiling the library. - * Provide backward compatibility for liburcu 0.3.x SIGURCU. - */ -#ifdef SIGURCU -#define SIGRCU SIGURCU -#endif - -#ifndef SIGRCU -#define SIGRCU SIGUSR1 -#endif - -enum rcu_state { - RCU_READER_ACTIVE_CURRENT, - RCU_READER_ACTIVE_OLD, - RCU_READER_INACTIVE, -}; - -/* - * Slave barriers are only guaranteed to be ordered wrt master barriers. - * - * The pair ordering is detailed as (O: ordered, X: not ordered) : - * slave master - * slave X O - * master O O - */ - #ifdef RCU_MEMBARRIER -#ifdef CONFIG_RCU_FORCE_SYS_MEMBARRIER -#define rcu_has_sys_membarrier_memb 1 -#else -extern int rcu_has_sys_membarrier_memb; -#endif - -static inline void smp_mb_slave(void) -{ - if (caa_likely(rcu_has_sys_membarrier_memb)) - cmm_barrier(); - else - cmm_smp_mb(); -} +#include #endif #ifdef RCU_MB -static inline void smp_mb_slave(void) -{ - cmm_smp_mb(); -} +#include #endif #ifdef RCU_SIGNAL -static inline void smp_mb_slave(void) -{ - cmm_barrier(); -} -#endif - -/* - * The trick here is that RCU_GP_CTR_PHASE must be a multiple of 8 so we can use - * a full 8-bits, 16-bits or 32-bits bitmask for the lower order bits. - */ -#define RCU_GP_COUNT (1UL << 0) -/* Use the amount of bits equal to half of the architecture long size */ -#define RCU_GP_CTR_PHASE (1UL << (sizeof(unsigned long) << 2)) -#define RCU_GP_CTR_NEST_MASK (RCU_GP_CTR_PHASE - 1) - -struct rcu_gp { - /* - * Global grace period counter. - * Contains the current RCU_GP_CTR_PHASE. - * Also has a RCU_GP_COUNT of 1, to accelerate the reader fast path. - * Written to only by writer with mutex taken. - * Read by both writer and readers. - */ - unsigned long ctr; - - int32_t futex; -} __attribute__((aligned(CAA_CACHE_LINE_SIZE))); - -extern struct rcu_gp rcu_gp; - -struct rcu_reader { - /* Data used by both reader and synchronize_rcu() */ - unsigned long ctr; - char need_mb; - /* Data used for registry */ - struct cds_list_head node __attribute__((aligned(CAA_CACHE_LINE_SIZE))); - pthread_t tid; - /* Reader registered flag, for internal checks. */ - unsigned int registered:1; -}; - -extern DECLARE_URCU_TLS(struct rcu_reader, rcu_reader); - -/* - * Wake-up waiting synchronize_rcu(). Called from many concurrent threads. - */ -static inline void wake_up_gp(void) -{ - if (caa_unlikely(uatomic_read(&rcu_gp.futex) == -1)) { - uatomic_set(&rcu_gp.futex, 0); - /* - * Ignoring return value until we can make this function - * return something (because urcu_die() is not publicly - * exposed). - */ - (void) futex_async(&rcu_gp.futex, FUTEX_WAKE, 1, - NULL, NULL, 0); - } -} - -static inline enum rcu_state rcu_reader_state(unsigned long *ctr) -{ - unsigned long v; - - /* - * Make sure both tests below are done on the same version of *value - * to insure consistency. - */ - v = CMM_LOAD_SHARED(*ctr); - if (!(v & RCU_GP_CTR_NEST_MASK)) - return RCU_READER_INACTIVE; - if (!((v ^ rcu_gp.ctr) & RCU_GP_CTR_PHASE)) - return RCU_READER_ACTIVE_CURRENT; - return RCU_READER_ACTIVE_OLD; -} - -/* - * Helper for _rcu_read_lock(). The format of rcu_gp.ctr (as well as - * the per-thread rcu_reader.ctr) has the upper bits containing a count of - * _rcu_read_lock() nesting, and a lower-order bit that contains either zero - * or RCU_GP_CTR_PHASE. The smp_mb_slave() ensures that the accesses in - * _rcu_read_lock() happen before the subsequent read-side critical section. - */ -static inline void _rcu_read_lock_update(unsigned long tmp) -{ - if (caa_likely(!(tmp & RCU_GP_CTR_NEST_MASK))) { - _CMM_STORE_SHARED(URCU_TLS(rcu_reader).ctr, _CMM_LOAD_SHARED(rcu_gp.ctr)); - smp_mb_slave(); - } else - _CMM_STORE_SHARED(URCU_TLS(rcu_reader).ctr, tmp + RCU_GP_COUNT); -} - -/* - * Enter an RCU read-side critical section. - * - * The first cmm_barrier() call ensures that the compiler does not reorder - * the body of _rcu_read_lock() with a mutex. - * - * This function and its helper are both less than 10 lines long. The - * intent is that this function meets the 10-line criterion in LGPL, - * allowing this function to be invoked directly from non-LGPL code. - */ -static inline void _rcu_read_lock(void) -{ - unsigned long tmp; - - urcu_assert(URCU_TLS(rcu_reader).registered); - cmm_barrier(); - tmp = URCU_TLS(rcu_reader).ctr; - urcu_assert((tmp & RCU_GP_CTR_NEST_MASK) != RCU_GP_CTR_NEST_MASK); - _rcu_read_lock_update(tmp); -} - -/* - * This is a helper function for _rcu_read_unlock(). - * - * The first smp_mb_slave() call ensures that the critical section is - * seen to precede the store to rcu_reader.ctr. - * The second smp_mb_slave() call ensures that we write to rcu_reader.ctr - * before reading the update-side futex. - */ -static inline void _rcu_read_unlock_update_and_wakeup(unsigned long tmp) -{ - if (caa_likely((tmp & RCU_GP_CTR_NEST_MASK) == RCU_GP_COUNT)) { - smp_mb_slave(); - _CMM_STORE_SHARED(URCU_TLS(rcu_reader).ctr, tmp - RCU_GP_COUNT); - smp_mb_slave(); - wake_up_gp(); - } else - _CMM_STORE_SHARED(URCU_TLS(rcu_reader).ctr, tmp - RCU_GP_COUNT); -} - -/* - * Exit an RCU read-side crtical section. Both this function and its - * helper are smaller than 10 lines of code, and are intended to be - * usable by non-LGPL code, as called out in LGPL. - */ -static inline void _rcu_read_unlock(void) -{ - unsigned long tmp; - - urcu_assert(URCU_TLS(rcu_reader).registered); - tmp = URCU_TLS(rcu_reader).ctr; - urcu_assert(tmp & RCU_GP_CTR_NEST_MASK); - _rcu_read_unlock_update_and_wakeup(tmp); - cmm_barrier(); /* Ensure the compiler does not reorder us with mutex */ -} - -/* - * Returns whether within a RCU read-side critical section. - * - * This function is less than 10 lines long. The intent is that this - * function meets the 10-line criterion for LGPL, allowing this function - * to be invoked directly from non-LGPL code. - */ -static inline int _rcu_read_ongoing(void) -{ - return URCU_TLS(rcu_reader).ctr & RCU_GP_CTR_NEST_MASK; -} - -#ifdef __cplusplus -} +#include #endif #endif /* _URCU_STATIC_H */ diff --git a/include/urcu/urcu-bp.h b/include/urcu/urcu-bp.h new file mode 100644 index 0000000..7b00aaa --- /dev/null +++ b/include/urcu/urcu-bp.h @@ -0,0 +1,195 @@ +#ifndef _URCU_BP_H +#define _URCU_BP_H + +/* + * urcu-bp.h + * + * Userspace RCU header, "bulletproof" version. + * + * Slower RCU read-side adapted for tracing library. Does not require thread + * registration nor unregistration. Also signal-safe. + * + * Copyright (c) 2009 Mathieu Desnoyers + * Copyright (c) 2009 Paul E. McKenney, IBM Corporation. + * + * LGPL-compatible code should include this header with : + * + * #define _LGPL_SOURCE + * #include + * + * 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 + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* + * Important ! + * + * Each thread containing read-side critical sections must be registered + * with rcu_register_thread() before calling rcu_read_lock(). + * rcu_unregister_thread() should be called before the thread exits. + */ + +/* + * See urcu-pointer.h and urcu/static/urcu-pointer.h for pointer + * publication headers. + */ +#include + +#ifdef _LGPL_SOURCE + +#include + +/* + * Mappings for static use of the userspace RCU library. + * Should only be used in LGPL-compatible code. + */ + +/* + * rcu_read_lock() + * rcu_read_unlock() + * + * Mark the beginning and end of a read-side critical section. + */ +#define urcu_bp_read_lock _urcu_bp_read_lock +#define urcu_bp_read_unlock _urcu_bp_read_unlock +#define urcu_bp_read_ongoing _urcu_bp_read_ongoing + +#define urcu_bp_dereference rcu_dereference +#define urcu_bp_cmpxchg_pointer rcu_cmpxchg_pointer +#define urcu_bp_xchg_pointer rcu_xchg_pointer +#define urcu_bp_set_pointer rcu_set_pointer + +#else /* !_LGPL_SOURCE */ + +/* + * library wrappers to be used by non-LGPL compatible source code. + * See LGPL-only urcu/static/urcu-pointer.h for documentation. + */ + +extern void urcu_bp_read_lock(void); +extern void urcu_bp_read_unlock(void); +extern int urcu_bp_read_ongoing(void); + +extern void *urcu_bp_dereference_sym(void *p); +#define urcu_bp_dereference(p) \ + __extension__ \ + ({ \ + __typeof__(p) _________p1 = URCU_FORCE_CAST(__typeof__(p), \ + urcu_bp_dereference_sym(URCU_FORCE_CAST(void *, p))); \ + (_________p1); \ + }) + +extern void *urcu_bp_cmpxchg_pointer_sym(void **p, void *old, void *_new); +#define urcu_bp_cmpxchg_pointer(p, old, _new) \ + __extension__ \ + ({ \ + __typeof__(*(p)) _________pold = (old); \ + __typeof__(*(p)) _________pnew = (_new); \ + __typeof__(*(p)) _________p1 = URCU_FORCE_CAST(__typeof__(*(p)), \ + urcu_bp_cmpxchg_pointer_sym(URCU_FORCE_CAST(void **, p), \ + _________pold, \ + _________pnew)); \ + (_________p1); \ + }) + +extern void *urcu_bp_xchg_pointer_sym(void **p, void *v); +#define urcu_bp_xchg_pointer(p, v) \ + __extension__ \ + ({ \ + __typeof__(*(p)) _________pv = (v); \ + __typeof__(*(p)) _________p1 = URCU_FORCE_CAST(__typeof__(*(p)),\ + urcu_bp_xchg_pointer_sym(URCU_FORCE_CAST(void **, p), \ + _________pv)); \ + (_________p1); \ + }) + +extern void *urcu_bp_set_pointer_sym(void **p, void *v); +#define urcu_bp_set_pointer(p, v) \ + __extension__ \ + ({ \ + __typeof__(*(p)) _________pv = (v); \ + __typeof__(*(p)) _________p1 = URCU_FORCE_CAST(__typeof__(*(p)), \ + urcu_bp_set_pointer_sym(URCU_FORCE_CAST(void **, p), \ + _________pv)); \ + (_________p1); \ + }) + +#endif /* !_LGPL_SOURCE */ + +extern void urcu_bp_synchronize_rcu(void); + +/* + * urcu_bp_before_fork, urcu_bp_after_fork_parent and urcu_bp_after_fork_child + * should be called around fork() system calls when the child process is not + * expected to immediately perform an exec(). For pthread users, see + * pthread_atfork(3). + */ +extern void urcu_bp_before_fork(void); +extern void urcu_bp_after_fork_parent(void); +extern void urcu_bp_after_fork_child(void); + +/* + * In the bulletproof version, the following functions are no-ops. + */ +static inline void urcu_bp_register_thread(void) +{ +} + +static inline void urcu_bp_unregister_thread(void) +{ +} + +static inline void urcu_bp_init(void) +{ +} + +/* + * Q.S. reporting are no-ops for these URCU flavors. + */ +static inline void urcu_bp_quiescent_state(void) +{ +} + +static inline void urcu_bp_thread_offline(void) +{ +} + +static inline void urcu_bp_thread_online(void) +{ +} + +#ifdef __cplusplus +} +#endif + +#include +#include +#include + +#ifndef URCU_API_MAP +#include +#endif + +#endif /* _URCU_BP_H */ diff --git a/include/urcu/urcu-mb.h b/include/urcu/urcu-mb.h new file mode 100644 index 0000000..2000375 --- /dev/null +++ b/include/urcu/urcu-mb.h @@ -0,0 +1,131 @@ +#ifndef _URCU_MB_H +#define _URCU_MB_H + +/* + * urcu-mb.h + * + * Userspace RCU header + * + * Copyright (c) 2009 Mathieu Desnoyers + * Copyright (c) 2009 Paul E. McKenney, IBM Corporation. + * + * LGPL-compatible code should include this header with : + * + * #define _LGPL_SOURCE + * #include + * + * 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 + +/* + * See urcu-pointer.h and urcu/static/urcu-pointer.h for pointer + * publication headers. + */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* + * Important ! + * + * Each thread containing read-side critical sections must be registered + * with rcu_register_thread_mb() before calling rcu_read_lock_mb(). + * rcu_unregister_thread_mb() should be called before the thread exits. + */ + +#ifdef _LGPL_SOURCE + +#include + +/* + * Mappings for static use of the userspace RCU library. + * Should only be used in LGPL-compatible code. + */ + +/* + * 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 urcu_mb_read_lock _urcu_mb_read_lock +#define urcu_mb_read_unlock _urcu_mb_read_unlock +#define urcu_mb_read_ongoing _urcu_mb_read_ongoing + +#else /* !_LGPL_SOURCE */ + +/* + * library wrappers to be used by non-LGPL compatible source code. + * See LGPL-only urcu/static/urcu-pointer.h for documentation. + */ + +extern void urcu_mb_read_lock(void); +extern void urcu_mb_read_unlock(void); +extern int urcu_mb_read_ongoing(void); + +#endif /* !_LGPL_SOURCE */ + +extern void urcu_mb_synchronize_rcu(void); + +/* + * Reader thread registration. + */ +extern void urcu_mb_register_thread(void); +extern void urcu_mb_unregister_thread(void); + +/* + * Explicit rcu initialization, for "early" use within library constructors. + */ +extern void urcu_mb_init(void); + +/* + * Q.S. reporting are no-ops for these URCU flavors. + */ +static inline void urcu_mb_quiescent_state(void) +{ +} + +static inline void urcu_mb_thread_offline(void) +{ +} + +static inline void urcu_mb_thread_online(void) +{ +} + +#ifdef __cplusplus +} +#endif + +#include +#include +#include + +#ifndef URCU_API_MAP +#include +#endif + +#endif /* _URCU_MB_H */ diff --git a/include/urcu/urcu-memb.h b/include/urcu/urcu-memb.h new file mode 100644 index 0000000..c0fffe8 --- /dev/null +++ b/include/urcu/urcu-memb.h @@ -0,0 +1,131 @@ +#ifndef _URCU_MEMB_H +#define _URCU_MEMB_H + +/* + * urcu-memb.h + * + * Userspace RCU header + * + * Copyright (c) 2009 Mathieu Desnoyers + * Copyright (c) 2009 Paul E. McKenney, IBM Corporation. + * + * LGPL-compatible code should include this header with : + * + * #define _LGPL_SOURCE + * #include + * + * 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 + +/* + * See urcu-pointer.h and urcu/static/urcu-pointer.h for pointer + * publication headers. + */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* + * Important ! + * + * Each thread containing read-side critical sections must be registered + * with rcu_register_thread_mb() before calling rcu_read_lock_mb(). + * rcu_unregister_thread_mb() should be called before the thread exits. + */ + +#ifdef _LGPL_SOURCE + +#include + +/* + * Mappings for static use of the userspace RCU library. + * Should only be used in LGPL-compatible code. + */ + +/* + * 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 urcu_memb_read_lock _urcu_memb_read_lock +#define urcu_memb_read_unlock _urcu_memb_read_unlock +#define urcu_memb_read_ongoing _urcu_memb_read_ongoing + +#else /* !_LGPL_SOURCE */ + +/* + * library wrappers to be used by non-LGPL compatible source code. + * See LGPL-only urcu/static/urcu-pointer.h for documentation. + */ + +extern void urcu_memb_read_lock(void); +extern void urcu_memb_read_unlock(void); +extern int urcu_memb_read_ongoing(void); + +#endif /* !_LGPL_SOURCE */ + +extern void urcu_memb_synchronize_rcu(void); + +/* + * Reader thread registration. + */ +extern void urcu_memb_register_thread(void); +extern void urcu_memb_unregister_thread(void); + +/* + * Explicit rcu initialization, for "early" use within library constructors. + */ +extern void urcu_memb_init(void); + +/* + * Q.S. reporting are no-ops for these URCU flavors. + */ +static inline void urcu_memb_quiescent_state(void) +{ +} + +static inline void urcu_memb_thread_offline(void) +{ +} + +static inline void urcu_memb_thread_online(void) +{ +} + +#ifdef __cplusplus +} +#endif + +#include +#include +#include + +#ifndef URCU_API_MAP +#include +#endif + +#endif /* _URCU_MEMB_H */ diff --git a/include/urcu/urcu-qsbr.h b/include/urcu/urcu-qsbr.h new file mode 100644 index 0000000..041db21 --- /dev/null +++ b/include/urcu/urcu-qsbr.h @@ -0,0 +1,144 @@ +#ifndef _URCU_QSBR_H +#define _URCU_QSBR_H + +/* + * urcu-qsbr.h + * + * Userspace RCU QSBR header. + * + * LGPL-compatible code should include this header with : + * + * #define _LGPL_SOURCE + * #include + * + * 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 + +/* + * See urcu-pointer.h and urcu/static/urcu-pointer.h for pointer + * publication headers. + */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifdef RCU_DEBUG /* For backward compatibility */ +#define DEBUG_RCU +#endif + +/* + * Important ! + * + * Each thread containing read-side critical sections must be registered + * with rcu_register_thread() before calling rcu_read_lock(). + * rcu_unregister_thread() should be called before the thread exits. + */ + +#ifdef _LGPL_SOURCE + +#include + +/* + * Mappings for static use of the userspace RCU library. + * Should only be used in LGPL-compatible code. + */ + +/* + * rcu_read_lock() + * rcu_read_unlock() + * + * Mark the beginning and end of a read-side critical section. + * DON'T FORGET TO USE rcu_register_thread/rcu_unregister_thread() + * FOR EACH THREAD WITH READ-SIDE CRITICAL SECTION. + */ +#define urcu_qsbr_read_lock _urcu_qsbr_read_lock +#define urcu_qsbr_read_unlock _urcu_qsbr_read_unlock +#define urcu_qsbr_read_ongoing _urcu_qsbr_read_ongoing + +#define urcu_qsbr_quiescent_state _urcu_qsbr_quiescent_state +#define urcu_qsbr_thread_offline _urcu_qsbr_thread_offline +#define urcu_qsbr_thread_online _urcu_qsbr_thread_online + +#else /* !_LGPL_SOURCE */ + +/* + * 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 + * in the LGPL header for any code to use. However, the debug version is not + * nops and may contain sanity checks. To activate it, applications must be + * recompiled with -DDEBUG_RCU (even non-LGPL/GPL applications), or + * compiled against a urcu/config.h that has CONFIG_RCU_DEBUG defined. + * This is the best trade-off between license/performance/code + * triviality and library debugging & tracing features we could come up + * with. + */ + +#if (!defined(BUILD_QSBR_LIB) && !defined(DEBUG_RCU) && !defined(CONFIG_RCU_DEBUG)) + +static inline void urcu_qsbr_read_lock(void) +{ +} + +static inline void urcu_qsbr_read_unlock(void) +{ +} + +#else /* #if (!defined(BUILD_QSBR_LIB) && !defined(DEBUG_RCU) && !defined(CONFIG_RCU_DEBUG)) */ + +extern void urcu_qsbr_read_lock(void); +extern void urcu_qsbr_read_unlock(void); + +#endif /* #else #if (!defined(BUILD_QSBR_LIB) && !defined(DEBUG_RCU) && !defined(CONFIG_RCU_DEBUG)) */ + +extern int urcu_qsbr_read_ongoing(void); +extern void urcu_qsbr_quiescent_state(void); +extern void urcu_qsbr_thread_offline(void); +extern void urcu_qsbr_thread_online(void); + +#endif /* !_LGPL_SOURCE */ + +extern void urcu_qsbr_synchronize_rcu(void); + +/* + * Reader thread registration. + */ +extern void urcu_qsbr_register_thread(void); +extern void urcu_qsbr_unregister_thread(void); + +#ifdef __cplusplus +} +#endif + +#include +#include +#include + +#ifndef URCU_API_MAP +#include +#endif + +#endif /* _URCU_QSBR_H */ diff --git a/include/urcu/urcu-signal.h b/include/urcu/urcu-signal.h new file mode 100644 index 0000000..8c36450 --- /dev/null +++ b/include/urcu/urcu-signal.h @@ -0,0 +1,131 @@ +#ifndef _URCU_SIGNAL_H +#define _URCU_SIGNAL_H + +/* + * urcu-signal.h + * + * Userspace RCU header + * + * Copyright (c) 2009 Mathieu Desnoyers + * Copyright (c) 2009 Paul E. McKenney, IBM Corporation. + * + * LGPL-compatible code should include this header with : + * + * #define _LGPL_SOURCE + * #include + * + * 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 + +/* + * See urcu-pointer.h and urcu/static/urcu-pointer.h for pointer + * publication headers. + */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* + * Important ! + * + * Each thread containing read-side critical sections must be registered + * with rcu_register_thread_mb() before calling rcu_read_lock_mb(). + * rcu_unregister_thread_mb() should be called before the thread exits. + */ + +#ifdef _LGPL_SOURCE + +#include + +/* + * Mappings for static use of the userspace RCU library. + * Should only be used in LGPL-compatible code. + */ + +/* + * 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 urcu_signal_read_lock _urcu_signal_read_lock +#define urcu_signal_read_unlock _urcu_signal_read_unlock +#define urcu_signal_read_ongoing _urcu_signal_read_ongoing + +#else /* !_LGPL_SOURCE */ + +/* + * library wrappers to be used by non-LGPL compatible source code. + * See LGPL-only urcu/static/urcu-pointer.h for documentation. + */ + +extern void urcu_signal_read_lock(void); +extern void urcu_signal_read_unlock(void); +extern int urcu_signal_read_ongoing(void); + +#endif /* !_LGPL_SOURCE */ + +extern void urcu_signal_synchronize_rcu(void); + +/* + * Reader thread registration. + */ +extern void urcu_signal_register_thread(void); +extern void urcu_signal_unregister_thread(void); + +/* + * Explicit rcu initialization, for "early" use within library constructors. + */ +extern void urcu_signal_init(void); + +/* + * Q.S. reporting are no-ops for these URCU flavors. + */ +static inline void urcu_signal_quiescent_state(void) +{ +} + +static inline void urcu_signal_thread_offline(void) +{ +} + +static inline void urcu_signal_thread_online(void) +{ +} + +#ifdef __cplusplus +} +#endif + +#include +#include +#include + +#ifndef URCU_API_MAP +#include +#endif + +#endif /* _URCU_SIGNAL_H */ diff --git a/include/urcu/urcu.h b/include/urcu/urcu.h new file mode 100644 index 0000000..79cf590 --- /dev/null +++ b/include/urcu/urcu.h @@ -0,0 +1,48 @@ +#ifndef _URCU_H +#define _URCU_H + +/* + * urcu.h + * + * Userspace RCU header + * + * Copyright (c) 2009 Mathieu Desnoyers + * Copyright (c) 2009 Paul E. McKenney, IBM Corporation. + * + * LGPL-compatible code should include this header with : + * + * #define _LGPL_SOURCE + * #include + * + * 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. + */ + +#if !defined(RCU_MEMBARRIER) && !defined(RCU_SIGNAL) && !defined(RCU_MB) +#define RCU_MEMBARRIER +#endif + +#ifdef RCU_MEMBARRIER +#include +#elif defined(RCU_SIGNAL) +#include +#elif defined(RCU_MB) +#include +#else +#error "Unknown urcu flavor" +#endif + +#endif /* _URCU_H */ diff --git a/src/Makefile.am b/src/Makefile.am index 60b833d..88ccc1f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,12 +7,8 @@ if USE_CYGWIN AM_LDFLAGS+=-no-undefined endif -include_HEADERS = urcu.h urcu-bp.h urcu-call-rcu.h urcu-defer.h \ - urcu-pointer.h urcu-qsbr.h urcu-flavor.h - dist_noinst_HEADERS = urcu-die.h urcu-wait.h compat-getcpu.h \ - compat-rand.h - + compat-rand.h urcu-utils.h if COMPAT_ARCH COMPAT=compat_arch_@ARCHTYPE@.c @@ -28,7 +24,7 @@ RCULFHASH = rculfhash.c rculfhash-mm-order.c rculfhash-mm-chunk.c \ lib_LTLIBRARIES = liburcu-common.la \ liburcu.la liburcu-qsbr.la \ liburcu-mb.la liburcu-signal.la liburcu-bp.la \ - liburcu-cds.la + liburcu-memb.la liburcu-cds.la # # liburcu-common contains wait-free queues (needed by call_rcu) as well @@ -37,9 +33,15 @@ lib_LTLIBRARIES = liburcu-common.la \ liburcu_common_la_SOURCES = wfqueue.c wfcqueue.c wfstack.c $(COMPAT) liburcu_la_SOURCES = urcu.c urcu-pointer.c $(COMPAT) +liburcu_la_CFLAGS = -DRCU_MEMBARRIER $(AM_CFLAGS) liburcu_la_LIBADD = liburcu-common.la +liburcu_memb_la_SOURCES = urcu.c urcu-pointer.c $(COMPAT) +liburcu_memb_la_CFLAGS = -DRCU_MEMBARRIER $(AM_CFLAGS) +liburcu_memb_la_LIBADD = liburcu-common.la + liburcu_qsbr_la_SOURCES = urcu-qsbr.c urcu-pointer.c $(COMPAT) +liburcu_qsbr_la_CFLAGS = -DRCU_QSBR $(AM_CFLAGS) liburcu_qsbr_la_LIBADD = liburcu-common.la liburcu_mb_la_SOURCES = urcu.c urcu-pointer.c $(COMPAT) diff --git a/src/urcu-bp.c b/src/urcu-bp.c index 5d07f04..66c877a 100644 --- a/src/urcu-bp.c +++ b/src/urcu-bp.c @@ -36,18 +36,19 @@ #include #include -#include "urcu/arch.h" -#include "urcu/wfcqueue.h" -#include "urcu/map/urcu-bp.h" -#include "urcu/static/urcu-bp.h" -#include "urcu-pointer.h" -#include "urcu/tls-compat.h" +#include +#include +#include +#include +#include +#include #include "urcu-die.h" +#define URCU_API_MAP /* Do not #define _LGPL_SOURCE to ensure we can emit the wrapper symbols */ #undef _LGPL_SOURCE -#include "urcu-bp.h" +#include #define _LGPL_SOURCE #ifndef MAP_ANONYMOUS @@ -85,7 +86,7 @@ void *mremap_wrapper(void *old_address, size_t old_size, #define INIT_NR_THREADS 8 #define ARENA_INIT_ALLOC \ sizeof(struct registry_chunk) \ - + INIT_NR_THREADS * sizeof(struct rcu_reader) + + INIT_NR_THREADS * sizeof(struct urcu_bp_reader) /* * Active attempts to check for reader Q.S. before calling sleep(). @@ -93,7 +94,7 @@ void *mremap_wrapper(void *old_address, size_t old_size, #define RCU_QS_ACTIVE_ATTEMPTS 100 static -int rcu_bp_refcount; +int urcu_bp_refcount; /* If the headers do not support membarrier system call, fall back smp_mb. */ #ifdef __NR_membarrier @@ -112,9 +113,9 @@ enum membarrier_cmd { }; static -void __attribute__((constructor)) rcu_bp_init(void); +void __attribute__((constructor)) _urcu_bp_init(void); static -void __attribute__((destructor)) rcu_bp_exit(void); +void __attribute__((destructor)) urcu_bp_exit(void); #ifndef CONFIG_RCU_FORCE_SYS_MEMBARRIER int urcu_bp_has_sys_membarrier; @@ -141,13 +142,16 @@ static int initialized; static pthread_key_t urcu_bp_key; -struct rcu_gp rcu_gp = { .ctr = RCU_GP_COUNT }; +struct urcu_bp_gp urcu_bp_gp = { .ctr = URCU_BP_GP_COUNT }; +__attribute__((alias("urcu_bp_gp"))) extern struct urcu_bp_gp rcu_gp_bp; /* * Pointer to registry elements. Written to only by each individual reader. Read * by both the reader and the writers. */ -DEFINE_URCU_TLS(struct rcu_reader *, rcu_reader); +DEFINE_URCU_TLS(struct urcu_bp_reader *, urcu_bp_reader); +__attribute__((alias("urcu_bp_reader"))) +extern struct urcu_bp_reader *rcu_reader_bp; static CDS_LIST_HEAD(registry); @@ -214,10 +218,10 @@ static void wait_for_readers(struct cds_list_head *input_readers, struct cds_list_head *qsreaders) { unsigned int wait_loops = 0; - struct rcu_reader *index, *tmp; + struct urcu_bp_reader *index, *tmp; /* - * Wait for each thread URCU_TLS(rcu_reader).ctr to either + * Wait for each thread URCU_TLS(urcu_bp_reader).ctr to either * indicate quiescence (not nested), or observe the current * rcu_gp.ctr value. */ @@ -226,18 +230,18 @@ static void wait_for_readers(struct cds_list_head *input_readers, wait_loops++; cds_list_for_each_entry_safe(index, tmp, input_readers, node) { - switch (rcu_reader_state(&index->ctr)) { - case RCU_READER_ACTIVE_CURRENT: + switch (urcu_bp_reader_state(&index->ctr)) { + case URCU_BP_READER_ACTIVE_CURRENT: if (cur_snap_readers) { cds_list_move(&index->node, cur_snap_readers); break; } /* Fall-through */ - case RCU_READER_INACTIVE: + case URCU_BP_READER_INACTIVE: cds_list_move(&index->node, qsreaders); break; - case RCU_READER_ACTIVE_OLD: + case URCU_BP_READER_ACTIVE_OLD: /* * Old snapshot. Leaving node in * input_readers will make us busy-loop @@ -263,7 +267,7 @@ static void wait_for_readers(struct cds_list_head *input_readers, } } -void synchronize_rcu(void) +void urcu_bp_synchronize_rcu(void) { CDS_LIST_HEAD(cur_snap_readers); CDS_LIST_HEAD(qsreaders); @@ -302,7 +306,7 @@ void synchronize_rcu(void) cmm_smp_mb(); /* Switch parity: 0 -> 1, 1 -> 0 */ - CMM_STORE_SHARED(rcu_gp.ctr, rcu_gp.ctr ^ RCU_GP_CTR_PHASE); + CMM_STORE_SHARED(rcu_gp.ctr, rcu_gp.ctr ^ URCU_BP_GP_CTR_PHASE); /* * Must commit qparity update to memory before waiting for other parity @@ -341,25 +345,29 @@ out: ret = pthread_sigmask(SIG_SETMASK, &oldmask, NULL); assert(!ret); } +__attribute__((alias("urcu_bp_synchronize_rcu"))) void synchronize_rcu_bp(); /* * library wrappers to be used by non-LGPL compatible source code. */ -void rcu_read_lock(void) +void urcu_bp_read_lock(void) { - _rcu_read_lock(); + _urcu_bp_read_lock(); } +__attribute__((alias("urcu_bp_read_lock"))) void rcu_read_lock_bp(); -void rcu_read_unlock(void) +void urcu_bp_read_unlock(void) { - _rcu_read_unlock(); + _urcu_bp_read_unlock(); } +__attribute__((alias("urcu_bp_read_unlock"))) void rcu_read_unlock_bp(); -int rcu_read_ongoing(void) +int urcu_bp_read_ongoing(void) { - return _rcu_read_ongoing(); + return _urcu_bp_read_ongoing(); } +__attribute__((alias("urcu_bp_read_ongoing"))) int rcu_read_ongoing_bp(); /* * Only grow for now. If empty, allocate a ARENA_INIT_ALLOC sized chunk. @@ -484,7 +492,7 @@ void add_thread(void) * Reader threads are pointing to the reader registry. This is * why its memory should never be relocated. */ - URCU_TLS(rcu_reader) = rcu_reader_reg; + URCU_TLS(urcu_bp_reader) = rcu_reader_reg; } /* Called with mutex locked */ @@ -519,11 +527,11 @@ static void remove_thread(struct rcu_reader *rcu_reader_reg) { cleanup_thread(find_chunk(rcu_reader_reg), rcu_reader_reg); - URCU_TLS(rcu_reader) = NULL; + URCU_TLS(urcu_bp_reader) = NULL; } /* Disable signals, take mutex, add to registry */ -void rcu_bp_register(void) +void urcu_bp_register(void) { sigset_t newmask, oldmask; int ret; @@ -539,13 +547,13 @@ void rcu_bp_register(void) * Check if a signal concurrently registered our thread since * the check in rcu_read_lock(). */ - if (URCU_TLS(rcu_reader)) + if (URCU_TLS(urcu_bp_reader)) goto end; /* * Take care of early registration before urcu_bp constructor. */ - rcu_bp_init(); + _urcu_bp_init(); mutex_lock(&rcu_registry_lock); add_thread(); @@ -555,10 +563,11 @@ end: if (ret) abort(); } +__attribute__((alias("urcu_bp_register"))) void rcu_bp_register(); /* Disable signals, take mutex, remove from registry */ static -void rcu_bp_unregister(struct rcu_reader *rcu_reader_reg) +void urcu_bp_unregister(struct rcu_reader *rcu_reader_reg) { sigset_t newmask, oldmask; int ret; @@ -576,7 +585,7 @@ void rcu_bp_unregister(struct rcu_reader *rcu_reader_reg) ret = pthread_sigmask(SIG_SETMASK, &oldmask, NULL); if (ret) abort(); - rcu_bp_exit(); + urcu_bp_exit(); } /* @@ -586,19 +595,19 @@ void rcu_bp_unregister(struct rcu_reader *rcu_reader_reg) static void urcu_bp_thread_exit_notifier(void *rcu_key) { - rcu_bp_unregister(rcu_key); + urcu_bp_unregister(rcu_key); } #ifdef CONFIG_RCU_FORCE_SYS_MEMBARRIER static -void rcu_sys_membarrier_status(bool available) +void urcu_bp_sys_membarrier_status(bool available) { if (!available) abort(); } #else static -void rcu_sys_membarrier_status(bool available) +void urcu_bp_sys_membarrier_status(bool available) { if (!available) return; @@ -607,7 +616,7 @@ void rcu_sys_membarrier_status(bool available) #endif static -void rcu_sys_membarrier_init(void) +void urcu_bp_sys_membarrier_init(void) { bool available = false; int mask; @@ -620,31 +629,31 @@ void rcu_sys_membarrier_init(void) available = true; } } - rcu_sys_membarrier_status(available); + urcu_bp_sys_membarrier_status(available); } static -void rcu_bp_init(void) +void _urcu_bp_init(void) { mutex_lock(&init_lock); - if (!rcu_bp_refcount++) { + if (!urcu_bp_refcount++) { int ret; ret = pthread_key_create(&urcu_bp_key, urcu_bp_thread_exit_notifier); if (ret) abort(); - rcu_sys_membarrier_init(); + urcu_bp_sys_membarrier_init(); initialized = 1; } mutex_unlock(&init_lock); } static -void rcu_bp_exit(void) +void urcu_bp_exit(void) { mutex_lock(&init_lock); - if (!--rcu_bp_refcount) { + if (!--urcu_bp_refcount) { struct registry_chunk *chunk, *tmp; int ret; @@ -667,7 +676,7 @@ void rcu_bp_exit(void) * any of those locks held. This ensures that the registry and data * protected by rcu_gp_lock are in a coherent state in the child. */ -void rcu_bp_before_fork(void) +void urcu_bp_before_fork(void) { sigset_t newmask, oldmask; int ret; @@ -680,8 +689,9 @@ void rcu_bp_before_fork(void) mutex_lock(&rcu_registry_lock); saved_fork_signal_mask = oldmask; } +__attribute__((alias("urcu_bp_before_fork"))) void rcu_bp_before_fork(); -void rcu_bp_after_fork_parent(void) +void urcu_bp_after_fork_parent(void) { sigset_t oldmask; int ret; @@ -692,6 +702,8 @@ void rcu_bp_after_fork_parent(void) ret = pthread_sigmask(SIG_SETMASK, &oldmask, NULL); assert(!ret); } +__attribute__((alias("urcu_bp_after_fork_parent"))) +void rcu_bp_after_fork_parent(void); /* * Prune all entries from registry except our own thread. Fits the Linux @@ -701,11 +713,11 @@ static void urcu_bp_prune_registry(void) { struct registry_chunk *chunk; - struct rcu_reader *rcu_reader_reg; + struct urcu_bp_reader *rcu_reader_reg; cds_list_for_each_entry(chunk, ®istry_arena.chunk_list, node) { - for (rcu_reader_reg = (struct rcu_reader *) &chunk->data[0]; - rcu_reader_reg < (struct rcu_reader *) &chunk->data[chunk->data_len]; + for (rcu_reader_reg = (struct urcu_bp_reader *) &chunk->data[0]; + rcu_reader_reg < (struct urcu_bp_reader *) &chunk->data[chunk->data_len]; rcu_reader_reg++) { if (!rcu_reader_reg->alloc) continue; @@ -716,7 +728,7 @@ void urcu_bp_prune_registry(void) } } -void rcu_bp_after_fork_child(void) +void urcu_bp_after_fork_child(void) { sigset_t oldmask; int ret; @@ -728,32 +740,43 @@ void rcu_bp_after_fork_child(void) ret = pthread_sigmask(SIG_SETMASK, &oldmask, NULL); assert(!ret); } +__attribute__((alias("urcu_bp_after_fork_child"))) +void rcu_bp_after_fork_child(void); -void *rcu_dereference_sym_bp(void *p) +void *urcu_bp_dereference_sym(void *p) { return _rcu_dereference(p); } +__attribute__((alias("urcu_bp_dereference_sym"))) +void *rcu_dereference_sym_bp(); -void *rcu_set_pointer_sym_bp(void **p, void *v) +void *urcu_bp_set_pointer_sym(void **p, void *v) { cmm_wmb(); uatomic_set(p, v); return v; } +__attribute__((alias("urcu_bp_set_pointer_sym"))) +void *rcu_set_pointer_sym_bp(); -void *rcu_xchg_pointer_sym_bp(void **p, void *v) +void *urcu_bp_xchg_pointer_sym(void **p, void *v) { cmm_wmb(); return uatomic_xchg(p, v); } +__attribute__((alias("urcu_bp_xchg_pointer_sym"))) +void *rcu_xchg_pointer_sym_bp(); -void *rcu_cmpxchg_pointer_sym_bp(void **p, void *old, void *_new) +void *urcu_bp_cmpxchg_pointer_sym(void **p, void *old, void *_new) { cmm_wmb(); return uatomic_cmpxchg(p, old, _new); } +__attribute__((alias("urcu_bp_cmpxchg_pointer_sym"))) +void *rcu_cmpxchg_pointer_sym_bp(); DEFINE_RCU_FLAVOR(rcu_flavor); +DEFINE_RCU_FLAVOR_ALIAS(rcu_flavor, alias_rcu_flavor); #include "urcu-call-rcu-impl.h" #include "urcu-defer-impl.h" diff --git a/src/urcu-bp.h b/src/urcu-bp.h deleted file mode 100644 index 7a265dc..0000000 --- a/src/urcu-bp.h +++ /dev/null @@ -1,191 +0,0 @@ -#ifndef _URCU_BP_H -#define _URCU_BP_H - -/* - * urcu-bp.h - * - * Userspace RCU header, "bulletproof" version. - * - * Slower RCU read-side adapted for tracing library. Does not require thread - * registration nor unregistration. Also signal-safe. - * - * Copyright (c) 2009 Mathieu Desnoyers - * Copyright (c) 2009 Paul E. McKenney, IBM Corporation. - * - * LGPL-compatible code should include this header with : - * - * #define _LGPL_SOURCE - * #include - * - * 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 - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -/* - * Important ! - * - * Each thread containing read-side critical sections must be registered - * with rcu_register_thread() before calling rcu_read_lock(). - * rcu_unregister_thread() should be called before the thread exits. - */ - -/* - * See urcu-pointer.h and urcu/static/urcu-pointer.h for pointer - * publication headers. - */ -#include - -#ifdef _LGPL_SOURCE - -#include - -/* - * Mappings for static use of the userspace RCU library. - * Should only be used in LGPL-compatible code. - */ - -/* - * rcu_read_lock() - * rcu_read_unlock() - * - * Mark the beginning and end of a read-side critical section. - */ -#define rcu_read_lock_bp _rcu_read_lock -#define rcu_read_unlock_bp _rcu_read_unlock -#define rcu_read_ongoing_bp _rcu_read_ongoing - -#define rcu_dereference_bp rcu_dereference -#define rcu_cmpxchg_pointer_bp rcu_cmpxchg_pointer -#define rcu_xchg_pointer_bp rcu_xchg_pointer -#define rcu_set_pointer_bp rcu_set_pointer - -#else /* !_LGPL_SOURCE */ - -/* - * library wrappers to be used by non-LGPL compatible source code. - * See LGPL-only urcu/static/urcu-pointer.h for documentation. - */ - -extern void rcu_read_lock(void); -extern void rcu_read_unlock(void); -extern int rcu_read_ongoing(void); - -extern void *rcu_dereference_sym_bp(void *p); -#define rcu_dereference_bp(p) \ - __extension__ \ - ({ \ - __typeof__(p) _________p1 = URCU_FORCE_CAST(__typeof__(p), \ - rcu_dereference_sym_bp(URCU_FORCE_CAST(void *, p))); \ - (_________p1); \ - }) - -extern void *rcu_cmpxchg_pointer_sym_bp(void **p, void *old, void *_new); -#define rcu_cmpxchg_pointer_bp(p, old, _new) \ - __extension__ \ - ({ \ - __typeof__(*(p)) _________pold = (old); \ - __typeof__(*(p)) _________pnew = (_new); \ - __typeof__(*(p)) _________p1 = URCU_FORCE_CAST(__typeof__(*(p)), \ - rcu_cmpxchg_pointer_sym_bp(URCU_FORCE_CAST(void **, p), \ - _________pold, \ - _________pnew)); \ - (_________p1); \ - }) - -extern void *rcu_xchg_pointer_sym_bp(void **p, void *v); -#define rcu_xchg_pointer_bp(p, v) \ - __extension__ \ - ({ \ - __typeof__(*(p)) _________pv = (v); \ - __typeof__(*(p)) _________p1 = URCU_FORCE_CAST(__typeof__(*(p)),\ - rcu_xchg_pointer_sym_bp(URCU_FORCE_CAST(void **, p), \ - _________pv)); \ - (_________p1); \ - }) - -extern void *rcu_set_pointer_sym_bp(void **p, void *v); -#define rcu_set_pointer_bp(p, v) \ - __extension__ \ - ({ \ - __typeof__(*(p)) _________pv = (v); \ - __typeof__(*(p)) _________p1 = URCU_FORCE_CAST(__typeof__(*(p)), \ - rcu_set_pointer_sym_bp(URCU_FORCE_CAST(void **, p), \ - _________pv)); \ - (_________p1); \ - }) - -#endif /* !_LGPL_SOURCE */ - -extern void synchronize_rcu(void); - -/* - * rcu_bp_before_fork, rcu_bp_after_fork_parent and rcu_bp_after_fork_child - * should be called around fork() system calls when the child process is not - * expected to immediately perform an exec(). For pthread users, see - * pthread_atfork(3). - */ -extern void rcu_bp_before_fork(void); -extern void rcu_bp_after_fork_parent(void); -extern void rcu_bp_after_fork_child(void); - -/* - * In the bulletproof version, the following functions are no-ops. - */ -static inline void rcu_register_thread(void) -{ -} - -static inline void rcu_unregister_thread(void) -{ -} - -static inline void rcu_init(void) -{ -} - -/* - * Q.S. reporting are no-ops for these URCU flavors. - */ -static inline void rcu_quiescent_state(void) -{ -} - -static inline void rcu_thread_offline(void) -{ -} - -static inline void rcu_thread_online(void) -{ -} - -#ifdef __cplusplus -} -#endif - -#include -#include -#include - -#endif /* _URCU_BP_H */ diff --git a/src/urcu-call-rcu-impl.h b/src/urcu-call-rcu-impl.h index 4562ba4..f7844cc 100644 --- a/src/urcu-call-rcu-impl.h +++ b/src/urcu-call-rcu-impl.h @@ -35,14 +35,15 @@ #include #include "compat-getcpu.h" -#include "urcu/wfcqueue.h" -#include "urcu-call-rcu.h" -#include "urcu-pointer.h" -#include "urcu/list.h" -#include "urcu/futex.h" -#include "urcu/tls-compat.h" -#include "urcu/ref.h" +#include +#include +#include +#include +#include +#include +#include #include "urcu-die.h" +#include "urcu-utils.h" #define SET_AFFINITY_CHECK_PERIOD (1U << 8) /* 256 */ #define SET_AFFINITY_CHECK_PERIOD_MASK (SET_AFFINITY_CHECK_PERIOD - 1) @@ -464,6 +465,8 @@ struct call_rcu_data *get_cpu_call_rcu_data(int cpu) return NULL; return rcu_dereference(pcpu_crdp[cpu]); } +__attribute__((alias(urcu_stringify(get_cpu_call_rcu_data)))) +struct call_rcu_data *alias_get_cpu_call_rcu_data(); /* * Return the tid corresponding to the call_rcu thread whose @@ -474,6 +477,8 @@ pthread_t get_call_rcu_thread(struct call_rcu_data *crdp) { return crdp->tid; } +__attribute__((alias(urcu_stringify(get_call_rcu_thread)))) +pthread_t alias_get_call_rcu_thread(); /* * Create a call_rcu_data structure (with thread) and return a pointer. @@ -488,6 +493,8 @@ static struct call_rcu_data *__create_call_rcu_data(unsigned long flags, return crdp; } +__attribute__((alias(urcu_stringify(create_call_rcu_data)))) +struct call_rcu_data *alias_create_call_rcu_data(); struct call_rcu_data *create_call_rcu_data(unsigned long flags, int cpu_affinity) { @@ -544,6 +551,8 @@ int set_cpu_call_rcu_data(int cpu, struct call_rcu_data *crdp) call_rcu_unlock(&call_rcu_mutex); return 0; } +__attribute__((alias(urcu_stringify(set_cpu_call_rcu_data)))) +int alias_set_cpu_call_rcu_data(); /* * Return a pointer to the default call_rcu_data structure, creating @@ -564,6 +573,8 @@ struct call_rcu_data *get_default_call_rcu_data(void) call_rcu_unlock(&call_rcu_mutex); return default_call_rcu_data; } +__attribute__((alias(urcu_stringify(get_default_call_rcu_data)))) +struct call_rcu_data *alias_get_default_call_rcu_data(); /* * Return the call_rcu_data structure that applies to the currently @@ -591,6 +602,8 @@ struct call_rcu_data *get_call_rcu_data(void) return get_default_call_rcu_data(); } +__attribute__((alias(urcu_stringify(get_call_rcu_data)))) +struct call_rcu_data *alias_get_call_rcu_data(); /* * Return a pointer to this task's call_rcu_data if there is one. @@ -600,6 +613,8 @@ struct call_rcu_data *get_thread_call_rcu_data(void) { return URCU_TLS(thread_call_rcu_data); } +__attribute__((alias(urcu_stringify(get_thread_call_rcu_data)))) +struct call_rcu_data *alias_get_thread_call_rcu_data(); /* * Set this task's call_rcu_data structure as specified, regardless @@ -616,6 +631,8 @@ void set_thread_call_rcu_data(struct call_rcu_data *crdp) { URCU_TLS(thread_call_rcu_data) = crdp; } +__attribute__((alias(urcu_stringify(set_thread_call_rcu_data)))) +void alias_set_thread_call_rcu_data(); /* * Create a separate call_rcu thread for each CPU. This does not @@ -667,6 +684,8 @@ int create_all_cpu_call_rcu_data(unsigned long flags) } return 0; } +__attribute__((alias(urcu_stringify(create_all_cpu_call_rcu_data)))) +int alias_create_all_cpu_call_rcu_data(); /* * Wake up the call_rcu thread corresponding to the specified @@ -714,6 +733,7 @@ void call_rcu(struct rcu_head *head, _call_rcu(head, func, crdp); _rcu_read_unlock(); } +__attribute__((alias(urcu_stringify(call_rcu)))) void alias_call_rcu(); /* * Free up the specified call_rcu_data structure, terminating the @@ -769,6 +789,8 @@ void call_rcu_data_free(struct call_rcu_data *crdp) free(crdp); } +__attribute__((alias(urcu_stringify(call_rcu_data_free)))) +void alias_call_rcu_data_free(); /* * Clean up all the per-CPU call_rcu threads. @@ -809,6 +831,16 @@ void free_all_cpu_call_rcu_data(void) } free(crdp); } +#ifdef RCU_QSBR +/* ABI6 has a non-namespaced free_all_cpu_call_rcu_data for qsbr */ +#undef free_all_cpu_call_rcu_data +__attribute__((alias("urcu_qsbr_free_all_cpu_call_rcu_data"))) +void free_all_cpu_call_rcu_data(); +#define free_all_cpu_call_rcu_data urcu_qsbr_free_all_cpu_call_rcu_data +#else +__attribute__((alias(urcu_stringify(free_all_cpu_call_rcu_data)))) +void alias_free_all_cpu_call_rcu_data(); +#endif static void free_completion(struct urcu_ref *ref) @@ -900,6 +932,8 @@ online: if (was_online) rcu_thread_online(); } +__attribute__((alias(urcu_stringify(rcu_barrier)))) +void alias_rcu_barrier(); /* * Acquire the call_rcu_mutex in order to ensure that the child sees @@ -928,6 +962,8 @@ void call_rcu_before_fork(void) (void) poll(NULL, 0, 1); } } +__attribute__((alias(urcu_stringify(call_rcu_before_fork)))) +void alias_call_rcu_before_fork(); /* * Clean up call_rcu data structures in the parent of a successful fork() @@ -950,6 +986,8 @@ void call_rcu_after_fork_parent(void) atfork->after_fork_parent(atfork->priv); call_rcu_unlock(&call_rcu_mutex); } +__attribute__((alias(urcu_stringify(call_rcu_after_fork_parent)))) +void alias_call_rcu_after_fork_parent(); /* * Clean up call_rcu data structures in the child of a successful fork() @@ -997,6 +1035,8 @@ void call_rcu_after_fork_child(void) call_rcu_data_free(crdp); } } +__attribute__((alias(urcu_stringify(call_rcu_after_fork_child)))) +void alias_call_rcu_after_fork_child(); void urcu_register_rculfhash_atfork(struct urcu_atfork *atfork) { @@ -1007,6 +1047,8 @@ void urcu_register_rculfhash_atfork(struct urcu_atfork *atfork) end: call_rcu_unlock(&call_rcu_mutex); } +__attribute__((alias(urcu_stringify(urcu_register_rculfhash_atfork)))) +void alias_urcu_register_rculfhash_atfork(); void urcu_unregister_rculfhash_atfork(struct urcu_atfork *atfork) { @@ -1017,3 +1059,5 @@ void urcu_unregister_rculfhash_atfork(struct urcu_atfork *atfork) end: call_rcu_unlock(&call_rcu_mutex); } +__attribute__((alias(urcu_stringify(urcu_unregister_rculfhash_atfork)))) +void alias_urcu_unregister_rculfhash_atfork(); diff --git a/src/urcu-call-rcu.h b/src/urcu-call-rcu.h deleted file mode 100644 index 339ebac..0000000 --- a/src/urcu-call-rcu.h +++ /dev/null @@ -1,101 +0,0 @@ -#ifndef _URCU_CALL_RCU_H -#define _URCU_CALL_RCU_H - -/* - * urcu-call-rcu.h - * - * Userspace RCU header - deferred execution - * - * Copyright (c) 2009 Mathieu Desnoyers - * Copyright (c) 2009 Paul E. McKenney, IBM Corporation. - * - * LGPL-compatible code should include this header with : - * - * #define _LGPL_SOURCE - * #include - * - * 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 - */ - -#include -#include - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* Note that struct call_rcu_data is opaque to callers. */ - -struct call_rcu_data; - -/* Flag values. */ - -#define URCU_CALL_RCU_RT (1U << 0) -#define URCU_CALL_RCU_RUNNING (1U << 1) -#define URCU_CALL_RCU_STOP (1U << 2) -#define URCU_CALL_RCU_STOPPED (1U << 3) -#define URCU_CALL_RCU_PAUSE (1U << 4) -#define URCU_CALL_RCU_PAUSED (1U << 5) - -/* - * The rcu_head data structure is placed in the structure to be freed - * via call_rcu(). - */ - -struct rcu_head { - struct cds_wfcq_node next; - void (*func)(struct rcu_head *head); -}; - -/* - * Exported functions - * - * Important: see rcu-api.md in userspace-rcu documentation for - * call_rcu family of functions usage detail, including the surrounding - * RCU usage required when using these primitives. - */ - -void call_rcu(struct rcu_head *head, - void (*func)(struct rcu_head *head)); - -struct call_rcu_data *create_call_rcu_data(unsigned long flags, - int cpu_affinity); -void call_rcu_data_free(struct call_rcu_data *crdp); - -struct call_rcu_data *get_default_call_rcu_data(void); -struct call_rcu_data *get_cpu_call_rcu_data(int cpu); -struct call_rcu_data *get_thread_call_rcu_data(void); -struct call_rcu_data *get_call_rcu_data(void); -pthread_t get_call_rcu_thread(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 create_all_cpu_call_rcu_data(unsigned long flags); -void free_all_cpu_call_rcu_data(void); - -void call_rcu_before_fork(void); -void call_rcu_after_fork_parent(void); -void call_rcu_after_fork_child(void); - -void rcu_barrier(void); - -#ifdef __cplusplus -} -#endif - -#endif /* _URCU_CALL_RCU_H */ diff --git a/src/urcu-defer-impl.h b/src/urcu-defer-impl.h index f965533..58ca1ab 100644 --- a/src/urcu-defer-impl.h +++ b/src/urcu-defer-impl.h @@ -50,6 +50,7 @@ #include #include #include "urcu-die.h" +#include "urcu-utils.h" /* * Number of entries in the per-thread defer queue. Must be power of 2. @@ -107,7 +108,7 @@ struct defer_queue { }; /* Do not #define _LGPL_SOURCE to ensure we can emit the wrapper symbols */ -#include "urcu-defer.h" +#include void __attribute__((destructor)) rcu_defer_exit(void); @@ -264,6 +265,8 @@ void rcu_defer_barrier_thread(void) _rcu_defer_barrier_thread(); mutex_unlock(&rcu_defer_mutex); } +__attribute__((alias(urcu_stringify(rcu_defer_barrier_thread)))) +void alias_rcu_defer_barrier_thread(); /* * rcu_defer_barrier - Execute all queued rcu callbacks. @@ -304,6 +307,8 @@ void rcu_defer_barrier(void) end: mutex_unlock(&rcu_defer_mutex); } +__attribute__((alias(urcu_stringify(rcu_defer_barrier)))) +void alias_rcu_defer_barrier(); /* * _defer_rcu - Queue a RCU callback. @@ -396,6 +401,7 @@ void defer_rcu(void (*fct)(void *p), void *p) { _defer_rcu(fct, p); } +__attribute__((alias(urcu_stringify(defer_rcu)))) void alias_defer_rcu(); static void start_defer_thread(void) { @@ -444,6 +450,8 @@ int rcu_defer_register_thread(void) mutex_unlock(&defer_thread_mutex); return 0; } +__attribute__((alias(urcu_stringify(rcu_defer_register_thread)))) +int alias_rcu_defer_register_thread(); void rcu_defer_unregister_thread(void) { @@ -462,10 +470,14 @@ void rcu_defer_unregister_thread(void) stop_defer_thread(); mutex_unlock(&defer_thread_mutex); } +__attribute__((alias(urcu_stringify(rcu_defer_unregister_thread)))) +void alias_rcu_defer_unregister_thread(); void rcu_defer_exit(void) { assert(cds_list_empty(®istry_defer)); } +__attribute__((alias(urcu_stringify(rcu_defer_exit)))) +void alias_rcu_defer_exit(); #endif /* _URCU_DEFER_IMPL_H */ diff --git a/src/urcu-defer.h b/src/urcu-defer.h deleted file mode 100644 index 43eca34..0000000 --- a/src/urcu-defer.h +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef _URCU_BATCH_H -#define _URCU_BATCH_H - -/* - * urcu-defer.h - * - * Userspace RCU header - deferred execution - * - * Copyright (c) 2009 Mathieu Desnoyers - * Copyright (c) 2009 Paul E. McKenney, IBM Corporation. - * - * LGPL-compatible code should include this header with : - * - * #define _LGPL_SOURCE - * #include - * - * 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 - */ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Note: the defer_rcu() API is currently EXPERIMENTAL. It may change in the - * future. - * - * Important ! - * - * Each thread queuing memory reclamation must be registered with - * rcu_defer_register_thread(). rcu_defer_unregister_thread() should be - * called before the thread exits. - * - * *NEVER* use defer_rcu() within a RCU read-side critical section, because this - * primitive need to call synchronize_rcu() if the thread queue is full. - */ - -extern void defer_rcu(void (*fct)(void *p), void *p); - -/* - * Thread registration for reclamation. - */ -extern int rcu_defer_register_thread(void); -extern void rcu_defer_unregister_thread(void); -extern void rcu_defer_barrier(void); -extern void rcu_defer_barrier_thread(void); - -#ifdef __cplusplus -} -#endif - -#endif /* _URCU_BATCH_H */ diff --git a/src/urcu-flavor.h b/src/urcu-flavor.h deleted file mode 100644 index 9cfbd6a..0000000 --- a/src/urcu-flavor.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef _URCU_FLAVOR_H -#define _URCU_FLAVOR_H - -/* - * urcu-flavor.h - * - * Userspace RCU header - rcu flavor declarations - * - * Copyright (c) 2011 Lai Jiangshan - * - * 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 - */ - -#ifdef __cplusplus -extern "C" { -#endif - -struct urcu_atfork { - void (*before_fork)(void *priv); - void (*after_fork_parent)(void *priv); - void (*after_fork_child)(void *priv); - void *priv; -}; - -void urcu_register_rculfhash_atfork(struct urcu_atfork *atfork); -void urcu_unregister_rculfhash_atfork(struct urcu_atfork *atfork); - -struct rcu_flavor_struct { - void (*read_lock)(void); - void (*read_unlock)(void); - int (*read_ongoing)(void); - void (*read_quiescent_state)(void); - void (*update_call_rcu)(struct rcu_head *head, - void (*func)(struct rcu_head *head)); - void (*update_synchronize_rcu)(void); - void (*update_defer_rcu)(void (*fct)(void *p), void *p); - - void (*thread_offline)(void); - void (*thread_online)(void); - void (*register_thread)(void); - void (*unregister_thread)(void); - - void (*barrier)(void); - - void (*register_rculfhash_atfork)(struct urcu_atfork *atfork); - void (*unregister_rculfhash_atfork)(struct urcu_atfork *atfork); -}; - -#define DEFINE_RCU_FLAVOR(x) \ -const struct rcu_flavor_struct x = { \ - .read_lock = rcu_read_lock, \ - .read_unlock = rcu_read_unlock, \ - .read_ongoing = rcu_read_ongoing, \ - .read_quiescent_state = rcu_quiescent_state, \ - .update_call_rcu = call_rcu, \ - .update_synchronize_rcu = synchronize_rcu, \ - .update_defer_rcu = defer_rcu, \ - .thread_offline = rcu_thread_offline, \ - .thread_online = rcu_thread_online, \ - .register_thread = rcu_register_thread, \ - .unregister_thread = rcu_unregister_thread,\ - .barrier = rcu_barrier, \ - .register_rculfhash_atfork = urcu_register_rculfhash_atfork, \ - .unregister_rculfhash_atfork = urcu_unregister_rculfhash_atfork,\ -} - -extern const struct rcu_flavor_struct rcu_flavor; - -#ifdef __cplusplus -} -#endif - -#endif /* _URCU_FLAVOR_H */ diff --git a/src/urcu-pointer.h b/src/urcu-pointer.h deleted file mode 100644 index dc1a0da..0000000 --- a/src/urcu-pointer.h +++ /dev/null @@ -1,129 +0,0 @@ -#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 __cplusplus -extern "C" { -#endif - -#if defined(_LGPL_SOURCE) || defined(URCU_INLINE_SMALL_FUNCTIONS) - -#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 - -/* - * type *rcu_cmpxchg_pointer(type **ptr, type *new, type *old) - * type *rcu_xchg_pointer(type **ptr, type *new) - * void 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 - -#else /* !(defined(_LGPL_SOURCE) || defined(URCU_INLINE_SMALL_FUNCTIONS)) */ - -extern void *rcu_dereference_sym(void *p); -#define rcu_dereference(p) \ - __extension__ \ - ({ \ - __typeof__(p) _________p1 = URCU_FORCE_CAST(__typeof__(p), \ - rcu_dereference_sym(URCU_FORCE_CAST(void *, p))); \ - (_________p1); \ - }) - -extern void *rcu_cmpxchg_pointer_sym(void **p, void *old, void *_new); -#define rcu_cmpxchg_pointer(p, old, _new) \ - __extension__ \ - ({ \ - __typeof__(*(p)) _________pold = (old); \ - __typeof__(*(p)) _________pnew = (_new); \ - __typeof__(*(p)) _________p1 = URCU_FORCE_CAST(__typeof__(*(p)), \ - rcu_cmpxchg_pointer_sym(URCU_FORCE_CAST(void **, p), \ - _________pold, \ - _________pnew)); \ - (_________p1); \ - }) - -extern void *rcu_xchg_pointer_sym(void **p, void *v); -#define rcu_xchg_pointer(p, v) \ - __extension__ \ - ({ \ - __typeof__(*(p)) _________pv = (v); \ - __typeof__(*(p)) _________p1 = URCU_FORCE_CAST(__typeof__(*(p)), \ - rcu_xchg_pointer_sym(URCU_FORCE_CAST(void **, p), \ - _________pv)); \ - (_________p1); \ - }) - -/* - * Note: rcu_set_pointer_sym returns @v because we don't want to break - * the ABI. At the API level, rcu_set_pointer() now returns void. Use of - * the return value is therefore deprecated, and will cause a build - * error. - */ -extern void *rcu_set_pointer_sym(void **p, void *v); -#define rcu_set_pointer(p, v) \ - do { \ - __typeof__(*(p)) _________pv = (v); \ - (void) rcu_set_pointer_sym(URCU_FORCE_CAST(void **, p), \ - _________pv); \ - } while (0) - -#endif /* !(defined(_LGPL_SOURCE) || defined(URCU_INLINE_SMALL_FUNCTIONS)) */ - -/* - * void 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)) - -#ifdef __cplusplus -} -#endif - -#endif /* _URCU_POINTER_H */ diff --git a/src/urcu-qsbr.c b/src/urcu-qsbr.c index e029ace..346748b 100644 --- a/src/urcu-qsbr.c +++ b/src/urcu-qsbr.c @@ -34,22 +34,23 @@ #include #include -#include "urcu/wfcqueue.h" -#include "urcu/map/urcu-qsbr.h" +#include +#include #define BUILD_QSBR_LIB -#include "urcu/static/urcu-qsbr.h" -#include "urcu-pointer.h" -#include "urcu/tls-compat.h" +#include +#include +#include #include "urcu-die.h" #include "urcu-wait.h" +#define URCU_API_MAP /* Do not #define _LGPL_SOURCE to ensure we can emit the wrapper symbols */ #undef _LGPL_SOURCE -#include "urcu-qsbr.h" +#include #define _LGPL_SOURCE -void __attribute__((destructor)) rcu_exit(void); +void __attribute__((destructor)) urcu_qsbr_exit(void); /* * rcu_gp_lock ensures mutual exclusion between threads calling @@ -66,7 +67,8 @@ static pthread_mutex_t rcu_gp_lock = PTHREAD_MUTEX_INITIALIZER; * rcu_registry_lock may nest inside rcu_gp_lock. */ static pthread_mutex_t rcu_registry_lock = PTHREAD_MUTEX_INITIALIZER; -struct rcu_gp rcu_gp = { .ctr = RCU_GP_ONLINE }; +struct urcu_gp urcu_qsbr_gp = { .ctr = URCU_QSBR_GP_ONLINE }; +__attribute__((alias("urcu_qsbr_gp"))) extern struct urcu_gp rcu_gp_qsbr; /* * Active attempts to check for reader Q.S. before calling futex(). @@ -77,7 +79,9 @@ struct rcu_gp rcu_gp = { .ctr = RCU_GP_ONLINE }; * Written to only by each individual reader. Read by both the reader and the * writers. */ -DEFINE_URCU_TLS(struct rcu_reader, rcu_reader); +DEFINE_URCU_TLS(struct urcu_qsbr_reader, urcu_qsbr_reader); +__attribute__((alias("urcu_qsbr_reader"))) +extern struct urcu_qsbr_reader rcu_reader_qsbr; static CDS_LIST_HEAD(registry); @@ -120,9 +124,9 @@ static void wait_gp(void) { /* Read reader_gp before read futex */ cmm_smp_rmb(); - if (uatomic_read(&rcu_gp.futex) != -1) + if (uatomic_read(&urcu_qsbr_gp.futex) != -1) return; - while (futex_noasync(&rcu_gp.futex, FUTEX_WAIT, -1, + while (futex_noasync(&urcu_qsbr_gp.futex, FUTEX_WAIT, -1, NULL, NULL, 0)) { switch (errno) { case EWOULDBLOCK: @@ -147,18 +151,18 @@ static void wait_for_readers(struct cds_list_head *input_readers, struct cds_list_head *qsreaders) { unsigned int wait_loops = 0; - struct rcu_reader *index, *tmp; + struct urcu_qsbr_reader *index, *tmp; /* - * Wait for each thread URCU_TLS(rcu_reader).ctr to either + * Wait for each thread URCU_TLS(urcu_qsbr_reader).ctr to either * indicate quiescence (offline), or for them to observe the - * current rcu_gp.ctr value. + * current urcu_qsbr_gp.ctr value. */ for (;;) { if (wait_loops < RCU_QS_ACTIVE_ATTEMPTS) wait_loops++; if (wait_loops >= RCU_QS_ACTIVE_ATTEMPTS) { - uatomic_set(&rcu_gp.futex, -1); + uatomic_set(&urcu_qsbr_gp.futex, -1); /* * Write futex before write waiting (the other side * reads them in the opposite order). @@ -171,18 +175,18 @@ static void wait_for_readers(struct cds_list_head *input_readers, cmm_smp_mb(); } cds_list_for_each_entry_safe(index, tmp, input_readers, node) { - switch (rcu_reader_state(&index->ctr)) { - case RCU_READER_ACTIVE_CURRENT: + switch (urcu_qsbr_reader_state(&index->ctr)) { + case URCU_READER_ACTIVE_CURRENT: if (cur_snap_readers) { cds_list_move(&index->node, cur_snap_readers); break; } /* Fall-through */ - case RCU_READER_INACTIVE: + case URCU_READER_INACTIVE: cds_list_move(&index->node, qsreaders); break; - case RCU_READER_ACTIVE_OLD: + case URCU_READER_ACTIVE_OLD: /* * Old snapshot. Leaving node in * input_readers will make us busy-loop @@ -197,7 +201,7 @@ static void wait_for_readers(struct cds_list_head *input_readers, if (wait_loops >= RCU_QS_ACTIVE_ATTEMPTS) { /* Read reader_gp before write futex */ cmm_smp_mb(); - uatomic_set(&rcu_gp.futex, 0); + uatomic_set(&urcu_qsbr_gp.futex, 0); } break; } else { @@ -224,7 +228,7 @@ static void wait_for_readers(struct cds_list_head *input_readers, */ #if (CAA_BITS_PER_LONG < 64) -void synchronize_rcu(void) +void urcu_qsbr_synchronize_rcu(void) { CDS_LIST_HEAD(cur_snap_readers); CDS_LIST_HEAD(qsreaders); @@ -232,7 +236,7 @@ void synchronize_rcu(void) DEFINE_URCU_WAIT_NODE(wait, URCU_WAIT_WAITING); struct urcu_waiters waiters; - was_online = rcu_read_ongoing(); + was_online = urcu_qsbr_read_ongoing(); /* All threads should read qparity before accessing data structure * where new ptr points to. In the "then" case, rcu_thread_offline @@ -243,7 +247,7 @@ void synchronize_rcu(void) * in threads registered as readers. */ if (was_online) - rcu_thread_offline(); + urcu_qsbr_thread_offline(); else cmm_smp_mb(); @@ -281,11 +285,11 @@ void synchronize_rcu(void) /* * Must finish waiting for quiescent state for original parity - * before committing next rcu_gp.ctr update to memory. Failure + * before committing next urcu_qsbr_gp.ctr update to memory. Failure * to do so could result in the writer waiting forever while new * readers are always accessing data (no progress). Enforce - * compiler-order of load URCU_TLS(rcu_reader).ctr before store - * to rcu_gp.ctr. + * compiler-order of load URCU_TLS(urcu_qsbr_reader).ctr before store + * to urcu_qsbr_gp.ctr. */ cmm_barrier(); @@ -297,14 +301,14 @@ void synchronize_rcu(void) cmm_smp_mb(); /* Switch parity: 0 -> 1, 1 -> 0 */ - CMM_STORE_SHARED(rcu_gp.ctr, rcu_gp.ctr ^ RCU_GP_CTR); + CMM_STORE_SHARED(urcu_qsbr_gp.ctr, urcu_qsbr_gp.ctr ^ URCU_QSBR_GP_CTR); /* - * Must commit rcu_gp.ctr update to memory before waiting for + * Must commit urcu_qsbr_gp.ctr update to memory before waiting for * quiescent state. Failure to do so could result in the writer * waiting forever while new readers are always accessing data - * (no progress). Enforce compiler-order of store to rcu_gp.ctr - * before load URCU_TLS(rcu_reader).ctr. + * (no progress). Enforce compiler-order of store to urcu_qsbr_gp.ctr + * before load URCU_TLS(urcu_qsbr_reader).ctr. */ cmm_barrier(); @@ -336,19 +340,19 @@ gp_end: * freed. */ if (was_online) - rcu_thread_online(); + urcu_qsbr_thread_online(); else cmm_smp_mb(); } #else /* !(CAA_BITS_PER_LONG < 64) */ -void synchronize_rcu(void) +void urcu_qsbr_synchronize_rcu(void) { CDS_LIST_HEAD(qsreaders); unsigned long was_online; DEFINE_URCU_WAIT_NODE(wait, URCU_WAIT_WAITING); struct urcu_waiters waiters; - was_online = rcu_read_ongoing(); + was_online = urcu_qsbr_read_ongoing(); /* * Mark the writer thread offline to make sure we don't wait for @@ -356,7 +360,7 @@ void synchronize_rcu(void) * in threads registered as readers. */ if (was_online) - rcu_thread_offline(); + urcu_qsbr_thread_offline(); else cmm_smp_mb(); @@ -386,14 +390,14 @@ void synchronize_rcu(void) goto out; /* Increment current G.P. */ - CMM_STORE_SHARED(rcu_gp.ctr, rcu_gp.ctr + RCU_GP_CTR); + CMM_STORE_SHARED(urcu_qsbr_gp.ctr, urcu_qsbr_gp.ctr + URCU_QSBR_GP_CTR); /* - * Must commit rcu_gp.ctr update to memory before waiting for + * Must commit urcu_qsbr_gp.ctr update to memory before waiting for * quiescent state. Failure to do so could result in the writer * waiting forever while new readers are always accessing data - * (no progress). Enforce compiler-order of store to rcu_gp.ctr - * before load URCU_TLS(rcu_reader).ctr. + * (no progress). Enforce compiler-order of store to urcu_qsbr_gp.ctr + * before load URCU_TLS(urcu_qsbr_reader).ctr. */ cmm_barrier(); @@ -421,74 +425,90 @@ out: urcu_wake_all_waiters(&waiters); gp_end: if (was_online) - rcu_thread_online(); + urcu_qsbr_thread_online(); else cmm_smp_mb(); } #endif /* !(CAA_BITS_PER_LONG < 64) */ +__attribute__((alias("urcu_qsbr_synchronize_rcu"))) +void synchronize_rcu_qsbr(); /* * library wrappers to be used by non-LGPL compatible source code. */ -void rcu_read_lock(void) +void urcu_qsbr_read_lock(void) { - _rcu_read_lock(); + _urcu_qsbr_read_lock(); } +__attribute__((alias("urcu_qsbr_read_lock"))) void rcu_read_lock_qsbr(); -void rcu_read_unlock(void) +void urcu_qsbr_read_unlock(void) { - _rcu_read_unlock(); + _urcu_qsbr_read_unlock(); } +__attribute__((alias("urcu_qsbr_read_unlock"))) void rcu_read_unlock_qsbr(); -int rcu_read_ongoing(void) +int urcu_qsbr_read_ongoing(void) { - return _rcu_read_ongoing(); + return _urcu_qsbr_read_ongoing(); } +__attribute__((alias("urcu_qsbr_read_ongoing"))) +void rcu_read_ongoing_qsbr(); -void rcu_quiescent_state(void) +void urcu_qsbr_quiescent_state(void) { - _rcu_quiescent_state(); + _urcu_qsbr_quiescent_state(); } +__attribute__((alias("urcu_qsbr_quiescent_state"))) +void rcu_quiescent_state_qsbr(); -void rcu_thread_offline(void) +void urcu_qsbr_thread_offline(void) { - _rcu_thread_offline(); + _urcu_qsbr_thread_offline(); } +__attribute__((alias("urcu_qsbr_thread_offline"))) +void rcu_thread_offline_qsbr(); -void rcu_thread_online(void) +void urcu_qsbr_thread_online(void) { - _rcu_thread_online(); + _urcu_qsbr_thread_online(); } +__attribute__((alias("urcu_qsbr_thread_online"))) +void rcu_thread_online_qsbr(); -void rcu_register_thread(void) +void urcu_qsbr_register_thread(void) { - URCU_TLS(rcu_reader).tid = pthread_self(); - assert(URCU_TLS(rcu_reader).ctr == 0); + URCU_TLS(urcu_qsbr_reader).tid = pthread_self(); + assert(URCU_TLS(urcu_qsbr_reader).ctr == 0); mutex_lock(&rcu_registry_lock); - assert(!URCU_TLS(rcu_reader).registered); - URCU_TLS(rcu_reader).registered = 1; - cds_list_add(&URCU_TLS(rcu_reader).node, ®istry); + assert(!URCU_TLS(urcu_qsbr_reader).registered); + URCU_TLS(urcu_qsbr_reader).registered = 1; + cds_list_add(&URCU_TLS(urcu_qsbr_reader).node, ®istry); mutex_unlock(&rcu_registry_lock); - _rcu_thread_online(); + _urcu_qsbr_thread_online(); } +__attribute__((alias("urcu_qsbr_register_thread"))) +void rcu_register_thread_qsbr(); -void rcu_unregister_thread(void) +void urcu_qsbr_unregister_thread(void) { /* * We have to make the thread offline otherwise we end up dealocking * with a waiting writer. */ - _rcu_thread_offline(); - assert(URCU_TLS(rcu_reader).registered); - URCU_TLS(rcu_reader).registered = 0; + _urcu_qsbr_thread_offline(); + assert(URCU_TLS(urcu_qsbr_reader).registered); + URCU_TLS(urcu_qsbr_reader).registered = 0; mutex_lock(&rcu_registry_lock); - cds_list_del(&URCU_TLS(rcu_reader).node); + cds_list_del(&URCU_TLS(urcu_qsbr_reader).node); mutex_unlock(&rcu_registry_lock); } +__attribute__((alias("urcu_qsbr_unregister_thread"))) +void rcu_unregister_thread_qsbr(); -void rcu_exit(void) +void urcu_qsbr_exit(void) { /* * Assertion disabled because call_rcu threads are now rcu @@ -496,8 +516,10 @@ void rcu_exit(void) * assert(cds_list_empty(®istry)); */ } +__attribute__((alias("urcu_qsbr_exit"))) void rcu_exit_qsbr(); DEFINE_RCU_FLAVOR(rcu_flavor); +DEFINE_RCU_FLAVOR_ALIAS(rcu_flavor, alias_rcu_flavor); #include "urcu-call-rcu-impl.h" #include "urcu-defer-impl.h" diff --git a/src/urcu-qsbr.h b/src/urcu-qsbr.h deleted file mode 100644 index 5e47ad6..0000000 --- a/src/urcu-qsbr.h +++ /dev/null @@ -1,140 +0,0 @@ -#ifndef _URCU_QSBR_H -#define _URCU_QSBR_H - -/* - * urcu-qsbr.h - * - * Userspace RCU QSBR header. - * - * LGPL-compatible code should include this header with : - * - * #define _LGPL_SOURCE - * #include - * - * 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 - -/* - * See urcu-pointer.h and urcu/static/urcu-pointer.h for pointer - * publication headers. - */ -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -#ifdef RCU_DEBUG /* For backward compatibility */ -#define DEBUG_RCU -#endif - -/* - * Important ! - * - * Each thread containing read-side critical sections must be registered - * with rcu_register_thread() before calling rcu_read_lock(). - * rcu_unregister_thread() should be called before the thread exits. - */ - -#ifdef _LGPL_SOURCE - -#include - -/* - * Mappings for static use of the userspace RCU library. - * Should only be used in LGPL-compatible code. - */ - -/* - * rcu_read_lock() - * rcu_read_unlock() - * - * Mark the beginning and end of a read-side critical section. - * DON'T FORGET TO USE rcu_register_thread/rcu_unregister_thread() - * FOR EACH THREAD WITH READ-SIDE CRITICAL SECTION. - */ -#define rcu_read_lock_qsbr _rcu_read_lock -#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_thread_offline_qsbr _rcu_thread_offline -#define rcu_thread_online_qsbr _rcu_thread_online - -#else /* !_LGPL_SOURCE */ - -/* - * 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 - * in the LGPL header for any code to use. However, the debug version is not - * nops and may contain sanity checks. To activate it, applications must be - * recompiled with -DDEBUG_RCU (even non-LGPL/GPL applications), or - * compiled against a urcu/config.h that has CONFIG_RCU_DEBUG defined. - * This is the best trade-off between license/performance/code - * triviality and library debugging & tracing features we could come up - * with. - */ - -#if (!defined(BUILD_QSBR_LIB) && !defined(DEBUG_RCU) && !defined(CONFIG_RCU_DEBUG)) - -static inline void rcu_read_lock(void) -{ -} - -static inline void rcu_read_unlock(void) -{ -} - -#else /* #if (!defined(BUILD_QSBR_LIB) && !defined(DEBUG_RCU) && !defined(CONFIG_RCU_DEBUG)) */ - -extern void rcu_read_lock(void); -extern void rcu_read_unlock(void); - -#endif /* #else #if (!defined(BUILD_QSBR_LIB) && !defined(DEBUG_RCU) && !defined(CONFIG_RCU_DEBUG)) */ - -extern int rcu_read_ongoing(void); -extern void rcu_quiescent_state(void); -extern void rcu_thread_offline(void); -extern void rcu_thread_online(void); - -#endif /* !_LGPL_SOURCE */ - -extern void synchronize_rcu(void); - -/* - * Reader thread registration. - */ -extern void rcu_register_thread(void); -extern void rcu_unregister_thread(void); - -#ifdef __cplusplus -} -#endif - -#include -#include -#include - -#endif /* _URCU_QSBR_H */ diff --git a/src/urcu-utils.h b/src/urcu-utils.h new file mode 100644 index 0000000..1d91bc9 --- /dev/null +++ b/src/urcu-utils.h @@ -0,0 +1,29 @@ +#ifndef _URCU_UTILS_H +#define _URCU_UTILS_H + +/* + * urcu-utils.h + * + * Userspace RCU library internal utils + * + * Copyright (c) 2018 Michael Jeanson + * + * 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 + */ + +#define urcu_stringify(a) _urcu_stringify(a) +#define _urcu_stringify(a) #a + +#endif /* _URCU_UTILS_H */ diff --git a/src/urcu.c b/src/urcu.c index c47f51b..c36119a 100644 --- a/src/urcu.c +++ b/src/urcu.c @@ -37,19 +37,21 @@ #include #include -#include "urcu/arch.h" -#include "urcu/wfcqueue.h" -#include "urcu/map/urcu.h" -#include "urcu/static/urcu.h" -#include "urcu-pointer.h" -#include "urcu/tls-compat.h" +#include +#include +#include +#include +#include +#include #include "urcu-die.h" #include "urcu-wait.h" +#include "urcu-utils.h" +#define URCU_API_MAP /* Do not #define _LGPL_SOURCE to ensure we can emit the wrapper symbols */ #undef _LGPL_SOURCE -#include "urcu.h" +#include #define _LGPL_SOURCE /* @@ -82,10 +84,16 @@ enum membarrier_cmd { #ifdef RCU_MEMBARRIER static int init_done; -static int has_sys_membarrier_private_expedited; +static int urcu_memb_has_sys_membarrier_private_expedited; #ifndef CONFIG_RCU_FORCE_SYS_MEMBARRIER -int rcu_has_sys_membarrier_memb; +/* + * Explicitly initialize to zero because we can't alias a non-static + * uninitialized variable. + */ +int urcu_memb_has_sys_membarrier = 0; +__attribute__((alias("urcu_memb_has_sys_membarrier"))) +extern int rcu_has_sys_membarrier_memb; #endif void __attribute__((constructor)) rcu_init(void); @@ -95,6 +103,8 @@ void __attribute__((constructor)) rcu_init(void); void rcu_init(void) { } +__attribute__((alias(urcu_stringify(rcu_init)))) +void alias_rcu_init(void); #endif #ifdef RCU_SIGNAL @@ -119,13 +129,17 @@ static pthread_mutex_t rcu_gp_lock = PTHREAD_MUTEX_INITIALIZER; * rcu_registry_lock may nest inside rcu_gp_lock. */ static pthread_mutex_t rcu_registry_lock = PTHREAD_MUTEX_INITIALIZER; -struct rcu_gp rcu_gp = { .ctr = RCU_GP_COUNT }; +struct urcu_gp rcu_gp = { .ctr = URCU_GP_COUNT }; +__attribute__((alias(urcu_stringify(rcu_gp)))) +extern struct urcu_gp alias_rcu_gp; /* * Written to only by each individual reader. Read by both the reader and the * writers. */ -DEFINE_URCU_TLS(struct rcu_reader, rcu_reader); +DEFINE_URCU_TLS(struct urcu_reader, rcu_reader); +__attribute__((alias(urcu_stringify(rcu_reader)))) +extern struct urcu_reader alias_rcu_reader; static CDS_LIST_HEAD(registry); @@ -169,8 +183,8 @@ static void mutex_unlock(pthread_mutex_t *mutex) #ifdef RCU_MEMBARRIER static void smp_mb_master(void) { - if (caa_likely(rcu_has_sys_membarrier_memb)) { - if (membarrier(has_sys_membarrier_private_expedited ? + if (caa_likely(urcu_memb_has_sys_membarrier)) { + if (membarrier(urcu_memb_has_sys_membarrier_private_expedited ? MEMBARRIER_CMD_PRIVATE_EXPEDITED : MEMBARRIER_CMD_SHARED, 0)) urcu_die(errno); @@ -190,7 +204,7 @@ static void smp_mb_master(void) #ifdef RCU_SIGNAL static void force_mb_all_readers(void) { - struct rcu_reader *index; + struct urcu_reader *index; /* * Ask for each threads to execute a cmm_smp_mb() so we can consider the @@ -283,7 +297,7 @@ static void wait_for_readers(struct cds_list_head *input_readers, struct cds_list_head *qsreaders) { unsigned int wait_loops = 0; - struct rcu_reader *index, *tmp; + struct urcu_reader *index, *tmp; #ifdef HAS_INCOHERENT_CACHES unsigned int wait_gp_loops = 0; #endif /* HAS_INCOHERENT_CACHES */ @@ -303,18 +317,18 @@ static void wait_for_readers(struct cds_list_head *input_readers, } cds_list_for_each_entry_safe(index, tmp, input_readers, node) { - switch (rcu_reader_state(&index->ctr)) { - case RCU_READER_ACTIVE_CURRENT: + switch (urcu_common_reader_state(&rcu_gp, &index->ctr)) { + case URCU_READER_ACTIVE_CURRENT: if (cur_snap_readers) { cds_list_move(&index->node, cur_snap_readers); break; } /* Fall-through */ - case RCU_READER_INACTIVE: + case URCU_READER_INACTIVE: cds_list_move(&index->node, qsreaders); break; - case RCU_READER_ACTIVE_OLD: + case URCU_READER_ACTIVE_OLD: /* * Old snapshot. Leaving node in * input_readers will make us busy-loop @@ -454,7 +468,7 @@ void synchronize_rcu(void) cmm_smp_mb(); /* Switch parity: 0 -> 1, 1 -> 0 */ - CMM_STORE_SHARED(rcu_gp.ctr, rcu_gp.ctr ^ RCU_GP_CTR_PHASE); + CMM_STORE_SHARED(rcu_gp.ctr, rcu_gp.ctr ^ URCU_GP_CTR_PHASE); /* * Must commit rcu_gp.ctr update to memory before waiting for quiescent @@ -501,6 +515,8 @@ out: */ urcu_wake_all_waiters(&waiters); } +__attribute__((alias(urcu_stringify(synchronize_rcu)))) +void alias_synchronize_rcu(); /* * library wrappers to be used by non-LGPL compatible source code. @@ -510,22 +526,28 @@ void rcu_read_lock(void) { _rcu_read_lock(); } +__attribute__((alias(urcu_stringify(rcu_read_lock)))) +void alias_rcu_read_lock(); void rcu_read_unlock(void) { _rcu_read_unlock(); } +__attribute__((alias(urcu_stringify(rcu_read_unlock)))) +void alias_rcu_read_unlock(); int rcu_read_ongoing(void) { return _rcu_read_ongoing(); } +__attribute__((alias(urcu_stringify(rcu_read_ongoing)))) +void alias_rcu_read_ongoing(); void rcu_register_thread(void) { URCU_TLS(rcu_reader).tid = pthread_self(); assert(URCU_TLS(rcu_reader).need_mb == 0); - assert(!(URCU_TLS(rcu_reader).ctr & RCU_GP_CTR_NEST_MASK)); + assert(!(URCU_TLS(rcu_reader).ctr & URCU_GP_CTR_NEST_MASK)); mutex_lock(&rcu_registry_lock); assert(!URCU_TLS(rcu_reader).registered); @@ -534,6 +556,8 @@ void rcu_register_thread(void) cds_list_add(&URCU_TLS(rcu_reader).node, ®istry); mutex_unlock(&rcu_registry_lock); } +__attribute__((alias(urcu_stringify(rcu_register_thread)))) +void alias_rcu_register_thread(); void rcu_unregister_thread(void) { @@ -543,6 +567,8 @@ void rcu_unregister_thread(void) cds_list_del(&URCU_TLS(rcu_reader).node); mutex_unlock(&rcu_registry_lock); } +__attribute__((alias(urcu_stringify(rcu_unregister_thread)))) +void alias_rcu_unregister_thread(); #ifdef RCU_MEMBARRIER @@ -559,7 +585,7 @@ void rcu_sys_membarrier_status(bool available) { if (!available) return; - rcu_has_sys_membarrier_memb = 1; + urcu_memb_has_sys_membarrier = 1; } #endif @@ -574,7 +600,7 @@ void rcu_sys_membarrier_init(void) if (mask & MEMBARRIER_CMD_PRIVATE_EXPEDITED) { if (membarrier(MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED, 0)) urcu_die(errno); - has_sys_membarrier_private_expedited = 1; + urcu_memb_has_sys_membarrier_private_expedited = 1; available = true; } else if (mask & MEMBARRIER_CMD_SHARED) { available = true; @@ -590,6 +616,8 @@ void rcu_init(void) init_done = 1; rcu_sys_membarrier_init(); } +__attribute__((alias(urcu_stringify(rcu_init)))) +void alias_rcu_init(void); #endif #ifdef RCU_SIGNAL @@ -629,6 +657,8 @@ void rcu_init(void) if (ret) urcu_die(errno); } +__attribute__((alias(urcu_stringify(rcu_init)))) +void alias_rcu_init(void); void rcu_exit(void) { @@ -641,10 +671,13 @@ void rcu_exit(void) * assert(cds_list_empty(®istry)); */ } +__attribute__((alias(urcu_stringify(rcu_exit)))) +void alias_rcu_exit(void); #endif /* #ifdef RCU_SIGNAL */ DEFINE_RCU_FLAVOR(rcu_flavor); +DEFINE_RCU_FLAVOR_ALIAS(rcu_flavor, alias_rcu_flavor); #include "urcu-call-rcu-impl.h" #include "urcu-defer-impl.h" diff --git a/src/urcu.h b/src/urcu.h deleted file mode 100644 index 85d4a4c..0000000 --- a/src/urcu.h +++ /dev/null @@ -1,137 +0,0 @@ -#ifndef _URCU_H -#define _URCU_H - -/* - * urcu.h - * - * Userspace RCU header - * - * Copyright (c) 2009 Mathieu Desnoyers - * Copyright (c) 2009 Paul E. McKenney, IBM Corporation. - * - * LGPL-compatible code should include this header with : - * - * #define _LGPL_SOURCE - * #include - * - * 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 - -/* - * See urcu-pointer.h and urcu/static/urcu-pointer.h for pointer - * publication headers. - */ -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -/* - * Important ! - * - * Each thread containing read-side critical sections must be registered - * with rcu_register_thread_mb() before calling rcu_read_lock_mb(). - * rcu_unregister_thread_mb() should be called before the thread exits. - */ - -#ifdef _LGPL_SOURCE - -#include - -/* - * Mappings for static use of the userspace RCU library. - * Should only be used in LGPL-compatible code. - */ - -/* - * 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. - */ -#ifdef RCU_MEMBARRIER -#define rcu_read_lock_memb _rcu_read_lock -#define rcu_read_unlock_memb _rcu_read_unlock -#define rcu_read_ongoing_memb _rcu_read_ongoing -#elif defined(RCU_SIGNAL) -#define rcu_read_lock_sig _rcu_read_lock -#define rcu_read_unlock_sig _rcu_read_unlock -#define rcu_read_ongoing_sig _rcu_read_ongoing -#elif defined(RCU_MB) -#define rcu_read_lock_mb _rcu_read_lock -#define rcu_read_unlock_mb _rcu_read_unlock -#define rcu_read_ongoing_mb _rcu_read_ongoing -#endif - -#else /* !_LGPL_SOURCE */ - -/* - * library wrappers to be used by non-LGPL compatible source code. - * See LGPL-only urcu/static/urcu-pointer.h for documentation. - */ - -extern void rcu_read_lock(void); -extern void rcu_read_unlock(void); -extern int rcu_read_ongoing(void); - -#endif /* !_LGPL_SOURCE */ - -extern void synchronize_rcu(void); - -/* - * Reader thread registration. - */ -extern void rcu_register_thread(void); -extern void rcu_unregister_thread(void); - -/* - * Explicit rcu initialization, for "early" use within library constructors. - */ -extern void rcu_init(void); - -/* - * Q.S. reporting are no-ops for these URCU flavors. - */ -static inline void rcu_quiescent_state(void) -{ -} - -static inline void rcu_thread_offline(void) -{ -} - -static inline void rcu_thread_online(void) -{ -} - -#ifdef __cplusplus -} -#endif - -#include -#include -#include - -#endif /* _URCU_H */