A new thread must be started in a non quiescent state. There is a call to ovsrcu_quiesce_end() in ovsthread_wrapper(), to enforce this.
ovs_thread_create(), instead, is executed in the parent thread, and calling ovsrcu_quiesce_end() there will cause the parent to end its (possible) quiescing state, which it's not required to start a child thread. This fixes a bug in ovs-rcu where the first call in the process to ovsrcu_quiesce_start() will not be honored, because the calling thread will need to create the 'urcu' thread (and creating a thread will wrongly end its quiescent state). ovsrcu_quiesce_start() ovs_rcu_quiesced() if (ovsthread_once_start(&once)) { ovs_thread_create("urcu") /*This will end the quiescent state*/ } This bug manifest itself especially when staring ovs-vswitchd with DPDK. In the DPDK case the first threads create are "vhost_thread" and "dpdk_watchdog". If dpdk_watchdog is the first to call ovsrcu_quiesce_start() (via xsleep()), the call is not honored and the RCU grace period lasts at least for DPDK_PORT_WATCHDOG_INTERVAL (5s on current master). If vhost_thread, on the other hand, is the first to call ovsrcu_quiesce_start(), the call is not honored and the RCU grace period lasts undefinitely, because no more calls to ovsrcu_quiesce_start() are issued from vhost_thread. For some reason (it's a race condition after all), on current master, dpdk_watchdog will always be the first to call ovsrcu_quiesce_start(), but with the upcoming DPDK database configuration changes, sometimes vhost_thread will issue the first call to ovsrcu_quiesce_start(). Sample ovs-vswitchd.log: 2016-03-23T22:34:28.532Z|00004|ovs_rcu(urcu3)|WARN|blocked 8000 ms waiting for vhost_thread2 to quiesce 2016-03-23T22:34:30.501Z|00118|ovs_rcu|WARN|blocked 8000 ms waiting for vhost_thread2 to quiesce 2016-03-23T22:34:36.532Z|00005|ovs_rcu(urcu3)|WARN|blocked 16000 ms waiting for vhost_thread2 to quiesce 2016-03-23T22:34:38.501Z|00119|ovs_rcu|WARN|blocked 16000 ms waiting for vhost_thread2 to quiesce The commit also adds a test for the ovs-rcu module to make sure that: * A new thread is started in a non quiescent state. * The first call to ovsrcu_quiesce_start() is honored. --- lib/ovs-thread.c | 1 - tests/automake.mk | 1 + tests/library.at | 4 ++++ tests/test-rcu.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 tests/test-rcu.c diff --git a/lib/ovs-thread.c b/lib/ovs-thread.c index 7777298..13bf6b0 100644 --- a/lib/ovs-thread.c +++ b/lib/ovs-thread.c @@ -370,7 +370,6 @@ ovs_thread_create(const char *name, void *(*start)(void *), void *arg) forbid_forking("multiple threads exist"); multithreaded = true; - ovsrcu_quiesce_end(); aux = xmalloc(sizeof *aux); aux->start = start; diff --git a/tests/automake.mk b/tests/automake.mk index 98c4df0..ca65ed5 100644 --- a/tests/automake.mk +++ b/tests/automake.mk @@ -327,6 +327,7 @@ tests_ovstest_SOURCES = \ tests/test-ovn.c \ tests/test-packets.c \ tests/test-random.c \ + tests/test-rcu.c \ tests/test-reconnect.c \ tests/test-rstp.c \ tests/test-sflow.c \ diff --git a/tests/library.at b/tests/library.at index 4094348..e1bac92 100644 --- a/tests/library.at +++ b/tests/library.at @@ -230,3 +230,7 @@ AT_CLEANUP AT_SETUP([test ofpbuf module]) AT_CHECK([ovstest test-ofpbuf], [0], []) AT_CLEANUP + +AT_SETUP([test rcu]) +AT_CHECK([ovstest test-rcu-quiesce], [0], []) +AT_CLEANUP diff --git a/tests/test-rcu.c b/tests/test-rcu.c new file mode 100644 index 0000000..7c0ffe4 --- /dev/null +++ b/tests/test-rcu.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2016 Nicira, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <config.h> +#undef NDEBUG +#include "fatal-signal.h" +#include "ovs-rcu.h" +#include "ovs-thread.h" +#include "ovstest.h" +#include "util.h" + +static void * +quiescer_main(void *aux OVS_UNUSED) +{ + ovs_assert(!ovsrcu_is_quiescent()); + ovsrcu_quiesce_start(); + ovs_assert(ovsrcu_is_quiescent()); + + return NULL; +} + +static void +test_rcu_quiesce(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) +{ + pthread_t quiescer; + + fatal_signal_init(); + quiescer = ovs_thread_create("quiescer", quiescer_main, NULL); + + xpthread_join(quiescer, NULL); +} + +OVSTEST_REGISTER("test-rcu-quiesce", test_rcu_quiesce); -- 2.1.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev