/*
- * Copyright (c) 2013 Nicira, Inc.
+ * Copyright (c) 2013, 2014 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <stdbool.h>
+#include "coverage.h"
#include "hash.h"
#include "hmap.h"
#include "latch.h"
#include "ovs-thread.h"
#include "poll-loop.h"
+COVERAGE_DEFINE(seq_change);
+
/* A sequence number object. */
struct seq {
uint64_t value OVS_GUARDED;
struct hmap_node hmap_node OVS_GUARDED; /* In 'seq->waiters'. */
unsigned int ovsthread_id OVS_GUARDED; /* Key in 'waiters' hmap. */
- struct seq_thread *thread OVS_GUARDED; /* Thread preparing to wait. */
- struct list list_node OVS_GUARDED; /* In 'thread->waiters'. */
+ struct seq_thread *thread OVS_GUARDED; /* Thread preparing to wait. */
+ struct ovs_list list_node OVS_GUARDED; /* In 'thread->waiters'. */
uint64_t value OVS_GUARDED; /* seq->value we're waiting to change. */
};
/* A thread that might be waiting on one or more seqs. */
struct seq_thread {
- struct list waiters OVS_GUARDED; /* Contains 'struct seq_waiter's. */
+ struct ovs_list waiters OVS_GUARDED; /* Contains 'struct seq_waiter's. */
struct latch latch OVS_GUARDED; /* Wakeup latch for this thread. */
bool waiting OVS_GUARDED; /* True if latch_wait() already called. */
};
-static struct ovs_mutex seq_mutex = OVS_ADAPTIVE_MUTEX_INITIALIZER;
+static struct ovs_mutex seq_mutex = OVS_MUTEX_INITIALIZER;
static uint64_t seq_next OVS_GUARDED_BY(seq_mutex) = 1;
seq_init();
seq = xmalloc(sizeof *seq);
+
+ COVERAGE_INC(seq_change);
+
ovs_mutex_lock(&seq_mutex);
seq->value = seq_next++;
hmap_init(&seq->waiters);
seq_change(struct seq *seq)
OVS_EXCLUDED(seq_mutex)
{
+ COVERAGE_INC(seq_change);
+
ovs_mutex_lock(&seq_mutex);
seq->value = seq_next++;
seq_wake_waiters(seq);
ovs_mutex_unlock(&seq_mutex);
}
-/* Returns 'seq''s current sequence number (which could change immediately). */
+/* 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(const struct seq *seq)
OVS_EXCLUDED(seq_mutex)
}
static void
-seq_wait__(struct seq *seq, uint64_t value)
+seq_wait__(struct seq *seq, uint64_t value, const char *where)
OVS_REQUIRES(seq_mutex)
{
unsigned int id = ovsthread_id_self();
if (waiter->value != value) {
/* The current value is different from the value we've already
* waited for, */
- poll_immediate_wake();
+ poll_immediate_wake_at(where);
} else {
/* Already waiting on 'value', nothing more to do. */
}
waiter = xmalloc(sizeof *waiter);
waiter->seq = seq;
hmap_insert(&seq->waiters, &waiter->hmap_node, hash);
+ waiter->ovsthread_id = id;
waiter->value = value;
waiter->thread = seq_thread_get();
list_push_back(&waiter->thread->waiters, &waiter->list_node);
if (!waiter->thread->waiting) {
- latch_wait(&waiter->thread->latch);
+ latch_wait_at(&waiter->thread->latch, where);
waiter->thread->waiting = true;
}
}
/* Causes the following poll_block() to wake up when 'seq''s sequence number
* changes from 'value'. (If 'seq''s sequence number isn't 'value', then
- * poll_block() won't block at all.) */
+ * poll_block() won't block at all.)
+ *
+ * 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.
+ *
+ * ('where' is used in debug logging. Commonly one would use seq_wait() to
+ * automatically provide the caller's source file and line number for
+ * 'where'.) */
void
-seq_wait(const struct seq *seq_, uint64_t value)
+seq_wait_at(const struct seq *seq_, uint64_t value, const char *where)
OVS_EXCLUDED(seq_mutex)
{
struct seq *seq = CONST_CAST(struct seq *, seq_);
ovs_mutex_lock(&seq_mutex);
if (value == seq->value) {
- seq_wait__(seq, value);
+ seq_wait__(seq, value, where);
} else {
- poll_immediate_wake();
+ poll_immediate_wake_at(where);
}
ovs_mutex_unlock(&seq_mutex);
}