更新日期: 2022/06/01 来源: https://gitee.com/weharmony/kernel_liteos_a_note
los_lockdep.c
浏览该文件的文档.
1/*
2 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this list of
9 * conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12 * of conditions and the following disclaimer in the documentation and/or other materials
13 * provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16 * to endorse or promote products derived from this software without specific prior written
17 * permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include "los_base.h"
33#include "los_spinlock.h"
34#include "los_task_pri.h"
35#include "los_printf_pri.h"
36#include "los_atomic.h"
37#include "los_exc.h"
38
39#ifdef LOSCFG_KERNEL_SMP_LOCKDEP
40
41#define PRINT_BUF_SIZE 256
42
43#define LOCKDEP_GET_NAME(lockDep, index) (((SPIN_LOCK_S *)((lockDep)->heldLocks[(index)].lockPtr))->name)
44#define LOCKDEP_GET_ADDR(lockDep, index) ((lockDep)->heldLocks[(index)].lockAddr)
45
47
48/* atomic insurance for lockdep check */
49STATIC INLINE VOID OsLockDepRequire(UINT32 *intSave)
50{
51 *intSave = LOS_IntLock();
53 /* busy waiting */
54 }
55}
56
57STATIC INLINE VOID OsLockDepRelease(UINT32 intSave)
58{
60 LOS_IntRestore(intSave);
61}
62
63STATIC INLINE UINT64 OsLockDepGetCycles(VOID)
64{
65 UINT32 high, low;
66
67 LOS_GetCpuCycle(&high, &low);
68 /* combine cycleHi and cycleLo into 8 bytes cycles */
69 return (((UINT64)high << 32) + low); // 32 bits for lower half of UINT64
70}
71
73{
74 CHAR *errorString = NULL;
75
76 switch (type) {
78 errorString = "double lock";
79 break;
81 errorString = "dead lock";
82 break;
84 errorString = "unlock without lock";
85 break;
87 errorString = "lockdep overflow";
88 break;
89 default:
90 errorString = "unknown error code";
91 break;
92 }
93
94 return errorString;
95}
96
97WEAK VOID OsLockDepPanic(enum LockDepErrType errType)
98{
99 /* halt here */
100 (VOID)errType;
101 (VOID)LOS_IntLock();
102 OsBackTrace();
103 while (1) {}
104}
105
106STATIC VOID OsLockDepPrint(const CHAR *fmt, va_list ap)
107{
108 UINT32 len;
109 CHAR buf[PRINT_BUF_SIZE] = {0};
110
111 len = vsnprintf_s(buf, PRINT_BUF_SIZE, PRINT_BUF_SIZE - 1, fmt, ap);
112 if ((len == -1) && (*buf == '\0')) {
113 /* parameter is illegal or some features in fmt dont support */
114 UartPuts("OsLockDepPrint is error\n", strlen("OsLockDepPrint is error\n"), 0);
115 return;
116 }
117 *(buf + len) = '\0';
118
119 UartPuts(buf, len, 0);
120}
121
122STATIC VOID OsPrintLockDepInfo(const CHAR *fmt, ...)
123{
124 va_list ap;
125 va_start(ap, fmt);
126 OsLockDepPrint(fmt, ap);
127 va_end(ap);
128}
129
130STATIC VOID OsLockDepDumpLock(const LosTaskCB *task, const SPIN_LOCK_S *lock,
131 const VOID *requestAddr, enum LockDepErrType errType)
132{
133 INT32 i;
134 const LockDep *lockDep = &task->lockDep;
135 const LosTaskCB *temp = task;
136
137 OsPrintLockDepInfo("lockdep check failed\n");
138 OsPrintLockDepInfo("error type : %s\n", OsLockDepErrorStringGet(errType));
139 OsPrintLockDepInfo("request addr : 0x%x\n", requestAddr);
140
141 while (1) {
142 OsPrintLockDepInfo("task name : %s\n", temp->taskName);
143 OsPrintLockDepInfo("task id : %u\n", temp->taskID);
144 OsPrintLockDepInfo("cpu num : %u\n", temp->currCpu);
145 OsPrintLockDepInfo("start dumping lockdep information\n");
146 for (i = 0; i < lockDep->lockDepth; i++) {
147 if (lockDep->heldLocks[i].lockPtr == lock) {
148 OsPrintLockDepInfo("[%d] %s <-- addr:0x%x\n", i, LOCKDEP_GET_NAME(lockDep, i),
149 LOCKDEP_GET_ADDR(lockDep, i));
150 } else {
151 OsPrintLockDepInfo("[%d] %s \n", i, LOCKDEP_GET_NAME(lockDep, i));
152 }
153 }
154 OsPrintLockDepInfo("[%d] %s <-- now\n", i, lock->name);
155
156 if (errType == LOCKDEP_ERR_DEAD_LOCK) {
157 temp = lock->owner;
158 lock = temp->lockDep.waitLock;
159 lockDep = &temp->lockDep;
160 }
161
162 if (temp == task) {
163 break;
164 }
165 }
166}
167
168STATIC BOOL OsLockDepCheckDependency(const LosTaskCB *current, LosTaskCB *lockOwner)
169{
170 BOOL checkResult = TRUE;
171 SPIN_LOCK_S *lockTemp = NULL;
172
173 do {
174 if (current == lockOwner) {
175 checkResult = FALSE;
176 return checkResult;
177 }
178 if (lockOwner->lockDep.waitLock != NULL) {
179 lockTemp = lockOwner->lockDep.waitLock;
180 lockOwner = lockTemp->owner;
181 } else {
182 break;
183 }
184 } while (lockOwner != SPINLOCK_OWNER_INIT);
185
186 return checkResult;
187}
188
190{
191 UINT32 intSave;
192 enum LockDepErrType checkResult = LOCKDEP_SUCCESS;
193#ifdef LOSCFG_COMPILER_CLANG_LLVM
194 VOID *requestAddr = (VOID *)__builtin_return_address(1);
195#else
196 VOID *requestAddr = (VOID *)__builtin_return_address(0);
197#endif
198 LosTaskCB *current = OsCurrTaskGet();
199 LockDep *lockDep = &current->lockDep;
200 LosTaskCB *lockOwner = NULL;
201
202 OsLockDepRequire(&intSave);
203
204 if (lockDep->lockDepth >= (INT32)MAX_LOCK_DEPTH) {
205 checkResult = LOCKDEP_ERR_OVERFLOW;
206 goto OUT;
207 }
208
209 lockOwner = lock->owner;
210 /* not owned by any tasks yet, not doing following checks */
211 if (lockOwner == SPINLOCK_OWNER_INIT) {
212 goto OUT;
213 }
214
215 if (current == lockOwner) {
216 checkResult = LOCKDEP_ERR_DOUBLE_LOCK;
217 goto OUT;
218 }
219
220 if (OsLockDepCheckDependency(current, lockOwner) != TRUE) {
221 checkResult = LOCKDEP_ERR_DEAD_LOCK;
222 goto OUT;
223 }
224
225OUT:
226 if (checkResult == LOCKDEP_SUCCESS) {
227 /*
228 * though the check may succeed, the waitLock still need to be set.
229 * because the OsLockDepCheckIn and OsLockDepRecord is not strictly multi-core
230 * sequential, there would be more than two tasks can pass the checking, but
231 * only one task can successfully obtain the lock.
232 */
233 lockDep->waitLock = lock;
234 lockDep->heldLocks[lockDep->lockDepth].lockAddr = requestAddr;
235 lockDep->heldLocks[lockDep->lockDepth].waitTime = OsLockDepGetCycles(); /* start time */
236 OsLockDepRelease(intSave);
237 return;
238 }
239 OsLockDepDumpLock(current, lock, requestAddr, checkResult);
240 OsLockDepRelease(intSave);
241 OsLockDepPanic(checkResult);
242}
243
245{
246 UINT32 intSave;
247 UINT64 cycles;
248 LosTaskCB *current = OsCurrTaskGet();
249 LockDep *lockDep = &current->lockDep;
250 HeldLocks *heldlock = &lockDep->heldLocks[lockDep->lockDepth];
251
252 OsLockDepRequire(&intSave);
253
254 /*
255 * OsLockDepCheckIn records start time t1, after the lock is obtained, we
256 * get the time t2, (t2 - t1) is the time of waiting for the lock
257 */
258 cycles = OsLockDepGetCycles();
259 heldlock->waitTime = cycles - heldlock->waitTime;
260 heldlock->holdTime = cycles;
261
262 /* record lock info */
263 lock->owner = current;
264 lock->cpuid = ArchCurrCpuid();
265
266 /* record lockdep info */
267 heldlock->lockPtr = lock;
268 lockDep->lockDepth++;
269 lockDep->waitLock = NULL;
270
271 OsLockDepRelease(intSave);
272}
273
275{
276 UINT32 intSave;
277 INT32 depth;
278 enum LockDepErrType checkResult = LOCKDEP_SUCCESS;
279#ifdef LOSCFG_COMPILER_CLANG_LLVM
280 VOID *requestAddr = (VOID *)__builtin_return_address(1);
281#else
282 VOID *requestAddr = (VOID *)__builtin_return_address(0);
283#endif
284 LosTaskCB *current = OsCurrTaskGet();
285 LosTaskCB *owner = NULL;
286 LockDep *lockDep = NULL;
287 HeldLocks *heldlocks = NULL;
288
289 OsLockDepRequire(&intSave);
290
291 owner = lock->owner;
292 if (owner == SPINLOCK_OWNER_INIT) {
293 checkResult = LOCKDEP_ERR_UNLOCK_WITOUT_LOCK;
294 OsLockDepDumpLock(current, lock, requestAddr, checkResult);
295 OsLockDepRelease(intSave);
296 OsLockDepPanic(checkResult);
297 return;
298 }
299
300 lockDep = &owner->lockDep;
301 heldlocks = &lockDep->heldLocks[0];
302 depth = lockDep->lockDepth;
303
304 /* find the lock position */
305 while (--depth >= 0) {
306 if (heldlocks[depth].lockPtr == lock) {
307 break;
308 }
309 }
310
311 LOS_ASSERT(depth >= 0);
312
313 /* record lock holding time */
314 heldlocks[depth].holdTime = OsLockDepGetCycles() - heldlocks[depth].holdTime;
315
316 /* if unlock an older lock, needs move heldLock records */
317 while (depth < lockDep->lockDepth - 1) {
318 lockDep->heldLocks[depth] = lockDep->heldLocks[depth + 1];
319 depth++;
320 }
321
322 lockDep->lockDepth--;
323 lock->cpuid = (UINT32)(-1);
324 lock->owner = SPINLOCK_OWNER_INIT;
325
326 OsLockDepRelease(intSave);
327}
328
330{
331 LosTaskCB *task = OsCurrTaskGet();
332 LockDep *lockDep = &task->lockDep;
333 SPIN_LOCK_S *lock = NULL;
334
335 /*
336 * Unlock spinlocks that running task has held.
337 * lockDepth will decrease after each spinlock is unlockded.
338 */
339 while (lockDep->lockDepth) {
340 lock = lockDep->heldLocks[lockDep->lockDepth - 1].lockPtr;
341 LOS_SpinUnlock(lock);
342 }
343}
344
345#else /* LOSCFG_KERNEL_SMP_LOCKDEP */
346
348{
349 (VOID)lock;
350
351 return;
352}
353
355{
356 (VOID)lock;
357
358 return;
359}
360
362{
363 (VOID)lock;
364
365 return;
366}
367
369{
370 return;
371}
372
373#endif
374
STATIC INLINE BOOL LOS_AtomicCmpXchg32bits(Atomic *v, INT32 val, INT32 oldVal)
Atomic exchange for 32-bit variable with compare. | 比较并交换32位原子数据,返回比较结果
Definition: los_atomic.h:890
STATIC INLINE VOID LOS_AtomicSet(Atomic *v, INT32 setVal)
Atomic setting.
Definition: los_atomic.h:147
VOID OsBackTrace(VOID)
Kernel backtrace function.
Definition: los_exc.c:1025
STATIC INLINE VOID LOS_IntRestore(UINT32 intSave)
Restore interrupts. | 恢复到使用LOS_IntLock关闭所有中断之前的状态
Definition: los_hwi.h:337
STATIC INLINE UINT32 LOS_IntLock(VOID)
Disable all interrupts. | 关闭当前处理器所有中断响应
Definition: los_hwi.h:286
LITE_OS_SEC_TEXT_MINOR VOID LOS_GetCpuCycle(UINT32 *highCnt, UINT32 *lowCnt)
获取自系统启动以来的Cycle数
Definition: los_hw_tick.c:54
原子操作 http://weharmonyos.com/openharmony/zh-cn/device-dev/kernel/kernel-small-basic-atomic....
volatile INT32 Atomic
Definition: los_atomic.h:102
STATIC INLINE UINT32 ArchCurrCpuid(VOID)
Definition: los_hw_cpu.h:168
STATIC BOOL OsLockDepCheckDependency(const LosTaskCB *current, LosTaskCB *lockOwner)
Definition: los_lockdep.c:168
STATIC INLINE CHAR * OsLockDepErrorStringGet(enum LockDepErrType type)
Definition: los_lockdep.c:72
STATIC VOID OsPrintLockDepInfo(const CHAR *fmt,...)
Definition: los_lockdep.c:122
STATIC INLINE UINT64 OsLockDepGetCycles(VOID)
Definition: los_lockdep.c:63
VOID OsLockDepCheckIn(SPIN_LOCK_S *lock)
Definition: los_lockdep.c:189
VOID OsLockDepCheckOut(SPIN_LOCK_S *lock)
Definition: los_lockdep.c:274
VOID OsLockDepRecord(SPIN_LOCK_S *lock)
Definition: los_lockdep.c:244
WEAK VOID OsLockDepPanic(enum LockDepErrType errType)
Definition: los_lockdep.c:97
VOID OsLockdepClearSpinlocks(VOID)
Definition: los_lockdep.c:329
STATIC VOID OsLockDepDumpLock(const LosTaskCB *task, const SPIN_LOCK_S *lock, const VOID *requestAddr, enum LockDepErrType errType)
Definition: los_lockdep.c:130
STATIC Atomic g_lockdepAvailable
Definition: los_lockdep.c:46
STATIC INLINE VOID OsLockDepRequire(UINT32 *intSave)
Definition: los_lockdep.c:49
STATIC VOID OsLockDepPrint(const CHAR *fmt, va_list ap)
Definition: los_lockdep.c:106
STATIC INLINE VOID OsLockDepRelease(UINT32 intSave)
Definition: los_lockdep.c:57
LockDepErrType
Definition: los_lockdep.h:45
@ LOCKDEP_ERR_DEAD_LOCK
Definition: los_lockdep.h:48
@ LOCKDEP_SUCCESS
Definition: los_lockdep.h:46
@ LOCKDEP_ERR_UNLOCK_WITOUT_LOCK
Definition: los_lockdep.h:49
@ LOCKDEP_ERR_DOUBLE_LOCK
Definition: los_lockdep.h:47
@ LOCKDEP_ERR_OVERFLOW
Definition: los_lockdep.h:51
STATIC INLINE LosTaskCB * OsCurrTaskGet(VOID)
VOID LOS_SpinUnlock(SPIN_LOCK_S *lock)
Definition: los_spinlock.c:84
signed int INT32
Definition: los_typedef.h:60
long unsigned int UINT64
Definition: los_typedef.h:66
unsigned int UINT32
Definition: los_typedef.h:57
char CHAR
Definition: los_typedef.h:63
size_t BOOL
Definition: los_typedef.h:88
VOID * lockPtr
Definition: los_lockdep.h:55
VOID * lockAddr
Definition: los_lockdep.h:56
UINT64 holdTime
Definition: los_lockdep.h:58
UINT64 waitTime
Definition: los_lockdep.h:57
INT32 lockDepth
Definition: los_lockdep.h:63
HeldLocks heldLocks[MAX_LOCK_DEPTH]
Definition: los_lockdep.h:64
VOID * waitLock
Definition: los_lockdep.h:62
UINT32 cpuid
Definition: los_spinlock.h:53
VOID * owner
Definition: los_spinlock.h:54
const CHAR * name
Definition: los_spinlock.h:55
LockDep lockDep
死锁依赖检测
UINT32 taskID
CHAR taskName[OS_TCB_NAME_LEN]
UINT16 currCpu
VOID UartPuts(const CHAR *s, UINT32 len, BOOL isLock)