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