[ovs-dev] [PATCH 07/18] lib/ovs-thread: Avoid atomic read in ovsthread_once_start().

Jarno Rajahalme jrajahalme at nicira.com
Fri Aug 22 20:58:18 UTC 2014


Avoiding the atomic read may help if a function using
ovsthread_once_start() is ever called in a loop, as the new
'maybe_not_done' can be kept in a register.  The atomic read will
still be done as long as 'maybe_not_done' is true.  Since
'maybe_not_done' is not an atomic variable, whis may happen
indefinitely, but if a loop starts with 'maybe_not_done' as false, no
atomic read operations are needed.

Signed-off-by: Jarno Rajahalme <jrajahalme at nicira.com>
---
 lib/ovs-thread.c |   11 ++++++++++-
 lib/ovs-thread.h |    7 ++++++-
 2 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/lib/ovs-thread.c b/lib/ovs-thread.c
index 8fd5c32..9e260b7 100644
--- a/lib/ovs-thread.c
+++ b/lib/ovs-thread.c
@@ -371,7 +371,16 @@ ovsthread_once_start__(struct ovsthread_once *once)
 void
 ovsthread_once_done(struct ovsthread_once *once)
 {
-    atomic_store(&once->done, true);
+    /* We need release semantics here, so that neither the atomic nor
+     * the non-atomic store may be moved ahead of any of the preceding
+     * initialization operations.  An atomic release-store could allow
+     * the following non-atomic store to be moved ahead of the preceding
+     * initialization operations.  A release atomic_thread_fence
+     * provides that prior memory accesses will not be reordered to
+     * take place after either of the stores. */
+    atomic_thread_fence(memory_order_release);
+    once->maybe_not_done = false;
+    atomic_store_relaxed(&once->done, true);
     ovs_mutex_unlock(&once->mutex);
 }
 
diff --git a/lib/ovs-thread.h b/lib/ovs-thread.h
index 962e867..1d072b1 100644
--- a/lib/ovs-thread.h
+++ b/lib/ovs-thread.h
@@ -533,12 +533,14 @@ void *ovsthread_getspecific(ovsthread_key_t);
  */
 
 struct ovsthread_once {
+    bool maybe_not_done;     /* Non-atomic, false positives possible. */
     atomic_bool done;
     struct ovs_mutex mutex;
 };
 
 #define OVSTHREAD_ONCE_INITIALIZER              \
     {                                           \
+        true,                                   \
         ATOMIC_VAR_INIT(false),                 \
         OVS_MUTEX_INITIALIZER,                  \
     }
@@ -570,7 +572,10 @@ ovsthread_once_is_done__(struct ovsthread_once *once)
 static inline bool
 ovsthread_once_start(struct ovsthread_once *once)
 {
-    return OVS_UNLIKELY(!ovsthread_once_is_done__(once)
+    /* Avoiding the atomic_read may help if a function using this is ever
+     * called in a loop, as 'maybe_not_done' can be kept in a register. */
+    return OVS_UNLIKELY(once->maybe_not_done
+                        && !ovsthread_once_is_done__(once)
                         && !ovsthread_once_start__(once));
 }
 
-- 
1.7.10.4




More information about the dev mailing list