1 /*
2 * Copyright (c) 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 #include "shared_mutex_private.h"
17 #include "dfx/log/ffrt_log_api.h"
18 #include "ffrt_trace.h"
19
20 #include "internal_inc/osal.h"
21 #include "internal_inc/types.h"
22 #include "tm/cpu_task.h"
23
24 namespace ffrt {
Lock()25 void SharedMutexPrivate::Lock()
26 {
27 mut.lock();
28 while (state & writeEntered) {
29 Wait(wList1, SharedMutexWaitType::WRITE);
30 }
31 state |= writeEntered;
32 while (state & readersMax) {
33 Wait(wList2, SharedMutexWaitType::NORMAL);
34 }
35 mut.unlock();
36 }
37
TryLock()38 bool SharedMutexPrivate::TryLock()
39 {
40 mut.lock();
41 if (state == 0) {
42 state = writeEntered;
43 mut.unlock();
44 return true;
45 }
46 mut.unlock();
47 return false;
48 }
49
LockShared()50 void SharedMutexPrivate::LockShared()
51 {
52 mut.lock();
53 while (state >= readersMax) {
54 Wait(wList1, SharedMutexWaitType::READ);
55 }
56 ++state;
57 mut.unlock();
58 }
59
TryLockShared()60 bool SharedMutexPrivate::TryLockShared()
61 {
62 mut.lock();
63 if (state < readersMax) {
64 ++state;
65 mut.unlock();
66 return true;
67 }
68 mut.unlock();
69 return false;
70 }
71
Unlock()72 void SharedMutexPrivate::Unlock()
73 {
74 mut.lock();
75 if (state == writeEntered) {
76 state = 0;
77 NotifyAll(wList1);
78 mut.unlock();
79 return;
80 }
81
82 --state;
83 if (state & writeEntered) {
84 if (state == writeEntered) {
85 NotifyOne(wList2);
86 }
87 } else {
88 if (state == readersMax - 1) {
89 NotifyOne(wList1);
90 } else if (!wList1.Empty()) {
91 NotifyAll(wList1);
92 }
93 }
94 mut.unlock();
95 }
96
Wait(LinkedList & wList,SharedMutexWaitType wtType)97 void SharedMutexPrivate::Wait(LinkedList& wList, SharedMutexWaitType wtType)
98 {
99 auto ctx = ExecuteCtx::Cur();
100 auto task = ctx->task;
101 if (ThreadWaitMode(task)) {
102 if (FFRT_UNLIKELY(LegacyMode(task))) {
103 task->blockType = BlockType::BLOCK_THREAD;
104 ctx->wn.task = task;
105 }
106 ctx->wn.wtType = wtType;
107 wList.PushBack(ctx->wn.node);
108
109 std::unique_lock<std::mutex> lk(ctx->wn.wl);
110 mut.unlock();
111 ctx->wn.cv.wait(lk);
112 } else {
113 FFRT_BLOCK_TRACER(task->gid, smx);
114 CoWait([&](CPUEUTask* task) -> bool {
115 task->fq_we.wtType = wtType;
116 wList.PushBack(task->fq_we.node);
117 mut.unlock();
118 return true;
119 });
120 }
121 mut.lock();
122 }
123
NotifyOne(LinkedList & wList)124 void SharedMutexPrivate::NotifyOne(LinkedList& wList)
125 {
126 WaitEntry* we = wList.PopFront(&WaitEntry::node);
127
128 if (we != nullptr) {
129 CPUEUTask* task = we->task;
130 if (ThreadNotifyMode(task) || we->weType == 2) { // 2 is weType
131 if (BlockThread(task)) {
132 task->blockType = BlockType::BLOCK_COROUTINE;
133 we->task = nullptr;
134 }
135
136 WaitUntilEntry* wue = static_cast<WaitUntilEntry*>(we);
137 std::unique_lock<std::mutex> lk(wue->wl);
138 wue->cv.notify_one();
139 } else {
140 CoRoutineFactory::CoWakeFunc(task, false);
141 }
142 }
143 }
144
NotifyAll(LinkedList & wList)145 void SharedMutexPrivate::NotifyAll(LinkedList& wList)
146 {
147 WaitEntry* we = wList.PopFront(&WaitEntry::node);
148
149 while (we != nullptr) {
150 CPUEUTask* task = we->task;
151 if (ThreadNotifyMode(task) || we->weType == 2) { // 2 is weType
152 if (BlockThread(task)) {
153 task->blockType = BlockType::BLOCK_COROUTINE;
154 we->task = nullptr;
155 }
156
157 WaitUntilEntry* wue = static_cast<WaitUntilEntry*>(we);
158 std::unique_lock<std::mutex> lk(wue->wl);
159 wue->cv.notify_one();
160 } else {
161 CoRoutineFactory::CoWakeFunc(task, false);
162 }
163
164 if (we->wtType == SharedMutexWaitType::READ) {
165 WaitEntry* weNext = wList.Front(&WaitEntry::node);
166 if (weNext != nullptr && weNext->wtType == SharedMutexWaitType::WRITE) {
167 return;
168 }
169 } else if (we->wtType == SharedMutexWaitType::WRITE) {
170 return;
171 }
172
173 we = wList.PopFront(&WaitEntry::node);
174 }
175 }
176 } // namespace ffrt
177
178 #ifdef __cplusplus
179 extern "C" {
180 #endif
181
182 API_ATTRIBUTE((visibility("default")))
183 int ffrt_rwlock_init(ffrt_rwlock_t* rwlock, const ffrt_rwlockattr_t* attr)
184 {
185 if (!rwlock) {
186 FFRT_LOGE("rwlock should not be empty");
187 return ffrt_error_inval;
188 }
189 if (attr != nullptr) {
190 FFRT_LOGE("only support normal rwlock");
191 return ffrt_error;
192 }
193 static_assert(sizeof(ffrt::SharedMutexPrivate) <= ffrt_rwlock_storage_size,
194 "size must be less than ffrt_rwlock_storage_size");
195
196 new (rwlock)ffrt::SharedMutexPrivate();
197 return ffrt_success;
198 }
199
200 API_ATTRIBUTE((visibility("default")))
201 int ffrt_rwlock_wrlock(ffrt_rwlock_t* rwlock)
202 {
203 if (!rwlock) {
204 FFRT_LOGE("rwlock should not be empty");
205 return ffrt_error_inval;
206 }
207 auto p = reinterpret_cast<ffrt::SharedMutexPrivate*>(rwlock);
208 p->Lock();
209 return ffrt_success;
210 }
211
212 API_ATTRIBUTE((visibility("default")))
213 int ffrt_rwlock_trywrlock(ffrt_rwlock_t* rwlock)
214 {
215 if (!rwlock) {
216 FFRT_LOGE("rwlock should not be empty");
217 return ffrt_error_inval;
218 }
219 auto p = reinterpret_cast<ffrt::SharedMutexPrivate*>(rwlock);
220 return p->TryLock() ? ffrt_success : ffrt_error_busy;
221 }
222
223 API_ATTRIBUTE((visibility("default")))
224 int ffrt_rwlock_rdlock(ffrt_rwlock_t* rwlock)
225 {
226 if (!rwlock) {
227 FFRT_LOGE("rwlock should not be empty");
228 return ffrt_error_inval;
229 }
230 auto p = reinterpret_cast<ffrt::SharedMutexPrivate*>(rwlock);
231 p->LockShared();
232 return ffrt_success;
233 }
234
235 API_ATTRIBUTE((visibility("default")))
236 int ffrt_rwlock_tryrdlock(ffrt_rwlock_t* rwlock)
237 {
238 if (!rwlock) {
239 FFRT_LOGE("rwlock should not be empty");
240 return ffrt_error_inval;
241 }
242 auto p = reinterpret_cast<ffrt::SharedMutexPrivate*>(rwlock);
243 return p->TryLockShared() ? ffrt_success : ffrt_error_busy;
244 }
245
246 API_ATTRIBUTE((visibility("default")))
247 int ffrt_rwlock_unlock(ffrt_rwlock_t* rwlock)
248 {
249 if (!rwlock) {
250 FFRT_LOGE("rwlock should not be empty");
251 return ffrt_error_inval;
252 }
253 auto p = reinterpret_cast<ffrt::SharedMutexPrivate*>(rwlock);
254 p->Unlock();
255 return ffrt_success;
256 }
257
258 API_ATTRIBUTE((visibility("default")))
259 int ffrt_rwlock_destroy(ffrt_rwlock_t* rwlock)
260 {
261 if (!rwlock) {
262 FFRT_LOGE("rwlock should not be empty");
263 return ffrt_error_inval;
264 }
265 auto p = reinterpret_cast<ffrt::SharedMutexPrivate*>(rwlock);
266 p->~SharedMutexPrivate();
267 return ffrt_success;
268 }
269
270 #ifdef __cplusplus
271 }
272 #endif
273