1 /*
2  * Copyright (c) 2021-2023 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 /**
17  * @file rwlock.h
18  *
19  * @brief Provides interfaces of RWLock in c_utils.
20  */
21 
22 #ifndef UTILS_RWLOCK_H
23 #define UTILS_RWLOCK_H
24 
25 #include <atomic>
26 #include <thread>
27 
28 #include "nocopyable.h"
29 
30 namespace OHOS {
31 namespace Utils {
32 
33 /**
34  * @brief Implements the <b>RWLock</b> class to ensure that read and write
35  * operations are thread-safe.
36  *
37  * Under RWLock, write operations are mutually exclusive,
38  * and read and write operations are mutually exclusive.
39  * However, read operations are not mutually exclusive.
40  */
41 class RWLock : NoCopyable {
42 public:
43 /**
44  * @brief Enumerates the lock states.
45  */
46     enum LockStatus {
47         LOCK_STATUS_WRITE = -1,
48         LOCK_STATUS_FREE = 0,
49     };
50 
51 /**
52  * @brief Creates an <b>RWLock</b> object.
53  *
54  * @param writeFirst Indicates whether the <b>RWLock</b> object is write-first.
55  */
RWLock()56     RWLock() : RWLock(true) {}
57     explicit RWLock(bool writeFirst);
58 
59 /**
60  * @brief Destroys this <b>RWLock</b> object.
61  */
~RWLock()62     ~RWLock() override {}
63 
64 /**
65  * @brief Obtains a read lock.
66  *
67  * If the thread has obtained a write lock, this function returns directly.
68  * In write-first mode, a read lock can be obtained only when the state
69  * is non-write-locked and no other threads are waiting to write data.
70  * In other modes, a read lock can be obtained when the state is
71  * non-write-locked.
72  */
73     void LockRead();
74 
75 /**
76  * @brief Releases the read lock.
77  *
78  * If the write lock has been obtained before,
79  * LockRead() will return directly.
80  * This function will also return directly when called.
81  */
82     void UnLockRead();
83 
84 /**
85  *@brief Obtains a write lock
86  *
87  * If the thread has obtained a write lock, this function returns directly
88  * to avoid acquiring a lock, because write locks are exclusive.
89  * The write lock can be obtained only when no other thread has obtained a read
90  * lock or a write lock; otherwise, the thread shall wait.
91  */
92     void LockWrite();
93 
94 /**
95  * @brief Releases the write lock.
96  *
97  * If the thread has not obtained a write lock, this function returns directly.
98  */
99     void UnLockWrite();
100 
101 private:
102     bool writeFirst_;  // Whether the thread is write-first. The value true means that the thread is write-first.
103     std::thread::id writeThreadID_;  // ID of the write thread.
104 
105     // Resource lock counter. -1 indicates the write state, 0 indicates the free state, and a value greater than 0
106     // indicates the shared read state.
107     std::atomic_int lockCount_;
108 
109     // Thread counter waiting for the write lock.
110     std::atomic_uint writeWaitCount_;
111 };
112 
113 /**
114  * @brief UniqueWriteGuard object controls the ownership of a lockable object
115  * within a scope, and is used only as acquisition
116  * and release of write locks.
117  * It is actually an encapsulation of the RWLock class, which can be locked
118  * at construction time and unlocked during destruction,
119  * providing a convenient RAII mechanism.
120  */
121 template <typename RWLockable>
122 class UniqueWriteGuard : NoCopyable {
123 public:
UniqueWriteGuard(RWLockable & rwLockable)124     explicit UniqueWriteGuard(RWLockable &rwLockable)
125         : rwLockable_(rwLockable)
126     {
127         rwLockable_.LockWrite();
128     }
129 
~UniqueWriteGuard()130     ~UniqueWriteGuard() override
131     {
132         rwLockable_.UnLockWrite();
133     }
134 
135 private:
136     UniqueWriteGuard() = delete;
137 
138 private:
139     RWLockable &rwLockable_;
140 };
141 
142 
143 /**
144  * @brief UniqueWriteGuard object controls the ownership of a lockable object
145  * within a scope, and is used only as acquisition
146  * and release of read locks.
147  * It is actually an encapsulation of the RWLock class, which can be locked
148  * at construction time and unlocked during destruction,
149  * providing a convenient RAII mechanism.
150  */
151 template <typename RWLockable>
152 class UniqueReadGuard : NoCopyable {
153 public:
UniqueReadGuard(RWLockable & rwLockable)154     explicit UniqueReadGuard(RWLockable &rwLockable)
155         : rwLockable_(rwLockable)
156     {
157         rwLockable_.LockRead();
158     }
159 
~UniqueReadGuard()160     ~UniqueReadGuard() override
161     {
162         rwLockable_.UnLockRead();
163     }
164 
165 private:
166     UniqueReadGuard() = delete;
167 
168 private:
169     RWLockable &rwLockable_;
170 };
171 
172 } // namespace Utils
173 } // namespace OHOS
174 #endif
175 
176