summaryrefslogtreecommitdiffstats
path: root/compiler-rt/test
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2019-02-13 13:21:24 +0000
committerDmitry Vyukov <dvyukov@google.com>2019-02-13 13:21:24 +0000
commit76e961207bd19b218f2afe66e55511261ee2f132 (patch)
treee5620207682df7031e6fbd7e54eb3eda365e0281 /compiler-rt/test
parentf81f7f3ef691058f3b1d970aa17b54284b8501ba (diff)
downloadbcm5719-llvm-76e961207bd19b218f2afe66e55511261ee2f132.tar.gz
bcm5719-llvm-76e961207bd19b218f2afe66e55511261ee2f132.zip
tsan: add fiber support This patch adds functions for managing fibers: __tsan_get_current_fiber() __tsan_create_fiber() __tsan_destroy_fiber() __tsan_switch_to_fiber() __tsan_set_fiber_name() See the added tests for use examples. Author: yuri (Yuri Per) Reviewed in: https://reviews.llvm.org/D54889 [The previous commit of this change was reverted, this is a resubmit with a squashed fix for check_analyze.sh and COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED] llvm-svn: 353947
Diffstat (limited to 'compiler-rt/test')
-rw-r--r--compiler-rt/test/tsan/fiber_asm.cc86
-rw-r--r--compiler-rt/test/tsan/fiber_from_thread.cc48
-rw-r--r--compiler-rt/test/tsan/fiber_longjmp.cc80
-rw-r--r--compiler-rt/test/tsan/fiber_race.cc36
-rw-r--r--compiler-rt/test/tsan/fiber_simple.cc36
-rw-r--r--compiler-rt/test/tsan/fiber_two_threads.cc62
6 files changed, 348 insertions, 0 deletions
diff --git a/compiler-rt/test/tsan/fiber_asm.cc b/compiler-rt/test/tsan/fiber_asm.cc
new file mode 100644
index 00000000000..806c70cce72
--- /dev/null
+++ b/compiler-rt/test/tsan/fiber_asm.cc
@@ -0,0 +1,86 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+// REQUIRES: x86_64-target-arch
+// UNSUPPORTED: darwin
+#include "test.h"
+
+struct ucontext {
+ void *sp;
+ void *fiber;
+};
+
+extern "C" {
+ void ucontext_do_switch(void **save, void **load);
+ void ucontext_trampoline();
+}
+
+__asm__(".global ucontext_do_switch\n"
+ "ucontext_do_switch:\n\t"
+ "pushq %rbp\n\t"
+ "pushq %r15\n\t"
+ "pushq %r14\n\t"
+ "pushq %r13\n\t"
+ "pushq %r12\n\t"
+ "pushq %rbx\n\t"
+ "movq %rsp, (%rdi)\n\t"
+ "movq (%rsi), %rsp\n\t"
+ "popq %rbx\n\t"
+ "popq %r12\n\t"
+ "popq %r13\n\t"
+ "popq %r14\n\t"
+ "popq %r15\n\t"
+ "popq %rbp\n\t"
+ "retq");
+
+__asm__(".global ucontext_trampoline\n"
+ "ucontext_trampoline:\n\t"
+ ".cfi_startproc\n\t"
+ ".cfi_undefined rip\n\t"
+ "movq %r12, %rdi\n\t"
+ "jmpq *%rbx\n\t"
+ ".cfi_endproc");
+
+void ucontext_init(ucontext *context, void *stack, unsigned stack_sz,
+ void (*func)(void*), void *arg) {
+ void **sp = reinterpret_cast<void **>(static_cast<char *>(stack) + stack_sz);
+ *(--sp) = 0;
+ *(--sp) = reinterpret_cast<void *>(ucontext_trampoline);
+ *(--sp) = 0; // rbp
+ *(--sp) = 0; // r15
+ *(--sp) = 0; // r14
+ *(--sp) = 0; // r13
+ *(--sp) = arg; // r12
+ *(--sp) = reinterpret_cast<void *>(func); // rbx
+ context->sp = sp;
+ context->fiber = __tsan_create_fiber(0);
+}
+
+void ucontext_free(ucontext *context) {
+ __tsan_destroy_fiber(context->fiber);
+}
+
+__attribute__((no_sanitize_thread))
+void ucontext_switch(ucontext *save, ucontext *load) {
+ save->fiber = __tsan_get_current_fiber();
+ __tsan_switch_to_fiber(load->fiber, 0);
+ ucontext_do_switch(&save->sp, &load->sp);
+}
+
+char stack[64 * 1024] __attribute__((aligned(16)));
+
+ucontext uc, orig_uc;
+
+void func(void *arg) {
+ __asm__ __volatile__(".cfi_undefined rip");
+ ucontext_switch(&uc, &orig_uc);
+}
+
+int main() {
+ ucontext_init(&uc, stack, sizeof(stack), func, 0);
+ ucontext_switch(&orig_uc, &uc);
+ ucontext_free(&uc);
+ fprintf(stderr, "PASS\n");
+ return 0;
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer:
+// CHECK: PASS
diff --git a/compiler-rt/test/tsan/fiber_from_thread.cc b/compiler-rt/test/tsan/fiber_from_thread.cc
new file mode 100644
index 00000000000..d8af1e8e7ea
--- /dev/null
+++ b/compiler-rt/test/tsan/fiber_from_thread.cc
@@ -0,0 +1,48 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+// UNSUPPORTED: darwin
+#include "test.h"
+#include <ucontext.h>
+
+char stack[64 * 1024] __attribute__((aligned(16)));
+
+ucontext_t uc, orig_uc1, orig_uc2;
+void *fiber, *orig_fiber1, *orig_fiber2;
+
+int var;
+
+void *Thread(void *x) {
+ orig_fiber2 = __tsan_get_current_fiber();
+ swapcontext(&orig_uc2, &orig_uc1);
+ return 0;
+}
+
+void func() {
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ pthread_join(t, 0);
+ __tsan_switch_to_fiber(orig_fiber1, 0);
+ swapcontext(&uc, &orig_uc1);
+}
+
+int main() {
+ orig_fiber1 = __tsan_get_current_fiber();
+ fiber = __tsan_create_fiber(0);
+ getcontext(&uc);
+ uc.uc_stack.ss_sp = stack;
+ uc.uc_stack.ss_size = sizeof(stack);
+ uc.uc_link = 0;
+ makecontext(&uc, func, 0);
+ var = 1;
+ __tsan_switch_to_fiber(fiber, 0);
+ swapcontext(&orig_uc1, &uc);
+ var = 2;
+ __tsan_switch_to_fiber(orig_fiber2, 0);
+ swapcontext(&orig_uc1, &orig_uc2);
+ var = 3;
+ __tsan_destroy_fiber(fiber);
+ fprintf(stderr, "PASS\n");
+ return 0;
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer:
+// CHECK: PASS
diff --git a/compiler-rt/test/tsan/fiber_longjmp.cc b/compiler-rt/test/tsan/fiber_longjmp.cc
new file mode 100644
index 00000000000..27d776a788c
--- /dev/null
+++ b/compiler-rt/test/tsan/fiber_longjmp.cc
@@ -0,0 +1,80 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+// UNSUPPORTED: darwin
+#include "test.h"
+#include <setjmp.h>
+#include <ucontext.h>
+
+char stack[64 * 1024] __attribute__((aligned(16)));
+
+sigjmp_buf jmpbuf, orig_jmpbuf[2];
+void *fiber, *orig_fiber[2];
+
+const unsigned N = 1000;
+
+__attribute__((noinline))
+void switch0() {
+ if (!sigsetjmp(jmpbuf, 0)) {
+ __tsan_switch_to_fiber(orig_fiber[0], 0);
+ siglongjmp(orig_jmpbuf[0], 1);
+ }
+}
+
+void func() {
+ if (!sigsetjmp(jmpbuf, 0)) {
+ __tsan_switch_to_fiber(orig_fiber[0], 0);
+ siglongjmp(orig_jmpbuf[0], 1);
+ }
+ for (;;) {
+ switch0();
+ if (!sigsetjmp(jmpbuf, 0)) {
+ __tsan_switch_to_fiber(orig_fiber[1], 0);
+ siglongjmp(orig_jmpbuf[1], 1);
+ }
+ }
+}
+
+void *Thread(void *x) {
+ orig_fiber[1] = __tsan_get_current_fiber();
+ for (unsigned i = 0; i < N; i++) {
+ barrier_wait(&barrier);
+ if (!sigsetjmp(orig_jmpbuf[1], 0)) {
+ __tsan_switch_to_fiber(fiber, 0);
+ siglongjmp(jmpbuf, 1);
+ }
+ barrier_wait(&barrier);
+ }
+ return 0;
+}
+
+int main() {
+ fiber = __tsan_create_fiber(0);
+ barrier_init(&barrier, 2);
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ orig_fiber[0] = __tsan_get_current_fiber();
+ ucontext_t uc, orig_uc;
+ getcontext(&uc);
+ uc.uc_stack.ss_sp = stack;
+ uc.uc_stack.ss_size = sizeof(stack);
+ uc.uc_link = 0;
+ makecontext(&uc, func, 0);
+ if (!sigsetjmp(orig_jmpbuf[0], 0)) {
+ __tsan_switch_to_fiber(fiber, 0);
+ swapcontext(&orig_uc, &uc);
+ }
+ for (unsigned i = 0; i < N; i++) {
+ if (!sigsetjmp(orig_jmpbuf[0], 0)) {
+ __tsan_switch_to_fiber(fiber, 0);
+ siglongjmp(jmpbuf, 1);
+ }
+ barrier_wait(&barrier);
+ barrier_wait(&barrier);
+ }
+ pthread_join(t, 0);
+ __tsan_destroy_fiber(fiber);
+ fprintf(stderr, "PASS\n");
+ return 0;
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer:
+// CHECK: PASS
diff --git a/compiler-rt/test/tsan/fiber_race.cc b/compiler-rt/test/tsan/fiber_race.cc
new file mode 100644
index 00000000000..89bcdddd5c3
--- /dev/null
+++ b/compiler-rt/test/tsan/fiber_race.cc
@@ -0,0 +1,36 @@
+// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s
+// UNSUPPORTED: darwin
+#include "test.h"
+#include <ucontext.h>
+
+char stack[64 * 1024] __attribute__((aligned(16)));
+
+ucontext_t uc, orig_uc;
+void *fiber, *orig_fiber;
+
+int var;
+
+void func() {
+ var = 1;
+ __tsan_switch_to_fiber(orig_fiber, __tsan_switch_to_fiber_no_sync);
+ swapcontext(&uc, &orig_uc);
+}
+
+int main() {
+ orig_fiber = __tsan_get_current_fiber();
+ fiber = __tsan_create_fiber(0);
+ getcontext(&uc);
+ uc.uc_stack.ss_sp = stack;
+ uc.uc_stack.ss_size = sizeof(stack);
+ uc.uc_link = 0;
+ makecontext(&uc, func, 0);
+ var = 2;
+ __tsan_switch_to_fiber(fiber, __tsan_switch_to_fiber_no_sync);
+ swapcontext(&orig_uc, &uc);
+ __tsan_destroy_fiber(fiber);
+ fprintf(stderr, "PASS\n");
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: PASS
diff --git a/compiler-rt/test/tsan/fiber_simple.cc b/compiler-rt/test/tsan/fiber_simple.cc
new file mode 100644
index 00000000000..ce529e7299d
--- /dev/null
+++ b/compiler-rt/test/tsan/fiber_simple.cc
@@ -0,0 +1,36 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+// UNSUPPORTED: darwin
+#include "test.h"
+#include <ucontext.h>
+
+char stack[64 * 1024] __attribute__((aligned(16)));
+
+ucontext_t uc, orig_uc;
+void *fiber, *orig_fiber;
+
+int var;
+
+void func() {
+ var = 1;
+ __tsan_switch_to_fiber(orig_fiber, 0);
+ swapcontext(&uc, &orig_uc);
+}
+
+int main() {
+ orig_fiber = __tsan_get_current_fiber();
+ fiber = __tsan_create_fiber(0);
+ getcontext(&uc);
+ uc.uc_stack.ss_sp = stack;
+ uc.uc_stack.ss_size = sizeof(stack);
+ uc.uc_link = 0;
+ makecontext(&uc, func, 0);
+ var = 2;
+ __tsan_switch_to_fiber(fiber, 0);
+ swapcontext(&orig_uc, &uc);
+ __tsan_destroy_fiber(fiber);
+ fprintf(stderr, "PASS\n");
+ return 0;
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer:
+// CHECK: PASS
diff --git a/compiler-rt/test/tsan/fiber_two_threads.cc b/compiler-rt/test/tsan/fiber_two_threads.cc
new file mode 100644
index 00000000000..eaadb65acc1
--- /dev/null
+++ b/compiler-rt/test/tsan/fiber_two_threads.cc
@@ -0,0 +1,62 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+// UNSUPPORTED: darwin
+#include "test.h"
+#include <ucontext.h>
+
+char stack[64 * 1024] __attribute__((aligned(16)));
+
+ucontext_t uc, orig_uc[2];
+void *fiber, *orig_fiber[2];
+
+const unsigned N = 1000;
+
+__attribute__((noinline))
+void switch0() {
+ __tsan_switch_to_fiber(orig_fiber[0], 0);
+ swapcontext(&uc, &orig_uc[0]);
+}
+
+void func() {
+ for (;;) {
+ switch0();
+ __tsan_switch_to_fiber(orig_fiber[1], 0);
+ swapcontext(&uc, &orig_uc[1]);
+ }
+}
+
+void *Thread(void *x) {
+ orig_fiber[1] = __tsan_get_current_fiber();
+ for (unsigned i = 0; i < N; i++) {
+ barrier_wait(&barrier);
+ __tsan_switch_to_fiber(fiber, 0);
+ swapcontext(&orig_uc[1], &uc);
+ barrier_wait(&barrier);
+ }
+ return 0;
+}
+
+int main() {
+ fiber = __tsan_create_fiber(0);
+ barrier_init(&barrier, 2);
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ orig_fiber[0] = __tsan_get_current_fiber();
+ getcontext(&uc);
+ uc.uc_stack.ss_sp = stack;
+ uc.uc_stack.ss_size = sizeof(stack);
+ uc.uc_link = 0;
+ makecontext(&uc, func, 0);
+ for (unsigned i = 0; i < N; i++) {
+ __tsan_switch_to_fiber(fiber, 0);
+ swapcontext(&orig_uc[0], &uc);
+ barrier_wait(&barrier);
+ barrier_wait(&barrier);
+ }
+ pthread_join(t, 0);
+ __tsan_destroy_fiber(fiber);
+ fprintf(stderr, "PASS\n");
+ return 0;
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer:
+// CHECK: PASS
OpenPOWER on IntegriCloud