summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_interceptors.cc36
-rw-r--r--compiler-rt/test/tsan/load_shared_lib.cc2
-rw-r--r--compiler-rt/test/tsan/test.h31
3 files changed, 51 insertions, 18 deletions
diff --git a/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc b/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc
index 2741af88b09..57a676f8d72 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc
+++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc
@@ -2683,3 +2683,39 @@ void InitializeInterceptors() {
}
} // namespace __tsan
+
+// Invisible barrier for tests.
+// There were several unsuccessful iterations for this functionality:
+// 1. Initially it was implemented in user code using
+// REAL(pthread_barrier_wait). But pthread_barrier_wait is not supported on
+// MacOS. Futexes are linux-specific for this matter.
+// 2. Then we switched to atomics+usleep(10). But usleep produced parasitic
+// "as-if synchronized via sleep" messages in reports which failed some
+// output tests.
+// 3. Then we switched to atomics+sched_yield. But this produced tons of tsan-
+// visible events, which lead to "failed to restore stack trace" failures.
+// Note that no_sanitize_thread attribute does not turn off atomic interception
+// so attaching it to the function defined in user code does not help.
+// That's why we now have what we have.
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_testonly_barrier_init(u64 *barrier, u32 count) {
+ if (count >= (1 << 8)) {
+ Printf("barrier_init: count is too large (%d)\n", count);
+ Die();
+ }
+ // 8 lsb is thread count, the remaining are count of entered threads.
+ *barrier = count;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_testonly_barrier_wait(u64 *barrier) {
+ unsigned old = __atomic_fetch_add(barrier, 1 << 8, __ATOMIC_RELAXED);
+ unsigned old_epoch = (old >> 8) / (old & 0xff);
+ for (;;) {
+ unsigned cur = __atomic_load_n(barrier, __ATOMIC_RELAXED);
+ unsigned cur_epoch = (cur >> 8) / (cur & 0xff);
+ if (cur_epoch != old_epoch)
+ return;
+ internal_sched_yield();
+ }
+}
diff --git a/compiler-rt/test/tsan/load_shared_lib.cc b/compiler-rt/test/tsan/load_shared_lib.cc
index b7934b82df7..f02280895f8 100644
--- a/compiler-rt/test/tsan/load_shared_lib.cc
+++ b/compiler-rt/test/tsan/load_shared_lib.cc
@@ -3,7 +3,7 @@
// symbolized correctly.
// RUN: %clangxx_tsan -O1 %s -DBUILD_SO -fPIC -shared -o %t-so.so
-// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t -rdynamic && %deflake %run %t | FileCheck %s
#ifdef BUILD_SO
diff --git a/compiler-rt/test/tsan/test.h b/compiler-rt/test/tsan/test.h
index e7ffefdcf21..cec7c0d32f8 100644
--- a/compiler-rt/test/tsan/test.h
+++ b/compiler-rt/test/tsan/test.h
@@ -14,27 +14,24 @@
// TSan-invisible barrier.
// Tests use it to establish necessary execution order in a way that does not
// interfere with tsan (does not establish synchronization between threads).
-// 8 lsb is thread count, the remaining are count of entered threads.
typedef unsigned long long invisible_barrier_t;
-void barrier_init(invisible_barrier_t *barrier, unsigned count) {
- if (count >= (1 << 8))
- exit(fprintf(stderr, "barrier_init: count is too large (%d)\n", count));
- *barrier = count;
+#ifdef __cplusplus
+extern "C" {
+#endif
+void __tsan_testonly_barrier_init(invisible_barrier_t *barrier,
+ unsigned count);
+void __tsan_testonly_barrier_wait(invisible_barrier_t *barrier);
+#ifdef __cplusplus
}
+#endif
-void barrier_wait(invisible_barrier_t *barrier) {
- unsigned old = __atomic_fetch_add(barrier, 1 << 8, __ATOMIC_RELAXED);
- unsigned old_epoch = (old >> 8) / (old & 0xff);
- for (;;) {
- unsigned cur = __atomic_load_n(barrier, __ATOMIC_RELAXED);
- unsigned cur_epoch = (cur >> 8) / (cur & 0xff);
- if (cur_epoch != old_epoch)
- return;
- // Can't use usleep, because it leads to spurious "As if synchronized via
- // sleep" messages which fail some output tests.
- sched_yield();
- }
+static inline void barrier_init(invisible_barrier_t *barrier, unsigned count) {
+ __tsan_testonly_barrier_init(barrier, count);
+}
+
+static inline void barrier_wait(invisible_barrier_t *barrier) {
+ __tsan_testonly_barrier_wait(barrier);
}
// Default instance of the barrier, but a test can declare more manually.
OpenPOWER on IntegriCloud