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 ctx->wn.task = nullptr;
113 } else {
114 FFRT_BLOCK_TRACER(task->gid, smx);
115 CoWait([&](CPUEUTask* task) -> bool {
116 task->fq_we.wtType = wtType;
117 wList.PushBack(task->fq_we.node);
118 mut.unlock();
119 return true;
120 });
121 }
122 mut.lock();
123 }
124
NotifyOne(LinkedList & wList)125 void SharedMutexPrivate::NotifyOne(LinkedList& wList)
126 {
127 WaitEntry* we = wList.PopFront(&WaitEntry::node);
128
129 if (we != nullptr) {
130 CPUEUTask* task = we->task;
131 if (ThreadNotifyMode(task) || we->weType == 2) { // 2 is weType
132 if (BlockThread(task)) {
133 task->blockType = BlockType::BLOCK_COROUTINE;
134 we->task = nullptr;
135 }
136
137 WaitUntilEntry* wue = static_cast<WaitUntilEntry*>(we);
138 std::unique_lock<std::mutex> lk(wue->wl);
139 wue->cv.notify_one();
140 } else {
141 CoRoutineFactory::CoWakeFunc(task, CoWakeType::NO_TIMEOUT_WAKE);
142 }
143 }
144 }
145
NotifyAll(LinkedList & wList)146 void SharedMutexPrivate::NotifyAll(LinkedList& wList)
147 {
148 WaitEntry* we = wList.PopFront(&WaitEntry::node);
149
150 while (we != nullptr) {
151 CPUEUTask* task = we->task;
152 if (ThreadNotifyMode(task) || we->weType == 2) { // 2 is weType
153 if (BlockThread(task)) {
154 task->blockType = BlockType::BLOCK_COROUTINE;
155 we->task = nullptr;
156 }
157
158 WaitUntilEntry* wue = static_cast<WaitUntilEntry*>(we);
159 std::unique_lock<std::mutex> lk(wue->wl);
160 wue->cv.notify_one();
161 } else {
162 CoRoutineFactory::CoWakeFunc(task, CoWakeType::NO_TIMEOUT_WAKE);
163 }
164
165 if (we->wtType == SharedMutexWaitType::READ) {
166 WaitEntry* weNext = wList.Front(&WaitEntry::node);
167 if (weNext != nullptr && weNext->wtType == SharedMutexWaitType::WRITE) {
168 return;
169 }
170 } else if (we->wtType == SharedMutexWaitType::WRITE) {
171 return;
172 }
173
174 we = wList.PopFront(&WaitEntry::node);
175 }
176 }
177 } // namespace ffrt
178
179 #ifdef __cplusplus
180 extern "C" {
181 #endif
182
183 API_ATTRIBUTE((visibility("default")))
ffrt_rwlock_init(ffrt_rwlock_t * rwlock,const ffrt_rwlockattr_t * attr)184 int ffrt_rwlock_init(ffrt_rwlock_t* rwlock, const ffrt_rwlockattr_t* attr)
185 {
186 if (!rwlock) {
187 FFRT_LOGE("rwlock should not be empty");
188 return ffrt_error_inval;
189 }
190 if (attr != nullptr) {
191 FFRT_LOGE("only support normal rwlock");
192 return ffrt_error;
193 }
194 static_assert(sizeof(ffrt::SharedMutexPrivate) <= ffrt_rwlock_storage_size,
195 "size must be less than ffrt_rwlock_storage_size");
196
197 new (rwlock)ffrt::SharedMutexPrivate();
198 return ffrt_success;
199 }
200
201 API_ATTRIBUTE((visibility("default")))
ffrt_rwlock_wrlock(ffrt_rwlock_t * rwlock)202 int ffrt_rwlock_wrlock(ffrt_rwlock_t* rwlock)
203 {
204 if (!rwlock) {
205 FFRT_LOGE("rwlock should not be empty");
206 return ffrt_error_inval;
207 }
208 auto p = reinterpret_cast<ffrt::SharedMutexPrivate*>(rwlock);
209 p->Lock();
210 return ffrt_success;
211 }
212
213 API_ATTRIBUTE((visibility("default")))
ffrt_rwlock_trywrlock(ffrt_rwlock_t * rwlock)214 int ffrt_rwlock_trywrlock(ffrt_rwlock_t* rwlock)
215 {
216 if (!rwlock) {
217 FFRT_LOGE("rwlock should not be empty");
218 return ffrt_error_inval;
219 }
220 auto p = reinterpret_cast<ffrt::SharedMutexPrivate*>(rwlock);
221 return p->TryLock() ? ffrt_success : ffrt_error_busy;
222 }
223
224 API_ATTRIBUTE((visibility("default")))
ffrt_rwlock_rdlock(ffrt_rwlock_t * rwlock)225 int ffrt_rwlock_rdlock(ffrt_rwlock_t* rwlock)
226 {
227 if (!rwlock) {
228 FFRT_LOGE("rwlock should not be empty");
229 return ffrt_error_inval;
230 }
231 auto p = reinterpret_cast<ffrt::SharedMutexPrivate*>(rwlock);
232 p->LockShared();
233 return ffrt_success;
234 }
235
236 API_ATTRIBUTE((visibility("default")))
ffrt_rwlock_tryrdlock(ffrt_rwlock_t * rwlock)237 int ffrt_rwlock_tryrdlock(ffrt_rwlock_t* rwlock)
238 {
239 if (!rwlock) {
240 FFRT_LOGE("rwlock should not be empty");
241 return ffrt_error_inval;
242 }
243 auto p = reinterpret_cast<ffrt::SharedMutexPrivate*>(rwlock);
244 return p->TryLockShared() ? ffrt_success : ffrt_error_busy;
245 }
246
247 API_ATTRIBUTE((visibility("default")))
ffrt_rwlock_unlock(ffrt_rwlock_t * rwlock)248 int ffrt_rwlock_unlock(ffrt_rwlock_t* rwlock)
249 {
250 if (!rwlock) {
251 FFRT_LOGE("rwlock should not be empty");
252 return ffrt_error_inval;
253 }
254 auto p = reinterpret_cast<ffrt::SharedMutexPrivate*>(rwlock);
255 p->Unlock();
256 return ffrt_success;
257 }
258
259 API_ATTRIBUTE((visibility("default")))
ffrt_rwlock_destroy(ffrt_rwlock_t * rwlock)260 int ffrt_rwlock_destroy(ffrt_rwlock_t* rwlock)
261 {
262 if (!rwlock) {
263 FFRT_LOGE("rwlock should not be empty");
264 return ffrt_error_inval;
265 }
266 auto p = reinterpret_cast<ffrt::SharedMutexPrivate*>(rwlock);
267 p->~SharedMutexPrivate();
268 return ffrt_success;
269 }
270
271 #ifdef __cplusplus
272 }
273 #endif
274