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