diff --git a/src/common.h b/src/common.h index 6df127206..eaae8fd07 100644 --- a/src/common.h +++ b/src/common.h @@ -39,6 +39,16 @@ #define OS_IS_CYGWIN #endif +// Check if Thread Sanitizer is enabled. +#if defined(__has_feature) +#if __has_feature(thread_sanitizer) +#define FISH_TSAN_WORKAROUNDS 1 +#endif +#endif +#ifdef __SANITIZE_THREAD__ +#define FISH_TSAN_WORKAROUNDS 1 +#endif + // Common string type. typedef std::wstring wcstring; typedef std::vector wcstring_list_t; diff --git a/src/iothread.cpp b/src/iothread.cpp index a841250de..f5434dda9 100644 --- a/src/iothread.cpp +++ b/src/iothread.cpp @@ -36,17 +36,7 @@ // properly instrumented with Thread Sanitizer, so it fails to recognize when our mutex is locked. // See https://github.com/google/sanitizers/issues/1259 // When using TSan, disable the wait-around feature. -#if defined(__has_feature) -#if __has_feature(thread_sanitizer) -#define IOTHREAD_TSAN_WORKAROUND 1 -#endif -#endif -#ifdef __SANITIZE_THREAD__ -#define IOTHREAD_TSAN_WORKAROUND 1 -#endif - -// The amount of time an IO thread many hang around to service requests, in milliseconds. -#ifdef IOTHREAD_TSAN_WORKAROUND +#ifdef FISH_TSAN_WORKAROUNDS #define IO_WAIT_FOR_WORK_DURATION_MS 0 #else #define IO_WAIT_FOR_WORK_DURATION_MS 500 diff --git a/src/topic_monitor.cpp b/src/topic_monitor.cpp index 96350bd4c..75f54a86b 100644 --- a/src/topic_monitor.cpp +++ b/src/topic_monitor.cpp @@ -10,20 +10,6 @@ #include "wcstringutil.h" #include "wutil.h" -// Whoof. Thread Sanitizer swallows signals and replays them at its leisure, at the point where -// instrumented code makes certain blocking calls. But tsan cannot interrupt a signal call, so -// if we're blocked in read() (like the topic monitor wants to be!), we'll never receive SIGCHLD -// and so deadlock. So if tsan is enabled, we mark our fd as non-blocking (so reads will never -// block) and use select() to poll it. -#if defined(__has_feature) -#if __has_feature(thread_sanitizer) -#define TOPIC_MONITOR_TSAN_WORKAROUND 1 -#endif -#endif -#ifdef __SANITIZE_THREAD__ -#define TOPIC_MONITOR_TSAN_WORKAROUND 1 -#endif - wcstring generation_list_t::describe() const { wcstring result; for (generation_t gen : this->as_array()) { @@ -49,7 +35,12 @@ binary_semaphore_t::binary_semaphore_t() : sem_ok_(false) { assert(pipes.has_value() && "Failed to make pubsub pipes"); pipes_ = pipes.acquire(); -#ifdef TOPIC_MONITOR_TSAN_WORKAROUND + // Whoof. Thread Sanitizer swallows signals and replays them at its leisure, at the point + // where instrumented code makes certain blocking calls. But tsan cannot interrupt a signal + // call, so if we're blocked in read() (like the topic monitor wants to be!), we'll never + // receive SIGCHLD and so deadlock. So if tsan is enabled, we mark our fd as non-blocking + // (so reads will never block) and use select() to poll it. +#ifdef FISH_TSAN_WORKAROUNDS DIE_ON_FAILURE(make_fd_nonblocking(pipes_.read.fd())); #endif } @@ -95,7 +86,7 @@ void binary_semaphore_t::wait() { int fd = pipes_.read.fd(); // We must read exactly one byte. for (;;) { -#ifdef TOPIC_MONITOR_TSAN_WORKAROUND +#ifdef FISH_TSAN_WORKAROUNDS // Under tsan our notifying pipe is non-blocking, so we would busy-loop on the read() // call until data is available (that is, fish would use 100% cpu while waiting for // processes). The select prevents that.