Virtuozzo QEMU development (svt-core@virtuozzo.com)
 help / color / mirror / Atom feed
From: "Denis V. Lunev" <den@openvz.org>
To: svt-core@virtuozzo.com
Cc: andrey.drobyshev@virtuozzo.com, den@openvz.org
Subject: [PATCH hci-8.0 05/12] oslib: add qemu_thread_states() #VSTOR-144507
Date: Wed, 16 Sep 2026 15:33:44 +0200	[thread overview]
Message-ID: <20260916133351.1640303-6-den@openvz.org> (raw)
In-Reply-To: <20260916133351.1640303-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 801dec40467..d3e85c606f0 100644
--- a/include/qemu/osdep.h
+++ b/include/qemu/osdep.h
@@ -644,6 +644,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 e3593f57eee..c4856f8cba5 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 4a6e66d021f..af39bab5620 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


  parent reply	other threads:[~2026-09-16 13:34 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-16 13:33 [PATCH hci-8.0 00/12] system: add a watchdog for the Big QEMU Lock Denis V. Lunev
2026-09-16 13:33 ` [PATCH hci-8.0 01/12] bql: Fix bql_locked status with condvar APIs #VSTOR-144507 Denis V. Lunev
2026-09-16 13:33 ` [PATCH hci-8.0 02/12] error-report: make real_time_iso8601() public #VSTOR-144507 Denis V. Lunev
2026-09-16 13:33 ` [PATCH hci-8.0 03/12] util/qemu-thread: track bql_locked across the timed condvar wait #VSTOR-144507 Denis V. Lunev
2026-09-16 13:33 ` [PATCH hci-8.0 04/12] oslib: add qemu_debugger_attached() #VSTOR-144507 Denis V. Lunev
2026-09-16 13:33 ` Denis V. Lunev [this message]
2026-09-16 13:33 ` [PATCH hci-8.0 06/12] oslib: report kernel stacks in qemu_thread_states() #VSTOR-144507 Denis V. Lunev
2026-09-16 13:33 ` [PATCH hci-8.0 07/12] util/qemu-thread: reserve a signal for thread introspection #VSTOR-144507 Denis V. Lunev
2026-09-16 13:33 ` [PATCH hci-8.0 08/12] oslib: report each thread's program counter #VSTOR-144507 Denis V. Lunev
2026-09-16 13:33 ` [PATCH hci-8.0 09/12] system/cpus: report a BQL held past a deadline #VSTOR-144507 Denis V. Lunev
2026-09-16 13:33 ` [PATCH hci-8.0 10/12] system/cpus: hold off the BQL watchdog under a debugger #VSTOR-144507 Denis V. Lunev
2026-09-16 13:33 ` [PATCH hci-8.0 11/12] system/cpus: add bql-watchdog-abort #VSTOR-144507 Denis V. Lunev
2026-09-16 13:33 ` [PATCH hci-8.0 12/12] tests/functional: cover the BQL watchdog #VSTOR-144507 Denis V. Lunev

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=20260916133351.1640303-6-den@openvz.org \
    --to=den@openvz.org \
    --cc=andrey.drobyshev@virtuozzo.com \
    --cc=svt-core@virtuozzo.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox