diff --git a/compiler-rt/lib/tsan/rtl/tsan_flags.inc b/compiler-rt/lib/tsan/rtl/tsan_flags.inc --- a/compiler-rt/lib/tsan/rtl/tsan_flags.inc +++ b/compiler-rt/lib/tsan/rtl/tsan_flags.inc @@ -43,6 +43,9 @@ bool, force_seq_cst_atomics, false, "If set, all atomics are effectively sequentially consistent (seq_cst), " "regardless of what user actually specified.") +TSAN_FLAG(bool, force_background_thread, false, + "If set, eagerly launch a background thread for memory reclamation " + "instead of waiting for a user call to pthread_create.") TSAN_FLAG(bool, halt_on_error, false, "Exit after first reported error.") TSAN_FLAG(int, atexit_sleep_ms, 1000, "Sleep in main thread before exiting for that many ms " diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp b/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp --- a/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp +++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp @@ -698,6 +698,18 @@ OnInitialize(); } +#if !SANITIZER_GO +# pragma clang diagnostic push +// We intentionally use a global constructor to delay the pthread call. +# pragma clang diagnostic ignored "-Wglobal-constructors" +static bool UNUSED __local_tsan_dyninit = [] { + if (flags()->force_background_thread) + MaybeSpawnBackgroundThread(); + return false; +}(); +# pragma clang diagnostic pop +#endif + void MaybeSpawnBackgroundThread() { // On MIPS, TSan initialization is run before // __pthread_initialize_minimal_internal() is finished, so we can not spawn diff --git a/compiler-rt/test/tsan/force_background_thread.cpp b/compiler-rt/test/tsan/force_background_thread.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/tsan/force_background_thread.cpp @@ -0,0 +1,21 @@ +// RUN: %clangxx_tsan -O1 %s -o %t +// RUN: %deflake %env_tsan_opts=force_background_thread=0:verbosity=1:memory_limit_mb=1000 %run %t 2>&1 | FileCheck %s --implicit-check-not "memory flush check" +// RUN: %deflake %env_tsan_opts=force_background_thread=1:verbosity=1:memory_limit_mb=1000 %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK,THREAD +// RUN: %deflake %env_tsan_opts=force_background_thread=0:verbosity=1:memory_limit_mb=1000 %run %t 1 2>&1 | FileCheck %s --check-prefixes=CHECK,THREAD +#include "test.h" + +void *Thread(void *a) { return nullptr; } + +int main(int argc, char *argv[]) { + if (argc > 1) { + pthread_t t; + pthread_create(&t, nullptr, Thread, nullptr); + void *p; + pthread_join(t, &p); + } + sleep(3); + return 1; +} + +// CHECK: Running under ThreadSanitizer +// THREAD: ThreadSanitizer: memory flush check