Annotate the futex implementation for TSAN

TSAN does not understand the futex system call.

Now, in QMutex and QSemaphore usage, futex is always wrapped by
atomic operations that always do an acquire (before waiting) and
a release (before waking waiters). That alone realizes a
synchronizes-with, and since Qt uses std::atomics, TSAN knows
what's going on and does not complain.

But what if one uses futex directly, or we change the
algorithms, or introduce some other new synchronization
primitive somewhere?  Luckily TSAN offers annotations for this
that we can use.

This patch annotates the main entry point for the futex syscall
with a pair of acquire/release semantics. A futex call
guarantees total ordering on the operations on the futex
word(s), whether the call succeeds or fails.

Change-Id: Ib80ff898c09fbb6fc73989247eb757bf70971a8a
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Giuseppe D'Angelo 2019-05-16 18:09:55 +02:00
parent eae4668afa
commit 59937de098

View File

@ -81,15 +81,43 @@ QT_END_NAMESPACE
// if not defined in linux/futex.h
# define FUTEX_PRIVATE_FLAG 128 // added in v2.6.22
# if QT_HAS_FEATURE(thread_sanitizer) || defined(__SANITIZE_THREAD__)
# include <sanitizer/tsan_interface.h>
inline void _q_tsan_acquire(void *addr, void *addr2)
{
__tsan_acquire(addr);
if (addr2)
__tsan_acquire(addr2);
}
inline void _q_tsan_release(void *addr, void *addr2)
{
if (addr2)
__tsan_release(addr2);
__tsan_release(addr);
}
# else
inline void _q_tsan_acquire(void *, void *) {}
inline void _q_tsan_release(void *, void *) {}
# endif // QT_HAS_FEATURE(thread_sanitizer) || defined(__SANITIZE_THREAD__)
QT_BEGIN_NAMESPACE
namespace QtLinuxFutex {
constexpr inline bool futexAvailable() { return true; }
inline int _q_futex(int *addr, int op, int val, quintptr val2 = 0,
int *addr2 = nullptr, int val3 = 0) noexcept
{
// A futex call ensures total ordering on the futex words
// (in either success or failure of the call). Instruct TSAN accordingly,
// as TSAN does not understand the futex(2) syscall.
_q_tsan_release(addr, addr2);
// we use __NR_futex because some libcs (like Android's bionic) don't
// provide SYS_futex etc.
return syscall(__NR_futex, addr, op | FUTEX_PRIVATE_FLAG, val, val2, addr2, val3);
int result = syscall(__NR_futex, addr, op | FUTEX_PRIVATE_FLAG, val, val2, addr2, val3);
_q_tsan_acquire(addr, addr2);
return result;
}
template <typename T> int *addr(T *ptr)
{