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