10b57cec5SDimitry Andric //===-- mutex.h -------------------------------------------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #ifndef SCUDO_MUTEX_H_ 100b57cec5SDimitry Andric #define SCUDO_MUTEX_H_ 110b57cec5SDimitry Andric 120b57cec5SDimitry Andric #include "atomic_helpers.h" 130b57cec5SDimitry Andric #include "common.h" 140b57cec5SDimitry Andric 150b57cec5SDimitry Andric #include <string.h> 160b57cec5SDimitry Andric 170b57cec5SDimitry Andric #if SCUDO_FUCHSIA 180b57cec5SDimitry Andric #include <lib/sync/mutex.h> // for sync_mutex_t 190b57cec5SDimitry Andric #endif 200b57cec5SDimitry Andric 210b57cec5SDimitry Andric namespace scudo { 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric class HybridMutex { 240b57cec5SDimitry Andric public: 250b57cec5SDimitry Andric bool tryLock(); 260b57cec5SDimitry Andric NOINLINE void lock() { 2768d75effSDimitry Andric if (LIKELY(tryLock())) 280b57cec5SDimitry Andric return; 290b57cec5SDimitry Andric // The compiler may try to fully unroll the loop, ending up in a 300b57cec5SDimitry Andric // NumberOfTries*NumberOfYields block of pauses mixed with tryLocks. This 310b57cec5SDimitry Andric // is large, ugly and unneeded, a compact loop is better for our purpose 320b57cec5SDimitry Andric // here. Use a pragma to tell the compiler not to unroll the loop. 330b57cec5SDimitry Andric #ifdef __clang__ 340b57cec5SDimitry Andric #pragma nounroll 350b57cec5SDimitry Andric #endif 360b57cec5SDimitry Andric for (u8 I = 0U; I < NumberOfTries; I++) { 370b57cec5SDimitry Andric yieldProcessor(NumberOfYields); 380b57cec5SDimitry Andric if (tryLock()) 390b57cec5SDimitry Andric return; 400b57cec5SDimitry Andric } 410b57cec5SDimitry Andric lockSlow(); 420b57cec5SDimitry Andric } 430b57cec5SDimitry Andric void unlock(); 440b57cec5SDimitry Andric 450b57cec5SDimitry Andric private: 4668d75effSDimitry Andric static constexpr u8 NumberOfTries = 8U; 4768d75effSDimitry Andric static constexpr u8 NumberOfYields = 8U; 480b57cec5SDimitry Andric 490b57cec5SDimitry Andric #if SCUDO_LINUX 50*fe6060f1SDimitry Andric atomic_u32 M = {}; 510b57cec5SDimitry Andric #elif SCUDO_FUCHSIA 52*fe6060f1SDimitry Andric sync_mutex_t M = {}; 530b57cec5SDimitry Andric #endif 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric void lockSlow(); 560b57cec5SDimitry Andric }; 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric class ScopedLock { 590b57cec5SDimitry Andric public: 600b57cec5SDimitry Andric explicit ScopedLock(HybridMutex &M) : Mutex(M) { Mutex.lock(); } 610b57cec5SDimitry Andric ~ScopedLock() { Mutex.unlock(); } 620b57cec5SDimitry Andric 630b57cec5SDimitry Andric private: 640b57cec5SDimitry Andric HybridMutex &Mutex; 650b57cec5SDimitry Andric 660b57cec5SDimitry Andric ScopedLock(const ScopedLock &) = delete; 670b57cec5SDimitry Andric void operator=(const ScopedLock &) = delete; 680b57cec5SDimitry Andric }; 690b57cec5SDimitry Andric 700b57cec5SDimitry Andric } // namespace scudo 710b57cec5SDimitry Andric 720b57cec5SDimitry Andric #endif // SCUDO_MUTEX_H_ 73