Print this page
8158 Want named threads API
9857 proc manpages should have LIBRARY section

@@ -22,24 +22,27 @@
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 /*
  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright (c) 2018, Joyent, Inc.
  */
 
 
 #include <mdb/mdb_modapi.h>
 #include <mdb/mdb_ks.h>
+#include <mdb/mdb_ctf.h>
 #include <sys/types.h>
 #include <sys/thread.h>
 #include <sys/lwp.h>
 #include <sys/proc.h>
 #include <sys/cpuvar.h>
 #include <sys/cpupart.h>
 #include <sys/disp.h>
 #include <sys/taskq_impl.h>
 #include <sys/stack.h>
+#include "thread.h"
 
 #ifndef STACK_BIAS
 #define STACK_BIAS      0
 #endif
 

@@ -559,10 +562,93 @@
             "\t-p\tprint process and lwp state\n"
             "\t-s\tprint signal state\n");
 }
 
 /*
+ * Return a string description of the thread, including the ID and the thread
+ * name.
+ *
+ * If ->t_name is NULL, and we're a system thread, we'll do a little more
+ * spelunking to find a useful string to return.
+ */
+int
+thread_getdesc(uintptr_t addr, boolean_t include_comm,
+    char *buf, size_t bufsize)
+{
+        char name[THREAD_NAME_MAX] = "";
+        kthread_t t;
+        proc_t p;
+
+        bzero(buf, bufsize);
+
+        if (mdb_vread(&t, sizeof (kthread_t), addr) == -1) {
+                mdb_warn("failed to read kthread_t at %p", addr);
+                return (-1);
+        }
+
+        if (t.t_tid == 0) {
+                taskq_t tq;
+
+                if (mdb_vread(&tq, sizeof (taskq_t),
+                    (uintptr_t)t.t_taskq) == -1)
+                        tq.tq_name[0] = '\0';
+
+                if (t.t_name != NULL) {
+                        if (mdb_readstr(buf, bufsize,
+                            (uintptr_t)t.t_name) == -1) {
+                                mdb_warn("error reading thread name");
+                        }
+                } else if (tq.tq_name[0] != '\0') {
+                        (void) mdb_snprintf(buf, bufsize, "tq:%s", tq.tq_name);
+                } else {
+                        mdb_snprintf(buf, bufsize, "%a()", t.t_startpc);
+                }
+
+                return (buf[0] == '\0' ? -1 : 0);
+        }
+
+        if (include_comm && mdb_vread(&p, sizeof (proc_t),
+            (uintptr_t)t.t_procp) == -1) {
+                mdb_warn("failed to read proc at %p", t.t_procp);
+                return (-1);
+        }
+
+        if (t.t_name != NULL) {
+                if (mdb_readstr(name, sizeof (name), (uintptr_t)t.t_name) == -1)
+                        mdb_warn("error reading thread name");
+
+                /*
+                 * Just to be safe -- if mdb_readstr() succeeds, it always NUL
+                 * terminates the output, but is unclear what it does on
+                 * failure.  In that case we attempt to show any partial content
+                 * w/ the warning in case it's useful, but explicitly
+                 * NUL-terminate to be safe.
+                 */
+                buf[bufsize - 1] = '\0';
+        }
+
+        if (name[0] != '\0') {
+                if (include_comm) {
+                        (void) mdb_snprintf(buf, bufsize, "%s/%u [%s]",
+                            p.p_user.u_comm, t.t_tid, name);
+                } else {
+                        (void) mdb_snprintf(buf, bufsize, "%u [%s]",
+                            t.t_tid, name);
+                }
+        } else {
+                if (include_comm) {
+                        (void) mdb_snprintf(buf, bufsize, "%s/%u",
+                            p.p_user.u_comm, t.t_tid);
+                } else {
+                        (void) mdb_snprintf(buf, bufsize, "%u", t.t_tid);
+                }
+        }
+
+        return (buf[0] == '\0' ? -1 : 0);
+}
+
+/*
  * List a combination of kthread_t and proc_t. Add stack traces in verbose mode.
  */
 int
 threadlist(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 {

@@ -569,12 +655,10 @@
         int i;
         uint_t count =  0;
         uint_t verbose = FALSE;
         uint_t notaskq = FALSE;
         kthread_t t;
-        taskq_t tq;
-        proc_t p;
         char cmd[80];
         mdb_arg_t cmdarg;
 
         if (!(flags & DCMD_ADDRSPEC)) {
                 if (mdb_walk_dcmd("thread", "threadlist", argc, argv) == -1) {

@@ -616,33 +700,26 @@
                 return (DCMD_OK);
 
         if (t.t_state == TS_FREE)
                 return (DCMD_OK);
 
-        if (mdb_vread(&p, sizeof (proc_t), (uintptr_t)t.t_procp) == -1) {
-                mdb_warn("failed to read proc at %p", t.t_procp);
+        if (!verbose) {
+                char desc[128];
+
+                if (thread_getdesc(addr, B_TRUE, desc, sizeof (desc)) == -1)
                 return (DCMD_ERR);
+
+                mdb_printf("%0?p %?p %?p %s\n", addr, t.t_procp, t.t_lwp, desc);
+                return (DCMD_OK);
         }
 
-        if (mdb_vread(&tq, sizeof (taskq_t), (uintptr_t)t.t_taskq) == -1)
-                tq.tq_name[0] = '\0';
-
-        if (verbose) {
                 mdb_printf("%0?p %?p %?p %3u %3d %?p\n",
                     addr, t.t_procp, t.t_lwp, t.t_cid, t.t_pri, t.t_wchan);
 
                 mdb_inc_indent(2);
 
-                mdb_printf("PC: %a", t.t_pc);
-                if (t.t_tid == 0) {
-                        if (tq.tq_name[0] != '\0')
-                                mdb_printf("    TASKQ: %s\n", tq.tq_name);
-                        else
-                                mdb_printf("    THREAD: %a()\n", t.t_startpc);
-                } else {
-                        mdb_printf("    CMD: %s\n", p.p_user.u_psargs);
-                }
+        mdb_printf("PC: %a\n", t.t_pc);
 
                 mdb_snprintf(cmd, sizeof (cmd), "<.$c%d", count);
                 cmdarg.a_type = MDB_TYPE_STRING;
                 cmdarg.a_un.a_str = cmd;
 

@@ -649,21 +726,10 @@
                 (void) mdb_call_dcmd("findstack", addr, flags, 1, &cmdarg);
 
                 mdb_dec_indent(2);
 
                 mdb_printf("\n");
-        } else {
-                mdb_printf("%0?p %?p %?p", addr, t.t_procp, t.t_lwp);
-                if (t.t_tid == 0) {
-                        if (tq.tq_name[0] != '\0')
-                                mdb_printf(" tq:%s\n", tq.tq_name);
-                        else
-                                mdb_printf(" %a()\n", t.t_startpc);
-                } else {
-                        mdb_printf(" %s/%u\n", p.p_user.u_comm, t.t_tid);
-                }
-        }
 
         return (DCMD_OK);
 }
 
 void

@@ -714,11 +780,10 @@
  */
 int
 stackinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 {
         kthread_t t;
-        proc_t p;
         uint64_t *ptr;  /* pattern pointer */
         caddr_t start;  /* kernel stack start */
         caddr_t end;    /* kernel stack end */
         caddr_t ustack; /* userland copy of kernel stack */
         size_t usize;   /* userland copy of kernel stack size */

@@ -728,10 +793,11 @@
         uint_t all = FALSE; /* don't show TS_FREE kthread by default */
         uint_t history = FALSE;
         int i = 0;
         unsigned int ukmem_stackinfo;
         uintptr_t allthreads;
+        char tdesc[128] = "";
 
         /* handle options */
         if (mdb_getopts(argc, argv,
             'a', MDB_OPT_SETBITS, TRUE, &all,
             'h', MDB_OPT_SETBITS, TRUE, &history, NULL) != argc) {

@@ -773,11 +839,11 @@
                         return (DCMD_OK);
                 }
 
                 mdb_printf("%<u>%?s%</u>", "THREAD");
                 mdb_printf(" %<u>%?s%</u>", "STACK");
-                mdb_printf("%<u>%s%</u>", "   SIZE  MAX CMD/LWPID or STARTPC");
+                mdb_printf("%<u>%s%</u>", "   SIZE  MAX LWP");
                 mdb_printf("\n");
                 usize = KMEM_STKINFO_LOG_SIZE * sizeof (kmem_stkinfo_t);
                 log = (kmem_stkinfo_t *)mdb_alloc(usize, UM_SLEEP);
                 if (mdb_readsym(&kaddr, sizeof (kaddr),
                     "kmem_stkinfo_log") == -1) {

@@ -796,23 +862,20 @@
                 }
                 for (i = 0; i < KMEM_STKINFO_LOG_SIZE; i++) {
                         if (log[i].kthread == NULL) {
                                 continue;
                         }
-                        mdb_printf("%0?p %0?p %6x %3d%%",
+
+                        (void) thread_getdesc((uintptr_t)log[i].kthread,
+                            B_TRUE, tdesc, sizeof (tdesc));
+
+                        mdb_printf("%0?p %0?p %6x %3d%% %s\n",
                             log[i].kthread,
                             log[i].start,
                             (uint_t)log[i].stksz,
-                            (int)log[i].percent);
-                        if (log[i].t_tid != 0) {
-                                mdb_printf(" %s/%u\n",
-                                    log[i].cmd, log[i].t_tid);
-                        } else {
-                                mdb_printf(" %p (%a)\n", log[i].t_startpc,
-                                    log[i].t_startpc);
+                            (int)log[i].percent, tdesc);
                         }
-                }
                 mdb_free((void *)log, usize);
                 return (DCMD_OK);
         }
 
         /* display header */

@@ -822,11 +885,11 @@
                         mdb_printf("MAX value is not available.\n");
                         mdb_printf("Use ::help stackinfo for more details.\n");
                 }
                 mdb_printf("%<u>%?s%</u>", "THREAD");
                 mdb_printf(" %<u>%?s%</u>", "STACK");
-                mdb_printf("%<u>%s%</u>", "   SIZE  CUR  MAX CMD/LWPID");
+                mdb_printf("%<u>%s%</u>", "   SIZE  CUR  MAX LWP");
                 mdb_printf("\n");
         }
 
         /* read kthread */
         if (mdb_vread(&t, sizeof (kthread_t), addr) == -1) {

@@ -836,16 +899,10 @@
 
         if (t.t_state == TS_FREE && all == FALSE) {
                 return (DCMD_OK);
         }
 
-        /* read proc */
-        if (mdb_vread(&p, sizeof (proc_t), (uintptr_t)t.t_procp) == -1) {
-                mdb_warn("failed to read proc at %p\n", t.t_procp);
-                return (DCMD_ERR);
-        }
-
         /*
          * Stack grows up or down, see thread_create(),
          * compute stack memory aera start and end (start < end).
          */
         if (t.t_stk > t.t_stkbase) {

@@ -876,18 +933,14 @@
             (caddr_t)t.t_sp + STACK_BIAS);
 
         mdb_printf(" %3d%%", percent);
         percent = 0;
 
+        (void) thread_getdesc(addr, B_TRUE, tdesc, sizeof (tdesc));
+
         if (ukmem_stackinfo == 0) {
-                mdb_printf("  n/a");
-                if (t.t_tid == 0) {
-                        mdb_printf(" %a()", t.t_startpc);
-                } else {
-                        mdb_printf(" %s/%u", p.p_user.u_comm, t.t_tid);
-                }
-                mdb_printf("\n");
+                mdb_printf("  n/a %s\n", tdesc);
                 return (DCMD_OK);
         }
 
         if ((((uintptr_t)start) & 0x7) != 0) {
                 start = (caddr_t)((((uintptr_t)start) & (~0x7)) + 8);

@@ -956,16 +1009,13 @@
         if (percent != 0) {
                 mdb_printf(" %3d%%", percent);
         } else {
                 mdb_printf("  n/a");
         }
-        if (t.t_tid == 0) {
-                mdb_printf(" %a()", t.t_startpc);
-        } else {
-                mdb_printf(" %s/%u", p.p_user.u_comm, t.t_tid);
-        }
-        mdb_printf("\n");
+
+        mdb_printf(" %s\n", tdesc);
+
         mdb_free((void *)ustack, usize + 8);
         return (DCMD_OK);
 }
 
 void

@@ -976,11 +1026,11 @@
             "kmem_stackinfo tunable\n");
         mdb_printf(
             "(an unsigned integer) is non zero at kthread creation time. ");
         mdb_printf("For example:\n");
         mdb_printf(
-            "          THREAD            STACK   SIZE  CUR  MAX CMD/LWPID\n");
+            "          THREAD            STACK   SIZE  CUR  MAX LWP\n");
         mdb_printf(
             "ffffff014f5f2c20 ffffff0004153000   4f00   4%%  43%% init/1\n");
         mdb_printf(
             "The stack size utilization for this kthread is at 4%%"
             " of its maximum size,\n");

@@ -1000,8 +1050,8 @@
             "-a shows also TS_FREE kthreads (interrupt kthreads)\n");
         mdb_printf(
             "-h shows history, dead kthreads that used their "
             "kernel stack the most\n");
         mdb_printf(
-            "\nSee Solaris Modular Debugger Guide for detailed usage.\n");
+            "\nSee illumos Modular Debugger Guide for detailed usage.\n");
         mdb_flush();
 }