• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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         ctx->wn.task = nullptr;
235         return;
236     } else {
237         FFRT_BLOCK_TRACER(task->gid, mtx);
238         CoWait([this](CPUEUTask* task) -> bool {
239             wlock.lock();
240             if (l.load(std::memory_order_relaxed) != sync_detail::WAIT) {
241                 wlock.unlock();
242                 return false;
243             }
244             list.PushBack(task->fq_we.node);
245             wlock.unlock();
246             // The ownership of the task belongs to ReadyTaskQueue, and the task cannot be accessed any more.
247             return true;
248         });
249     }
250 }
251 
wake()252 void mutexPrivate::wake()
253 {
254     wlock.lock();
255     if (list.Empty()) {
256         wlock.unlock();
257         return;
258     }
259     WaitEntry* we = list.PopFront(&WaitEntry::node);
260     if (we == nullptr) {
261         wlock.unlock();
262         return;
263     }
264     CPUEUTask* task = we->task;
265     if (ThreadNotifyMode(task) || we->weType == 2) {
266         WaitUntilEntry* wue = static_cast<WaitUntilEntry*>(we);
267         std::unique_lock lk(wue->wl);
268         if (BlockThread(task)) {
269             task->blockType = BlockType::BLOCK_COROUTINE;
270             we->task = nullptr;
271         }
272         wlock.unlock();
273         wue->cv.notify_one();
274     } else {
275         wlock.unlock();
276         CoRoutineFactory::CoWakeFunc(task, CoWakeType::NO_TIMEOUT_WAKE);
277     }
278 }
279 } // namespace ffrt
280 
281 #ifdef __cplusplus
282 extern "C" {
283 #endif
284 API_ATTRIBUTE((visibility("default")))
ffrt_mutexattr_init(ffrt_mutexattr_t * attr)285 int ffrt_mutexattr_init(ffrt_mutexattr_t* attr)
286 {
287     if (attr == nullptr) {
288         FFRT_LOGE("attr should not be empty");
289         return ffrt_error_inval;
290     }
291     attr->storage = static_cast<long>(ffrt_mutex_default);
292     return ffrt_success;
293 }
294 
295 API_ATTRIBUTE((visibility("default")))
ffrt_mutexattr_settype(ffrt_mutexattr_t * attr,int type)296 int ffrt_mutexattr_settype(ffrt_mutexattr_t* attr, int type)
297 {
298     if (attr == nullptr) {
299         FFRT_LOGE("attr should not be empty");
300         return ffrt_error_inval;
301     }
302     if (type != ffrt_mutex_normal && type != ffrt_mutex_recursive && type != ffrt_mutex_default) {
303         FFRT_LOGE("mutex type is invaild");
304         return ffrt_error_inval;
305     }
306     attr->storage = static_cast<long>(type);
307     return ffrt_success;
308 }
309 
310 API_ATTRIBUTE((visibility("default")))
ffrt_mutexattr_gettype(ffrt_mutexattr_t * attr,int * type)311 int ffrt_mutexattr_gettype(ffrt_mutexattr_t* attr, int* type)
312 {
313     if (attr == nullptr || type == nullptr) {
314         FFRT_LOGE("attr or type should not be empty");
315         return ffrt_error_inval;
316     }
317     *type = static_cast<int>(attr->storage);
318     return ffrt_success;
319 }
320 
321 API_ATTRIBUTE((visibility("default")))
ffrt_mutexattr_destroy(ffrt_mutexattr_t * attr)322 int ffrt_mutexattr_destroy(ffrt_mutexattr_t* attr)
323 {
324     if (attr == nullptr) {
325         FFRT_LOGE("attr should not be empty");
326         return ffrt_error_inval;
327     }
328     return ffrt_success;
329 }
330 
331 API_ATTRIBUTE((visibility("default")))
ffrt_mutex_init(ffrt_mutex_t * mutex,const ffrt_mutexattr_t * attr)332 int ffrt_mutex_init(ffrt_mutex_t* mutex, const ffrt_mutexattr_t* attr)
333 {
334     if (!mutex) {
335         FFRT_LOGE("mutex should not be empty");
336         return ffrt_error_inval;
337     }
338     if (attr == nullptr || attr->storage == static_cast<long>(ffrt_mutex_normal)) {
339         static_assert(sizeof(ffrt::mutexPrivate) <= ffrt_mutex_storage_size,
340         "size must be less than ffrt_mutex_storage_size");
341         new (mutex)ffrt::mutexPrivate();
342         return ffrt_success;
343     } else if (attr->storage == static_cast<long>(ffrt_mutex_recursive)) {
344         static_assert(sizeof(ffrt::RecursiveMutexPrivate) <= ffrt_mutex_storage_size,
345         "size must be less than ffrt_mutex_storage_size");
346         new (mutex)ffrt::RecursiveMutexPrivate();
347         return ffrt_success;
348     }
349     return ffrt_error_inval;
350 }
351 
352 API_ATTRIBUTE((visibility("default")))
ffrt_mutex_lock(ffrt_mutex_t * mutex)353 int ffrt_mutex_lock(ffrt_mutex_t* mutex)
354 {
355     if (!mutex) {
356         FFRT_LOGE("mutex should not be empty");
357         return ffrt_error_inval;
358     }
359     auto p = reinterpret_cast<ffrt::mutexBase*>(mutex);
360     p->lock();
361     return ffrt_success;
362 }
363 
364 API_ATTRIBUTE((visibility("default")))
ffrt_mutex_unlock(ffrt_mutex_t * mutex)365 int ffrt_mutex_unlock(ffrt_mutex_t* mutex)
366 {
367     if (!mutex) {
368         FFRT_LOGE("mutex should not be empty");
369         return ffrt_error_inval;
370     }
371     auto p = reinterpret_cast<ffrt::mutexBase*>(mutex);
372     p->unlock();
373     return ffrt_success;
374 }
375 
376 API_ATTRIBUTE((visibility("default")))
ffrt_mutex_trylock(ffrt_mutex_t * mutex)377 int ffrt_mutex_trylock(ffrt_mutex_t* mutex)
378 {
379     if (!mutex) {
380         FFRT_LOGE("mutex should not be empty");
381         return ffrt_error_inval;
382     }
383     auto p = reinterpret_cast<ffrt::mutexBase*>(mutex);
384     return p->try_lock() ? ffrt_success : ffrt_error_busy;
385 }
386 
387 API_ATTRIBUTE((visibility("default")))
ffrt_mutex_destroy(ffrt_mutex_t * mutex)388 int ffrt_mutex_destroy(ffrt_mutex_t* mutex)
389 {
390     if (!mutex) {
391         FFRT_LOGE("mutex should not be empty");
392         return ffrt_error_inval;
393     }
394     auto p = reinterpret_cast<ffrt::mutexBase*>(mutex);
395     p->~mutexBase();
396     return ffrt_success;
397 }
398 
399 #ifdef __cplusplus
400 }
401 #endif
402