73 lines
		
	
	
		
			1.7 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			73 lines
		
	
	
		
			1.7 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===-- 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
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| #ifndef SCUDO_MUTEX_H_
 | |
| #define SCUDO_MUTEX_H_
 | |
| 
 | |
| #include "atomic_helpers.h"
 | |
| #include "common.h"
 | |
| 
 | |
| #include <string.h>
 | |
| 
 | |
| #if SCUDO_FUCHSIA
 | |
| #include <lib/sync/mutex.h> // for sync_mutex_t
 | |
| #endif
 | |
| 
 | |
| namespace scudo {
 | |
| 
 | |
| class HybridMutex {
 | |
| public:
 | |
|   bool tryLock();
 | |
|   NOINLINE void lock() {
 | |
|     if (LIKELY(tryLock()))
 | |
|       return;
 | |
|       // The compiler may try to fully unroll the loop, ending up in a
 | |
|       // NumberOfTries*NumberOfYields block of pauses mixed with tryLocks. This
 | |
|       // is large, ugly and unneeded, a compact loop is better for our purpose
 | |
|       // here. Use a pragma to tell the compiler not to unroll the loop.
 | |
| #ifdef __clang__
 | |
| #pragma nounroll
 | |
| #endif
 | |
|     for (u8 I = 0U; I < NumberOfTries; I++) {
 | |
|       yieldProcessor(NumberOfYields);
 | |
|       if (tryLock())
 | |
|         return;
 | |
|     }
 | |
|     lockSlow();
 | |
|   }
 | |
|   void unlock();
 | |
| 
 | |
| private:
 | |
|   static constexpr u8 NumberOfTries = 8U;
 | |
|   static constexpr u8 NumberOfYields = 8U;
 | |
| 
 | |
| #if SCUDO_LINUX
 | |
|   atomic_u32 M = {};
 | |
| #elif SCUDO_FUCHSIA
 | |
|   sync_mutex_t M = {};
 | |
| #endif
 | |
| 
 | |
|   void lockSlow();
 | |
| };
 | |
| 
 | |
| class ScopedLock {
 | |
| public:
 | |
|   explicit ScopedLock(HybridMutex &M) : Mutex(M) { Mutex.lock(); }
 | |
|   ~ScopedLock() { Mutex.unlock(); }
 | |
| 
 | |
| private:
 | |
|   HybridMutex &Mutex;
 | |
| 
 | |
|   ScopedLock(const ScopedLock &) = delete;
 | |
|   void operator=(const ScopedLock &) = delete;
 | |
| };
 | |
| 
 | |
| } // namespace scudo
 | |
| 
 | |
| #endif // SCUDO_MUTEX_H_
 |