mirror of
https://github.com/apache/nuttx.git
synced 2026-05-31 23:40:19 +08:00
misc/assert: add backtrace dump support for mutex hold task
Signed-off-by: fangpeina <fangpeina@xiaomi.com>
This commit is contained in:
@@ -49,6 +49,9 @@ struct mutex_s
|
|||||||
{
|
{
|
||||||
sem_t sem;
|
sem_t sem;
|
||||||
pid_t holder;
|
pid_t holder;
|
||||||
|
#if CONFIG_LIBC_MUTEX_BACKTRACE > 0
|
||||||
|
FAR void *backtrace[CONFIG_LIBC_MUTEX_BACKTRACE];
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct mutex_s mutex_t;
|
typedef struct mutex_s mutex_t;
|
||||||
|
|||||||
@@ -132,3 +132,10 @@ config LIBC_PATHBUFFER_MALLOC
|
|||||||
default y
|
default y
|
||||||
---help---
|
---help---
|
||||||
Enable malloc path buffer from the heap when pathbuffer is insufficient.
|
Enable malloc path buffer from the heap when pathbuffer is insufficient.
|
||||||
|
|
||||||
|
config LIBC_MUTEX_BACKTRACE
|
||||||
|
int "The depth of mutex backtrace"
|
||||||
|
default 0
|
||||||
|
---help---
|
||||||
|
Config the depth of backtrace, dumping the backtrace of thread which
|
||||||
|
last acquired the mutex. Disable mutex backtrace by 0.
|
||||||
|
|||||||
@@ -59,6 +59,35 @@ static bool nxmutex_is_reset(FAR mutex_t *mutex)
|
|||||||
return mutex->holder == NXMUTEX_RESET;
|
return mutex->holder == NXMUTEX_RESET;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: nxmutex_add_backtrace
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* This function add the backtrace of the holder of the mutex.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* mutex - mutex descriptor.
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#if CONFIG_LIBC_MUTEX_BACKTRACE > 0
|
||||||
|
static void nxmutex_add_backtrace(FAR mutex_t *mutex)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
n = sched_backtrace(mutex->holder, mutex->backtrace,
|
||||||
|
CONFIG_LIBC_MUTEX_BACKTRACE, 0);
|
||||||
|
if (n < CONFIG_LIBC_MUTEX_BACKTRACE)
|
||||||
|
{
|
||||||
|
mutex->backtrace[n] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# define nxmutex_add_backtrace(mutex)
|
||||||
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Functions
|
* Public Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@@ -225,6 +254,7 @@ int nxmutex_lock(FAR mutex_t *mutex)
|
|||||||
if (ret >= 0)
|
if (ret >= 0)
|
||||||
{
|
{
|
||||||
mutex->holder = _SCHED_GETTID();
|
mutex->holder = _SCHED_GETTID();
|
||||||
|
nxmutex_add_backtrace(mutex);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (ret != -EINTR && ret != -ECANCELED)
|
else if (ret != -EINTR && ret != -ECANCELED)
|
||||||
@@ -268,6 +298,8 @@ int nxmutex_trylock(FAR mutex_t *mutex)
|
|||||||
}
|
}
|
||||||
|
|
||||||
mutex->holder = _SCHED_GETTID();
|
mutex->holder = _SCHED_GETTID();
|
||||||
|
nxmutex_add_backtrace(mutex);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,6 +351,7 @@ int nxmutex_clocklock(FAR mutex_t *mutex, clockid_t clockid,
|
|||||||
if (ret >= 0)
|
if (ret >= 0)
|
||||||
{
|
{
|
||||||
mutex->holder = _SCHED_GETTID();
|
mutex->holder = _SCHED_GETTID();
|
||||||
|
nxmutex_add_backtrace(mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
+32
-10
@@ -49,6 +49,7 @@
|
|||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
|
#include <execinfo.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -170,10 +171,10 @@ static void stack_dump(uintptr_t sp, uintptr_t stack_top)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: dump_stack
|
* Name: dump_stackinfo
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static void dump_stack(FAR const char *tag, uintptr_t sp,
|
static void dump_stackinfo(FAR const char *tag, uintptr_t sp,
|
||||||
uintptr_t base, size_t size, size_t used)
|
uintptr_t base, size_t size, size_t used)
|
||||||
{
|
{
|
||||||
uintptr_t top = base + size;
|
uintptr_t top = base + size;
|
||||||
@@ -272,7 +273,7 @@ static void dump_stacks(FAR struct tcb_s *rtcb, uintptr_t sp)
|
|||||||
#if CONFIG_ARCH_INTERRUPTSTACK > 0
|
#if CONFIG_ARCH_INTERRUPTSTACK > 0
|
||||||
if (intstack_sp != 0 || force)
|
if (intstack_sp != 0 || force)
|
||||||
{
|
{
|
||||||
dump_stack("IRQ",
|
dump_stackinfo("IRQ",
|
||||||
intstack_sp,
|
intstack_sp,
|
||||||
intstack_base,
|
intstack_base,
|
||||||
intstack_size,
|
intstack_size,
|
||||||
@@ -298,18 +299,17 @@ static void dump_stacks(FAR struct tcb_s *rtcb, uintptr_t sp)
|
|||||||
#ifdef CONFIG_ARCH_KERNEL_STACK
|
#ifdef CONFIG_ARCH_KERNEL_STACK
|
||||||
if (kernelstack_sp != 0 || force)
|
if (kernelstack_sp != 0 || force)
|
||||||
{
|
{
|
||||||
dump_stack("Kernel",
|
dump_stackinfo("Kernel",
|
||||||
kernelstack_sp,
|
kernelstack_sp,
|
||||||
kernelstack_base,
|
kernelstack_base,
|
||||||
kernelstack_size,
|
kernelstack_size,
|
||||||
0
|
0);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (tcbstack_sp != 0 || force)
|
if (tcbstack_sp != 0 || force)
|
||||||
{
|
{
|
||||||
dump_stack("User",
|
dump_stackinfo("User",
|
||||||
tcbstack_sp,
|
tcbstack_sp,
|
||||||
tcbstack_base,
|
tcbstack_base,
|
||||||
tcbstack_size,
|
tcbstack_size,
|
||||||
@@ -531,6 +531,27 @@ static void dump_tasks(void)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: dump_lockholder
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#if CONFIG_LIBC_MUTEX_BACKTRACE > 0
|
||||||
|
static void dump_lockholder(pid_t tid)
|
||||||
|
{
|
||||||
|
char buf[CONFIG_LIBC_MUTEX_BACKTRACE * BACKTRACE_PTR_FMT_WIDTH + 1] = "";
|
||||||
|
FAR mutex_t *mutex;
|
||||||
|
|
||||||
|
mutex = (FAR mutex_t *)nxsched_get_tcb(tid)->waitobj;
|
||||||
|
|
||||||
|
backtrace_format(buf, sizeof(buf), mutex->backtrace,
|
||||||
|
CONFIG_LIBC_MUTEX_BACKTRACE);
|
||||||
|
|
||||||
|
_alert("Mutex holder(%d) backtrace:%s\n", mutex->holder, buf);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# define dump_lockholder(tid)
|
||||||
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: dump_deadlock
|
* Name: dump_deadlock
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@@ -546,11 +567,12 @@ static void dump_deadlock(void)
|
|||||||
_alert("Deadlock detected\n");
|
_alert("Deadlock detected\n");
|
||||||
while (i-- > 0)
|
while (i-- > 0)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_SCHED_BACKTRACE
|
# ifdef CONFIG_SCHED_BACKTRACE
|
||||||
sched_dumpstack(deadlock[i]);
|
sched_dumpstack(deadlock[i]);
|
||||||
#else
|
dump_lockholder(deadlock[i]);
|
||||||
|
# else
|
||||||
_alert("deadlock pid: %d\n", deadlock[i]);
|
_alert("deadlock pid: %d\n", deadlock[i]);
|
||||||
#endif
|
# endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user