[ovs-dev] [PATCH] ovs-rcu: Add new ovsrcu_index type.
Daniele Di Proietto
diproiettod at vmware.com
Wed Aug 3 00:03:03 UTC 2016
With RCU in Open vSwitch it's very easy to protect objects accessed by
a pointer, but sometimes a pointer is not available.
One example is the vhost id for DPDK 16.07. Until DPDK 16.04 a pointer
was used to access a vhost device with RCU semantics. From DPDK 16.07
an integer id (which is an array index) is used to access a vhost
device. Ideally, we want the exact same RCU semantics that we had for
the pointer, on the integer (atomicity, memory barriers, behaviour
around quiescent states)
This commit implements a new type in ovs-rcu: ovsrcu_index. The newly
implemented ovsrcu_index_*() functions should be used to access the
type.
Even though we say "Do not, in general, declare a typedef for a struct,
union, or enum.", I think we're not in the "general" case.
Signed-off-by: Daniele Di Proietto <diproiettod at vmware.com>
---
lib/ovs-rcu.h | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 84 insertions(+)
diff --git a/lib/ovs-rcu.h b/lib/ovs-rcu.h
index dc75749..2887bb8 100644
--- a/lib/ovs-rcu.h
+++ b/lib/ovs-rcu.h
@@ -125,6 +125,36 @@
* ovs_mutex_unlock(&mutex);
* }
*
+ * In some rare cases an object may not be addressable with a pointer, but only
+ * through an array index (e.g. because it's provided by another library). It
+ * is still possible to have RCU semantics by using the ovsrcu_index type.
+ *
+ * static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER;
+ *
+ * ovsrcu_index port_id;
+ *
+ * void tx()
+ * {
+ * int id = ovsrcu_index_get(&port_id);
+ * if (id == -1) {
+ * return;
+ * }
+ * port_tx(id);
+ * }
+ *
+ * void delete()
+ * {
+ * int id;
+ *
+ * ovs_mutex_lock(&mutex);
+ * id = ovsrcu_index_get_protected(&port_id);
+ * ovsrcu_index_set(&port_id, -1);
+ * ovs_mutex_unlock(&mutex);
+ *
+ * ovsrcu_synchronize();
+ * port_delete(id);
+ * }
+ *
*/
#include "compiler.h"
@@ -213,6 +243,60 @@ void ovsrcu_postpone__(void (*function)(void *aux), void *aux);
(void) sizeof(*(ARG)), \
ovsrcu_postpone__((void (*)(void *))(FUNCTION), ARG))
+/* An array index protected by RCU semantics. This is an easier alternative to
+ * an RCU protected pointer to a malloc'd int. */
+typedef struct { atomic_int v; } ovsrcu_index;
+
+static inline int ovsrcu_index_get__(const ovsrcu_index *i, memory_order order)
+{
+ int ret;
+ atomic_read_explicit(CONST_CAST(atomic_int *, &i->v), &ret, order);
+ return ret;
+}
+
+/* Returns the index contained in 'i'. The returned value can be used until
+ * the next grace period. */
+static inline int ovsrcu_index_get(const ovsrcu_index *i)
+{
+ return ovsrcu_index_get__(i, memory_order_consume);
+}
+
+/* Returns the index contained in 'i'. This is an alternative to
+ * ovsrcu_index_get() that can be used when there's no possible concurrent
+ * writer. */
+static inline int ovsrcu_index_get_protected(const ovsrcu_index *i)
+{
+ return ovsrcu_index_get__(i, memory_order_relaxed);
+}
+
+static inline void ovsrcu_index_set__(ovsrcu_index *i, int value,
+ memory_order order)
+{
+ atomic_store_explicit(&i->v, value, order);
+}
+
+/* Writes the index 'value' in 'i'. The previous value of 'i' may still be
+ * used by readers until the next grace period. */
+static inline void ovsrcu_index_set(ovsrcu_index *i, int value)
+{
+ ovsrcu_index_set__(i, value, memory_order_release);
+}
+
+/* Writes the index 'value' in 'i'. This is an alternative to
+ * ovsrcu_index_set() that can be used when there's no possible concurrent
+ * reader. */
+static inline void ovsrcu_index_set_hidden(ovsrcu_index *i, int value)
+{
+ ovsrcu_index_set__(i, value, memory_order_relaxed);
+}
+
+/* Initializes 'i' with 'value'. This is safe to call as long as there are no
+ * concurrent readers. */
+static inline void ovsrcu_index_init(ovsrcu_index *i, int value)
+{
+ atomic_init(&i->v, value);
+}
+
/* Quiescent states. */
void ovsrcu_quiesce_start(void);
void ovsrcu_quiesce_end(void);
--
2.8.1
More information about the dev
mailing list