1 //===---- ExclusiveAccess.h - Helper for exclusive access data structures -===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 //===----------------------------------------------------------------------===// 10 11 #ifndef OMPTARGET_EXCLUSIVE_ACCESS 12 #define OMPTARGET_EXCLUSIVE_ACCESS 13 14 #include <cassert> 15 #include <cstddef> 16 #include <cstdint> 17 #include <mutex> 18 19 /// Forward declaration. 20 template <typename Ty> struct Accessor; 21 22 /// A protected object is a simple wrapper to allocate an object of type \p Ty 23 /// together with a mutex that guards accesses to the object. The only way to 24 /// access the object is through the "exclusive accessor" which will lock the 25 /// mutex accordingly. 26 template <typename Ty> struct ProtectedObj { 27 using AccessorTy = Accessor<Ty>; 28 29 /// Get an exclusive access Accessor object. \p DoNotGetAccess allows to 30 /// create an accessor that is not owning anything based on a boolean 31 /// condition. 32 AccessorTy getExclusiveAccessor(bool DoNotGetAccess = false); 33 34 private: 35 Ty Obj; 36 std::mutex Mtx; 37 friend struct Accessor<Ty>; 38 }; 39 40 /// Helper to provide transparent exclusive access to protected objects. 41 template <typename Ty> struct Accessor { 42 /// Default constructor does not own anything and cannot access anything. 43 Accessor() : Ptr(nullptr) {} 44 45 /// Constructor to get exclusive access by locking the mutex protecting the 46 /// underlying object. 47 Accessor(ProtectedObj<Ty> &PO) : Ptr(&PO) { lock(); } 48 49 /// Constructor to get exclusive access by taking it from \p Other. 50 Accessor(Accessor<Ty> &&Other) : Ptr(Other.Ptr) { Other.Ptr = nullptr; } 51 52 Accessor(Accessor &Other) = delete; 53 54 /// If the object is still owned when the lifetime ends we give up access. 55 ~Accessor() { unlock(); } 56 57 /// Give up access to the underlying object, virtually "destroying" the 58 /// accessor even if the object is still life. 59 void destroy() { 60 unlock(); 61 Ptr = nullptr; 62 } 63 64 /// Provide transparent access to the underlying object. 65 Ty &operator*() { 66 assert(Ptr && "Trying to access an object through a non-owning (or " 67 "destroyed) accessor!"); 68 return Ptr->Obj; 69 } 70 Ty *operator->() { 71 assert(Ptr && "Trying to access an object through a non-owning (or " 72 "destroyed) accessor!"); 73 return &Ptr->Obj; 74 } 75 76 private: 77 /// Lock the underlying object if there is one. 78 void lock() { 79 if (Ptr) 80 Ptr->Mtx.lock(); 81 } 82 83 /// Unlock the underlying object if there is one. 84 void unlock() { 85 if (Ptr) 86 Ptr->Mtx.unlock(); 87 } 88 89 /// Pointer to the underlying object or null if the accessor lost access, 90 /// e.g., after a destroy call. 91 ProtectedObj<Ty> *Ptr; 92 }; 93 94 template <typename Ty> 95 Accessor<Ty> ProtectedObj<Ty>::getExclusiveAccessor(bool DoNotGetAccess) { 96 if (DoNotGetAccess) 97 return Accessor<Ty>(); 98 return Accessor<Ty>(*this); 99 } 100 101 #endif 102