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(); }