xref: /llvm-project/offload/include/ExclusiveAccess.h (revision 330d8983d25d08580fc1642fea48b2473f47a9da)
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