diff --git a/compiler-rt/lib/gwp_asan/CMakeLists.txt b/compiler-rt/lib/gwp_asan/CMakeLists.txt --- a/compiler-rt/lib/gwp_asan/CMakeLists.txt +++ b/compiler-rt/lib/gwp_asan/CMakeLists.txt @@ -7,6 +7,8 @@ ) set(GWP_ASAN_HEADERS + definitions.h + mutex.h random.h ) diff --git a/compiler-rt/lib/gwp_asan/definitions.h b/compiler-rt/lib/gwp_asan/definitions.h new file mode 100644 --- /dev/null +++ b/compiler-rt/lib/gwp_asan/definitions.h @@ -0,0 +1,27 @@ +//===-- gwp_asan_definitions.h ----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef GWP_ASAN_DEFINITIONS_H_ +#define GWP_ASAN_DEFINITIONS_H_ + +#ifdef LIKELY +# undef LIKELY +#endif // defined(LIKELY) +#define LIKELY(X) __builtin_expect(!!(X), 1) + +#ifdef UNLIKELY +# undef UNLIKELY +#endif // defined(UNLIKELY) +#define UNLIKELY(X) __builtin_expect(!!(X), 0) + +#ifdef ALWAYS_INLINE +# undef ALWAYS_INLINE +#endif // defined(ALWAYS_INLINE) +#define ALWAYS_INLINE inline __attribute__((always_inline)) + +#endif // GWP_ASAN_DEFINITIONS_H_ diff --git a/compiler-rt/lib/gwp_asan/mutex.h b/compiler-rt/lib/gwp_asan/mutex.h new file mode 100644 --- /dev/null +++ b/compiler-rt/lib/gwp_asan/mutex.h @@ -0,0 +1,94 @@ +//===-- mutex.h -------------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// TODO(hctim): Move this implementation and Scudo's implementation into a +// unified base implementation. We shouldn't need to have separate +// implementations for this. + +#ifndef GWP_ASAN_MUTEX_H_ +#define GWP_ASAN_MUTEX_H_ + +#include "gwp_asan/definitions.h" + +#include + +#ifdef __unix__ +#include +#endif // defined(__unix__) + +namespace gwp_asan { +class Mutex { +public: + void lock(); + bool tryLock(); + void unlock(); + +private: + void yieldProcessor(uint8_t Count); + void yieldPlatform(); + + void lockSlow(); + + bool Locked = false; +}; + +class ScopedLock { +public: + explicit ScopedLock(Mutex *Mx) : Mu(Mx) { Mu->lock(); } + ~ScopedLock() { Mu->unlock(); } + +private: + Mutex *Mu; +}; + +ALWAYS_INLINE void Mutex::lock() { + if (tryLock()) + return; + lockSlow(); +} + +ALWAYS_INLINE bool Mutex::tryLock() { + return !__atomic_exchange_n(&Locked, true, __ATOMIC_ACQUIRE); +} + +ALWAYS_INLINE void Mutex::unlock() { + __atomic_store_n(&Locked, false, __ATOMIC_RELEASE); +} + +ALWAYS_INLINE void Mutex::yieldProcessor(uint8_t Count) { +#if defined(__i386__) || defined(__x86_64__) + asm volatile("" ::: "memory"); + for (uint8_t i = 0; i < Count; ++i) + asm volatile("pause"); +#elif defined(__aarch64__) || defined(__arm__) + asm volatile("" ::: "memory"); + for (uint8_t i = 0; i < Count; ++i) + asm volatile("yield"); +#endif + asm volatile("" ::: "memory"); +} + +ALWAYS_INLINE void Mutex::lockSlow() { + for (uint32_t i = 0;; ++i) { + if (i < 10) + yieldProcessor(10); + else + yieldPlatform(); + + if (!__atomic_load_n(&Locked, __ATOMIC_RELAXED) && tryLock()) + return; + } +} + +#ifdef __unix__ +ALWAYS_INLINE void Mutex::yieldPlatform() { sched_yield(); } +#endif // defined(__unix__) + +} // namespace gwp_asan + +#endif // GWP_ASAN_MUTEX_H_