RCU dereference check if within read-side critical section
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Wed, 12 Nov 2014 20:16:08 +0000 (15:16 -0500)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Thu, 13 Nov 2014 19:30:31 +0000 (14:30 -0500)
Need to link with liburcu-common in addition to urcu flavor.

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
14 files changed:
Makefile.am
tests/benchmark/Makefile.am
tests/regression/Makefile.am
tests/unit/Makefile.am
urcu-bp.h
urcu-checker.c [new file with mode: 0644]
urcu-pointer.h
urcu-qsbr.h
urcu.c
urcu.h
urcu/static/urcu-bp.h
urcu/static/urcu-qsbr.h
urcu/static/urcu.h
urcu/urcu-checker.h [new file with mode: 0644]

index 752510d717783c9d0868c6701767613b617ba357..7ead5f06283ec8d96521b159898ee03cef48ef6f 100644 (file)
@@ -24,7 +24,7 @@ nobase_dist_include_HEADERS = urcu/compiler.h urcu/hlist.h urcu/list.h \
                $(top_srcdir)/urcu/map/*.h \
                $(top_srcdir)/urcu/static/*.h \
                urcu/rand-compat.h \
-               urcu/tls-compat.h
+               urcu/tls-compat.h urcu/urcu-checker.h
 nobase_nodist_include_HEADERS = urcu/arch.h urcu/uatomic.h urcu/config.h
 
 dist_noinst_HEADERS = urcu-die.h urcu-wait.h
@@ -57,7 +57,8 @@ lib_LTLIBRARIES = liburcu-common.la \
 # liburcu-common contains wait-free queues (needed by call_rcu) as well
 # as futex fallbacks.
 #
-liburcu_common_la_SOURCES = wfqueue.c wfcqueue.c wfstack.c $(COMPAT)
+liburcu_common_la_SOURCES = wfqueue.c wfcqueue.c wfstack.c $(COMPAT) \
+               urcu-checker.c
 
 liburcu_la_SOURCES = urcu.c urcu-pointer.c $(COMPAT)
 liburcu_la_LIBADD = liburcu-common.la
index 85d454d829de1b64fb34db503e369d91ec294f10..b8cf35d054d8afe72cb1e365ebc9444e608eb8c6 100644 (file)
@@ -23,12 +23,12 @@ noinst_PROGRAMS = test_urcu test_urcu_dynamic_link test_urcu_timing \
        test_urcu_lfs_rcu_dynlink
 
 URCU_COMMON_LIB=$(top_builddir)/liburcu-common.la
-URCU_LIB=$(top_builddir)/liburcu.la
-URCU_QSBR_LIB=$(top_builddir)/liburcu-qsbr.la
-URCU_MB_LIB=$(top_builddir)/liburcu-mb.la
-URCU_SIGNAL_LIB=$(top_builddir)/liburcu-signal.la
-URCU_BP_LIB=$(top_builddir)/liburcu-bp.la
-URCU_CDS_LIB=$(top_builddir)/liburcu-cds.la
+URCU_LIB=$(top_builddir)/liburcu.la $(URCU_COMMON_LIB)
+URCU_QSBR_LIB=$(top_builddir)/liburcu-qsbr.la $(URCU_COMMON_LIB)
+URCU_MB_LIB=$(top_builddir)/liburcu-mb.la $(URCU_COMMON_LIB)
+URCU_SIGNAL_LIB=$(top_builddir)/liburcu-signal.la $(URCU_COMMON_LIB)
+URCU_BP_LIB=$(top_builddir)/liburcu-bp.la $(URCU_COMMON_LIB)
+URCU_CDS_LIB=$(top_builddir)/liburcu-cds.la $(URCU_COMMON_LIB)
 
 DEBUG_YIELD_LIB=$(builddir)/../common/libdebug-yield.la
 
index 8dfe542ff22e63f8d7825d6e801b714b37e14329..354ad1a9f69b2e6d44b36a5c9f92dd90fcfa23e3 100644 (file)
@@ -13,12 +13,12 @@ noinst_PROGRAMS = test_urcu_fork \
 noinst_HEADERS = rcutorture.h
 
 URCU_COMMON_LIB=$(top_builddir)/liburcu-common.la
-URCU_LIB=$(top_builddir)/liburcu.la
-URCU_QSBR_LIB=$(top_builddir)/liburcu-qsbr.la
-URCU_MB_LIB=$(top_builddir)/liburcu-mb.la
-URCU_SIGNAL_LIB=$(top_builddir)/liburcu-signal.la
-URCU_BP_LIB=$(top_builddir)/liburcu-bp.la
-URCU_CDS_LIB=$(top_builddir)/liburcu-cds.la
+URCU_LIB=$(top_builddir)/liburcu.la $(URCU_COMMON_LIB)
+URCU_QSBR_LIB=$(top_builddir)/liburcu-qsbr.la $(URCU_COMMON_LIB)
+URCU_MB_LIB=$(top_builddir)/liburcu-mb.la $(URCU_COMMON_LIB)
+URCU_SIGNAL_LIB=$(top_builddir)/liburcu-signal.la $(URCU_COMMON_LIB)
+URCU_BP_LIB=$(top_builddir)/liburcu-bp.la $(URCU_COMMON_LIB)
+URCU_CDS_LIB=$(top_builddir)/liburcu-cds.la $(URCU_COMMON_LIB)
 
 test_urcu_fork_SOURCES = test_urcu_fork.c
 test_urcu_fork_LDADD = $(URCU_LIB)
index 8cc4acbd9e217c3e70486dfb58334a86a45cd1a9..cd40b399372919f707e99f2968c616af547198e3 100644 (file)
@@ -10,12 +10,12 @@ noinst_PROGRAMS = test_uatomic \
 noinst_HEADERS = test_urcu_multiflavor.h
 
 URCU_COMMON_LIB=$(top_builddir)/liburcu-common.la
-URCU_LIB=$(top_builddir)/liburcu.la
-URCU_QSBR_LIB=$(top_builddir)/liburcu-qsbr.la
-URCU_MB_LIB=$(top_builddir)/liburcu-mb.la
-URCU_SIGNAL_LIB=$(top_builddir)/liburcu-signal.la
-URCU_BP_LIB=$(top_builddir)/liburcu-bp.la
-URCU_CDS_LIB=$(top_builddir)/liburcu-cds.la
+URCU_LIB=$(top_builddir)/liburcu.la $(URCU_COMMON_LIB)
+URCU_QSBR_LIB=$(top_builddir)/liburcu-qsbr.la $(URCU_COMMON_LIB)
+URCU_MB_LIB=$(top_builddir)/liburcu-mb.la $(URCU_COMMON_LIB)
+URCU_SIGNAL_LIB=$(top_builddir)/liburcu-signal.la $(URCU_COMMON_LIB)
+URCU_BP_LIB=$(top_builddir)/liburcu-bp.la $(URCU_COMMON_LIB)
+URCU_CDS_LIB=$(top_builddir)/liburcu-cds.la $(URCU_COMMON_LIB)
 
 test_uatomic_SOURCES = test_uatomic.c
 test_uatomic_LDADD = $(URCU_COMMON_LIB)
index 4718f3b38e93aac09c2e670925e7247a72d04684..8704ddbf64e8c583511daa3281c7b9f3c3dd1df9 100644 (file)
--- a/urcu-bp.h
+++ b/urcu-bp.h
@@ -88,8 +88,8 @@ extern "C" {
  * See LGPL-only urcu/static/urcu-pointer.h for documentation.
  */
 
-extern void rcu_read_lock(void);
-extern void rcu_read_unlock(void);
+extern void test_rcu_read_lock(void);
+extern void test_rcu_read_unlock(void);
 extern int rcu_read_ongoing(void);
 
 extern void *rcu_dereference_sym_bp(void *p);
diff --git a/urcu-checker.c b/urcu-checker.c
new file mode 100644 (file)
index 0000000..234bd9b
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * urcu-checker.c
+ *
+ * Userspace RCU library checker
+ *
+ * Copyright (c) 2014 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <urcu/urcu-checker.h>
+#include <urcu/tls-compat.h>
+
+#define URCU_DEBUG_STACK_LEN   10
+
+struct urcu_debug_entry {
+       void *ip;
+       int depth;
+};
+
+struct urcu_debug_stack {
+       struct urcu_debug_entry stack[URCU_DEBUG_STACK_LEN];
+       int stackend;
+};
+
+static DEFINE_URCU_TLS(struct urcu_debug_stack, rcu_debug_stack);
+
+void rcu_read_lock_debug(void)
+{
+       struct urcu_debug_stack *r = &URCU_TLS(rcu_debug_stack);
+
+       r->stack[r->stackend++].ip = __builtin_return_address(0);
+}
+
+void rcu_read_unlock_debug(void)
+{
+       struct urcu_debug_stack *r = &URCU_TLS(rcu_debug_stack);
+
+       assert(r->stackend != 0);
+       r->stack[--r->stackend].ip = NULL;
+}
+
+void rcu_read_ongoing_check_debug(const char *func)
+{
+       struct urcu_debug_stack *r = &URCU_TLS(rcu_debug_stack);
+
+       if (r->stackend == 0) {
+               fprintf(stderr, "URCU LOCKED CHECK failure: %p\n",
+                       __builtin_return_address(0));
+               abort();
+       }
+}
index 5be986ca65a0d6aab3027812fdbc2f0b4acdffb5..6c79c58fe9e6293a41772bba1d2a91aad8b503be 100644 (file)
@@ -29,6 +29,7 @@
 #include <urcu/compiler.h>
 #include <urcu/arch.h>
 #include <urcu/uatomic.h>
+#include <urcu/urcu-checker.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -44,7 +45,11 @@ extern "C" {
  * Fetch a RCU-protected pointer. Typically used to copy the variable ptr to a
  * local variable.
  */
-#define rcu_dereference                _rcu_dereference
+#define rcu_dereference(p)                             \
+       ({                                              \
+               rcu_read_ongoing_check_debug(__func__); \
+               _rcu_dereference(p);                    \
+       })
 
 /*
  * type *rcu_cmpxchg_pointer(type **ptr, type *new, type *old)
index b4a28a78a6a84490611f1a12277197f4a02092d6..60f6171b451c38038cbce7b29620bb42b72bef3e 100644 (file)
@@ -108,6 +108,9 @@ extern void rcu_read_unlock(void);
 
 #endif /* !RCU_DEBUG */
 
+#define test_rcu_read_lock             rcu_read_lock_qsbr
+#define test_rcu_read_unlock           rcu_read_unlock_qsbr
+
 extern int rcu_read_ongoing(void);
 extern void rcu_quiescent_state(void);
 extern void rcu_thread_offline(void);
diff --git a/urcu.c b/urcu.c
index ae3490f7cb2cdc1f7cdb1d26f77c0ee22620e9eb..d86cb6cad2a646ae27608429512a3b971ebd435a 100644 (file)
--- a/urcu.c
+++ b/urcu.c
@@ -441,6 +441,8 @@ int rcu_read_ongoing(void)
        return _rcu_read_ongoing();
 }
 
+
+
 void rcu_register_thread(void)
 {
        URCU_TLS(rcu_reader).tid = pthread_self();
diff --git a/urcu.h b/urcu.h
index b8ca700ddcdb750270c5e39bd86080b559102363..0a1dd4bf97b374f230c8bb3a3577f52687831713 100644 (file)
--- a/urcu.h
+++ b/urcu.h
@@ -33,6 +33,9 @@
 
 #include <stdlib.h>
 #include <pthread.h>
+#include <urcu/tls-compat.h>
+#include <stdio.h>
+#include <assert.h>
 
 /*
  * See urcu-pointer.h and urcu/static/urcu-pointer.h for pointer
index b6d5f132778380c57af501307cf25e017c92c8ec..0bdefff2b15de3339806e4e3df7cb2117148a651 100644 (file)
@@ -39,6 +39,7 @@
 #include <urcu/uatomic.h>
 #include <urcu/list.h>
 #include <urcu/tls-compat.h>
+#include <urcu/urcu-checker.h>
 
 /*
  * This code section can only be included in LGPL 2.1 compatible source code.
@@ -155,6 +156,7 @@ static inline void _rcu_read_lock(void)
 {
        unsigned long tmp;
 
+       rcu_read_lock_debug();
        if (caa_unlikely(!URCU_TLS(rcu_reader)))
                rcu_bp_register(); /* If not yet registered. */
        cmm_barrier();  /* Ensure the compiler does not reorder us with mutex */
@@ -175,6 +177,7 @@ static inline void _rcu_read_unlock(void)
        cmm_smp_mb();
        _CMM_STORE_SHARED(URCU_TLS(rcu_reader)->ctr, URCU_TLS(rcu_reader)->ctr - RCU_GP_COUNT);
        cmm_barrier();  /* Ensure the compiler does not reorder us with mutex */
+       rcu_read_unlock_debug();
 }
 
 /*
index 8f2ca32a2f111c4b1469c010c5f1fcb4669039a5..1ef830aba1833fa888ebdfa3ee4daa1034cbdf8c 100644 (file)
@@ -43,6 +43,7 @@
 #include <urcu/list.h>
 #include <urcu/futex.h>
 #include <urcu/tls-compat.h>
+#include <urcu/urcu-checker.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -132,6 +133,7 @@ static inline enum rcu_state rcu_reader_state(unsigned long *ctr)
  */
 static inline void _rcu_read_lock(void)
 {
+       rcu_read_lock_debug();
        rcu_assert(URCU_TLS(rcu_reader).ctr);
 }
 
@@ -144,6 +146,7 @@ static inline void _rcu_read_lock(void)
  */
 static inline void _rcu_read_unlock(void)
 {
+       rcu_read_unlock_debug();
 }
 
 /*
index b5fc09f93553578ae32f660b9c65a49a9ea3517f..0fe32e88cea48241a463054f4e4411aee0428e3a 100644 (file)
@@ -42,6 +42,7 @@
 #include <urcu/futex.h>
 #include <urcu/tls-compat.h>
 #include <urcu/rand-compat.h>
+#include <urcu/urcu-checker.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -219,6 +220,7 @@ static inline void _rcu_read_lock(void)
 {
        unsigned long tmp;
 
+       rcu_read_lock_debug();
        cmm_barrier();
        tmp = URCU_TLS(rcu_reader).ctr;
        _rcu_read_lock_update(tmp);
@@ -255,6 +257,7 @@ static inline void _rcu_read_unlock(void)
        tmp = URCU_TLS(rcu_reader).ctr;
        _rcu_read_unlock_update_and_wakeup(tmp);
        cmm_barrier();  /* Ensure the compiler does not reorder us with mutex */
+       rcu_read_unlock_debug();
 }
 
 /*
diff --git a/urcu/urcu-checker.h b/urcu/urcu-checker.h
new file mode 100644 (file)
index 0000000..cba6a0d
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef _URCU_CHECKER_H
+#define _URCU_CHECKER_H
+
+/*
+ * urcu-checker.h
+ *
+ * Userspace RCU checker header
+ *
+ * Copyright (c) 2014 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * LGPL-compatible code should include this header with :
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+void rcu_read_lock_debug(void);
+void rcu_read_unlock_debug(void);
+void rcu_read_ongoing_check_debug(const char *func);
+
+#endif /* _URCU_CHECKER_H */
This page took 0.031981 seconds and 4 git commands to generate.