urcu-memb,mb,signal: Implement grace period polling
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Thu, 2 Feb 2023 19:32:15 +0000 (14:32 -0500)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Fri, 10 Feb 2023 17:19:35 +0000 (12:19 -0500)
Implement a grace period polling mechanism for each urcu flavor. Its use
is documented in README.md.

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Change-Id: Ibd4642f2821ecd55ce40b9372d2be7ab451f9644

20 files changed:
README.md
include/Makefile.am
include/urcu/flavor.h
include/urcu/map/clear.h
include/urcu/map/urcu-bp.h
include/urcu/map/urcu-mb.h
include/urcu/map/urcu-memb.h
include/urcu/map/urcu-qsbr.h
include/urcu/map/urcu-signal.h
include/urcu/urcu-bp.h
include/urcu/urcu-mb.h
include/urcu/urcu-memb.h
include/urcu/urcu-poll.h [new file with mode: 0644]
include/urcu/urcu-qsbr.h
include/urcu/urcu-signal.h
src/Makefile.am
src/urcu-bp.c
src/urcu-poll-impl.h [new file with mode: 0644]
src/urcu-qsbr.c
src/urcu.c

index 2fe14c3db756394d2cdf2c09ebe5e1b018c89324..ba5bb08deab9dd8f3a912b4d92835b37151c46d3 100644 (file)
--- a/README.md
+++ b/README.md
@@ -250,6 +250,14 @@ protected pointer.
 After, `urcu_<flavor>_synchronize_rcu()` must be called. When it
 returns, the old values are not in usage anymore.
 
+As an alternative to `urcu_<flavor>_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_<flavor>_start_poll_synchronize_rcu()`
+to start the grace period polling, and then invoke
+`urcu_<flavor>_poll_state_synchronize_rcu()`, which returns true if
+the grace period has completed, false otherwise.
+
 
 ### Usage of `liburcu-defer`
 
index b55bcf0271290e6e440c5b66ce87089dd5903063..ba1fe600163b5f595f54ab4b8fa7c1f0d1992c8d 100644 (file)
@@ -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
index 1a920896fc9474c0ef7babe1eafa7eec5babca90..20d32b65297922f9b3e52d164cbcff4dabdefff9 100644 (file)
@@ -23,6 +23,8 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include <urcu/urcu-poll.h>
+
 #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;
index 8aff77871113610ff527407a7db2ed3c63bcf0e5..1169394ccbf9f520545c507c3567eb8a20c5d2c2 100644 (file)
@@ -76,3 +76,6 @@
 
 #undef urcu_register_rculfhash_atfork
 #undef urcu_unregister_rculfhash_atfork
+
+#undef start_poll_synchronize_rcu
+#undef poll_state_synchronize_rcu
index 6f0a15a1df0a0541199d346c847e2d00cfbcf246..9ccc6c292861fbf056b0ec420a98d5ed98b6c9dd 100644 (file)
@@ -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
index d3e9513b233976968c4d8f8551b1b75947f457f9..e551227c0f947383e4730f33304b9d726d0f359a 100644 (file)
@@ -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
index 1e9740fd3e3d14b37083b28a854f93e7b7cd9028..b267493ed638886a614e46d24cb426245ceab8a7 100644 (file)
@@ -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
index ce4d50b8cf25c0f78584ceb43825623a7879cea2..04759832352a2e92f7af08da733a6ac321d442f2 100644 (file)
 #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
 
index 29ccaad052df1e9e0a1d4f9b659243e3aad577d3..f151359a02f680ba5951c9d00c4dce8f643a3833 100644 (file)
@@ -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
index e28c2bff8e7db3e0fda163b1655369e6799ceac4..7eefa0ea70e2eb832e712338890db1e7d4710798 100644 (file)
@@ -36,6 +36,7 @@
 
 #include <stdlib.h>
 #include <pthread.h>
+#include <stdbool.h>
 
 #include <urcu/map/urcu-bp.h>
 
@@ -52,6 +53,7 @@
  * publication headers.
  */
 #include <urcu/pointer.h>
+#include <urcu/urcu-poll.h>
 
 #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
index ab485f112f6177c37fa9d1bebe3bc5ef15f4c470..e2fc8b5885d5a3c87aca2de79b506abe1b18124f 100644 (file)
 
 #include <stdlib.h>
 #include <pthread.h>
+#include <stdbool.h>
 
 /*
  * See urcu/pointer.h and urcu/static/pointer.h for pointer
  * publication headers.
  */
 #include <urcu/pointer.h>
+#include <urcu/urcu-poll.h>
 
 #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.
  */
index c11c93e850fcb065e4dc07ce982701364a8c97b7..2711e129231e8fd5236092550875d7477b855d09 100644 (file)
 
 #include <stdlib.h>
 #include <pthread.h>
+#include <stdbool.h>
 
 /*
  * See urcu/pointer.h and urcu/static/pointer.h for pointer
  * publication headers.
  */
 #include <urcu/pointer.h>
+#include <urcu/urcu-poll.h>
 
 #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 (file)
index 0000000..ce1012f
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef _URCU_POLL_H
+#define _URCU_POLL_H
+
+/*
+ * urcu-poll.h
+ *
+ * Userspace RCU polling header
+ *
+ * Copyright (c) 2023 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * 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 */
index fd6cbda31bef58441344dd23d45a5f28b377dc28..5c5a0304211683e1eda0b4a022690ff4bb7e535d 100644 (file)
@@ -30,6 +30,7 @@
 
 #include <stdlib.h>
 #include <pthread.h>
+#include <stdbool.h>
 
 #include <urcu/config.h>
 
@@ -38,6 +39,7 @@
  * publication headers.
  */
 #include <urcu/pointer.h>
+#include <urcu/urcu-poll.h>
 
 #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.
  */
index 59c5d0131d514e15b5da3b95cf717bcca395f424..58f202f2bfb9f7e0a3c285cb2961ac950380f56d 100644 (file)
 
 #include <stdlib.h>
 #include <pthread.h>
+#include <stdbool.h>
 
 /*
  * See urcu/pointer.h and urcu/static/pointer.h for pointer
  * publication headers.
  */
 #include <urcu/pointer.h>
+#include <urcu/urcu-poll.h>
 
 #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.
  */
index cf6c32c6cad3628937cee581193032725ddd600a..4567a24a6b23681f969e5a291ff061ec11aff3d7 100644 (file)
@@ -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
index a097d7f00312a1372123f5c61a732f0e8270354d..1a437f61cd23f1e0a1486cd766efce5581264259 100644 (file)
@@ -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 (file)
index 0000000..dc13788
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * urcu-poll-impl.h
+ *
+ * Userspace RCU library - Grace period polling API
+ *
+ * Copyright (c) 2023 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * 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 <pthread.h>
+#include <stdbool.h>
+
+#include <urcu/urcu-poll.h>
+#include <urcu/call-rcu.h>
+
+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;
+}
index a3382857a7f358ab2f6bd548df6504c35e8bbadf..b538edc734ca231909d8154add1a2b90bc2072f9 100644 (file)
@@ -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"
index cf4d6d03f711750c05e91991f2a64687640b4438..0877bfc942b7eb168774a9db1ae3181c71e92bf3 100644 (file)
@@ -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"
This page took 0.034362 seconds and 4 git commands to generate.