You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2023/06/22 08:08:12 UTC
[nuttx] 02/02: sched:Automatically find deadlocks when assert
This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 4ae17a6f7b0961d835a098677a7b7b15ad3aa42d
Author: anjiahao <an...@xiaomi.com>
AuthorDate: Mon Jun 19 10:40:09 2023 +0800
sched:Automatically find deadlocks when assert
When asserting, automatically analyze whether
there is a deadlock in the thread, and if there
is a deadlock, print out the deadlocked thread.
The principle is to analyze whether there is
a lock ring through the tcb holder.
Signed-off-by: anjiahao <an...@xiaomi.com>
---
arch/Kconfig | 6 +++
include/nuttx/sched.h | 17 ++++++++
sched/misc/Make.defs | 4 ++
sched/misc/assert.c | 33 +++++++++++++++
sched/misc/deadlock.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 175 insertions(+)
diff --git a/arch/Kconfig b/arch/Kconfig
index f5a6b1ecb5..c5ca90d438 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -902,6 +902,12 @@ config ARCH_USBDUMP
---help---
Enable to do USB trace after assertions
+config ARCH_DEADLOCKDUMP
+ bool "Dump dead lock thread"
+ default "n"
+ ---help---
+ This option will dump the dead lock thread when assert happen..
+
config ENDIAN_BIG
bool "Big Endian Architecture"
default n
diff --git a/include/nuttx/sched.h b/include/nuttx/sched.h
index 200a83528e..b77c19106b 100644
--- a/include/nuttx/sched.h
+++ b/include/nuttx/sched.h
@@ -1555,6 +1555,23 @@ pid_t nxsched_getpid(void);
pid_t nxsched_getppid(void);
+/****************************************************************************
+ * Name: nxsched_collect_deadlock
+ *
+ * Description:
+ * Check if there is a deadlock and get the thread pid of the deadlock.
+ *
+ * Input parameters:
+ * pid - The array to store the thread pid of the deadlock.
+ * count - The size of the pid array.
+ *
+ * Returned Value:
+ * The number of thread deadlocks.
+ *
+ ****************************************************************************/
+
+size_t nxsched_collect_deadlock(FAR pid_t *pid, size_t count);
+
#undef EXTERN
#if defined(__cplusplus)
}
diff --git a/sched/misc/Make.defs b/sched/misc/Make.defs
index 0e955f3ec1..91f156655a 100644
--- a/sched/misc/Make.defs
+++ b/sched/misc/Make.defs
@@ -20,6 +20,10 @@
CSRCS += assert.c panic_notifier.c reboot_notifier.c
+ifeq ($(CONFIG_ARCH_DEADLOCKDUMP),y)
+CSRCS += deadlock.c
+endif
+
# Include init build support
DEPPATH += --dep-path misc
diff --git a/sched/misc/assert.c b/sched/misc/assert.c
index a1d09353be..b232c794cf 100644
--- a/sched/misc/assert.c
+++ b/sched/misc/assert.c
@@ -50,6 +50,8 @@
* Pre-processor Definitions
****************************************************************************/
+#define DEADLOCK_MAX 8
+
#ifndef CONFIG_BOARD_RESET_ON_ASSERT
# define CONFIG_BOARD_RESET_ON_ASSERT 0
#endif
@@ -511,6 +513,31 @@ static void dump_core(pid_t pid)
}
#endif
+/****************************************************************************
+ * Name: dump_deadlock
+ ****************************************************************************/
+
+#ifdef CONFIG_ARCH_DEADLOCKDUMP
+static void dump_deadlock(void)
+{
+ pid_t deadlock[DEADLOCK_MAX];
+ size_t i = nxsched_collect_deadlock(deadlock, DEADLOCK_MAX);
+
+ if (i > 0)
+ {
+ _alert("Deadlock detected\n");
+ while (i-- > 0)
+ {
+#ifdef CONFIG_SCHED_BACKTRACE
+ sched_dumpstack(deadlock[i]);
+#else
+ _alert("deadlock pid: %d\n", deadlock[i])
+#endif
+ }
+ }
+}
+#endif
+
/****************************************************************************
* Public Functions
****************************************************************************/
@@ -594,6 +621,12 @@ void _assert(FAR const char *filename, int linenum,
{
show_tasks();
+#ifdef CONFIG_ARCH_DEADLOCKDUMP
+ /* Deadlock Dump */
+
+ dump_deadlock();
+#endif
+
#ifdef CONFIG_ARCH_USBDUMP
/* Dump USB trace data */
diff --git a/sched/misc/deadlock.c b/sched/misc/deadlock.c
new file mode 100644
index 0000000000..dad646c273
--- /dev/null
+++ b/sched/misc/deadlock.c
@@ -0,0 +1,115 @@
+/****************************************************************************
+ * sched/misc/deadlock.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/mutex.h>
+#include <nuttx/sched.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+struct deadlock_info_s
+{
+ FAR pid_t *pid;
+ size_t count;
+ size_t found;
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name:find_circular_lock
+ ****************************************************************************/
+
+static void collect_deadlock(FAR struct tcb_s *tcb, FAR void *arg)
+{
+ FAR struct deadlock_info_s *info = arg;
+ size_t index;
+
+ for (index = 0; index < info->found; index++)
+ {
+ if (info->pid[index] == tcb->pid)
+ {
+ return;
+ }
+ }
+
+ for (index = info->found; index < info->count; index++)
+ {
+ FAR sem_t *sem = tcb->waitobj;
+ pid_t next;
+ size_t i;
+
+ if (tcb->task_state != TSTATE_WAIT_SEM || sem == NULL ||
+ !(sem->flags & SEM_TYPE_MUTEX))
+ {
+ return;
+ }
+
+ next = ((FAR mutex_t *)sem)->holder;
+ for (i = info->found; i < index; i++)
+ {
+ if (info->pid[i] == next)
+ {
+ info->found = index;
+ return;
+ }
+ }
+
+ info->pid[index] = tcb->pid;
+ tcb = nxsched_get_tcb(next);
+ }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nxsched_collect_deadlock
+ *
+ * Description:
+ * Check if there is a deadlock and get the thread pid of the deadlock.
+ *
+ * Input parameters:
+ * pid - The array to store the thread pid of the deadlock.
+ * count - The size of the pid array.
+ *
+ * Returned Value:
+ * The number of thread deadlocks.
+ *
+ ****************************************************************************/
+
+size_t nxsched_collect_deadlock(FAR pid_t *pid, size_t count)
+{
+ struct deadlock_info_s info;
+
+ info.pid = pid;
+ info.count = count;
+ info.found = 0;
+ nxsched_foreach(collect_deadlock, &info);
+ return info.found;
+}