diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2019-02-13 13:21:24 +0000 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2019-02-13 13:21:24 +0000 |
| commit | 76e961207bd19b218f2afe66e55511261ee2f132 (patch) | |
| tree | e5620207682df7031e6fbd7e54eb3eda365e0281 /compiler-rt/test | |
| parent | f81f7f3ef691058f3b1d970aa17b54284b8501ba (diff) | |
| download | bcm5719-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.cc | 86 | ||||
| -rw-r--r-- | compiler-rt/test/tsan/fiber_from_thread.cc | 48 | ||||
| -rw-r--r-- | compiler-rt/test/tsan/fiber_longjmp.cc | 80 | ||||
| -rw-r--r-- | compiler-rt/test/tsan/fiber_race.cc | 36 | ||||
| -rw-r--r-- | compiler-rt/test/tsan/fiber_simple.cc | 36 | ||||
| -rw-r--r-- | compiler-rt/test/tsan/fiber_two_threads.cc | 62 |
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 |

