@@ -170,7 +170,7 @@ ovsrcu_try_quiesce(void)
ovs_assert(!single_threaded());
perthread = ovsrcu_perthread_get();
if (!seq_try_lock()) {
- perthread->seqno = seq_read_protected(global_seqno);
+ perthread->seqno = seq_read(global_seqno);
if (perthread->cbset) {
ovsrcu_flush_cbset__(perthread, true);
}
@@ -32,7 +32,7 @@ COVERAGE_DEFINE(seq_change);
/* A sequence number object. */
struct seq {
- uint64_t value OVS_GUARDED;
+ atomic_uint64_t value;
struct hmap waiters OVS_GUARDED; /* Contains 'struct seq_waiter's. */
};
@@ -72,6 +72,7 @@ static void seq_wake_waiters(struct seq *) OVS_REQUIRES(seq_mutex);
struct seq * OVS_EXCLUDED(seq_mutex)
seq_create(void)
{
+ uint64_t seq_value;
struct seq *seq;
seq_init();
@@ -81,7 +82,8 @@ seq_create(void)
COVERAGE_INC(seq_change);
ovs_mutex_lock(&seq_mutex);
- seq->value = seq_next++;
+ seq_value = seq_next++;
+ atomic_store_relaxed(&seq->value, seq_value);
hmap_init(&seq->waiters);
ovs_mutex_unlock(&seq_mutex);
@@ -126,9 +128,11 @@ void
seq_change_protected(struct seq *seq)
OVS_REQUIRES(seq_mutex)
{
+ uint64_t seq_value = seq_next++;
+
COVERAGE_INC(seq_change);
- seq->value = seq_next++;
+ atomic_store_explicit(&seq->value, seq_value, memory_order_release);
seq_wake_waiters(seq);
}
@@ -143,18 +147,6 @@ seq_change(struct seq *seq)
ovs_mutex_unlock(&seq_mutex);
}
-/* Returns 'seq''s current sequence number (which could change immediately).
- *
- * seq_read() and seq_wait() can be used together to yield a race-free wakeup
- * when an object changes, even without an ability to lock the object. See
- * Usage in seq.h for details. */
-uint64_t
-seq_read_protected(const struct seq *seq)
- OVS_REQUIRES(seq_mutex)
-{
- return seq->value;
-}
-
/* Returns 'seq''s current sequence number (which could change immediately).
*
* seq_read() and seq_wait() can be used together to yield a race-free wakeup
@@ -162,14 +154,12 @@ seq_read_protected(const struct seq *seq)
* Usage in seq.h for details. */
uint64_t
seq_read(const struct seq *seq)
- OVS_EXCLUDED(seq_mutex)
{
uint64_t value;
- ovs_mutex_lock(&seq_mutex);
- value = seq_read_protected(seq);
- ovs_mutex_unlock(&seq_mutex);
-
+ /* Note that the odd CONST_CAST() is here to keep sparse happy. */
+ atomic_read_explicit(&CONST_CAST(struct seq *, seq)->value, &value,
+ memory_order_acquire);
return value;
}
@@ -226,7 +216,7 @@ seq_wait_at(const struct seq *seq_, uint64_t value, const char *where)
struct seq *seq = CONST_CAST(struct seq *, seq_);
ovs_mutex_lock(&seq_mutex);
- if (value == seq->value) {
+ if (value == seq_read(seq_)) {
seq_wait__(seq, value, where);
} else {
poll_immediate_wake_at(where);
@@ -128,7 +128,6 @@ void seq_unlock(void);
/* For observers. */
uint64_t seq_read(const struct seq *);
-uint64_t seq_read_protected(const struct seq *);
void seq_wait_at(const struct seq *, uint64_t value, const char *where);
#define seq_wait(seq, value) seq_wait_at(seq, value, OVS_SOURCE_LOCATOR)
Make the read of the current seq->value atomic, i.e., not needing to acquire the global mutex when reading it. On 64-bit systems, this incurs no overhead, and it will avoid the mutex and potentially a system call. For incrementing the value followed by waking up the threads, we are still taking the mutex, so the current behavior is not changing. The seq_read() behavior is already defined as, "Returns seq's current sequence number (which could change immediately)". So the change should not impact the current behavior. Signed-off-by: Eelco Chaudron <echaudro@redhat.com> --- v2: Update acquire and release semantics for seq->value. lib/ovs-rcu.c | 2 +- lib/seq.c | 32 +++++++++++--------------------- lib/seq.h | 1 - 3 files changed, 12 insertions(+), 23 deletions(-)