From: Olivier Dion Date: Mon, 14 Aug 2023 20:40:30 +0000 (-0400) Subject: Phase 1 of deprecating liburcu-signal X-Git-Url: https://git.liburcu.org/?p=urcu.git;a=commitdiff_plain;h=97d13221f8a10e9ba38821dea2c2ff299d166c71 Phase 1 of deprecating liburcu-signal The first phase of liburcu-signal deprecation consists of implementing it in term of liburcu-mb. In other words, liburcu-signal is identical to liburcu-mb at the exception of the function symbols and public header files. This is done by: 1) Removing the RCU_SIGNAL specific code in urcu.c 2) Making the RCU_MB specific code also specific to RCU_SIGNAL in urcu.c 3) Rewriting _urcu_signal_read_unlock_update_and_wakeup to use a atomic store with CMM_SEQ_CST instead of a store CMM_RELAXED with cmm_barrier() around it. We could keep the explicit barriers, but that would require to add some cmm_annotate annotations. Therefore, to be less intrusive in a public header file, simply use the CMM_SEQ_CST like for the mb flavor. Change-Id: Ie406f7df2f47da0a9f464df94b968ad9204821f3 Signed-off-by: Olivier Dion Signed-off-by: Mathieu Desnoyers --- diff --git a/README.md b/README.md index d7966a2..58db299 100644 --- a/README.md +++ b/README.md @@ -220,9 +220,10 @@ results in slower reads. 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`. - +NOTE: The `liburcu-signal` flavor is *deprecated* and will be removed in the +future. It is now identical to `liburcu-mb` at the exception of the symbols and +public header files. It is therefore slower than previous versions. Users are +encouraged to migrate to the `liburcu-memb` flavor. ### Usage of `liburcu-bp` diff --git a/include/urcu/static/urcu-signal.h b/include/urcu/static/urcu-signal.h index baee229..0f78ac0 100644 --- a/include/urcu/static/urcu-signal.h +++ b/include/urcu/static/urcu-signal.h @@ -95,13 +95,14 @@ static inline void _urcu_signal_read_lock(void) */ static inline void _urcu_signal_read_unlock_update_and_wakeup(unsigned long tmp) { + unsigned long *ctr = &URCU_TLS(urcu_signal_reader).ctr; + 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(); + uatomic_store(ctr, tmp - URCU_GP_COUNT, CMM_SEQ_CST); urcu_common_wake_up_gp(&urcu_signal_gp); - } else - _CMM_STORE_SHARED(URCU_TLS(urcu_signal_reader).ctr, tmp - URCU_GP_COUNT); + } else { + uatomic_store(ctr, tmp - URCU_GP_COUNT, CMM_RELAXED); + } } /* diff --git a/src/urcu.c b/src/urcu.c index 76c8720..984e929 100644 --- a/src/urcu.c +++ b/src/urcu.c @@ -86,20 +86,12 @@ int urcu_memb_has_sys_membarrier = 0; void __attribute__((constructor)) rcu_init(void); #endif -#ifdef RCU_MB +#if defined(RCU_MB) || defined(RCU_SIGNAL) void rcu_init(void) { } #endif -#ifdef RCU_SIGNAL -static int init_done; - -void __attribute__((constructor)) rcu_init(void); - -static DEFINE_URCU_TLS(int, rcu_signal_was_blocked); -#endif - void __attribute__((destructor)) rcu_exit(void); static void urcu_call_rcu_exit(void); @@ -179,62 +171,13 @@ static void smp_mb_master(void) } #endif -#ifdef RCU_MB +#if defined(RCU_MB) || defined(RCU_SIGNAL) static void smp_mb_master(void) { cmm_smp_mb(); } #endif -#ifdef RCU_SIGNAL -static void force_mb_all_readers(void) -{ - struct urcu_reader *index; - - /* - * Ask for each threads to execute a cmm_smp_mb() so we can consider the - * compiler barriers around rcu read lock as real memory barriers. - */ - if (cds_list_empty(®istry)) - return; - /* - * pthread_kill has a cmm_smp_mb(). But beware, we assume it performs - * a cache flush on architectures with non-coherent cache. Let's play - * safe and don't assume anything : we use cmm_smp_mc() to make sure the - * cache flush is enforced. - */ - cds_list_for_each_entry(index, ®istry, node) { - CMM_STORE_SHARED(index->need_mb, 1); - pthread_kill(index->tid, SIGRCU); - } - /* - * Wait for sighandler (and thus mb()) to execute on every thread. - * - * Note that the pthread_kill() will never be executed on systems - * that correctly deliver signals in a timely manner. However, it - * is not uncommon for kernels to have bugs that can result in - * lost or unduly delayed signals. - * - * If you are seeing the below pthread_kill() executing much at - * all, we suggest testing the underlying kernel and filing the - * relevant bug report. For Linux kernels, we recommend getting - * the Linux Test Project (LTP). - */ - cds_list_for_each_entry(index, ®istry, node) { - while (CMM_LOAD_SHARED(index->need_mb)) { - pthread_kill(index->tid, SIGRCU); - (void) poll(NULL, 0, 1); - } - } - cmm_smp_mb(); /* read ->need_mb before ending the barrier */ -} - -static void smp_mb_master(void) -{ - force_mb_all_readers(); -} -#endif /* #ifdef RCU_SIGNAL */ - /* * synchronize_rcu() waiting. Single thread. * Always called with rcu_registry lock held. Releases this lock and @@ -243,9 +186,7 @@ static void smp_mb_master(void) static void wait_gp(void) { /* - * Read reader_gp before read futex. smp_mb_master() needs to - * be called with the rcu registry lock held in RCU_SIGNAL - * flavor. + * Read reader_gp before read futex. */ smp_mb_master(); /* Temporarily unlock the registry lock. */ @@ -535,52 +476,8 @@ int rcu_read_ongoing(void) return _rcu_read_ongoing(); } -#ifdef RCU_SIGNAL -/* - * Make sure the signal used by the urcu-signal flavor is unblocked - * while the thread is registered. - */ -static -void urcu_signal_unblock(void) -{ - sigset_t mask, oldmask; - int ret; - - ret = sigemptyset(&mask); - urcu_posix_assert(!ret); - ret = sigaddset(&mask, SIGRCU); - urcu_posix_assert(!ret); - ret = pthread_sigmask(SIG_UNBLOCK, &mask, &oldmask); - urcu_posix_assert(!ret); - URCU_TLS(rcu_signal_was_blocked) = sigismember(&oldmask, SIGRCU); -} - -static -void urcu_signal_restore(void) -{ - sigset_t mask; - int ret; - - if (!URCU_TLS(rcu_signal_was_blocked)) - return; - ret = sigemptyset(&mask); - urcu_posix_assert(!ret); - ret = sigaddset(&mask, SIGRCU); - urcu_posix_assert(!ret); - ret = pthread_sigmask(SIG_BLOCK, &mask, NULL); - urcu_posix_assert(!ret); -} -#else -static -void urcu_signal_unblock(void) { } -static -void urcu_signal_restore(void) { } -#endif - void rcu_register_thread(void) { - urcu_signal_unblock(); - URCU_TLS(rcu_reader).tid = pthread_self(); urcu_posix_assert(URCU_TLS(rcu_reader).need_mb == 0); urcu_posix_assert(!(URCU_TLS(rcu_reader).ctr & URCU_GP_CTR_NEST_MASK)); @@ -600,8 +497,6 @@ void rcu_unregister_thread(void) URCU_TLS(rcu_reader).registered = 0; cds_list_del(&URCU_TLS(rcu_reader).node); mutex_unlock(&rcu_registry_lock); - - urcu_signal_restore(); } #ifdef RCU_MEMBARRIER @@ -652,57 +547,6 @@ void rcu_init(void) } #endif -#ifdef RCU_SIGNAL -static void sigrcu_handler(int signo __attribute__((unused)), - siginfo_t *siginfo __attribute__((unused)), - void *context __attribute__((unused))) -{ - /* - * Executing this cmm_smp_mb() is the only purpose of this signal handler. - * It punctually promotes cmm_barrier() into cmm_smp_mb() on every thread it is - * executed on. - */ - cmm_smp_mb(); - _CMM_STORE_SHARED(URCU_TLS(rcu_reader).need_mb, 0); - cmm_smp_mb(); -} - -/* - * rcu_init constructor. Called when the library is linked, but also when - * reader threads are calling rcu_register_thread(). - * Should only be called by a single thread at a given time. This is ensured by - * holing the rcu_registry_lock from rcu_register_thread() or by running - * at library load time, which should not be executed by multiple - * threads nor concurrently with rcu_register_thread() anyway. - */ -void rcu_init(void) -{ - struct sigaction act; - int ret; - - if (init_done) - return; - init_done = 1; - - act.sa_sigaction = sigrcu_handler; - act.sa_flags = SA_SIGINFO | SA_RESTART; - sigemptyset(&act.sa_mask); - ret = sigaction(SIGRCU, &act, NULL); - if (ret) - urcu_die(errno); -} - -/* - * Don't unregister the SIGRCU signal handler anymore, because - * call_rcu threads could still be using it shortly before the - * application exits. - * Assertion disabled because call_rcu threads are now rcu - * readers, and left running at exit. - * urcu_posix_assert(cds_list_empty(®istry)); - */ - -#endif /* #ifdef RCU_SIGNAL */ - void rcu_exit(void) { urcu_call_rcu_exit();