*
* Brackets a time period during which the current thread is quiescent.
*
- * A newly created thread is initially active, not quiescent.
+ * A newly created thread is initially active, not quiescent. When a process
+ * becomes multithreaded, the main thread becomes active, not quiescent.
*
* When a quiescient state has occurred in every thread, we say that a "grace
* period" has occurred. Following a grace period, all of the callbacks
pthread_t
ovs_thread_create(const char *name, void *(*start)(void *), void *arg)
{
+ static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
struct ovsthread_aux *aux;
pthread_t thread;
int error;
forbid_forking("multiple threads exist");
multithreaded = true;
- ovsrcu_quiesce_end();
+
+ if (ovsthread_once_start(&once)) {
+ /* The first call to this function has to happen in the main thread.
+ * Before the process becomes multithreaded we make sure that the
+ * main thread is considered non quiescent.
+ *
+ * For other threads this is done in ovs_thread_wrapper(), but the
+ * main thread has no such wrapper.
+ *
+ * There's no reason to call ovsrcu_quiesce_end() in subsequent
+ * invocations of this function and it might introduce problems
+ * for other threads. */
+ ovsrcu_quiesce_end();
+ ovsthread_once_done(&once);
+ }
aux = xmalloc(sizeof *aux);
aux->start = start;
--- /dev/null
+/*
+ * 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)
+{
+ /* A new thread must be not be quiescent */
+ ovs_assert(!ovsrcu_is_quiescent());
+ ovsrcu_quiesce_start();
+ /* After the above call it must be quiescent */
+ 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);
+
+ /* This is the main thread of the process. After spawning its first
+ * thread it must not be quiescent. */
+ ovs_assert(!ovsrcu_is_quiescent());
+
+ xpthread_join(quiescer, NULL);
+}
+
+OVSTEST_REGISTER("test-rcu-quiesce", test_rcu_quiesce);