From: "Denis V. Lunev" <den@openvz.org>
To: qemu-devel@nongnu.org
Cc: den@openvz.org, "Paolo Bonzini" <pbonzini@redhat.com>,
"Richard Henderson" <richard.henderson@linaro.org>,
"Philippe Mathieu-Daudé" <philmd@oss.qualcomm.com>,
"Zhao Liu" <zhao1.liu@intel.com>, "Stefan Weil" <sw@weilnetz.de>
Subject: [PATCH 03/10] oslib: add qemu_thread_states()
Date: Tue, 15 Sep 2026 22:34:47 +0200 [thread overview]
Message-ID: <20260915203455.580999-4-den@openvz.org> (raw)
In-Reply-To: <20260915203455.580999-1-den@openvz.org>
From: Denis V. Lunev <den@openvz.org>
A watchdog that reports a hang wants to say what every thread was doing,
and that answer is host specific. Put it beside the other process
introspection helpers rather than in the code that happens to need it
first.
Describe each thread by id, name, scheduler state and the wait channel
it is parked on, all of which Linux exposes in /proc/self/task without
privilege. That is already enough to separate a thread blocked on a
userspace lock, which waits in a futex, from one blocked in the kernel,
which names the primitive it sits on. Skip the caller, which is
reporting rather than hanging.
Hosts with no way to answer return NULL, leaving the caller to print
its own message and nothing more.
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Richard Henderson <richard.henderson@linaro.org>
Cc: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Cc: Zhao Liu <zhao1.liu@intel.com>
Cc: Stefan Weil <sw@weilnetz.de>
Signed-off-by: Denis V. Lunev <den@openvz.org>
---
include/qemu/osdep.h | 10 +++++++
util/oslib-posix.c | 71 ++++++++++++++++++++++++++++++++++++++++++++
util/oslib-win32.c | 5 ++++
3 files changed, 86 insertions(+)
diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h
index 96afe09632..8039bf91b8 100644
--- a/include/qemu/osdep.h
+++ b/include/qemu/osdep.h
@@ -667,6 +667,16 @@ int qemu_get_thread_id(void);
*/
bool qemu_debugger_attached(void);
+/**
+ * qemu_thread_states:
+ *
+ * Returns a newly allocated, newline terminated description of every thread
+ * in this process apart from the caller: its id, name, scheduler state and
+ * the wait channel it is parked on, or NULL on a host that cannot report any
+ * of that.
+ */
+char *qemu_thread_states(void);
+
/**
* qemu_kill_thread:
* @tid: thread id.
diff --git a/util/oslib-posix.c b/util/oslib-posix.c
index 4eb6a40628..79887d370c 100644
--- a/util/oslib-posix.c
+++ b/util/oslib-posix.c
@@ -134,6 +134,77 @@ bool qemu_debugger_attached(void)
#endif
}
+#ifdef CONFIG_LINUX
+
+static char *read_task_file(const char *tid, const char *name)
+{
+ g_autofree char *path = g_strdup_printf("/proc/self/task/%s/%s", tid, name);
+ char *buf = NULL;
+
+ g_file_get_contents(path, &buf, NULL, NULL);
+ return buf;
+}
+
+static void append_thread_state(GString *out, const char *tid)
+{
+ g_autofree char *comm = read_task_file(tid, "comm");
+ g_autofree char *stat = NULL;
+ g_autofree char *wchan = NULL;
+ char state = '?';
+ char *rparen;
+
+ if (!comm) {
+ return;
+ }
+ g_strchomp(comm);
+
+ stat = read_task_file(tid, "stat");
+ if (stat) {
+ /* comm can hold anything, ')' included, so scan from the right */
+ rparen = strrchr(stat, ')');
+ if (rparen && rparen[1] == ' ') {
+ state = rparen[2];
+ }
+ }
+ g_string_append_printf(out, " %-7s %-16s %c\n", tid, comm, state);
+
+ wchan = read_task_file(tid, "wchan");
+ if (wchan && wchan[0]) {
+ g_string_append_printf(out, " wchan %s\n", wchan);
+ }
+}
+
+char *qemu_thread_states(void)
+{
+ g_autoptr(GDir) dir = g_dir_open("/proc/self/task", 0, NULL);
+ const char *tid;
+ GString *out;
+
+ if (!dir) {
+ return NULL;
+ }
+ out = g_string_new(NULL);
+ while ((tid = g_dir_read_name(dir))) {
+ if (atoi(tid) != qemu_get_thread_id()) {
+ append_thread_state(out, tid);
+ }
+ }
+ if (!out->len) {
+ g_string_free(out, TRUE);
+ return NULL;
+ }
+ return g_string_free(out, FALSE);
+}
+
+#else
+
+char *qemu_thread_states(void)
+{
+ return NULL;
+}
+
+#endif /* CONFIG_LINUX */
+
int qemu_kill_thread(int tid, int sig)
{
#if defined(__linux__)
diff --git a/util/oslib-win32.c b/util/oslib-win32.c
index 6663d83151..d18886847c 100644
--- a/util/oslib-win32.c
+++ b/util/oslib-win32.c
@@ -233,6 +233,11 @@ bool qemu_debugger_attached(void)
return IsDebuggerPresent();
}
+char *qemu_thread_states(void)
+{
+ return NULL;
+}
+
char *
qemu_get_local_state_dir(void)
{
--
2.53.0
next prev parent reply other threads:[~2026-09-15 20:36 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-15 20:34 [PATCH 0/10] system: add a watchdog for the Big QEMU Lock Denis V. Lunev
2026-09-15 20:34 ` [PATCH 01/10] util/qemu-thread: track bql_locked across the timed condvar wait Denis V. Lunev
2026-09-15 20:34 ` [PATCH 02/10] oslib: add qemu_debugger_attached() Denis V. Lunev
2026-09-15 20:34 ` Denis V. Lunev [this message]
2026-09-15 20:34 ` [PATCH 04/10] oslib: report kernel stacks in qemu_thread_states() Denis V. Lunev
2026-09-15 20:34 ` [PATCH 05/10] util/qemu-thread: reserve a signal for thread introspection Denis V. Lunev
2026-09-15 20:34 ` [PATCH 06/10] oslib: report each thread's program counter Denis V. Lunev
2026-09-15 20:34 ` [PATCH 07/10] system/cpus: report a BQL held past a deadline Denis V. Lunev
2026-09-15 20:34 ` [PATCH 08/10] system/cpus: hold off the BQL watchdog under a debugger Denis V. Lunev
2026-09-15 20:34 ` [PATCH 09/10] system/cpus: add bql-watchdog-abort Denis V. Lunev
2026-09-15 20:34 ` [PATCH 10/10] tests/functional: cover the BQL watchdog Denis V. Lunev
2026-09-16 4:57 ` Thomas Huth
2026-09-16 6:44 ` Marc-André Lureau
2026-09-16 7:56 ` Denis V. Lunev
2026-09-18 21:56 ` [PATCH 0/10] system: add a watchdog for the Big QEMU Lock Fabiano Rosas
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260915203455.580999-4-den@openvz.org \
--to=den@openvz.org \
--cc=pbonzini@redhat.com \
--cc=philmd@oss.qualcomm.com \
--cc=qemu-devel@nongnu.org \
--cc=richard.henderson@linaro.org \
--cc=sw@weilnetz.de \
--cc=zhao1.liu@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.