Unify thread sanitizer detection

We now have two files that need to know if thread sanitizer is enabled. They
can share the detection code.
This commit is contained in:
ridiculousfish 2021-02-06 22:17:16 -08:00
parent ced56d492f
commit 0f1281bec6
3 changed files with 18 additions and 27 deletions

View file

@ -39,6 +39,16 @@
#define OS_IS_CYGWIN #define OS_IS_CYGWIN
#endif #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. // Common string type.
typedef std::wstring wcstring; typedef std::wstring wcstring;
typedef std::vector<wcstring> wcstring_list_t; typedef std::vector<wcstring> wcstring_list_t;

View file

@ -36,17 +36,7 @@
// properly instrumented with Thread Sanitizer, so it fails to recognize when our mutex is locked. // properly instrumented with Thread Sanitizer, so it fails to recognize when our mutex is locked.
// See https://github.com/google/sanitizers/issues/1259 // See https://github.com/google/sanitizers/issues/1259
// When using TSan, disable the wait-around feature. // When using TSan, disable the wait-around feature.
#if defined(__has_feature) #ifdef FISH_TSAN_WORKAROUNDS
#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
#define IO_WAIT_FOR_WORK_DURATION_MS 0 #define IO_WAIT_FOR_WORK_DURATION_MS 0
#else #else
#define IO_WAIT_FOR_WORK_DURATION_MS 500 #define IO_WAIT_FOR_WORK_DURATION_MS 500

View file

@ -10,20 +10,6 @@
#include "wcstringutil.h" #include "wcstringutil.h"
#include "wutil.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 generation_list_t::describe() const {
wcstring result; wcstring result;
for (generation_t gen : this->as_array()) { 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"); assert(pipes.has_value() && "Failed to make pubsub pipes");
pipes_ = pipes.acquire(); 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())); DIE_ON_FAILURE(make_fd_nonblocking(pipes_.read.fd()));
#endif #endif
} }
@ -95,7 +86,7 @@ void binary_semaphore_t::wait() {
int fd = pipes_.read.fd(); int fd = pipes_.read.fd();
// We must read exactly one byte. // We must read exactly one byte.
for (;;) { 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() // 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 // call until data is available (that is, fish would use 100% cpu while waiting for
// processes). The select prevents that. // processes). The select prevents that.