diff --git a/include/nuttx/mutex.h b/include/nuttx/mutex.h index c112a96137..acf1e2b0c6 100644 --- a/include/nuttx/mutex.h +++ b/include/nuttx/mutex.h @@ -49,6 +49,9 @@ struct mutex_s { sem_t sem; pid_t holder; +#if CONFIG_LIBC_MUTEX_BACKTRACE > 0 + FAR void *backtrace[CONFIG_LIBC_MUTEX_BACKTRACE]; +#endif }; typedef struct mutex_s mutex_t; diff --git a/libs/libc/misc/Kconfig b/libs/libc/misc/Kconfig index 77ed665c50..f33397babe 100644 --- a/libs/libc/misc/Kconfig +++ b/libs/libc/misc/Kconfig @@ -132,3 +132,10 @@ config LIBC_PATHBUFFER_MALLOC default y ---help--- 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. diff --git a/libs/libc/misc/lib_mutex.c b/libs/libc/misc/lib_mutex.c index 6e0acc9245..46e0a255b0 100644 --- a/libs/libc/misc/lib_mutex.c +++ b/libs/libc/misc/lib_mutex.c @@ -59,6 +59,35 @@ static bool nxmutex_is_reset(FAR mutex_t *mutex) 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 ****************************************************************************/ @@ -225,6 +254,7 @@ int nxmutex_lock(FAR mutex_t *mutex) if (ret >= 0) { mutex->holder = _SCHED_GETTID(); + nxmutex_add_backtrace(mutex); break; } else if (ret != -EINTR && ret != -ECANCELED) @@ -268,6 +298,8 @@ int nxmutex_trylock(FAR mutex_t *mutex) } mutex->holder = _SCHED_GETTID(); + nxmutex_add_backtrace(mutex); + return ret; } @@ -319,6 +351,7 @@ int nxmutex_clocklock(FAR mutex_t *mutex, clockid_t clockid, if (ret >= 0) { mutex->holder = _SCHED_GETTID(); + nxmutex_add_backtrace(mutex); } return ret; diff --git a/sched/misc/assert.c b/sched/misc/assert.c index af6cfd0e6a..e7b4fccf79 100644 --- a/sched/misc/assert.c +++ b/sched/misc/assert.c @@ -49,6 +49,7 @@ #include #include +#include #include #include #include @@ -170,11 +171,11 @@ 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, - uintptr_t base, size_t size, size_t used) +static void dump_stackinfo(FAR const char *tag, uintptr_t sp, + uintptr_t base, size_t size, size_t used) { uintptr_t top = base + size; @@ -272,16 +273,16 @@ static void dump_stacks(FAR struct tcb_s *rtcb, uintptr_t sp) #if CONFIG_ARCH_INTERRUPTSTACK > 0 if (intstack_sp != 0 || force) { - dump_stack("IRQ", - intstack_sp, - intstack_base, - intstack_size, + dump_stackinfo("IRQ", + intstack_sp, + intstack_base, + intstack_size, #ifdef CONFIG_STACK_COLORATION - up_check_intstack(cpu) + up_check_intstack(cpu) #else - 0 + 0 #endif - ); + ); /* Try to restore SP from current_regs if assert from interrupt. */ @@ -298,27 +299,26 @@ static void dump_stacks(FAR struct tcb_s *rtcb, uintptr_t sp) #ifdef CONFIG_ARCH_KERNEL_STACK if (kernelstack_sp != 0 || force) { - dump_stack("Kernel", - kernelstack_sp, - kernelstack_base, - kernelstack_size, - 0 - ); + dump_stackinfo("Kernel", + kernelstack_sp, + kernelstack_base, + kernelstack_size, + 0); } #endif if (tcbstack_sp != 0 || force) { - dump_stack("User", - tcbstack_sp, - tcbstack_base, - tcbstack_size, + dump_stackinfo("User", + tcbstack_sp, + tcbstack_base, + tcbstack_size, #ifdef CONFIG_STACK_COLORATION - up_check_tcbstack(rtcb) + up_check_tcbstack(rtcb) #else - 0 + 0 #endif - ); + ); } } @@ -531,6 +531,27 @@ static void dump_tasks(void) #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 ****************************************************************************/ @@ -546,11 +567,12 @@ static void dump_deadlock(void) _alert("Deadlock detected\n"); while (i-- > 0) { -#ifdef CONFIG_SCHED_BACKTRACE +# ifdef CONFIG_SCHED_BACKTRACE sched_dumpstack(deadlock[i]); -#else + dump_lockholder(deadlock[i]); +# else _alert("deadlock pid: %d\n", deadlock[i]); -#endif +# endif } } }