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