1 /**
2  * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef PANDA_VERIFIER_SYNCHRONIZED_HPP_
17 #define PANDA_VERIFIER_SYNCHRONIZED_HPP_
18 
19 #include "verification/util/callable.h"
20 
21 #include "libpandabase/os/mutex.h"
22 
23 #include "macros.h"
24 
25 #include <utility>
26 
27 namespace ark::verifier {
28 template <class C, class Friend1 = C, class Friend2 = C>
29 class Synchronized {
30     struct ConstProxy {
31         ConstProxy() = delete;
32         ConstProxy(const ConstProxy &) = delete;
ConstProxyark::verifier::Synchronized::ConstProxy33         ConstProxy(ConstProxy &&other)
34         {
35             obj = other.obj;
36             other.obj = nullptr;
37         }
38         const Synchronized *obj;  // NOLINT(misc-non-private-member-variables-in-classes)
39         explicit ConstProxy(const Synchronized *paramObj) ACQUIRE_SHARED(obj->rwLock_) : obj {paramObj}
40         {
41             obj->rwLock_.ReadLock();
42         }
operator ->() const43         const C *operator->() const
44         {
45             ASSERT(obj != nullptr);
46             return &obj->c_;
47         }
48         ~ConstProxy() RELEASE_SHARED(obj->rwLock_)
49         {
50             if (obj != nullptr) {
51                 obj->rwLock_.Unlock();
52             }
53         }
54         NO_COPY_OPERATOR(ConstProxy);
55         NO_MOVE_OPERATOR(ConstProxy);
56     };
57 
58     struct Proxy {
59         Proxy() = delete;
60         Proxy(const Proxy &) = delete;
Proxyark::verifier::Proxy61         Proxy(Proxy &&other)
62         {
63             obj = other.obj;
64             other.obj = nullptr;
65         }
66         Synchronized *obj;  // NOLINT(misc-non-private-member-variables-in-classes)
67         explicit Proxy(Synchronized *paramObj) ACQUIRE(obj->rwLock_) : obj {paramObj}
68         {
69             obj->rwLock_.WriteLock();
70         }
operator ->()71         C *operator->()
72         {
73             ASSERT(obj != nullptr);
74             return &obj->c_;
75         }
76         ~Proxy() RELEASE(obj->rwLock_)
77         {
78             if (obj != nullptr) {
79                 obj->rwLock_.Unlock();
80             }
81         }
82         NO_COPY_OPERATOR(Proxy);
83         NO_MOVE_OPERATOR(Proxy);
84     };
85 
86     C c_;
87 
88     // GetObj() should be ideally annotated with REQUIRES/REQUIRES_SHARED and c with GUARDED_BY, but then the current
89     // design of LibCache::FastAPI can't be annotated correctly
GetObj()90     C &GetObj()
91     {
92         return c_;
93     }
94 
GetObj() const95     const C &GetObj() const
96     {
97         return c_;
98     }
99 
ACQUIRE(rwLock_)100     void WriteLock() ACQUIRE(rwLock_)
101     {
102         rwLock_.WriteLock();
103     }
104 
ACQUIRE_SHARED(rwLock_)105     void ReadLock() ACQUIRE_SHARED(rwLock_)
106     {
107         rwLock_.ReadLock();
108     }
109 
RELEASE_GENERIC(rwLock_)110     void Unlock() RELEASE_GENERIC(rwLock_)
111     {
112         rwLock_.Unlock();
113     }
114 
115     friend Friend1;
116     friend Friend2;
117 
118 public:
119     template <typename... Args>
Synchronized(Args &&....args)120     explicit Synchronized(Args &&...args) : c_(std::forward<Args>(args)...)
121     {
122     }
123 
operator ->() const124     ConstProxy operator->() const
125     {
126         return ConstProxy(this);
127     }
128 
operator ->()129     Proxy operator->()
130     {
131         return Proxy(this);
132     }
133 
134     template <typename Handler>
Apply(Handler &&handler)135     auto Apply(Handler &&handler)
136     {
137         os::memory::WriteLockHolder lockHolder {rwLock_};
138         return handler(c_);
139     }
140 
141     template <typename Handler>
Apply(Handler &&handler) const142     auto Apply(Handler &&handler) const
143     {
144         os::memory::ReadLockHolder lockHolder {rwLock_};
145         return handler(c_);
146     }
147 
148 private:
149     mutable ark::os::memory::RWLock rwLock_;
150 };
151 }  // namespace ark::verifier
152 
153 #endif  // !PANDA_VERIFIER_SYNCHRONIZED_HPP_
154