[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