forked from OSchip/llvm-project
Revert "tsan: add fiber support"
This reverts commit r353817 because we think it broke AARch64 and PowerPC buildbots. llvm-svn: 353939
This commit is contained in:
parent
aa4118a873
commit
4152a09e55
|
@ -136,24 +136,6 @@ void __tsan_external_assign_tag(void *addr, void *tag);
|
|||
void __tsan_external_read(void *addr, void *caller_pc, void *tag);
|
||||
void __tsan_external_write(void *addr, void *caller_pc, void *tag);
|
||||
|
||||
// Fiber switching API.
|
||||
// - TSAN context for fiber can be created by __tsan_create_fiber
|
||||
// and freed by __tsan_destroy_fiber.
|
||||
// - TSAN context of current fiber or thread can be obtained
|
||||
// by calling __tsan_get_current_fiber.
|
||||
// - __tsan_switch_to_fiber should be called immediatly before switch
|
||||
// to fiber, such as call of swapcontext.
|
||||
// - Fiber name can be set by __tsan_set_fiber_name.
|
||||
void *__tsan_get_current_fiber(void);
|
||||
void *__tsan_create_fiber(unsigned flags);
|
||||
void __tsan_destroy_fiber(void *fiber);
|
||||
void __tsan_switch_to_fiber(void *fiber, unsigned flags);
|
||||
void __tsan_set_fiber_name(void *fiber, const char *name);
|
||||
|
||||
// Flags for __tsan_switch_to_fiber:
|
||||
// Do not establish a happens-before relation between fibers
|
||||
const unsigned __tsan_switch_to_fiber_no_sync = 1 << 0;
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
|
|
@ -31,7 +31,6 @@ enum ThreadStatus {
|
|||
enum class ThreadType {
|
||||
Regular, // Normal thread
|
||||
Worker, // macOS Grand Central Dispatch (GCD) worker thread
|
||||
Fiber, // Fiber
|
||||
};
|
||||
|
||||
// Generic thread context. Specific sanitizer tools may inherit from it.
|
||||
|
|
|
@ -554,7 +554,6 @@ static void LongJmp(ThreadState *thr, uptr *env) {
|
|||
|
||||
// FIXME: put everything below into a common extern "C" block?
|
||||
extern "C" void __tsan_setjmp(uptr sp, uptr mangled_sp) {
|
||||
cur_thread_init();
|
||||
SetJmp(cur_thread(), sp, mangled_sp);
|
||||
}
|
||||
|
||||
|
@ -943,7 +942,6 @@ extern "C" void *__tsan_thread_start_func(void *arg) {
|
|||
void *param = p->param;
|
||||
int tid = 0;
|
||||
{
|
||||
cur_thread_init();
|
||||
ThreadState *thr = cur_thread();
|
||||
// Thread-local state is not initialized yet.
|
||||
ScopedIgnoreInterceptors ignore;
|
||||
|
@ -1055,9 +1053,6 @@ TSAN_INTERCEPTOR(int, pthread_detach, void *th) {
|
|||
TSAN_INTERCEPTOR(void, pthread_exit, void *retval) {
|
||||
{
|
||||
SCOPED_INTERCEPTOR_RAW(pthread_exit, retval);
|
||||
#if !SANITIZER_MAC && !SANITIZER_ANDROID
|
||||
CHECK_EQ(thr, &cur_thread_placeholder);
|
||||
#endif
|
||||
}
|
||||
REAL(pthread_exit)(retval);
|
||||
}
|
||||
|
@ -1986,7 +1981,6 @@ static bool is_sync_signal(ThreadSignalContext *sctx, int sig) {
|
|||
void ALWAYS_INLINE rtl_generic_sighandler(bool sigact, int sig,
|
||||
__sanitizer_siginfo *info,
|
||||
void *ctx) {
|
||||
cur_thread_init();
|
||||
ThreadState *thr = cur_thread();
|
||||
ThreadSignalContext *sctx = SigCtx(thr);
|
||||
if (sig < 0 || sig >= kSigCount) {
|
||||
|
|
|
@ -23,7 +23,6 @@ LibIgnore *libignore();
|
|||
|
||||
#if !SANITIZER_GO
|
||||
INLINE bool in_symbolizer() {
|
||||
cur_thread_init();
|
||||
return UNLIKELY(cur_thread()->in_symbolizer);
|
||||
}
|
||||
#endif
|
||||
|
@ -31,7 +30,6 @@ INLINE bool in_symbolizer() {
|
|||
} // namespace __tsan
|
||||
|
||||
#define SCOPED_INTERCEPTOR_RAW(func, ...) \
|
||||
cur_thread_init(); \
|
||||
ThreadState *thr = cur_thread(); \
|
||||
const uptr caller_pc = GET_CALLER_PC(); \
|
||||
ScopedInterceptor si(thr, #func, caller_pc); \
|
||||
|
|
|
@ -24,7 +24,6 @@ typedef u32 uint32_t;
|
|||
typedef u64 uint64_t;
|
||||
|
||||
void __tsan_init() {
|
||||
cur_thread_init();
|
||||
Initialize(cur_thread());
|
||||
}
|
||||
|
||||
|
@ -124,33 +123,6 @@ void __sanitizer_unaligned_store64(uu64 *addr, u64 v) {
|
|||
__tsan_unaligned_write8(addr);
|
||||
*addr = v;
|
||||
}
|
||||
|
||||
#if !SANITIZER_MAC && !SANITIZER_ANDROID
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void *__tsan_get_current_fiber() {
|
||||
return cur_thread();
|
||||
}
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void *__tsan_create_fiber(unsigned flags) {
|
||||
return FiberCreate(cur_thread(), CALLERPC, flags);
|
||||
}
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __tsan_destroy_fiber(void *fiber) {
|
||||
FiberDestroy(cur_thread(), CALLERPC, static_cast<ThreadState *>(fiber));
|
||||
}
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __tsan_switch_to_fiber(void *fiber, unsigned flags) {
|
||||
FiberSwitch(cur_thread(), CALLERPC, static_cast<ThreadState *>(fiber), flags);
|
||||
}
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __tsan_set_fiber_name(void *fiber, const char *name) {
|
||||
ThreadSetName(static_cast<ThreadState *>(fiber), name);
|
||||
}
|
||||
#endif // !SANITIZER_MAC && !SANITIZER_ANDROID
|
||||
} // extern "C"
|
||||
|
||||
void __tsan_acquire(void *addr) {
|
||||
|
|
|
@ -384,9 +384,6 @@ struct ThreadState {
|
|||
// taken by epoch between synchs.
|
||||
// This way we can save one load from tls.
|
||||
u64 fast_synch_epoch;
|
||||
// Technically `current` should be a separate THREADLOCAL variable;
|
||||
// but it is placed here in order to share cache line with previous fields.
|
||||
ThreadState* current;
|
||||
// This is a slow path flag. On fast path, fast_state.GetIgnoreBit() is read.
|
||||
// We do not distinguish beteween ignoring reads and writes
|
||||
// for better performance.
|
||||
|
@ -465,20 +462,11 @@ struct ThreadState {
|
|||
#if SANITIZER_MAC || SANITIZER_ANDROID
|
||||
ThreadState *cur_thread();
|
||||
void cur_thread_finalize();
|
||||
INLINE void cur_thread_init() { }
|
||||
#else
|
||||
__attribute__((tls_model("initial-exec")))
|
||||
extern THREADLOCAL char cur_thread_placeholder[];
|
||||
INLINE ThreadState *cur_thread() {
|
||||
return reinterpret_cast<ThreadState *>(cur_thread_placeholder)->current;
|
||||
}
|
||||
INLINE void cur_thread_init() {
|
||||
ThreadState *thr = reinterpret_cast<ThreadState *>(cur_thread_placeholder);
|
||||
if (UNLIKELY(!thr->current))
|
||||
thr->current = thr;
|
||||
}
|
||||
INLINE void set_cur_thread(ThreadState *thr) {
|
||||
reinterpret_cast<ThreadState *>(cur_thread_placeholder)->current = thr;
|
||||
return reinterpret_cast<ThreadState *>(&cur_thread_placeholder);
|
||||
}
|
||||
INLINE void cur_thread_finalize() { }
|
||||
#endif // SANITIZER_MAC || SANITIZER_ANDROID
|
||||
|
@ -880,16 +868,6 @@ uptr ALWAYS_INLINE HeapEnd() {
|
|||
}
|
||||
#endif
|
||||
|
||||
ThreadState *FiberCreate(ThreadState *thr, uptr pc, unsigned flags);
|
||||
void FiberDestroy(ThreadState *thr, uptr pc, ThreadState *fiber);
|
||||
void FiberSwitch(ThreadState *thr, uptr pc, ThreadState *fiber, unsigned flags);
|
||||
|
||||
// These need to match __tsan_switch_to_fiber_* flags defined in
|
||||
// tsan_interface.h. See documentation there as well.
|
||||
enum FiberSwitchFlags {
|
||||
FiberSwitchFlagNoSync = 1 << 0, // __tsan_switch_to_fiber_no_sync
|
||||
};
|
||||
|
||||
} // namespace __tsan
|
||||
|
||||
#endif // TSAN_RTL_H
|
||||
|
|
|
@ -246,8 +246,7 @@ void ThreadStart(ThreadState *thr, int tid, tid_t os_id,
|
|||
uptr tls_addr = 0;
|
||||
uptr tls_size = 0;
|
||||
#if !SANITIZER_GO
|
||||
if (thread_type != ThreadType::Fiber)
|
||||
GetThreadStackAndTls(tid == 0, &stk_addr, &stk_size, &tls_addr, &tls_size);
|
||||
GetThreadStackAndTls(tid == 0, &stk_addr, &stk_size, &tls_addr, &tls_size);
|
||||
|
||||
if (tid) {
|
||||
if (stk_addr && stk_size)
|
||||
|
@ -405,40 +404,4 @@ void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr,
|
|||
}
|
||||
}
|
||||
|
||||
#if !SANITIZER_MAC && !SANITIZER_ANDROID && !SANITIZER_GO
|
||||
void FiberSwitchImpl(ThreadState *from, ThreadState *to) {
|
||||
Processor *proc = from->proc();
|
||||
ProcUnwire(proc, from);
|
||||
ProcWire(proc, to);
|
||||
set_cur_thread(to);
|
||||
}
|
||||
|
||||
ThreadState *FiberCreate(ThreadState *thr, uptr pc, unsigned flags) {
|
||||
void *mem = internal_alloc(MBlockThreadContex, sizeof(ThreadState));
|
||||
ThreadState *fiber = static_cast<ThreadState *>(mem);
|
||||
internal_memset(fiber, 0, sizeof(*fiber));
|
||||
int tid = ThreadCreate(thr, pc, 0, true);
|
||||
FiberSwitchImpl(thr, fiber);
|
||||
ThreadStart(fiber, tid, 0, ThreadType::Fiber);
|
||||
FiberSwitchImpl(fiber, thr);
|
||||
return fiber;
|
||||
}
|
||||
|
||||
void FiberDestroy(ThreadState *thr, uptr pc, ThreadState *fiber) {
|
||||
FiberSwitchImpl(thr, fiber);
|
||||
ThreadFinish(fiber);
|
||||
FiberSwitchImpl(fiber, thr);
|
||||
internal_free(fiber);
|
||||
}
|
||||
|
||||
void FiberSwitch(ThreadState *thr, uptr pc,
|
||||
ThreadState *fiber, unsigned flags) {
|
||||
if (!(flags & FiberSwitchFlagNoSync))
|
||||
Release(thr, pc, (uptr)fiber);
|
||||
FiberSwitchImpl(thr, fiber);
|
||||
if (!(flags & FiberSwitchFlagNoSync))
|
||||
Acquire(fiber, pc, (uptr)fiber);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace __tsan
|
||||
|
|
|
@ -1,86 +0,0 @@
|
|||
// 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
|
|
@ -1,48 +0,0 @@
|
|||
// 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
|
|
@ -1,80 +0,0 @@
|
|||
// 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
|
|
@ -1,36 +0,0 @@
|
|||
// 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
|
|
@ -1,36 +0,0 @@
|
|||
// 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
|
|
@ -1,62 +0,0 @@
|
|||
// 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
|
Loading…
Reference in New Issue