From: Mathieu Desnoyers Date: Thu, 29 Nov 2018 20:49:11 +0000 (-0500) Subject: Update README following API changes X-Git-Tag: v0.11.0~23 X-Git-Url: https://git.lttng.org./?a=commitdiff_plain;h=f328865f6a3f75fc14388be0e9fc5507015af3a8;p=userspace-rcu.git Update README following API changes Signed-off-by: Mathieu Desnoyers --- diff --git a/README.md b/README.md index 4615746..7a33cd7 100644 --- a/README.md +++ b/README.md @@ -37,8 +37,8 @@ Architectures supported Currently, the following architectures are supported: - - Linux x86 (i386, i486, i586, i686) - - x86 64-bit + - x86 (i386, i486, i586, i686) + - amd64 / x86_64 - PowerPC 32/64 - S390, S390x - ARM 32/64 @@ -49,8 +49,17 @@ Currently, the following architectures are supported: - Sparcv9 32/64 - Tilera - hppa/PA-RISC + - m68k + - RISC-V + +Tested on: + + - Linux all architectures + - FreeBSD 8.2/8.3/9.0/9.1/10.0 i386/amd64 + - Solaris 10/11 i386 + - Cygwin i386/amd64 + - MacOSX amd64 -Tested on Linux, FreeBSD 8.2/8.3/9.0/9.1/10.0 i386/amd64, and Cygwin. Should also work on: - Android @@ -149,11 +158,22 @@ the library major version number. Applications using `URCU_INLINE_SMALL_FUNCTIONS` may be unable to use debugging features of Userspace RCU without being recompiled. +There are multiple flavors of liburcu available: + + - `memb`, + - `qsbr`, + - `mb`, + - `signal`, + - `bp`. + +The API members start with the prefix "urcu__", where + is the chosen flavor name. + -### Usage of `liburcu` +### Usage of `liburcu-memb` - 1. `#include ` - 2. Link the application with `-lurcu` + 1. `#include ` + 2. Link the application with `-lurcu-memb` This is the preferred version of the library, in terms of grace-period detection speed, read-side speed and flexibility. @@ -168,7 +188,7 @@ supported. ### Usage of `liburcu-qsbr` - 1. `#include ` + 1. `#include ` 2. Link with `-lurcu-qsbr` The QSBR flavor of RCU needs to have each reader thread executing @@ -180,9 +200,8 @@ expense of more intrusiveness in the application code. ### Usage of `liburcu-mb` - 1. `#include ` - 2. Compile any `_LGPL_SOURCE` code using this library with `-DRCU_MB` - 3. Link with `-lurcu-mb` + 1. `#include ` + 2. Link with `-lurcu-mb` This version of the urcu library uses memory barriers on the writer and reader sides. This results in faster grace-period detection, but @@ -191,9 +210,8 @@ results in slower reads. ### Usage of `liburcu-signal` - 1. `#include ` - 2. Compile any `_LGPL_SOURCE` code using this library with `-DRCU_SIGNAL` - 3. Link the application with `-lurcu-signal` + 1. `#include ` + 2. Link the application with `-lurcu-signal` Version of the library that requires a signal, typically `SIGUSR1`. Can be overridden with `-DSIGRCU` by modifying `Makefile.build.inc`. @@ -201,115 +219,117 @@ be overridden with `-DSIGRCU` by modifying `Makefile.build.inc`. ### Usage of `liburcu-bp` - 1. `#include ` + 1. `#include ` 2. Link with `-lurcu-bp` The BP library flavor stands for "bulletproof". It is specifically designed to help tracing library to hook on applications without -requiring to modify these applications. `rcu_init()`, -`rcu_register_thread()` and `rcu_unregister_thread()` all become nops. -The state is dealt with by the library internally at the expense of -read-side and write-side performance. +requiring to modify these applications. `urcu_bp_init()`, +`urcu_bp_register_thread()` and `urcu_bp_unregister_thread()` all become +nops. The state is dealt with by the library internally at the expense +of read-side and write-side performance. ### Initialization Each thread that has reader critical sections (that uses -`rcu_read_lock()`/`rcu_read_unlock()` must first register to the URCU -library. This is done by calling `rcu_register_thread()`. Unregistration -must be performed before exiting the thread by using -`rcu_unregister_thread()`. +`urcu__read_lock()`/`urcu__read_unlock()` must first +register to the URCU library. This is done by calling +`urcu__register_thread()`. Unregistration must be performed +before exiting the thread by using `urcu__unregister_thread()`. ### Reading Reader critical sections must be protected by locating them between -calls to `rcu_read_lock()` and `rcu_read_unlock()`. Inside that lock, -`rcu_dereference()` may be called to read an RCU protected pointer. +calls to `urcu__read_lock()` and `urcu__read_unlock()`. +Inside that lock, `rcu_dereference()` may be called to read an RCU +protected pointer. ### Writing `rcu_assign_pointer()` and `rcu_xchg_pointer()` may be called anywhere. -After, `synchronize_rcu()` must be called. When it returns, the old -values are not in usage anymore. +After, `urcu__synchronize_rcu()` must be called. When it +returns, the old values are not in usage anymore. ### Usage of `liburcu-defer` - - Follow instructions for either `liburcu`, `liburcu-qsbr`, + - Follow instructions for either `liburcu-memb`, `liburcu-qsbr`, `liburcu-mb`, `liburcu-signal`, or `liburcu-bp` above. The `liburcu-defer` functionality is pulled into each of those library modules. - - Provides `defer_rcu()` primitive to enqueue delayed callbacks. Queued - callbacks are executed in batch periodically after a grace period. - Do _not_ use `defer_rcu()` within a read-side critical section, because - it may call `synchronize_rcu()` if the thread queue is full. - This can lead to deadlock or worse. - - Requires that `rcu_defer_barrier()` must be called in library destructor - if a library queues callbacks and is expected to be unloaded with - `dlclose()`. + - Provides `urcu__defer_rcu()` primitive to enqueue delayed + callbacks. Queued callbacks are executed in batch periodically after + a grace period. Do _not_ use `urcu__defer_rcu()` within a + read-side critical section, because it may call + `urcu__synchronize_rcu()` if the thread queue is full. This + can lead to deadlock or worse. + - Requires that `urcu__defer_barrier()` must be called in + library destructor if a library queues callbacks and is expected to + be unloaded with `dlclose()`. Its API is currently experimental. It may change in future library releases. ### Usage of `urcu-call-rcu` - - Follow instructions for either `liburcu`, `liburcu-qsbr`, + - Follow instructions for either `liburcu-memb`, `liburcu-qsbr`, `liburcu-mb`, `liburcu-signal`, or `liburcu-bp` above. The `urcu-call-rcu` functionality is pulled into each of those library modules. - - Provides the `call_rcu()` primitive to enqueue delayed callbacks - in a manner similar to `defer_rcu()`, but without ever delaying - for a grace period. On the other hand, `call_rcu()`'s best-case - overhead is not quite as good as that of `defer_rcu()`. - - Provides `call_rcu()` to allow asynchronous handling of RCU - grace periods. A number of additional functions are provided - to manage the helper threads used by `call_rcu()`, but reasonable - defaults are used if these additional functions are not invoked. - See [`doc/rcu-api.md`](doc/rcu-api.md) in userspace-rcu documentation - for more details. + - Provides the `urcu__call_rcu()` primitive to enqueue delayed + callbacks in a manner similar to `urcu__defer_rcu()`, but + without ever delaying for a grace period. On the other hand, + `urcu__call_rcu()`'s best-case overhead is not quite as good + as that of `urcu__defer_rcu()`. + - Provides `urcu__call_rcu()` to allow asynchronous handling + of RCU grace periods. A number of additional functions are provided + to manage the helper threads used by `urcu__call_rcu()`, but + reasonable defaults are used if these additional functions are not + invoked. See [`doc/rcu-api.md`](doc/rcu-api.md) in userspace-rcu + documentation for more details. ### Being careful with signals -The `liburcu` library uses signals internally. The signal handler is +The `liburcu-signal` library uses signals internally. The signal handler is registered with the `SA_RESTART` flag. However, these signals may cause some non-restartable system calls to fail with `errno = EINTR`. Care should be taken to restart system calls manually if they fail with this error. A list of non-restartable system calls may be found in -`signal(7)`. The `liburcu-mb` and `liburcu-qsbr` versions of the Userspace RCU -library do not require any signal. +`signal(7)`. Read-side critical sections are allowed in a signal handler, -except those setup with `sigaltstack(2)`, with `liburcu` and +except those setup with `sigaltstack(2)`, with `liburcu-memb` and `liburcu-mb`. Be careful, however, to disable these signals -between thread creation and calls to `rcu_register_thread()`, because a -signal handler nesting on an unregistered thread would not be -allowed to call `rcu_read_lock()`. +between thread creation and calls to `urcu__register_thread()`, +because a signal handler nesting on an unregistered thread would not be +allowed to call `urcu__read_lock()`. Read-side critical sections are _not_ allowed in a signal handler with `liburcu-qsbr`, unless signals are disabled explicitly around each -`rcu_quiescent_state()` calls, when threads are put offline and around -calls to `synchronize_rcu()`. Even then, we do not recommend it. +`urcu_qsbr_quiescent_state()` calls, when threads are put offline and around +calls to `urcu_qsbr_synchronize_rcu()`. Even then, we do not recommend it. ### Interaction with mutexes One must be careful to do not cause deadlocks due to interaction of -`synchronize_rcu()` and RCU read-side with mutexes. If `synchronize_rcu()` -is called with a mutex held, this mutex (or any mutex which has this -mutex in its dependency chain) should not be acquired from within a RCU -read-side critical section. +`urcu__synchronize_rcu()` and RCU read-side with mutexes. If +`urcu__synchronize_rcu()` is called with a mutex held, this +mutex (or any mutex which has this mutex in its dependency chain) should +not be acquired from within a RCU read-side critical section. This is especially important to understand in the context of the QSBR flavor: a registered reader thread being "online" by default should be considered as within a RCU read-side critical section unless explicitly put "offline". Therefore, if -`synchronize_rcu()` is called with a mutex held, this mutex, as -well as any mutex which has this mutex in its dependency chain -should only be taken when the RCU reader thread is "offline" -(this can be performed by calling `rcu_thread_offline()`). +`urcu_qsbr_synchronize_rcu()` is called with a mutex held, this mutex, +as well as any mutex which has this mutex in its dependency chain should +only be taken when the RCU reader thread is "offline" (this can be +performed by calling `urcu_qsbr_thread_offline()`). ### Interaction with `fork()` @@ -323,28 +343,28 @@ threads) should be released before a `fork()` is performed, except for the rather common scenario where `fork()` is immediately followed by `exec()` in the child process. The only implementation not subject to that rule is `liburcu-bp`, which is designed to handle `fork()` by calling -`rcu_bp_before_fork`, `rcu_bp_after_fork_parent` and -`rcu_bp_after_fork_child`. - -Applications that use `call_rcu()` and that `fork()` without -doing an immediate `exec()` must take special action. The parent -must invoke `call_rcu_before_fork()` before the `fork()` and -`call_rcu_after_fork_parent()` after the `fork()`. The child -process must invoke `call_rcu_after_fork_child()`. -Even though these three APIs are suitable for passing to -`pthread_atfork()`, use of `pthread_atfork()` is **STRONGLY -DISCOURAGED** for programs calling the glibc memory allocator -(`malloc()`, `calloc()`, `free()`, ...) within `call_rcu` callbacks. -This is due to limitations in the way glibc memory allocator -handles calls to the memory allocator from concurrent threads -while the `pthread_atfork()` handlers are executing. +`urcu_bp_before_fork`, `urcu_bp_after_fork_parent` and +`urcu_bp_after_fork_child`. + +Applications that use `urcu__call_rcu()` and that `fork()` +without doing an immediate `exec()` must take special action. The +parent must invoke `urcu__call_rcu_before_fork()` before the +`fork()` and `urcu__call_rcu_after_fork_parent()` after the +`fork()`. The child process must invoke +`urcu__call_rcu_after_fork_child()`. Even though these three +APIs are suitable for passing to `pthread_atfork()`, use of +`pthread_atfork()` is **STRONGLY DISCOURAGED** for programs calling the +glibc memory allocator (`malloc()`, `calloc()`, `free()`, ...) within +`urcu__call_rcu` callbacks. This is due to limitations in the +way glibc memory allocator handles calls to the memory allocator from +concurrent threads while the `pthread_atfork()` handlers are executing. Combining e.g.: - - call to `free()` from callbacks executed within `call_rcu` worker - threads, - - executing `call_rcu` atfork handlers within the glibc pthread - atfork mechanism, + - call to `free()` from callbacks executed within + `urcu__call_rcu` worker threads, + - executing `urcu__call_rcu` atfork handlers within the glibc + pthread atfork mechanism, will sometimes trigger interesting process hangs. This usually hangs on a memory allocator lock within glibc.