From 111bda8f5fa6ff4d5d50605ccbe56d9622498ef4 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Thu, 2 Feb 2023 14:32:15 -0500 Subject: [PATCH] urcu-memb,mb,signal: Implement grace period polling Implement a grace period polling mechanism for each urcu flavor. Its use is documented in README.md. Signed-off-by: Mathieu Desnoyers Change-Id: Ibd4642f2821ecd55ce40b9372d2be7ab451f9644 --- README.md | 8 +++ include/Makefile.am | 3 +- include/urcu/flavor.h | 7 +++ include/urcu/map/clear.h | 3 + include/urcu/map/urcu-bp.h | 3 + include/urcu/map/urcu-mb.h | 3 + include/urcu/map/urcu-memb.h | 3 + include/urcu/map/urcu-qsbr.h | 4 ++ include/urcu/map/urcu-signal.h | 3 + include/urcu/urcu-bp.h | 8 +++ include/urcu/urcu-mb.h | 8 +++ include/urcu/urcu-memb.h | 8 +++ include/urcu/urcu-poll.h | 30 ++++++++++ include/urcu/urcu-qsbr.h | 8 +++ include/urcu/urcu-signal.h | 8 +++ src/Makefile.am | 1 + src/urcu-bp.c | 1 + src/urcu-poll-impl.h | 100 +++++++++++++++++++++++++++++++++ src/urcu-qsbr.c | 1 + src/urcu.c | 1 + 20 files changed, 210 insertions(+), 1 deletion(-) create mode 100644 include/urcu/urcu-poll.h create mode 100644 src/urcu-poll-impl.h diff --git a/README.md b/README.md index 2fe14c3..ba5bb08 100644 --- a/README.md +++ b/README.md @@ -250,6 +250,14 @@ protected pointer. After, `urcu__synchronize_rcu()` must be called. When it returns, the old values are not in usage anymore. +As an alternative to `urcu__synchronize_rcu()`, +it is also possible to use the urcu polling mechanism to wait for a +grace period to elapse. This can be done by using +`urcu__start_poll_synchronize_rcu()` +to start the grace period polling, and then invoke +`urcu__poll_state_synchronize_rcu()`, which returns true if +the grace period has completed, false otherwise. + ### Usage of `liburcu-defer` diff --git a/include/Makefile.am b/include/Makefile.am index b55bcf0..ba1fe60 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -87,7 +87,8 @@ nobase_include_HEADERS = \ urcu/urcu-signal.h \ urcu/wfcqueue.h \ urcu/wfqueue.h \ - urcu/wfstack.h + urcu/wfstack.h \ + urcu/urcu-poll.h # Don't distribute generated headers nobase_nodist_include_HEADERS = urcu/config.h diff --git a/include/urcu/flavor.h b/include/urcu/flavor.h index 1a92089..20d32b6 100644 --- a/include/urcu/flavor.h +++ b/include/urcu/flavor.h @@ -23,6 +23,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include + #ifdef __cplusplus extern "C" { #endif @@ -58,6 +60,9 @@ struct rcu_flavor_struct { void (*register_rculfhash_atfork)(struct urcu_atfork *atfork); void (*unregister_rculfhash_atfork)(struct urcu_atfork *atfork); + + struct urcu_gp_poll_state (*update_start_poll_synchronize_rcu)(void); + bool (*update_poll_state_synchronize_rcu)(struct urcu_gp_poll_state state); }; #define DEFINE_RCU_FLAVOR(x) \ @@ -76,6 +81,8 @@ const struct rcu_flavor_struct x = { \ .barrier = rcu_barrier, \ .register_rculfhash_atfork = urcu_register_rculfhash_atfork, \ .unregister_rculfhash_atfork = urcu_unregister_rculfhash_atfork,\ + .update_start_poll_synchronize_rcu = start_poll_synchronize_rcu,\ + .update_poll_state_synchronize_rcu = poll_state_synchronize_rcu,\ } extern const struct rcu_flavor_struct rcu_flavor; diff --git a/include/urcu/map/clear.h b/include/urcu/map/clear.h index 8aff778..1169394 100644 --- a/include/urcu/map/clear.h +++ b/include/urcu/map/clear.h @@ -76,3 +76,6 @@ #undef urcu_register_rculfhash_atfork #undef urcu_unregister_rculfhash_atfork + +#undef start_poll_synchronize_rcu +#undef poll_state_synchronize_rcu diff --git a/include/urcu/map/urcu-bp.h b/include/urcu/map/urcu-bp.h index 6f0a15a..9ccc6c2 100644 --- a/include/urcu/map/urcu-bp.h +++ b/include/urcu/map/urcu-bp.h @@ -83,6 +83,9 @@ #define urcu_unregister_rculfhash_atfork \ urcu_bp_unregister_rculfhash_atfork +#define start_poll_synchronize_rcu urcu_bp_start_poll_synchronize_rcu +#define poll_state_synchronize_rcu urcu_bp_poll_state_synchronize_rcu + /* Compat identifiers for prior undocumented multiflavor usage */ #ifndef URCU_NO_COMPAT_IDENTIFIERS diff --git a/include/urcu/map/urcu-mb.h b/include/urcu/map/urcu-mb.h index d3e9513..e551227 100644 --- a/include/urcu/map/urcu-mb.h +++ b/include/urcu/map/urcu-mb.h @@ -78,6 +78,9 @@ #define urcu_unregister_rculfhash_atfork \ urcu_mb_unregister_rculfhash_atfork +#define start_poll_synchronize_rcu urcu_mb_start_poll_synchronize_rcu +#define poll_state_synchronize_rcu urcu_mb_poll_state_synchronize_rcu + /* Compat identifiers for prior undocumented multiflavor usage */ #ifndef URCU_NO_COMPAT_IDENTIFIERS diff --git a/include/urcu/map/urcu-memb.h b/include/urcu/map/urcu-memb.h index 1e9740f..b267493 100644 --- a/include/urcu/map/urcu-memb.h +++ b/include/urcu/map/urcu-memb.h @@ -78,6 +78,9 @@ #define urcu_unregister_rculfhash_atfork \ urcu_memb_unregister_rculfhash_atfork +#define start_poll_synchronize_rcu urcu_memb_start_poll_synchronize_rcu +#define poll_state_synchronize_rcu urcu_memb_poll_state_synchronize_rcu + /* Compat identifiers for prior undocumented multiflavor usage */ #ifndef URCU_NO_COMPAT_IDENTIFIERS diff --git a/include/urcu/map/urcu-qsbr.h b/include/urcu/map/urcu-qsbr.h index ce4d50b..0475983 100644 --- a/include/urcu/map/urcu-qsbr.h +++ b/include/urcu/map/urcu-qsbr.h @@ -77,6 +77,10 @@ #define urcu_unregister_rculfhash_atfork \ urcu_qsbr_unregister_rculfhash_atfork +#define start_poll_synchronize_rcu urcu_qsbr_start_poll_synchronize_rcu +#define poll_state_synchronize_rcu urcu_qsbr_poll_state_synchronize_rcu + + /* Compat identifiers for prior undocumented multiflavor usage */ #ifndef URCU_NO_COMPAT_IDENTIFIERS diff --git a/include/urcu/map/urcu-signal.h b/include/urcu/map/urcu-signal.h index 29ccaad..f151359 100644 --- a/include/urcu/map/urcu-signal.h +++ b/include/urcu/map/urcu-signal.h @@ -78,6 +78,9 @@ #define urcu_unregister_rculfhash_atfork \ urcu_signal_unregister_rculfhash_atfork +#define start_poll_synchronize_rcu urcu_signal_start_poll_synchronize_rcu +#define poll_state_synchronize_rcu urcu_signal_poll_state_synchronize_rcu + /* Compat identifiers for prior undocumented multiflavor usage */ #ifndef URCU_NO_COMPAT_IDENTIFIERS diff --git a/include/urcu/urcu-bp.h b/include/urcu/urcu-bp.h index e28c2bf..7eefa0e 100644 --- a/include/urcu/urcu-bp.h +++ b/include/urcu/urcu-bp.h @@ -36,6 +36,7 @@ #include #include +#include #include @@ -52,6 +53,7 @@ * publication headers. */ #include +#include #ifdef __cplusplus extern "C" { @@ -140,6 +142,12 @@ extern void *urcu_bp_set_pointer_sym(void **p, void *v); extern void urcu_bp_synchronize_rcu(void); +/* + * RCU grace period polling API. + */ +extern struct urcu_gp_poll_state urcu_bp_start_poll_synchronize_rcu(void); +extern bool urcu_bp_poll_state_synchronize_rcu(struct urcu_gp_poll_state state); + /* * 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 diff --git a/include/urcu/urcu-mb.h b/include/urcu/urcu-mb.h index ab485f1..e2fc8b5 100644 --- a/include/urcu/urcu-mb.h +++ b/include/urcu/urcu-mb.h @@ -33,12 +33,14 @@ #include #include +#include /* * See urcu/pointer.h and urcu/static/pointer.h for pointer * publication headers. */ #include +#include #ifdef __cplusplus extern "C" { @@ -90,6 +92,12 @@ extern int urcu_mb_read_ongoing(void); extern void urcu_mb_synchronize_rcu(void); +/* + * RCU grace period polling API. + */ +extern struct urcu_gp_poll_state urcu_mb_start_poll_synchronize_rcu(void); +extern bool urcu_mb_poll_state_synchronize_rcu(struct urcu_gp_poll_state state); + /* * Reader thread registration. */ diff --git a/include/urcu/urcu-memb.h b/include/urcu/urcu-memb.h index c11c93e..2711e12 100644 --- a/include/urcu/urcu-memb.h +++ b/include/urcu/urcu-memb.h @@ -33,12 +33,14 @@ #include #include +#include /* * See urcu/pointer.h and urcu/static/pointer.h for pointer * publication headers. */ #include +#include #ifdef __cplusplus extern "C" { @@ -90,6 +92,12 @@ extern int urcu_memb_read_ongoing(void); extern void urcu_memb_synchronize_rcu(void); +/* + * RCU grace period polling API. + */ +extern struct urcu_gp_poll_state urcu_memb_start_poll_synchronize_rcu(void); +extern bool urcu_memb_poll_state_synchronize_rcu(struct urcu_gp_poll_state state); + /* * Reader thread registration. */ diff --git a/include/urcu/urcu-poll.h b/include/urcu/urcu-poll.h new file mode 100644 index 0000000..ce1012f --- /dev/null +++ b/include/urcu/urcu-poll.h @@ -0,0 +1,30 @@ +#ifndef _URCU_POLL_H +#define _URCU_POLL_H + +/* + * urcu-poll.h + * + * Userspace RCU polling header + * + * Copyright (c) 2023 Mathieu Desnoyers + * + * 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 + */ + +struct urcu_gp_poll_state { + unsigned long grace_period_id; +}; + +#endif /* _URCU_POLL_H */ diff --git a/include/urcu/urcu-qsbr.h b/include/urcu/urcu-qsbr.h index fd6cbda..5c5a030 100644 --- a/include/urcu/urcu-qsbr.h +++ b/include/urcu/urcu-qsbr.h @@ -30,6 +30,7 @@ #include #include +#include #include @@ -38,6 +39,7 @@ * publication headers. */ #include +#include #ifdef __cplusplus extern "C" { @@ -125,6 +127,12 @@ extern void urcu_qsbr_thread_online(void); extern void urcu_qsbr_synchronize_rcu(void); +/* + * RCU grace period polling API. + */ +extern struct urcu_gp_poll_state urcu_qsbr_start_poll_synchronize_rcu(void); +extern bool urcu_qsbr_poll_state_synchronize_rcu(struct urcu_gp_poll_state state); + /* * Reader thread registration. */ diff --git a/include/urcu/urcu-signal.h b/include/urcu/urcu-signal.h index 59c5d01..58f202f 100644 --- a/include/urcu/urcu-signal.h +++ b/include/urcu/urcu-signal.h @@ -33,12 +33,14 @@ #include #include +#include /* * See urcu/pointer.h and urcu/static/pointer.h for pointer * publication headers. */ #include +#include #ifdef __cplusplus extern "C" { @@ -90,6 +92,12 @@ extern int urcu_signal_read_ongoing(void); extern void urcu_signal_synchronize_rcu(void); +/* + * RCU grace period polling API. + */ +extern struct urcu_gp_poll_state urcu_signal_start_poll_synchronize_rcu(void); +extern bool urcu_signal_poll_state_synchronize_rcu(struct urcu_gp_poll_state state); + /* * Reader thread registration. */ diff --git a/src/Makefile.am b/src/Makefile.am index cf6c32c..4567a24 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -57,4 +57,5 @@ pkgconfig_DATA = liburcu-cds.pc liburcu.pc liburcu-bp.pc liburcu-qsbr.pc \ EXTRA_DIST = \ urcu-call-rcu-impl.h \ urcu-defer-impl.h \ + urcu-poll-impl.h \ rculfhash-internal.h diff --git a/src/urcu-bp.c b/src/urcu-bp.c index a097d7f..1a437f6 100644 --- a/src/urcu-bp.c +++ b/src/urcu-bp.c @@ -769,3 +769,4 @@ DEFINE_RCU_FLAVOR(rcu_flavor); #include "urcu-call-rcu-impl.h" #include "urcu-defer-impl.h" +#include "urcu-poll-impl.h" diff --git a/src/urcu-poll-impl.h b/src/urcu-poll-impl.h new file mode 100644 index 0000000..dc13788 --- /dev/null +++ b/src/urcu-poll-impl.h @@ -0,0 +1,100 @@ +/* + * urcu-poll-impl.h + * + * Userspace RCU library - Grace period polling API + * + * Copyright (c) 2023 Mathieu Desnoyers + * + * 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 +#include + +struct urcu_poll_worker_state { + struct urcu_gp_poll_state current_state; + struct urcu_gp_poll_state latest_target; /* Most recent snapshot taken */ + struct rcu_head rcu_head; + pthread_mutex_t lock; + bool active; +}; + +static struct urcu_poll_worker_state poll_worker_gp_state = { + .lock = PTHREAD_MUTEX_INITIALIZER, +}; + +static +void urcu_poll_worker_cb(struct rcu_head *head __attribute__((unused))) +{ + mutex_lock(&poll_worker_gp_state.lock); + /* A new grace period has been reached. */ + poll_worker_gp_state.current_state.grace_period_id++; + if ((long)(poll_worker_gp_state.latest_target.grace_period_id - poll_worker_gp_state.current_state.grace_period_id) >= 0) { + /* Need to re-queue. */ + call_rcu(&poll_worker_gp_state.rcu_head, urcu_poll_worker_cb); + } else { + /* No user waiting for a target grace period. */ + poll_worker_gp_state.active = false; + } + mutex_unlock(&poll_worker_gp_state.lock); +} + +/* + * Start polling on grace period. If no worker is currently active, + * snapshot the current value and start a worker callback. If the worker + * is currently active, snapshot the current value + 1, and set this + * value as the latest snapshot, which will cause the worker to re-queue + * itself with call_rcu to issue one more grace period. + * + * Because it uses call_rcu, it needs to be called from a registered RCU + * thread. + */ +struct urcu_gp_poll_state start_poll_synchronize_rcu(void) +{ + struct urcu_gp_poll_state new_target_gp_state; + bool was_active = false; + + mutex_lock(&poll_worker_gp_state.lock); + new_target_gp_state.grace_period_id = poll_worker_gp_state.current_state.grace_period_id; + was_active = poll_worker_gp_state.active; + if (!was_active) + poll_worker_gp_state.active = true; + else + new_target_gp_state.grace_period_id++; + poll_worker_gp_state.latest_target.grace_period_id = new_target_gp_state.grace_period_id; + if (!was_active) + call_rcu(&poll_worker_gp_state.rcu_head, urcu_poll_worker_cb); + mutex_unlock(&poll_worker_gp_state.lock); + return new_target_gp_state; +} + +/* + * Poll the grace period state. Return true if quiescence was reached + * since the snapshot was taken, return false if quiescence was not + * reached since snapshot. + */ +bool poll_state_synchronize_rcu(struct urcu_gp_poll_state target_gp_state) +{ + bool target_gp_reached = false; + + mutex_lock(&poll_worker_gp_state.lock); + if ((long)(target_gp_state.grace_period_id - poll_worker_gp_state.current_state.grace_period_id) < 0) + target_gp_reached = true; + mutex_unlock(&poll_worker_gp_state.lock); + return target_gp_reached; +} diff --git a/src/urcu-qsbr.c b/src/urcu-qsbr.c index a338285..b538edc 100644 --- a/src/urcu-qsbr.c +++ b/src/urcu-qsbr.c @@ -515,3 +515,4 @@ DEFINE_RCU_FLAVOR(rcu_flavor); #include "urcu-call-rcu-impl.h" #include "urcu-defer-impl.h" +#include "urcu-poll-impl.h" diff --git a/src/urcu.c b/src/urcu.c index cf4d6d0..0877bfc 100644 --- a/src/urcu.c +++ b/src/urcu.c @@ -714,3 +714,4 @@ DEFINE_RCU_FLAVOR(rcu_flavor); #include "urcu-call-rcu-impl.h" #include "urcu-defer-impl.h" +#include "urcu-poll-impl.h" -- 2.34.1