@@ -251,10 +251,16 @@ AT_KEYWORDS([barrier])
AT_CHECK([ovstest test-barrier], [0], [])
AT_CLEANUP
-AT_SETUP([rcu])
+AT_SETUP([rcu quiescing])
+AT_KEYWORDS([rcu])
AT_CHECK([ovstest test-rcu-quiesce], [0], [])
AT_CLEANUP
+AT_SETUP([rcu postponing])
+AT_KEYWORDS([rcu])
+AT_CHECK([ovstest test-rcu], [0], [])
+AT_CLEANUP
+
AT_SETUP([stopwatch module])
AT_CHECK([ovstest test-stopwatch], [0], [......
], [ignore])
@@ -49,3 +49,62 @@ test_rcu_quiesce(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
}
OVSTEST_REGISTER("test-rcu-quiesce", test_rcu_quiesce);
+
+struct rcu_user_aux {
+ bool done;
+};
+
+static void
+rcu_user_deferred(struct rcu_user_aux *aux)
+{
+ aux->done = true;
+}
+
+static void *
+rcu_user_main(void *aux_)
+{
+ struct rcu_user_aux *aux = aux_;
+
+ ovsrcu_quiesce();
+
+ aux->done = false;
+ ovsrcu_postpone(rcu_user_deferred, aux);
+
+ ovsrcu_quiesce();
+
+ return NULL;
+}
+
+#define N_THREAD 4
+
+static void
+test_rcu(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
+{
+ struct rcu_user_aux aux[N_THREAD] = {0};
+ struct rcu_user_aux main_aux = {0};
+ pthread_t users[N_THREAD];
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(users); i++) {
+ users[i] = ovs_thread_create("user", rcu_user_main, &aux[i]);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(users); i++) {
+ xpthread_join(users[i], NULL);
+ }
+
+ /* Register a last callback and verify that it will be properly executed
+ * even if the RCU lib is exited without this thread quiescing.
+ */
+ ovsrcu_postpone(rcu_user_deferred, &main_aux);
+
+ ovsrcu_exit();
+
+ ovs_assert(main_aux.done);
+
+ for (i = 0; i < ARRAY_SIZE(users); i++) {
+ ovs_assert(aux[i].done);
+ }
+}
+
+OVSTEST_REGISTER("test-rcu", test_rcu);
Add a simple postponing test verifying RCU callbacks have executed and RCU exits in order. Add as part of library unit-tests. Signed-off-by: Gaetan Rivet <grive@u256.net> --- tests/library.at | 8 ++++++- tests/test-rcu.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-)