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 <unistd.h>
17 #include "cpp/mutex.h"
18 #ifndef _GNU_SOURCE
19 #define _GNU_SOURCE
20 #endif
21 
22 #include <map>
23 #include <functional>
24 #include "sync/sync.h"
25 #include "eu/co_routine.h"
26 #include "internal_inc/osal.h"
27 #include "internal_inc/types.h"
28 #include "sync/mutex_private.h"
29 #include "dfx/log/ffrt_log_api.h"
30 #include "ffrt_trace.h"
31 #include "tm/cpu_task.h"
32 
33 namespace ffrt {
try_lock()34 bool mutexPrivate::try_lock()
35 {
36     int v = sync_detail::UNLOCK;
37     bool ret = l.compare_exchange_strong(v, sync_detail::LOCK, std::memory_order_acquire, std::memory_order_relaxed);
38 #ifdef FFRT_MUTEX_DEADLOCK_CHECK
39     if (ret) {
40         uint64_t task = ExecuteCtx::Cur()->task ? reinterpret_cast<uint64_t>(ExecuteCtx::Cur()->task) : GetTid();
41         MutexGraph::Instance().AddNode(task, 0, false);
42         owner.store(task, std::memory_order_relaxed);
43     }
44 #endif
45     return ret;
46 }
47 
lock()48 void mutexPrivate::lock()
49 {
50 #ifdef FFRT_MUTEX_DEADLOCK_CHECK
51     uint64_t task;
52     uint64_t ownerTask;
53     task = ExecuteCtx::Cur()->task ? reinterpret_cast<uint64_t>(ExecuteCtx::Cur()->task) : GetTid();
54     ownerTask = owner.load(std::memory_order_relaxed);
55     if (ownerTask) {
56         MutexGraph::Instance().AddNode(task, ownerTask, true);
57     } else {
58         MutexGraph::Instance().AddNode(task, 0, false);
59     }
60 #endif
61     int v = sync_detail::UNLOCK;
62     if (l.compare_exchange_strong(v, sync_detail::LOCK, std::memory_order_acquire, std::memory_order_relaxed)) {
63         goto lock_out;
64     }
65     if (l.load(std::memory_order_relaxed) == sync_detail::WAIT) {
66         wait();
67     }
68     while (l.exchange(sync_detail::WAIT, std::memory_order_acquire) != sync_detail::UNLOCK) {
69         wait();
70     }
71 
72 lock_out:
73 #ifdef FFRT_MUTEX_DEADLOCK_CHECK
74     owner.store(task, std::memory_order_relaxed);
75 #endif
76     return;
77 }
78 
try_lock()79 bool RecursiveMutexPrivate::try_lock()
80 {
81     auto ctx = ExecuteCtx::Cur();
82     auto task = ctx->task;
83     if ((!USE_COROUTINE) || (task == nullptr)) {
84         fMutex.lock();
85         if (taskLockNums.first == UINT64_MAX) {
86             fMutex.unlock();
87             if (mt.try_lock()) {
88                 fMutex.lock();
89                 taskLockNums = std::make_pair(GetTid(), 1);
90                 fMutex.unlock();
91                 return true;
92             } else {
93                 return false;
94             }
95         }
96 
97         if (taskLockNums.first == GetTid()) {
98             taskLockNums.second += 1;
99             fMutex.unlock();
100             return true;
101         }
102 
103         fMutex.unlock();
104         return false;
105     }
106 
107     fMutex.lock();
108     if (taskLockNums.first == UINT64_MAX) {
109         fMutex.unlock();
110         if (mt.try_lock()) {
111             fMutex.lock();
112             taskLockNums = std::make_pair(task->gid | 0x8000000000000000, 1);
113             fMutex.unlock();
114             return true;
115         } else {
116             return false;
117         }
118     }
119 
120     if (taskLockNums.first == (task->gid | 0x8000000000000000)) {
121         taskLockNums.second += 1;
122         fMutex.unlock();
123         return true;
124     }
125 
126     fMutex.unlock();
127     return false;
128 }
129 
lock()130 void RecursiveMutexPrivate::lock()
131 {
132     auto ctx = ExecuteCtx::Cur();
133     auto task = ctx->task;
134     if ((!USE_COROUTINE) || (task == nullptr)) {
135         fMutex.lock();
136         if (taskLockNums.first != GetTid()) {
137             fMutex.unlock();
138             mt.lock();
139             fMutex.lock();
140             taskLockNums = std::make_pair(GetTid(), 1);
141             fMutex.unlock();
142             return;
143         }
144 
145         taskLockNums.second += 1;
146         fMutex.unlock();
147         return;
148     }
149 
150     fMutex.lock();
151     if (taskLockNums.first != (task->gid | 0x8000000000000000)) {
152         fMutex.unlock();
153         mt.lock();
154         fMutex.lock();
155         taskLockNums = std::make_pair(task->gid | 0x8000000000000000, 1);
156         fMutex.unlock();
157         return;
158     }
159 
160     taskLockNums.second += 1;
161     fMutex.unlock();
162 }
163 
unlock()164 void RecursiveMutexPrivate::unlock()
165 {
166     auto ctx = ExecuteCtx::Cur();
167     auto task = ctx->task;
168     if ((!USE_COROUTINE) || (task == nullptr)) {
169         fMutex.lock();
170         if (taskLockNums.first != GetTid()) {
171             fMutex.unlock();
172             return;
173         }
174 
175         if (taskLockNums.second == 1) {
176             taskLockNums = std::make_pair(UINT64_MAX, 0);
177             fMutex.unlock();
178             mt.unlock();
179             return;
180         }
181 
182         taskLockNums.second -= 1;
183         fMutex.unlock();
184         return;
185     }
186 
187     fMutex.lock();
188     if (taskLockNums.first != (task->gid | 0x8000000000000000)) {
189         fMutex.unlock();
190         return;
191     }
192 
193     if (taskLockNums.second == 1) {
194         taskLockNums = std::make_pair(UINT64_MAX, 0);
195         fMutex.unlock();
196         mt.unlock();
197         return;
198     }
199 
200     taskLockNums.second -= 1;
201     fMutex.unlock();
202 }
203 
unlock()204 void mutexPrivate::unlock()
205 {
206 #ifdef FFRT_MUTEX_DEADLOCK_CHECK
207     uint64_t ownerTask = owner.load(std::memory_order_relaxed);
208     owner.store(0, std::memory_order_relaxed);
209     MutexGraph::Instance().RemoveNode(ownerTask);
210 #endif
211     if (l.exchange(sync_detail::UNLOCK, std::memory_order_release) == sync_detail::WAIT) {
212         wake();
213     }
214 }
215 
wait()216 void mutexPrivate::wait()
217 {
218     auto ctx = ExecuteCtx::Cur();
219     auto task = ctx->task;
220     if (ThreadWaitMode(task)) {
221         wlock.lock();
222         if (l.load(std::memory_order_relaxed) != sync_detail::WAIT) {
223             wlock.unlock();
224             return;
225         }
226         list.PushBack(ctx->wn.node);
227         std::unique_lock<std::mutex> lk(ctx->wn.wl);
228         if (FFRT_UNLIKELY(LegacyMode(task))) {
229             task->blockType = BlockType::BLOCK_THREAD;
230             ctx->wn.task = task;
231         }
232         wlock.unlock();
233         ctx->wn.cv.wait(lk);
234         return;
235     } else {
236         FFRT_BLOCK_TRACER(task->gid, mtx);
237         CoWait([this](CPUEUTask* task) -> bool {
238             wlock.lock();
239             if (l.load(std::memory_order_relaxed) != sync_detail::WAIT) {
240                 wlock.unlock();
241                 return false;
242             }
243             list.PushBack(task->fq_we.node);
244             wlock.unlock();
245             // The ownership of the task belongs to ReadyTaskQueue, and the task cannot be accessed any more.
246             return true;
247         });
248     }
249 }
250 
wake()251 void mutexPrivate::wake()
252 {
253     wlock.lock();
254     if (list.Empty()) {
255         wlock.unlock();
256         return;
257     }
258     WaitEntry* we = list.PopFront(&WaitEntry::node);
259     if (we == nullptr) {
260         wlock.unlock();
261         return;
262     }
263     CPUEUTask* task = we->task;
264     if (ThreadNotifyMode(task) || we->weType == 2) {
265         WaitUntilEntry* wue = static_cast<WaitUntilEntry*>(we);
266         std::unique_lock lk(wue->wl);
267         if (BlockThread(task)) {
268             task->blockType = BlockType::BLOCK_COROUTINE;
269             we->task = nullptr;
270         }
271         wlock.unlock();
272         wue->cv.notify_one();
273     } else {
274         wlock.unlock();
275         CoRoutineFactory::CoWakeFunc(task, false);
276     }
277 }
278 } // namespace ffrt
279 
280 #ifdef __cplusplus
281 extern "C" {
282 #endif
283 API_ATTRIBUTE((visibility("default")))
284 int ffrt_mutexattr_init(ffrt_mutexattr_t* attr)
285 {
286     if (attr == nullptr) {
287         FFRT_LOGE("attr should not be empty");
288         return ffrt_error_inval;
289     }
290     attr->storage = static_cast<long>(ffrt_mutex_default);
291     return ffrt_success;
292 }
293 
294 API_ATTRIBUTE((visibility("default")))
295 int ffrt_mutexattr_settype(ffrt_mutexattr_t* attr, int type)
296 {
297     if (attr == nullptr) {
298         FFRT_LOGE("attr should not be empty");
299         return ffrt_error_inval;
300     }
301     if (type != ffrt_mutex_normal && type != ffrt_mutex_recursive && type != ffrt_mutex_default) {
302         FFRT_LOGE("mutex type is invaild");
303         return ffrt_error_inval;
304     }
305     attr->storage = static_cast<long>(type);
306     return ffrt_success;
307 }
308 
309 API_ATTRIBUTE((visibility("default")))
310 int ffrt_mutexattr_gettype(ffrt_mutexattr_t* attr, int* type)
311 {
312     if (attr == nullptr || type == nullptr) {
313         FFRT_LOGE("attr or type should not be empty");
314         return ffrt_error_inval;
315     }
316     *type = static_cast<int>(attr->storage);
317     return ffrt_success;
318 }
319 
320 API_ATTRIBUTE((visibility("default")))
321 int ffrt_mutexattr_destroy(ffrt_mutexattr_t* attr)
322 {
323     if (attr == nullptr) {
324         FFRT_LOGE("attr should not be empty");
325         return ffrt_error_inval;
326     }
327     return ffrt_success;
328 }
329 
330 API_ATTRIBUTE((visibility("default")))
331 int ffrt_mutex_init(ffrt_mutex_t* mutex, const ffrt_mutexattr_t* attr)
332 {
333     if (!mutex) {
334         FFRT_LOGE("mutex should not be empty");
335         return ffrt_error_inval;
336     }
337     if (attr == nullptr || attr->storage == static_cast<long>(ffrt_mutex_normal)) {
338         static_assert(sizeof(ffrt::mutexPrivate) <= ffrt_mutex_storage_size,
339         "size must be less than ffrt_mutex_storage_size");
340         new (mutex)ffrt::mutexPrivate();
341         return ffrt_success;
342     } else if (attr->storage == static_cast<long>(ffrt_mutex_recursive)) {
343         static_assert(sizeof(ffrt::RecursiveMutexPrivate) <= ffrt_mutex_storage_size,
344         "size must be less than ffrt_mutex_storage_size");
345         new (mutex)ffrt::RecursiveMutexPrivate();
346         return ffrt_success;
347     }
348     return ffrt_error_inval;
349 }
350 
351 API_ATTRIBUTE((visibility("default")))
352 int ffrt_mutex_lock(ffrt_mutex_t* mutex)
353 {
354     if (!mutex) {
355         FFRT_LOGE("mutex should not be empty");
356         return ffrt_error_inval;
357     }
358     auto p = reinterpret_cast<ffrt::mutexBase*>(mutex);
359     p->lock();
360     return ffrt_success;
361 }
362 
363 API_ATTRIBUTE((visibility("default")))
364 int ffrt_mutex_unlock(ffrt_mutex_t* mutex)
365 {
366     if (!mutex) {
367         FFRT_LOGE("mutex should not be empty");
368         return ffrt_error_inval;
369     }
370     auto p = reinterpret_cast<ffrt::mutexBase*>(mutex);
371     p->unlock();
372     return ffrt_success;
373 }
374 
375 API_ATTRIBUTE((visibility("default")))
376 int ffrt_mutex_trylock(ffrt_mutex_t* mutex)
377 {
378     if (!mutex) {
379         FFRT_LOGE("mutex should not be empty");
380         return ffrt_error_inval;
381     }
382     auto p = reinterpret_cast<ffrt::mutexBase*>(mutex);
383     return p->try_lock() ? ffrt_success : ffrt_error_busy;
384 }
385 
386 API_ATTRIBUTE((visibility("default")))
387 int ffrt_mutex_destroy(ffrt_mutex_t* mutex)
388 {
389     if (!mutex) {
390         FFRT_LOGE("mutex should not be empty");
391         return ffrt_error_inval;
392     }
393     auto p = reinterpret_cast<ffrt::mutexBase*>(mutex);
394     p->~mutexBase();
395     return ffrt_success;
396 }
397 
398 #ifdef __cplusplus
399 }
400 #endif
401