xref: /freebsd/contrib/llvm-project/compiler-rt/lib/scudo/standalone/mutex.h (revision fe6060f10f634930ff71b7c50291ddc610da2475)
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