[ovs-dev] [PATCH RFC 5/8] ovs-rcu: New library.

Ben Pfaff blp at nicira.com
Thu Jan 23 00:11:55 UTC 2014


Signed-off-by: Ben Pfaff <blp at nicira.com>
---
 configure.ac                  |    1 +
 lib/automake.mk               |    3 ++
 lib/ovs-rcu-liburcu.h         |   65 +++++++++++++++++++++++++++++++++++++++++
 lib/ovs-rcu-norcu.h           |   58 ++++++++++++++++++++++++++++++++++++
 lib/ovs-rcu.h                 |   36 +++++++++++++++++++++++
 lib/ovs-thread.c              |   23 +++++++++++++--
 lib/timeval.c                 |   13 +++++++++
 m4/openvswitch.m4             |   16 ++++++++++
 ofproto/ofproto-dpif-upcall.c |    5 ++++
 9 files changed, 218 insertions(+), 2 deletions(-)
 create mode 100644 lib/ovs-rcu-liburcu.h
 create mode 100644 lib/ovs-rcu-norcu.h
 create mode 100644 lib/ovs-rcu.h

diff --git a/configure.ac b/configure.ac
index 9b6c69e..a9c5cfe 100644
--- a/configure.ac
+++ b/configure.ac
@@ -70,6 +70,7 @@ AC_CHECK_FUNCS([mlockall strnlen getloadavg statvfs getmntent_r])
 AC_CHECK_HEADERS([mntent.h sys/statvfs.h linux/types.h linux/if_ether.h stdatomic.h])
 AC_CHECK_HEADERS([net/if_mib.h], [], [], [[#include <sys/types.h>
 #include <net/if.h>]])
+OVS_CHECK_LIBURCU
 
 OVS_CHECK_PKIDIR
 OVS_CHECK_RUNDIR
diff --git a/lib/automake.mk b/lib/automake.mk
index 94ba060..b2950ad 100644
--- a/lib/automake.mk
+++ b/lib/automake.mk
@@ -141,6 +141,9 @@ lib_libopenvswitch_la_SOURCES = \
 	lib/ovs-atomic-pthreads.c \
 	lib/ovs-atomic-pthreads.h \
 	lib/ovs-atomic.h \
+	lib/ovs-rcu-liburcu.h \
+	lib/ovs-rcu-norcu.h \
+	lib/ovs-rcu.h \
 	lib/ovs-thread.c \
 	lib/ovs-thread.h \
 	lib/ovsdb-data.c \
diff --git a/lib/ovs-rcu-liburcu.h b/lib/ovs-rcu-liburcu.h
new file mode 100644
index 0000000..b1ea4ea
--- /dev/null
+++ b/lib/ovs-rcu-liburcu.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 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.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* This header implements RCU primitives using liburcu. */
+#ifndef IN_OVS_RCU_H
+#error "This header should only be included indirectly via ovs-rcu.h."
+#endif
+
+#include <urcu-qsbr.h>
+
+struct ovs_rcuref {
+    struct ovs_refcount refcnt;
+    struct rcu_head rcu_head;
+};
+
+static inline void
+ovs_rcuref_init(struct ovs_rcuref *rcuref)
+{
+    ovs_refcount_init(&rcuref->refcnt);
+}
+
+static inline void
+ovs_rcuref_destroy(struct ovs_rcuref *rcuref)
+{
+    ovs_refcount_destroy(&rcuref->refcnt);
+}
+
+static inline void
+ovs_rcuref_ref(struct ovs_rcuref *rcuref, enum ovs_rcuref_type type)
+{
+    if (type == OVS_RCUREF_OWNER) {
+        ovs_refcount_ref(&rcuref->refcnt);
+    } else {
+        rcu_read_lock();
+    }
+}
+
+#define OVS_RCUREF_CONTAINER_OF(RCU_HEAD, STRUCT, MEMBER) \
+    CONTAINER_OF(RCU_HEAD, STRUCT, MEMBER.rcu_head)
+
+static inline void
+ovs_rcuref_unref(struct ovs_rcuref *rcuref, enum ovs_rcuref_type type,
+                 void (*free_cb)(struct rcu_head *))
+{
+    if (type == OVS_RCUREF_OWNER) {
+        if (ovs_refcount_unref(&rcuref->refcnt) == 1) {
+            call_rcu(&rcuref->rcu_head, free_cb);
+        }
+    } else {
+        rcu_read_unlock();
+    }
+}
diff --git a/lib/ovs-rcu-norcu.h b/lib/ovs-rcu-norcu.h
new file mode 100644
index 0000000..3cee8f7
--- /dev/null
+++ b/lib/ovs-rcu-norcu.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 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.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* This header implements RCU primitives without any actual RCU library. */
+#ifndef IN_OVS_RCU_H
+#error "This header should only be included indirectly via ovs-rcu.h."
+#endif
+
+/* struct rcu_head is permanently incomplete; nothing ever defines it. */
+struct rcu_head;
+
+struct ovs_rcuref {
+    struct ovs_refcount refcnt;
+};
+
+static inline void
+ovs_rcuref_init(struct ovs_rcuref *rcuref)
+{
+    ovs_refcount_init(&rcuref->refcnt);
+}
+
+static inline void
+ovs_rcuref_destroy(struct ovs_rcuref *rcuref)
+{
+    ovs_refcount_destroy(&rcuref->refcnt);
+}
+
+static inline void
+ovs_rcuref_ref_notowner(struct ovs_rcuref *rcuref)
+{
+    ovs_refcount_ref(&rcuref->refcnt);
+}
+
+#define OVS_RCUREF_CONTAINER_OF(RCU_HEAD, STRUCT, MEMBER) \
+    CONTAINER_OF((struct rcuref *) (RCU_HEAD), STRUCT, MEMBER)
+
+static inline void
+ovs_rcuref_unref(struct ovs_rcuref *rcuref,
+                 enum ovs_rcuref_type type OVS_UNUSED,
+                 void (*free_cb)(struct rcu_head *))
+{
+    if (ovs_refcount_unref(&rcuref->refcnt) == 1) {
+        free_cb((struct rcu_head *) rcuref);
+    }
+}
diff --git a/lib/ovs-rcu.h b/lib/ovs-rcu.h
new file mode 100644
index 0000000..fe6ed61
--- /dev/null
+++ b/lib/ovs-rcu.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 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.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OVS_RCU_H
+#define OVS_RCU_H 1
+
+#include "compiler.h"
+#include "ovs-atomic.h"
+
+enum ovs_rcuref_type {
+    OVS_RCUREF_OWNER,
+    OVS_RCUREF_NOTOWNER
+};
+
+#define IN_OVS_RCU_H
+#ifdef HAVE_LIBURCU
+#include "ovs-rcu-liburcu.h"
+#else
+#include "ovs-rcu-norcu.h"
+#endif
+#undef IN_OVS_RCU_H
+
+#endif /* ovs-rcu.h */
diff --git a/lib/ovs-thread.c b/lib/ovs-thread.c
index 8364376..ce1f452 100644
--- a/lib/ovs-thread.c
+++ b/lib/ovs-thread.c
@@ -20,6 +20,7 @@
 #include <poll.h>
 #include <stdlib.h>
 #include <unistd.h>
+#include <urcu-qsbr.h>
 #include "compiler.h"
 #include "hash.h"
 #include "poll-loop.h"
@@ -185,7 +186,12 @@ void
 ovs_mutex_cond_wait(pthread_cond_t *cond, const struct ovs_mutex *mutex_)
 {
     struct ovs_mutex *mutex = CONST_CAST(struct ovs_mutex *, mutex_);
-    int error = pthread_cond_wait(cond, &mutex->lock);
+    int error;
+
+    rcu_thread_offline();
+    error = pthread_cond_wait(cond, &mutex->lock);
+    rcu_thread_online();
+
     if (OVS_UNLIKELY(error)) {
         ovs_abort(error, "pthread_cond_wait failed");
     }
@@ -198,6 +204,12 @@ struct ovsthread_aux {
     void *arg;
 };
 
+static void
+unregister_rcu(void *unused OVS_UNUSED)
+{
+    rcu_unregister_thread();
+}
+
 static void *
 ovsthread_wrapper(void *aux_)
 {
@@ -206,14 +218,21 @@ ovsthread_wrapper(void *aux_)
     struct ovsthread_aux *auxp = aux_;
     struct ovsthread_aux aux;
     unsigned int id;
+    void *retval;
 
     atomic_add(&next_id, 1, &id);
     *ovsthread_id_get() = id;
 
+    rcu_register_thread();
+
     aux = *auxp;
     free(auxp);
 
-    return aux.start(aux.arg);
+    pthread_cleanup_push(unregister_rcu, NULL);
+    retval = aux.start(aux.arg);
+    pthread_cleanup_pop(true);
+
+    return retval;
 }
 
 void
diff --git a/lib/timeval.c b/lib/timeval.c
index 691cf74..0f6ab3e 100644
--- a/lib/timeval.c
+++ b/lib/timeval.c
@@ -25,6 +25,7 @@
 #include <sys/time.h>
 #include <sys/resource.h>
 #include <unistd.h>
+#include <urcu-qsbr.h>
 #include "coverage.h"
 #include "dummy.h"
 #include "dynamic-string.h"
@@ -97,6 +98,8 @@ do_init_time(void)
     struct timespec ts;
 
     coverage_init();
+    rcu_register_thread();
+    rcu_read_lock();
 
     init_clock(&monotonic_clock, (!clock_gettime(CLOCK_MONOTONIC, &ts)
                                   ? CLOCK_MONOTONIC
@@ -261,6 +264,12 @@ time_poll(struct pollfd *pollfds, int n_pollfds, HANDLE *handles OVS_UNUSED,
             time_left = timeout_when - now;
         }
 
+        if (!time_left) {
+            rcu_quiescent_state();
+        } else {
+            rcu_thread_offline();
+        }
+
 #ifndef _WIN32
         retval = poll(pollfds, n_pollfds, time_left);
         if (retval < 0) {
@@ -281,6 +290,10 @@ time_poll(struct pollfd *pollfds, int n_pollfds, HANDLE *handles OVS_UNUSED,
         }
 #endif
 
+        if (time_left) {
+            rcu_thread_online();
+        }
+
         if (deadline <= time_msec()) {
             fatal_signal_handler(SIGALRM);
             if (retval < 0) {
diff --git a/m4/openvswitch.m4 b/m4/openvswitch.m4
index c0af6d4..6f01955 100644
--- a/m4/openvswitch.m4
+++ b/m4/openvswitch.m4
@@ -427,3 +427,19 @@ dnl OVS_CHECK_INCLUDE_NEXT
 AC_DEFUN([OVS_CHECK_INCLUDE_NEXT],
   [AC_REQUIRE([gl_CHECK_NEXT_HEADERS])
    gl_CHECK_NEXT_HEADERS([$1])])
+
+dnl OVS_CHECK_LIBURCU.
+dnl
+dnl If liburcu-qsbr and <urcu-qsbr.h> are available, links against the
+dnl library and defines HAVE_LIBURCU.
+AC_DEFUN([OVS_CHECK_LIBURCU],
+  [save_LIBS=$LIBS
+   LIBS="-lurcu-qsbr $LIBS"
+   AC_LINK_IFELSE(
+     [AC_LANG_PROGRAM([#include <urcu-qsbr.h>
+#include <urcu-call-rcu.h>
+], [rcu_quiescent_state();])],
+     [AC_DEFINE([HAVE_LIBURCU], 1,
+                [Define to 1 if liburcu-qsbr and <urcu-qsbr.h> are
+                 available.])],
+     [LIBS=$save_LIBS])])
diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c
index 1e0c12c..791a5af 100644
--- a/ofproto/ofproto-dpif-upcall.c
+++ b/ofproto/ofproto-dpif-upcall.c
@@ -18,6 +18,7 @@
 #include <errno.h>
 #include <stdbool.h>
 #include <inttypes.h>
+#include <urcu-qsbr.h>
 
 #include "connmgr.h"
 #include "coverage.h"
@@ -288,6 +289,8 @@ void
 udpif_set_threads(struct udpif *udpif, size_t n_handlers,
                   size_t n_revalidators)
 {
+    rcu_thread_offline();
+
     /* Stop the old threads (if any). */
     if (udpif->handlers &&
         (udpif->n_handlers != n_handlers
@@ -398,6 +401,8 @@ udpif_set_threads(struct udpif *udpif, size_t n_handlers,
         xpthread_create(&udpif->dispatcher, NULL, udpif_dispatcher, udpif);
         xpthread_create(&udpif->flow_dumper, NULL, udpif_flow_dumper, udpif);
     }
+
+    rcu_thread_online();
 }
 
 /* Notifies 'udpif' that something changed which may render previous
-- 
1.7.10.4




More information about the dev mailing list