summaryrefslogtreecommitdiffstats
path: root/compiler-rt/lib
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/lib
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/lib')
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h1
-rwxr-xr-xcompiler-rt/lib/tsan/check_analyze.sh8
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_interceptors.cc8
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_interceptors.h2
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_interface.cc28
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_rtl.h24
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc39
7 files changed, 100 insertions, 10 deletions
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h b/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h
index fc38d0f80d2..493aa988f7e 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h
@@ -31,6 +31,7 @@ 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.
diff --git a/compiler-rt/lib/tsan/check_analyze.sh b/compiler-rt/lib/tsan/check_analyze.sh
index 5e7a9a96742..a2a7e82b47a 100755
--- a/compiler-rt/lib/tsan/check_analyze.sh
+++ b/compiler-rt/lib/tsan/check_analyze.sh
@@ -36,17 +36,11 @@ check() {
for f in write1 write2 write4 write8; do
check $f rsp 1
- check $f push 1
- check $f pop 8
-done
-
-for f in read1; do
- check $f rsp 1
check $f push 2
check $f pop 16
done
-for f in read2 read4 read8; do
+for f in read1 read2 read4 read8; do
check $f rsp 1
check $f push 3
check $f pop 24
diff --git a/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc b/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc
index b9f245e409b..e4b8def7831 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc
+++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc
@@ -153,7 +153,7 @@ const int SIG_SETMASK = 2;
#endif
#define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED \
- (!cur_thread()->is_inited)
+ (cur_thread_init(), !cur_thread()->is_inited)
namespace __tsan {
struct SignalDesc {
@@ -554,6 +554,7 @@ 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);
}
@@ -942,6 +943,7 @@ 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;
@@ -1053,6 +1055,9 @@ 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);
}
@@ -1981,6 +1986,7 @@ 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) {
diff --git a/compiler-rt/lib/tsan/rtl/tsan_interceptors.h b/compiler-rt/lib/tsan/rtl/tsan_interceptors.h
index 29b0f76f971..88d1edd775d 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_interceptors.h
+++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors.h
@@ -23,6 +23,7 @@ LibIgnore *libignore();
#if !SANITIZER_GO
INLINE bool in_symbolizer() {
+ cur_thread_init();
return UNLIKELY(cur_thread()->in_symbolizer);
}
#endif
@@ -30,6 +31,7 @@ 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); \
diff --git a/compiler-rt/lib/tsan/rtl/tsan_interface.cc b/compiler-rt/lib/tsan/rtl/tsan_interface.cc
index 09a84015295..8101ba19382 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_interface.cc
+++ b/compiler-rt/lib/tsan/rtl/tsan_interface.cc
@@ -24,6 +24,7 @@ typedef u32 uint32_t;
typedef u64 uint64_t;
void __tsan_init() {
+ cur_thread_init();
Initialize(cur_thread());
}
@@ -123,6 +124,33 @@ 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) {
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.h b/compiler-rt/lib/tsan/rtl/tsan_rtl.h
index 37ca731e923..1804deaf56a 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl.h
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.h
@@ -384,6 +384,9 @@ 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.
@@ -462,11 +465,20 @@ 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);
+ 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;
}
INLINE void cur_thread_finalize() { }
#endif // SANITIZER_MAC || SANITIZER_ANDROID
@@ -868,6 +880,16 @@ 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
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc b/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc
index de429a553d1..60513489448 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc
@@ -246,7 +246,8 @@ void ThreadStart(ThreadState *thr, int tid, tid_t os_id,
uptr tls_addr = 0;
uptr tls_size = 0;
#if !SANITIZER_GO
- GetThreadStackAndTls(tid == 0, &stk_addr, &stk_size, &tls_addr, &tls_size);
+ if (thread_type != ThreadType::Fiber)
+ GetThreadStackAndTls(tid == 0, &stk_addr, &stk_size, &tls_addr, &tls_size);
if (tid) {
if (stk_addr && stk_size)
@@ -404,4 +405,40 @@ 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
OpenPOWER on IntegriCloud