xref: /openbsd-src/gnu/llvm/compiler-rt/lib/scudo/standalone/mutex.h (revision d89ec533011f513df1010f142a111086a0785f09)
13cab2bb3Spatrick //===-- mutex.h -------------------------------------------------*- C++ -*-===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick 
93cab2bb3Spatrick #ifndef SCUDO_MUTEX_H_
103cab2bb3Spatrick #define SCUDO_MUTEX_H_
113cab2bb3Spatrick 
123cab2bb3Spatrick #include "atomic_helpers.h"
133cab2bb3Spatrick #include "common.h"
143cab2bb3Spatrick 
153cab2bb3Spatrick #include <string.h>
163cab2bb3Spatrick 
173cab2bb3Spatrick #if SCUDO_FUCHSIA
183cab2bb3Spatrick #include <lib/sync/mutex.h> // for sync_mutex_t
193cab2bb3Spatrick #endif
203cab2bb3Spatrick 
213cab2bb3Spatrick namespace scudo {
223cab2bb3Spatrick 
233cab2bb3Spatrick class HybridMutex {
243cab2bb3Spatrick public:
253cab2bb3Spatrick   bool tryLock();
lock()263cab2bb3Spatrick   NOINLINE void lock() {
273cab2bb3Spatrick     if (LIKELY(tryLock()))
283cab2bb3Spatrick       return;
293cab2bb3Spatrick       // The compiler may try to fully unroll the loop, ending up in a
303cab2bb3Spatrick       // NumberOfTries*NumberOfYields block of pauses mixed with tryLocks. This
313cab2bb3Spatrick       // is large, ugly and unneeded, a compact loop is better for our purpose
323cab2bb3Spatrick       // here. Use a pragma to tell the compiler not to unroll the loop.
333cab2bb3Spatrick #ifdef __clang__
343cab2bb3Spatrick #pragma nounroll
353cab2bb3Spatrick #endif
363cab2bb3Spatrick     for (u8 I = 0U; I < NumberOfTries; I++) {
373cab2bb3Spatrick       yieldProcessor(NumberOfYields);
383cab2bb3Spatrick       if (tryLock())
393cab2bb3Spatrick         return;
403cab2bb3Spatrick     }
413cab2bb3Spatrick     lockSlow();
423cab2bb3Spatrick   }
433cab2bb3Spatrick   void unlock();
443cab2bb3Spatrick 
453cab2bb3Spatrick private:
463cab2bb3Spatrick   static constexpr u8 NumberOfTries = 8U;
473cab2bb3Spatrick   static constexpr u8 NumberOfYields = 8U;
483cab2bb3Spatrick 
493cab2bb3Spatrick #if SCUDO_LINUX
50*d89ec533Spatrick   atomic_u32 M = {};
513cab2bb3Spatrick #elif SCUDO_FUCHSIA
52*d89ec533Spatrick   sync_mutex_t M = {};
533cab2bb3Spatrick #endif
543cab2bb3Spatrick 
553cab2bb3Spatrick   void lockSlow();
563cab2bb3Spatrick };
573cab2bb3Spatrick 
583cab2bb3Spatrick class ScopedLock {
593cab2bb3Spatrick public:
ScopedLock(HybridMutex & M)603cab2bb3Spatrick   explicit ScopedLock(HybridMutex &M) : Mutex(M) { Mutex.lock(); }
~ScopedLock()613cab2bb3Spatrick   ~ScopedLock() { Mutex.unlock(); }
623cab2bb3Spatrick 
633cab2bb3Spatrick private:
643cab2bb3Spatrick   HybridMutex &Mutex;
653cab2bb3Spatrick 
663cab2bb3Spatrick   ScopedLock(const ScopedLock &) = delete;
673cab2bb3Spatrick   void operator=(const ScopedLock &) = delete;
683cab2bb3Spatrick };
693cab2bb3Spatrick 
703cab2bb3Spatrick } // namespace scudo
713cab2bb3Spatrick 
723cab2bb3Spatrick #endif // SCUDO_MUTEX_H_
73