102 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8//9//===----------------------------------------------------------------------===//10 11#ifndef OMPTARGET_EXCLUSIVE_ACCESS12#define OMPTARGET_EXCLUSIVE_ACCESS13 14#include <cassert>15#include <cstddef>16#include <cstdint>17#include <mutex>18 19/// Forward declaration.20template <typename Ty> struct Accessor;21 22/// A protected object is a simple wrapper to allocate an object of type \p Ty23/// together with a mutex that guards accesses to the object. The only way to24/// access the object is through the "exclusive accessor" which will lock the25/// mutex accordingly.26template <typename Ty> struct ProtectedObj {27 using AccessorTy = Accessor<Ty>;28 29 /// Get an exclusive access Accessor object. \p DoNotGetAccess allows to30 /// create an accessor that is not owning anything based on a boolean31 /// condition.32 AccessorTy getExclusiveAccessor(bool DoNotGetAccess = false);33 34private:35 Ty Obj;36 std::mutex Mtx;37 friend struct Accessor<Ty>;38};39 40/// Helper to provide transparent exclusive access to protected objects.41template <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 the46 /// 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" the58 /// 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 76private: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 94template <typename Ty>95Accessor<Ty> ProtectedObj<Ty>::getExclusiveAccessor(bool DoNotGetAccess) {96 if (DoNotGetAccess)97 return Accessor<Ty>();98 return Accessor<Ty>(*this);99}100 101#endif102