Print this page
8158 Want named threads API
9857 proc manpages should have LIBRARY section
*** 22,45 ****
--- 22,48 ----
* 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,568 ****
--- 562,654 ----
"\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,580 ****
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) {
--- 655,664 ----
*** 616,648 ****
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);
return (DCMD_ERR);
}
- 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_snprintf(cmd, sizeof (cmd), "<.$c%d", count);
cmdarg.a_type = MDB_TYPE_STRING;
cmdarg.a_un.a_str = cmd;
--- 700,725 ----
return (DCMD_OK);
if (t.t_state == TS_FREE)
return (DCMD_OK);
! 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);
}
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\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,669 ****
(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
--- 726,735 ----
*** 714,724 ****
*/
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 */
--- 780,789 ----
*** 728,737 ****
--- 793,803 ----
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,783 ****
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("\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) {
--- 839,849 ----
return (DCMD_OK);
}
mdb_printf("%<u>%?s%</u>", "THREAD");
mdb_printf(" %<u>%?s%</u>", "STACK");
! 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,818 ****
}
for (i = 0; i < KMEM_STKINFO_LOG_SIZE; i++) {
if (log[i].kthread == NULL) {
continue;
}
! mdb_printf("%0?p %0?p %6x %3d%%",
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);
}
- }
mdb_free((void *)log, usize);
return (DCMD_OK);
}
/* display header */
--- 862,881 ----
}
for (i = 0; i < KMEM_STKINFO_LOG_SIZE; i++) {
if (log[i].kthread == NULL) {
continue;
}
!
! (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, tdesc);
}
mdb_free((void *)log, usize);
return (DCMD_OK);
}
/* display header */
*** 822,832 ****
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("\n");
}
/* read kthread */
if (mdb_vread(&t, sizeof (kthread_t), addr) == -1) {
--- 885,895 ----
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 LWP");
mdb_printf("\n");
}
/* read kthread */
if (mdb_vread(&t, sizeof (kthread_t), addr) == -1) {
*** 836,851 ****
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) {
--- 899,908 ----
*** 876,893 ****
(caddr_t)t.t_sp + STACK_BIAS);
mdb_printf(" %3d%%", percent);
percent = 0;
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");
return (DCMD_OK);
}
if ((((uintptr_t)start) & 0x7) != 0) {
start = (caddr_t)((((uintptr_t)start) & (~0x7)) + 8);
--- 933,946 ----
(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 %s\n", tdesc);
return (DCMD_OK);
}
if ((((uintptr_t)start) & 0x7) != 0) {
start = (caddr_t)((((uintptr_t)start) & (~0x7)) + 8);
*** 956,971 ****
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_free((void *)ustack, usize + 8);
return (DCMD_OK);
}
void
--- 1009,1021 ----
if (percent != 0) {
mdb_printf(" %3d%%", percent);
} else {
mdb_printf(" n/a");
}
!
! mdb_printf(" %s\n", tdesc);
!
mdb_free((void *)ustack, usize + 8);
return (DCMD_OK);
}
void
*** 976,986 ****
"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");
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");
--- 1026,1036 ----
"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 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,1007 ****
"-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");
mdb_flush();
}
--- 1050,1057 ----
"-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 illumos Modular Debugger Guide for detailed usage.\n");
mdb_flush();
}