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