• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
46 STATIC Atomic g_lockdepAvailable = 1;
47 
48 /* atomic insurance for lockdep check */
OsLockDepRequire(UINT32 * intSave)49 STATIC INLINE VOID OsLockDepRequire(UINT32 *intSave)
50 {
51     *intSave = LOS_IntLock();
52     while (LOS_AtomicCmpXchg32bits(&g_lockdepAvailable, 0, 1)) {
53         /* busy waiting */
54     }
55 }
56 
OsLockDepRelease(UINT32 intSave)57 STATIC INLINE VOID OsLockDepRelease(UINT32 intSave)
58 {
59     LOS_AtomicSet(&g_lockdepAvailable, 1);
60     LOS_IntRestore(intSave);
61 }
62 
OsLockDepGetCycles(VOID)63 STATIC 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 
OsLockDepErrorStringGet(enum LockDepErrType type)72 STATIC INLINE CHAR *OsLockDepErrorStringGet(enum LockDepErrType type)
73 {
74     CHAR *errorString = NULL;
75 
76     switch (type) {
77         case LOCKDEP_ERR_DOUBLE_LOCK:
78             errorString = "double lock";
79             break;
80         case LOCKDEP_ERR_DEAD_LOCK:
81             errorString = "dead lock";
82             break;
83         case LOCKDEP_ERR_UNLOCK_WITOUT_LOCK:
84             errorString = "unlock without lock";
85             break;
86         case LOCKDEP_ERR_OVERFLOW:
87             errorString = "lockdep overflow";
88             break;
89         default:
90             errorString = "unknown error code";
91             break;
92     }
93 
94     return errorString;
95 }
96 
OsLockDepPanic(enum LockDepErrType errType)97 WEAK VOID OsLockDepPanic(enum LockDepErrType errType)
98 {
99     /* halt here */
100     (VOID)errType;
101     (VOID)LOS_IntLock();
102     OsBackTrace();
103     while (1) {}
104 }
105 
OsLockDepPrint(const CHAR * fmt,va_list ap)106 STATIC 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 
OsPrintLockDepInfo(const CHAR * fmt,...)122 STATIC 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 
OsLockDepDumpLock(const LosTaskCB * task,const SPIN_LOCK_S * lock,const VOID * requestAddr,enum LockDepErrType errType)130 STATIC 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 
OsLockDepCheckDependency(const LosTaskCB * current,LosTaskCB * lockOwner)168 STATIC 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 
OsLockDepCheckIn(SPIN_LOCK_S * lock)189 VOID OsLockDepCheckIn(SPIN_LOCK_S *lock)
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 
225 OUT:
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 
OsLockDepRecord(SPIN_LOCK_S * lock)244 VOID OsLockDepRecord(SPIN_LOCK_S *lock)
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 
OsLockDepCheckOut(SPIN_LOCK_S * lock)274 VOID OsLockDepCheckOut(SPIN_LOCK_S *lock)
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 
OsLockdepClearSpinlocks(VOID)329 VOID OsLockdepClearSpinlocks(VOID)
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 
OsLockDepCheckIn(SPIN_LOCK_S * lock)347 VOID OsLockDepCheckIn(SPIN_LOCK_S *lock)
348 {
349     (VOID)lock;
350 
351     return;
352 }
353 
OsLockDepRecord(SPIN_LOCK_S * lock)354 VOID OsLockDepRecord(SPIN_LOCK_S *lock)
355 {
356     (VOID)lock;
357 
358     return;
359 }
360 
OsLockDepCheckOut(SPIN_LOCK_S * lock)361 VOID OsLockDepCheckOut(SPIN_LOCK_S *lock)
362 {
363     (VOID)lock;
364 
365     return;
366 }
367 
OsLockdepClearSpinlocks(VOID)368 VOID OsLockdepClearSpinlocks(VOID)
369 {
370     return;
371 }
372 
373 #endif
374 
375