[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