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
#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> wcstring_list_t;

View File

@ -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

View File

@ -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.