Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: "Alexandra Hájková" <ahajkova@redhat.com>
To: gdb-patches@sourceware.org
Cc: ezulian@redhat.com
Subject: [PATCH] Add drg_why_sleeping.py
Date: Mon, 31 Aug 2026 22:54:54 +0200	[thread overview]
Message-ID: <20260831205514.1987454-2-ahajkova@redhat.com> (raw)
In-Reply-To: <20260831205514.1987454-1-ahajkova@redhat.com>

---
 .../lib/gdb/command/drgn_why_sleeping.py      | 72 ++++++++++++++++++
 sleep_test.c                                  | 76 +++++++++++++++++++
 2 files changed, 148 insertions(+)
 create mode 100644 gdb/python/lib/gdb/command/drgn_why_sleeping.py
 create mode 100644 sleep_test.c

diff --git a/gdb/python/lib/gdb/command/drgn_why_sleeping.py b/gdb/python/lib/gdb/command/drgn_why_sleeping.py
new file mode 100644
index 00000000000..ea11a73faae
--- /dev/null
+++ b/gdb/python/lib/gdb/command/drgn_why_sleeping.py
@@ -0,0 +1,72 @@
+# GDB 'drgn_why_sleeping' command.
+# Copyright (C) 2026 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""Implementation of the GDB 'drgn_why_sleeping' command using the GDB Python API."""
+
+import gdb
+import drgn
+from drgn.helpers.linux.pid import find_task
+from drgn.helpers.linux.sched import task_state_to_char
+
+class DrgnWhySleeping(gdb.Command):
+    """Look at kernel stack and show what is the thread blocked at.
+
+    Usage: Run GDB as root to be able to read from /proc/kcore.
+           The command needs debugging symbols for the running kernel.
+           (gdb) source ~/binutils-gdb/gdb/python/lib/gdb/command/drgn_why_sleeping.py
+           (gdb) info threads
+           (gdb) thread n
+           (gdb) drgn_why_sleeping
+    """
+
+    def __init__(self):
+        super(DrgnWhySleeping, self).__init__(
+            name="drgn_why_sleeping", command_class=gdb.COMMAND_STATUS, prefix=False
+        )
+
+    def invoke(self, arg_str, from_tty):
+        if gdb.selected_thread() is None:
+            raise gdb.GdbError(
+                (
+                    "Can't find selected thread. "
+                )
+            )
+        tid = gdb.selected_thread().ptid[1]
+
+        try:
+            prog = drgn.program_from_kernel()
+        except Exception as e:
+            raise gdb.GdbError(
+                    "Can't read /proc/kcore, %s. Try running GDB as root. " % str(e)
+                    )
+        task = find_task(prog, tid)
+        task_state = task_state_to_char(task)
+        stack = prog.stack_trace(task)
+        print(f"Task state: {task_state}")
+        if arg_str:
+            for frame in stack:
+                if frame.name == arg_str:
+                    print(frame.name)
+                    for var in frame.locals():
+                        print(f"  {var} = {frame[var]}")
+                    break
+            else:
+                print("Frame not found: %s" % arg_str)
+        else:
+            for frame in stack:
+                print(frame.name)
+
+DrgnWhySleeping()
diff --git a/sleep_test.c b/sleep_test.c
new file mode 100644
index 00000000000..c324e55944c
--- /dev/null
+++ b/sleep_test.c
@@ -0,0 +1,76 @@
+/*
+ * sleep_test.c - reproducer for testing drgn_why_sleeping GDB command
+ *
+ * Creates three threads, each blocked in a different kind of interruptible
+ * sleep, then prints the PID and waits so GDB can attach.
+ *
+ * Compile: gcc -g -o sleep_test sleep_test.c -lpthread
+ */
+
+#include <stdio.h>
+#include <pthread.h>
+#include <unistd.h>
+
+static pthread_mutex_t mutex_a = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t mutex_b = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t  cond    = PTHREAD_COND_INITIALIZER;
+static int pipe_fds[2];
+
+/* Blocked trying to acquire mutex_a, which main holds. */
+static void *mutex_waiter(void *arg)
+{
+    printf("[thread 1] blocking on mutex_a...\n");
+    fflush(stdout);
+    pthread_mutex_lock(&mutex_a);
+    /* never reached during the test */
+    pthread_mutex_unlock(&mutex_a);
+    return NULL;
+}
+
+/* Blocked in pthread_cond_wait; nobody will ever signal cond. */
+static void *cond_waiter(void *arg)
+{
+    pthread_mutex_lock(&mutex_b);
+    printf("[thread 2] blocking on cond...\n");
+    fflush(stdout);
+    pthread_cond_wait(&cond, &mutex_b);
+    /* never reached during the test */
+    pthread_mutex_unlock(&mutex_b);
+    return NULL;
+}
+
+/* Blocked in read(); nobody will write to the pipe. */
+static void *pipe_reader(void *arg)
+{
+    char buf[16];
+    printf("[thread 3] blocking on pipe read...\n");
+    fflush(stdout);
+    read(pipe_fds[0], buf, sizeof(buf));
+    /* never reached during the test */
+    return NULL;
+}
+
+int main(void)
+{
+    pthread_t t1, t2, t3;
+
+    pipe(pipe_fds);
+
+    /* Hold mutex_a before creating thread 1 so it blocks immediately. */
+    pthread_mutex_lock(&mutex_a);
+
+    pthread_create(&t1, NULL, mutex_waiter, NULL);
+    pthread_create(&t2, NULL, cond_waiter,  NULL);
+    pthread_create(&t3, NULL, pipe_reader,  NULL);
+
+    /* Give threads time to reach their blocking calls. */
+    sleep(1);
+
+    printf("\n[main] PID %d ready — attach GDB now\n", getpid());
+    fflush(stdout);
+
+    /* Block here so GDB has time to attach. */
+    pause();
+
+    return 0;
+}
-- 
2.52.0


  reply	other threads:[~2026-08-31 20:56 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-31 20:54 [RFC PATCH 0/1] gdb/python: add drg_why_sleeping command Alexandra Hájková
2026-08-31 20:54 ` Alexandra Hájková [this message]
2026-09-01 16:52   ` [PATCH] Add drg_why_sleeping.py Tom Tromey
2026-09-02 15:29     ` Alexandra Petlanova Hajkova

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=20260831205514.1987454-2-ahajkova@redhat.com \
    --to=ahajkova@redhat.com \
    --cc=ezulian@redhat.com \
    --cc=gdb-patches@sourceware.org \
    /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