lib/ovs-rcu.h had some of the comments duplicated.

Add ovsrcu_init() that can be used like ovsrcu_set() when the RCU
protected pointer is not yet visible any readers.

Use OVS_CONSTRUCTOR to initialize the ovs-rcu module.

Signed-off-by: Jarno Rajahalme <jrajaha...@nicira.com>
---
 lib/ovs-rcu.c |   46 +++++++++++++++++-----------------------------
 lib/ovs-rcu.h |   52 +++++++++++++++++++++++-----------------------------
 2 files changed, 40 insertions(+), 58 deletions(-)

diff --git a/lib/ovs-rcu.c b/lib/ovs-rcu.c
index 7aed6db..c11c0f0 100644
--- a/lib/ovs-rcu.c
+++ b/lib/ovs-rcu.c
@@ -55,20 +55,34 @@ static struct ovs_mutex ovsrcu_threads_mutex;
 static struct guarded_list flushed_cbsets;
 static struct seq *flushed_cbsets_seq;
 
-static void ovsrcu_init(void);
 static void ovsrcu_flush_cbset(struct ovsrcu_perthread *);
 static void ovsrcu_unregister__(struct ovsrcu_perthread *);
 static bool ovsrcu_call_postponed(void);
 static void *ovsrcu_postpone_thread(void *arg OVS_UNUSED);
 static void ovsrcu_synchronize(void);
 
+static void
+ovsrcu_thread_exit_cb(void *perthread)
+{
+    ovsrcu_unregister__(perthread);
+}
+
+OVS_CONSTRUCTOR(ovsrcu_constructor)
+{
+    global_seqno = seq_create();
+    xpthread_key_create(&perthread_key, ovsrcu_thread_exit_cb);
+    list_init(&ovsrcu_threads);
+    ovs_mutex_init(&ovsrcu_threads_mutex);
+
+    guarded_list_init(&flushed_cbsets);
+    flushed_cbsets_seq = seq_create();
+}
+
 static struct ovsrcu_perthread *
 ovsrcu_perthread_get(void)
 {
     struct ovsrcu_perthread *perthread;
 
-    ovsrcu_init();
-
     perthread = pthread_getspecific(perthread_key);
     if (!perthread) {
         const char *name = get_subprogram_name();
@@ -121,7 +135,6 @@ ovsrcu_quiesce_start(void)
 {
     struct ovsrcu_perthread *perthread;
 
-    ovsrcu_init();
     perthread = pthread_getspecific(perthread_key);
     if (perthread) {
         pthread_setspecific(perthread_key, NULL);
@@ -136,7 +149,6 @@ ovsrcu_quiesce_start(void)
 void
 ovsrcu_quiesce(void)
 {
-    ovsrcu_init();
     ovsrcu_perthread_get()->seqno = seq_read(global_seqno);
     seq_change(global_seqno);
 
@@ -146,7 +158,6 @@ ovsrcu_quiesce(void)
 bool
 ovsrcu_is_quiescent(void)
 {
-    ovsrcu_init();
     return pthread_getspecific(perthread_key) == NULL;
 }
 
@@ -300,26 +311,3 @@ ovsrcu_unregister__(struct ovsrcu_perthread *perthread)
 
     seq_change(global_seqno);
 }
-
-static void
-ovsrcu_thread_exit_cb(void *perthread)
-{
-    ovsrcu_unregister__(perthread);
-}
-
-static void
-ovsrcu_init(void)
-{
-    static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
-    if (ovsthread_once_start(&once)) {
-        global_seqno = seq_create();
-        xpthread_key_create(&perthread_key, ovsrcu_thread_exit_cb);
-        list_init(&ovsrcu_threads);
-        ovs_mutex_init(&ovsrcu_threads_mutex);
-
-        guarded_list_init(&flushed_cbsets);
-        flushed_cbsets_seq = seq_create();
-
-        ovsthread_once_done(&once);
-    }
-}
diff --git a/lib/ovs-rcu.h b/lib/ovs-rcu.h
index 0b40133..775b829 100644
--- a/lib/ovs-rcu.h
+++ b/lib/ovs-rcu.h
@@ -78,27 +78,33 @@
  * Use ovsrcu_get(TYPE, VAR) to read an RCU-protected pointer, e.g. to read the
  * pointer variable declared above:
  *
- *     struct flow *flow = ovsrcu_get(struct flow *, flowp);
+ *     struct flow *flow = ovsrcu_get(struct flow *, &flowp);
+ *
+ * If the pointer variable is currently protected against change (because
+ * the current thread holds a mutex that protects it), ovsrcu_get_protected()
+ * may be used instead.  Only on the Alpha architecture is this likely to
+ * generate different code, but it may be useful documentation.
+ *
+ * (With GNU C or Clang, you get a compiler error if TYPE is wrong; other
+ * compilers will merrily carry along accepting the wrong type.)
  *
  * Use ovsrcu_set() to write an RCU-protected pointer and ovsrcu_postpone() to
- * free the previous data.  If more than one thread can write the pointer, then
- * some form of external synchronization, e.g. a mutex, is needed to prevent
- * writers from interfering with one another.  For example, to write the
- * pointer variable declared above while safely freeing the old value:
+ * free the previous data.  ovsrcu_init() can be used on (newly created) RCU-
+ * protected pointer that is not yet visible to the readers.  If more than one
+ * thread can write the pointer, then some form of external synchronization,
+ * e.g. a mutex, is needed to prevent writers from interfering with one
+ * another.  For example, to write the pointer variable declared above while
+ * safely freeing the old value:
  *
  *     static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER;
  *
- *     static void
- *     free_flow(struct flow *flow)
- *     {
- *         free(flow);
- *     }
+ *     OVSRCU_TYPE(struct flow *) flowp;
  *
  *     void
  *     change_flow(struct flow *new_flow)
  *     {
  *         ovs_mutex_lock(&mutex);
- *         ovsrcu_postpone(free_flow,
+ *         ovsrcu_postpone(free,
  *                         ovsrcu_get_protected(struct flow *, &flowp));
  *         ovsrcu_set(&flowp, new_flow);
  *         ovs_mutex_unlock(&mutex);
@@ -109,24 +115,6 @@
 #include "compiler.h"
 #include "ovs-atomic.h"
 
-/* Use OVSRCU_TYPE(TYPE) to declare a pointer to RCU-protected data, e.g. the
- * following declares an RCU-protected "struct flow *" named flowp:
- *
- *     OVSRCU_TYPE(struct flow *) flowp;
- *
- * Use ovsrcu_get(TYPE, VAR) to read an RCU-protected pointer, e.g. to read the
- * pointer variable declared above:
- *
- *     struct flow *flow = ovsrcu_get(struct flow *, &flowp);
- *
- * If the pointer variable is currently protected against change (because
- * the current thread holds a mutex that protects it), ovsrcu_get_protected()
- * may be used instead.  Only on the Alpha architecture is this likely to
- * generate different code, but it may be useful documentation.
- *
- * (With GNU C or Clang, you get a compiler error if TYPE is wrong; other
- * compilers will merrily carry along accepting the wrong type.)
- */
 #if __GNUC__
 #define OVSRCU_TYPE(TYPE) struct { ATOMIC(TYPE) p; }
 #define OVSRCU_TYPE_INITIALIZER { NULL }
@@ -168,6 +156,12 @@ ovsrcu_get__(const struct ovsrcu_pointer *pointer, 
memory_order order)
 #define ovsrcu_set(VAR, VALUE) \
     atomic_store_explicit(&(VAR)->p, VALUE, memory_order_release)
 
+/* This can be used for initializing RCU pointers before any readers can
+ * see them.  A later ovsrcu_set() needs to make the bigger structure this
+ * is part of visible to the readers. */
+#define ovsrcu_init(VAR, VALUE) \
+    atomic_store_explicit(&(VAR)->p, VALUE, memory_order_relaxed)
+
 /* Calls FUNCTION passing ARG as its pointer-type argument following the next
  * grace period.  See "Usage" above for example.  */
 void ovsrcu_postpone__(void (*function)(void *aux), void *aux);
-- 
1.7.10.4

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to