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