1*10889SJonathan.Adams@Sun.COM /* 2*10889SJonathan.Adams@Sun.COM * CDDL HEADER START 3*10889SJonathan.Adams@Sun.COM * 4*10889SJonathan.Adams@Sun.COM * The contents of this file are subject to the terms of the 5*10889SJonathan.Adams@Sun.COM * Common Development and Distribution License (the "License"). 6*10889SJonathan.Adams@Sun.COM * You may not use this file except in compliance with the License. 7*10889SJonathan.Adams@Sun.COM * 8*10889SJonathan.Adams@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*10889SJonathan.Adams@Sun.COM * or http://www.opensolaris.org/os/licensing. 10*10889SJonathan.Adams@Sun.COM * See the License for the specific language governing permissions 11*10889SJonathan.Adams@Sun.COM * and limitations under the License. 12*10889SJonathan.Adams@Sun.COM * 13*10889SJonathan.Adams@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 14*10889SJonathan.Adams@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*10889SJonathan.Adams@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 16*10889SJonathan.Adams@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 17*10889SJonathan.Adams@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 18*10889SJonathan.Adams@Sun.COM * 19*10889SJonathan.Adams@Sun.COM * CDDL HEADER END 20*10889SJonathan.Adams@Sun.COM */ 21*10889SJonathan.Adams@Sun.COM /* 22*10889SJonathan.Adams@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23*10889SJonathan.Adams@Sun.COM * Use is subject to license terms. 24*10889SJonathan.Adams@Sun.COM */ 25*10889SJonathan.Adams@Sun.COM 26*10889SJonathan.Adams@Sun.COM #include <mdb/mdb_param.h> 27*10889SJonathan.Adams@Sun.COM #include <mdb/mdb_modapi.h> 28*10889SJonathan.Adams@Sun.COM #include <mdb/mdb_ks.h> 29*10889SJonathan.Adams@Sun.COM #include <sys/taskq.h> 30*10889SJonathan.Adams@Sun.COM #include <sys/taskq_impl.h> 31*10889SJonathan.Adams@Sun.COM 32*10889SJonathan.Adams@Sun.COM #include "taskq.h" 33*10889SJonathan.Adams@Sun.COM 34*10889SJonathan.Adams@Sun.COM typedef struct tqarray_ent { 35*10889SJonathan.Adams@Sun.COM uintptr_t tq_addr; 36*10889SJonathan.Adams@Sun.COM char tq_name[TASKQ_NAMELEN + 1]; 37*10889SJonathan.Adams@Sun.COM int tq_instance; 38*10889SJonathan.Adams@Sun.COM uint_t tq_flags; 39*10889SJonathan.Adams@Sun.COM } tqarray_ent_t; 40*10889SJonathan.Adams@Sun.COM 41*10889SJonathan.Adams@Sun.COM typedef struct tq_info { 42*10889SJonathan.Adams@Sun.COM tqarray_ent_t *tqi_array; 43*10889SJonathan.Adams@Sun.COM size_t tqi_count; 44*10889SJonathan.Adams@Sun.COM size_t tqi_size; 45*10889SJonathan.Adams@Sun.COM } tq_info_t; 46*10889SJonathan.Adams@Sun.COM 47*10889SJonathan.Adams@Sun.COM /* 48*10889SJonathan.Adams@Sun.COM * We sort taskqs as follows: 49*10889SJonathan.Adams@Sun.COM * 50*10889SJonathan.Adams@Sun.COM * DYNAMIC last 51*10889SJonathan.Adams@Sun.COM * NOINSTANCE first 52*10889SJonathan.Adams@Sun.COM * within NOINSTANCE, sort by order of creation (instance #) 53*10889SJonathan.Adams@Sun.COM * within non-NOINSTANCE, sort by name (case-insensitive) then instance # 54*10889SJonathan.Adams@Sun.COM */ 55*10889SJonathan.Adams@Sun.COM int 56*10889SJonathan.Adams@Sun.COM tqcmp(const void *lhs, const void *rhs) 57*10889SJonathan.Adams@Sun.COM { 58*10889SJonathan.Adams@Sun.COM const tqarray_ent_t *l = lhs; 59*10889SJonathan.Adams@Sun.COM const tqarray_ent_t *r = rhs; 60*10889SJonathan.Adams@Sun.COM uint_t lflags = l->tq_flags; 61*10889SJonathan.Adams@Sun.COM uint_t rflags = r->tq_flags; 62*10889SJonathan.Adams@Sun.COM int ret; 63*10889SJonathan.Adams@Sun.COM 64*10889SJonathan.Adams@Sun.COM if ((lflags & TASKQ_DYNAMIC) && !(rflags & TASKQ_DYNAMIC)) 65*10889SJonathan.Adams@Sun.COM return (1); 66*10889SJonathan.Adams@Sun.COM if (!(lflags & TASKQ_DYNAMIC) && (rflags & TASKQ_DYNAMIC)) 67*10889SJonathan.Adams@Sun.COM return (-1); 68*10889SJonathan.Adams@Sun.COM 69*10889SJonathan.Adams@Sun.COM if ((lflags & TASKQ_NOINSTANCE) && !(rflags & TASKQ_NOINSTANCE)) 70*10889SJonathan.Adams@Sun.COM return (-1); 71*10889SJonathan.Adams@Sun.COM if (!(lflags & TASKQ_NOINSTANCE) && (rflags & TASKQ_NOINSTANCE)) 72*10889SJonathan.Adams@Sun.COM return (1); 73*10889SJonathan.Adams@Sun.COM 74*10889SJonathan.Adams@Sun.COM if (!(lflags & TASKQ_NOINSTANCE) && 75*10889SJonathan.Adams@Sun.COM (ret = strcasecmp(l->tq_name, r->tq_name)) != 0) 76*10889SJonathan.Adams@Sun.COM return (ret); 77*10889SJonathan.Adams@Sun.COM 78*10889SJonathan.Adams@Sun.COM if (l->tq_instance < r->tq_instance) 79*10889SJonathan.Adams@Sun.COM return (-1); 80*10889SJonathan.Adams@Sun.COM if (l->tq_instance > r->tq_instance) 81*10889SJonathan.Adams@Sun.COM return (1); 82*10889SJonathan.Adams@Sun.COM return (0); 83*10889SJonathan.Adams@Sun.COM } 84*10889SJonathan.Adams@Sun.COM 85*10889SJonathan.Adams@Sun.COM /*ARGSUSED*/ 86*10889SJonathan.Adams@Sun.COM int 87*10889SJonathan.Adams@Sun.COM tq_count(uintptr_t addr, const void *ignored, void *arg) 88*10889SJonathan.Adams@Sun.COM { 89*10889SJonathan.Adams@Sun.COM tq_info_t *ti = arg; 90*10889SJonathan.Adams@Sun.COM 91*10889SJonathan.Adams@Sun.COM ti->tqi_size++; 92*10889SJonathan.Adams@Sun.COM return (WALK_NEXT); 93*10889SJonathan.Adams@Sun.COM } 94*10889SJonathan.Adams@Sun.COM 95*10889SJonathan.Adams@Sun.COM /*ARGSUSED*/ 96*10889SJonathan.Adams@Sun.COM int 97*10889SJonathan.Adams@Sun.COM tq_fill(uintptr_t addr, const void *ignored, tq_info_t *ti) 98*10889SJonathan.Adams@Sun.COM { 99*10889SJonathan.Adams@Sun.COM int idx = ti->tqi_count; 100*10889SJonathan.Adams@Sun.COM taskq_t tq; 101*10889SJonathan.Adams@Sun.COM tqarray_ent_t *tqe = &ti->tqi_array[idx]; 102*10889SJonathan.Adams@Sun.COM 103*10889SJonathan.Adams@Sun.COM if (idx == ti->tqi_size) { 104*10889SJonathan.Adams@Sun.COM mdb_warn("taskq: inadequate slop\n"); 105*10889SJonathan.Adams@Sun.COM return (WALK_ERR); 106*10889SJonathan.Adams@Sun.COM } 107*10889SJonathan.Adams@Sun.COM if (mdb_vread(&tq, sizeof (tq), addr) == -1) { 108*10889SJonathan.Adams@Sun.COM mdb_warn("unable to read taskq_t at %p", addr); 109*10889SJonathan.Adams@Sun.COM return (WALK_NEXT); 110*10889SJonathan.Adams@Sun.COM } 111*10889SJonathan.Adams@Sun.COM 112*10889SJonathan.Adams@Sun.COM ti->tqi_count++; 113*10889SJonathan.Adams@Sun.COM tqe->tq_addr = addr; 114*10889SJonathan.Adams@Sun.COM strncpy(tqe->tq_name, tq.tq_name, TASKQ_NAMELEN); 115*10889SJonathan.Adams@Sun.COM tqe->tq_instance = tq.tq_instance; 116*10889SJonathan.Adams@Sun.COM tqe->tq_flags = tq.tq_flags; 117*10889SJonathan.Adams@Sun.COM 118*10889SJonathan.Adams@Sun.COM return (WALK_NEXT); 119*10889SJonathan.Adams@Sun.COM } 120*10889SJonathan.Adams@Sun.COM 121*10889SJonathan.Adams@Sun.COM void 122*10889SJonathan.Adams@Sun.COM taskq_help(void) 123*10889SJonathan.Adams@Sun.COM { 124*10889SJonathan.Adams@Sun.COM mdb_printf("%s", 125*10889SJonathan.Adams@Sun.COM " -a Only show taskqs with active threads.\n" 126*10889SJonathan.Adams@Sun.COM " -t Display active thread stacks in each taskq.\n" 127*10889SJonathan.Adams@Sun.COM " -T Display all thread stacks in each taskq.\n" 128*10889SJonathan.Adams@Sun.COM " -m min_maxq\n" 129*10889SJonathan.Adams@Sun.COM " Only show Dynamic taskqs and taskqs with a MAXQ of at\n" 130*10889SJonathan.Adams@Sun.COM " least min_maxq.\n" 131*10889SJonathan.Adams@Sun.COM " -n name\n" 132*10889SJonathan.Adams@Sun.COM " Only show taskqs which contain name somewhere in their\n" 133*10889SJonathan.Adams@Sun.COM " name.\n"); 134*10889SJonathan.Adams@Sun.COM } 135*10889SJonathan.Adams@Sun.COM 136*10889SJonathan.Adams@Sun.COM int 137*10889SJonathan.Adams@Sun.COM taskq(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 138*10889SJonathan.Adams@Sun.COM { 139*10889SJonathan.Adams@Sun.COM taskq_t tq; 140*10889SJonathan.Adams@Sun.COM 141*10889SJonathan.Adams@Sun.COM const char *name = NULL; 142*10889SJonathan.Adams@Sun.COM uintptr_t minmaxq = 0; 143*10889SJonathan.Adams@Sun.COM uint_t active = FALSE; 144*10889SJonathan.Adams@Sun.COM uint_t print_threads = FALSE; 145*10889SJonathan.Adams@Sun.COM uint_t print_threads_all = FALSE; 146*10889SJonathan.Adams@Sun.COM 147*10889SJonathan.Adams@Sun.COM size_t tact, tcount, queued, maxq; 148*10889SJonathan.Adams@Sun.COM 149*10889SJonathan.Adams@Sun.COM if (mdb_getopts(argc, argv, 150*10889SJonathan.Adams@Sun.COM 'a', MDB_OPT_SETBITS, TRUE, &active, 151*10889SJonathan.Adams@Sun.COM 'm', MDB_OPT_UINTPTR, &minmaxq, 152*10889SJonathan.Adams@Sun.COM 'n', MDB_OPT_STR, &name, 153*10889SJonathan.Adams@Sun.COM 't', MDB_OPT_SETBITS, TRUE, &print_threads, 154*10889SJonathan.Adams@Sun.COM 'T', MDB_OPT_SETBITS, TRUE, &print_threads_all, 155*10889SJonathan.Adams@Sun.COM NULL) != argc) 156*10889SJonathan.Adams@Sun.COM return (DCMD_USAGE); 157*10889SJonathan.Adams@Sun.COM 158*10889SJonathan.Adams@Sun.COM if (!(flags & DCMD_ADDRSPEC)) { 159*10889SJonathan.Adams@Sun.COM size_t idx; 160*10889SJonathan.Adams@Sun.COM tq_info_t tqi; 161*10889SJonathan.Adams@Sun.COM 162*10889SJonathan.Adams@Sun.COM bzero(&tqi, sizeof (tqi)); 163*10889SJonathan.Adams@Sun.COM 164*10889SJonathan.Adams@Sun.COM if (mdb_walk("taskq_cache", tq_count, &tqi) == -1) { 165*10889SJonathan.Adams@Sun.COM mdb_warn("unable to walk taskq_cache"); 166*10889SJonathan.Adams@Sun.COM return (DCMD_ERR); 167*10889SJonathan.Adams@Sun.COM } 168*10889SJonathan.Adams@Sun.COM tqi.tqi_size += 10; /* slop */ 169*10889SJonathan.Adams@Sun.COM tqi.tqi_array = mdb_zalloc( 170*10889SJonathan.Adams@Sun.COM sizeof (*tqi.tqi_array) * tqi.tqi_size, UM_SLEEP|UM_GC); 171*10889SJonathan.Adams@Sun.COM 172*10889SJonathan.Adams@Sun.COM if (mdb_walk("taskq_cache", (mdb_walk_cb_t)tq_fill, 173*10889SJonathan.Adams@Sun.COM &tqi) == -1) { 174*10889SJonathan.Adams@Sun.COM mdb_warn("unable to walk taskq_cache"); 175*10889SJonathan.Adams@Sun.COM return (DCMD_ERR); 176*10889SJonathan.Adams@Sun.COM } 177*10889SJonathan.Adams@Sun.COM qsort(tqi.tqi_array, tqi.tqi_count, sizeof (*tqi.tqi_array), 178*10889SJonathan.Adams@Sun.COM tqcmp); 179*10889SJonathan.Adams@Sun.COM 180*10889SJonathan.Adams@Sun.COM flags &= ~DCMD_PIPE; 181*10889SJonathan.Adams@Sun.COM flags |= DCMD_LOOP | DCMD_LOOPFIRST | DCMD_ADDRSPEC; 182*10889SJonathan.Adams@Sun.COM for (idx = 0; idx < tqi.tqi_count; idx++) { 183*10889SJonathan.Adams@Sun.COM int ret = taskq(tqi.tqi_array[idx].tq_addr, flags, 184*10889SJonathan.Adams@Sun.COM argc, argv); 185*10889SJonathan.Adams@Sun.COM if (ret != DCMD_OK) 186*10889SJonathan.Adams@Sun.COM return (ret); 187*10889SJonathan.Adams@Sun.COM flags &= ~DCMD_LOOPFIRST; 188*10889SJonathan.Adams@Sun.COM } 189*10889SJonathan.Adams@Sun.COM 190*10889SJonathan.Adams@Sun.COM return (DCMD_OK); 191*10889SJonathan.Adams@Sun.COM } 192*10889SJonathan.Adams@Sun.COM 193*10889SJonathan.Adams@Sun.COM if (DCMD_HDRSPEC(flags) && !(flags & DCMD_PIPE_OUT)) { 194*10889SJonathan.Adams@Sun.COM mdb_printf("%<u>%-?s %-31s %4s/%4s %4s %5s %4s%</u>\n", 195*10889SJonathan.Adams@Sun.COM "ADDR", "NAME", "ACT", "THDS", 196*10889SJonathan.Adams@Sun.COM "Q'ED", "MAXQ", "INST"); 197*10889SJonathan.Adams@Sun.COM } 198*10889SJonathan.Adams@Sun.COM 199*10889SJonathan.Adams@Sun.COM if (mdb_vread(&tq, sizeof (tq), addr) == -1) { 200*10889SJonathan.Adams@Sun.COM mdb_warn("failed to read taskq_t at %p", addr); 201*10889SJonathan.Adams@Sun.COM return (DCMD_ERR); 202*10889SJonathan.Adams@Sun.COM } 203*10889SJonathan.Adams@Sun.COM 204*10889SJonathan.Adams@Sun.COM /* terminate the name, just in case */ 205*10889SJonathan.Adams@Sun.COM tq.tq_name[sizeof (tq.tq_name) - 1] = 0; 206*10889SJonathan.Adams@Sun.COM 207*10889SJonathan.Adams@Sun.COM tact = tq.tq_active; 208*10889SJonathan.Adams@Sun.COM tcount = tq.tq_nthreads; 209*10889SJonathan.Adams@Sun.COM queued = tq.tq_tasks - tq.tq_executed; 210*10889SJonathan.Adams@Sun.COM maxq = tq.tq_maxtasks; 211*10889SJonathan.Adams@Sun.COM 212*10889SJonathan.Adams@Sun.COM if (tq.tq_flags & TASKQ_DYNAMIC) { 213*10889SJonathan.Adams@Sun.COM size_t bsize = tq.tq_nbuckets * sizeof (*tq.tq_buckets); 214*10889SJonathan.Adams@Sun.COM size_t idx; 215*10889SJonathan.Adams@Sun.COM taskq_bucket_t *b = mdb_zalloc(bsize, UM_SLEEP | UM_GC); 216*10889SJonathan.Adams@Sun.COM 217*10889SJonathan.Adams@Sun.COM if (mdb_vread(b, bsize, (uintptr_t)tq.tq_buckets) == -1) { 218*10889SJonathan.Adams@Sun.COM mdb_warn("unable to read buckets for taskq %p", addr); 219*10889SJonathan.Adams@Sun.COM return (DCMD_ERR); 220*10889SJonathan.Adams@Sun.COM } 221*10889SJonathan.Adams@Sun.COM 222*10889SJonathan.Adams@Sun.COM tcount += (tq.tq_tcreates - tq.tq_tdeaths); 223*10889SJonathan.Adams@Sun.COM 224*10889SJonathan.Adams@Sun.COM for (idx = 0; idx < tq.tq_nbuckets; idx++) { 225*10889SJonathan.Adams@Sun.COM tact += b[idx].tqbucket_nalloc; 226*10889SJonathan.Adams@Sun.COM } 227*10889SJonathan.Adams@Sun.COM } 228*10889SJonathan.Adams@Sun.COM 229*10889SJonathan.Adams@Sun.COM /* filter out taskqs that aren't of interest. */ 230*10889SJonathan.Adams@Sun.COM if (name != NULL && strstr(tq.tq_name, name) == NULL) 231*10889SJonathan.Adams@Sun.COM return (DCMD_OK); 232*10889SJonathan.Adams@Sun.COM if (active && tact == 0 && queued == 0) 233*10889SJonathan.Adams@Sun.COM return (DCMD_OK); 234*10889SJonathan.Adams@Sun.COM if (!(tq.tq_flags & TASKQ_DYNAMIC) && maxq < minmaxq) 235*10889SJonathan.Adams@Sun.COM return (DCMD_OK); 236*10889SJonathan.Adams@Sun.COM 237*10889SJonathan.Adams@Sun.COM if (flags & DCMD_PIPE_OUT) { 238*10889SJonathan.Adams@Sun.COM mdb_printf("%#lr\n", addr); 239*10889SJonathan.Adams@Sun.COM return (DCMD_OK); 240*10889SJonathan.Adams@Sun.COM } 241*10889SJonathan.Adams@Sun.COM 242*10889SJonathan.Adams@Sun.COM mdb_printf("%?p %-31s %4d/%4d %4d ", 243*10889SJonathan.Adams@Sun.COM addr, tq.tq_name, tact, tcount, queued); 244*10889SJonathan.Adams@Sun.COM 245*10889SJonathan.Adams@Sun.COM if (tq.tq_flags & TASKQ_DYNAMIC) 246*10889SJonathan.Adams@Sun.COM mdb_printf("%5s ", "-"); 247*10889SJonathan.Adams@Sun.COM else 248*10889SJonathan.Adams@Sun.COM mdb_printf("%5d ", maxq); 249*10889SJonathan.Adams@Sun.COM 250*10889SJonathan.Adams@Sun.COM if (tq.tq_flags & TASKQ_NOINSTANCE) 251*10889SJonathan.Adams@Sun.COM mdb_printf("%4s", "-"); 252*10889SJonathan.Adams@Sun.COM else 253*10889SJonathan.Adams@Sun.COM mdb_printf("%4x", tq.tq_instance); 254*10889SJonathan.Adams@Sun.COM 255*10889SJonathan.Adams@Sun.COM mdb_printf("\n"); 256*10889SJonathan.Adams@Sun.COM 257*10889SJonathan.Adams@Sun.COM if (print_threads || print_threads_all) { 258*10889SJonathan.Adams@Sun.COM int ret; 259*10889SJonathan.Adams@Sun.COM char strbuf[128]; 260*10889SJonathan.Adams@Sun.COM const char *arg = 261*10889SJonathan.Adams@Sun.COM print_threads_all ? "" : "-C \"taskq_thread_wait\""; 262*10889SJonathan.Adams@Sun.COM 263*10889SJonathan.Adams@Sun.COM /* 264*10889SJonathan.Adams@Sun.COM * We can't use mdb_pwalk_dcmd() here, because ::stacks needs 265*10889SJonathan.Adams@Sun.COM * to get the full pipeline. 266*10889SJonathan.Adams@Sun.COM */ 267*10889SJonathan.Adams@Sun.COM mdb_snprintf(strbuf, sizeof (strbuf), 268*10889SJonathan.Adams@Sun.COM "%p::walk taskq_thread | ::stacks -a %s", 269*10889SJonathan.Adams@Sun.COM addr, arg); 270*10889SJonathan.Adams@Sun.COM 271*10889SJonathan.Adams@Sun.COM (void) mdb_inc_indent(4); 272*10889SJonathan.Adams@Sun.COM ret = mdb_eval(strbuf); 273*10889SJonathan.Adams@Sun.COM (void) mdb_dec_indent(4); 274*10889SJonathan.Adams@Sun.COM 275*10889SJonathan.Adams@Sun.COM /* abort, since they could have control-Ced the eval */ 276*10889SJonathan.Adams@Sun.COM if (ret == -1) 277*10889SJonathan.Adams@Sun.COM return (DCMD_ABORT); 278*10889SJonathan.Adams@Sun.COM } 279*10889SJonathan.Adams@Sun.COM 280*10889SJonathan.Adams@Sun.COM return (DCMD_OK); 281*10889SJonathan.Adams@Sun.COM } 282*10889SJonathan.Adams@Sun.COM 283*10889SJonathan.Adams@Sun.COM /* 284*10889SJonathan.Adams@Sun.COM * Dump a taskq_ent_t given its address. 285*10889SJonathan.Adams@Sun.COM */ 286*10889SJonathan.Adams@Sun.COM /*ARGSUSED*/ 287*10889SJonathan.Adams@Sun.COM int 288*10889SJonathan.Adams@Sun.COM taskq_ent(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 289*10889SJonathan.Adams@Sun.COM { 290*10889SJonathan.Adams@Sun.COM taskq_ent_t taskq_ent; 291*10889SJonathan.Adams@Sun.COM 292*10889SJonathan.Adams@Sun.COM if (!(flags & DCMD_ADDRSPEC)) { 293*10889SJonathan.Adams@Sun.COM return (DCMD_USAGE); 294*10889SJonathan.Adams@Sun.COM } 295*10889SJonathan.Adams@Sun.COM 296*10889SJonathan.Adams@Sun.COM if (mdb_vread(&taskq_ent, sizeof (taskq_ent_t), addr) == -1) { 297*10889SJonathan.Adams@Sun.COM mdb_warn("failed to read taskq_ent_t at %p", addr); 298*10889SJonathan.Adams@Sun.COM return (DCMD_ERR); 299*10889SJonathan.Adams@Sun.COM } 300*10889SJonathan.Adams@Sun.COM 301*10889SJonathan.Adams@Sun.COM if (DCMD_HDRSPEC(flags)) { 302*10889SJonathan.Adams@Sun.COM mdb_printf("%<u>%-?s %-?s %-s%</u>\n", 303*10889SJonathan.Adams@Sun.COM "ENTRY", "ARG", "FUNCTION"); 304*10889SJonathan.Adams@Sun.COM } 305*10889SJonathan.Adams@Sun.COM 306*10889SJonathan.Adams@Sun.COM mdb_printf("%-?p %-?p %a\n", addr, taskq_ent.tqent_arg, 307*10889SJonathan.Adams@Sun.COM taskq_ent.tqent_func); 308*10889SJonathan.Adams@Sun.COM 309*10889SJonathan.Adams@Sun.COM return (DCMD_OK); 310*10889SJonathan.Adams@Sun.COM } 311*10889SJonathan.Adams@Sun.COM 312*10889SJonathan.Adams@Sun.COM 313*10889SJonathan.Adams@Sun.COM /* 314*10889SJonathan.Adams@Sun.COM * Given the address of the (taskq_t) task queue head, walk the queue listing 315*10889SJonathan.Adams@Sun.COM * the address of every taskq_ent_t. 316*10889SJonathan.Adams@Sun.COM */ 317*10889SJonathan.Adams@Sun.COM int 318*10889SJonathan.Adams@Sun.COM taskq_ent_walk_init(mdb_walk_state_t *wsp) 319*10889SJonathan.Adams@Sun.COM { 320*10889SJonathan.Adams@Sun.COM taskq_t tq_head; 321*10889SJonathan.Adams@Sun.COM 322*10889SJonathan.Adams@Sun.COM 323*10889SJonathan.Adams@Sun.COM if (wsp->walk_addr == NULL) { 324*10889SJonathan.Adams@Sun.COM mdb_warn("start address required\n"); 325*10889SJonathan.Adams@Sun.COM return (WALK_ERR); 326*10889SJonathan.Adams@Sun.COM } 327*10889SJonathan.Adams@Sun.COM 328*10889SJonathan.Adams@Sun.COM 329*10889SJonathan.Adams@Sun.COM /* 330*10889SJonathan.Adams@Sun.COM * Save the address of the list head entry. This terminates the list. 331*10889SJonathan.Adams@Sun.COM */ 332*10889SJonathan.Adams@Sun.COM wsp->walk_data = (void *) 333*10889SJonathan.Adams@Sun.COM ((size_t)wsp->walk_addr + OFFSETOF(taskq_t, tq_task)); 334*10889SJonathan.Adams@Sun.COM 335*10889SJonathan.Adams@Sun.COM 336*10889SJonathan.Adams@Sun.COM /* 337*10889SJonathan.Adams@Sun.COM * Read in taskq head, set walk_addr to point to first taskq_ent_t. 338*10889SJonathan.Adams@Sun.COM */ 339*10889SJonathan.Adams@Sun.COM if (mdb_vread((void *)&tq_head, sizeof (taskq_t), wsp->walk_addr) == 340*10889SJonathan.Adams@Sun.COM -1) { 341*10889SJonathan.Adams@Sun.COM mdb_warn("failed to read taskq list head at %p", 342*10889SJonathan.Adams@Sun.COM wsp->walk_addr); 343*10889SJonathan.Adams@Sun.COM } 344*10889SJonathan.Adams@Sun.COM wsp->walk_addr = (uintptr_t)tq_head.tq_task.tqent_next; 345*10889SJonathan.Adams@Sun.COM 346*10889SJonathan.Adams@Sun.COM 347*10889SJonathan.Adams@Sun.COM /* 348*10889SJonathan.Adams@Sun.COM * Check for null list (next=head) 349*10889SJonathan.Adams@Sun.COM */ 350*10889SJonathan.Adams@Sun.COM if (wsp->walk_addr == (uintptr_t)wsp->walk_data) { 351*10889SJonathan.Adams@Sun.COM return (WALK_DONE); 352*10889SJonathan.Adams@Sun.COM } 353*10889SJonathan.Adams@Sun.COM 354*10889SJonathan.Adams@Sun.COM return (WALK_NEXT); 355*10889SJonathan.Adams@Sun.COM } 356*10889SJonathan.Adams@Sun.COM 357*10889SJonathan.Adams@Sun.COM 358*10889SJonathan.Adams@Sun.COM int 359*10889SJonathan.Adams@Sun.COM taskq_ent_walk_step(mdb_walk_state_t *wsp) 360*10889SJonathan.Adams@Sun.COM { 361*10889SJonathan.Adams@Sun.COM taskq_ent_t tq_ent; 362*10889SJonathan.Adams@Sun.COM int status; 363*10889SJonathan.Adams@Sun.COM 364*10889SJonathan.Adams@Sun.COM 365*10889SJonathan.Adams@Sun.COM if (mdb_vread((void *)&tq_ent, sizeof (taskq_ent_t), wsp->walk_addr) == 366*10889SJonathan.Adams@Sun.COM -1) { 367*10889SJonathan.Adams@Sun.COM mdb_warn("failed to read taskq_ent_t at %p", wsp->walk_addr); 368*10889SJonathan.Adams@Sun.COM return (DCMD_ERR); 369*10889SJonathan.Adams@Sun.COM } 370*10889SJonathan.Adams@Sun.COM 371*10889SJonathan.Adams@Sun.COM status = wsp->walk_callback(wsp->walk_addr, (void *)&tq_ent, 372*10889SJonathan.Adams@Sun.COM wsp->walk_cbdata); 373*10889SJonathan.Adams@Sun.COM 374*10889SJonathan.Adams@Sun.COM wsp->walk_addr = (uintptr_t)tq_ent.tqent_next; 375*10889SJonathan.Adams@Sun.COM 376*10889SJonathan.Adams@Sun.COM 377*10889SJonathan.Adams@Sun.COM /* Check if we're at the last element (next=head) */ 378*10889SJonathan.Adams@Sun.COM if (wsp->walk_addr == (uintptr_t)wsp->walk_data) { 379*10889SJonathan.Adams@Sun.COM return (WALK_DONE); 380*10889SJonathan.Adams@Sun.COM } 381*10889SJonathan.Adams@Sun.COM 382*10889SJonathan.Adams@Sun.COM return (status); 383*10889SJonathan.Adams@Sun.COM } 384*10889SJonathan.Adams@Sun.COM 385*10889SJonathan.Adams@Sun.COM typedef struct taskq_thread_info { 386*10889SJonathan.Adams@Sun.COM uintptr_t tti_addr; 387*10889SJonathan.Adams@Sun.COM uintptr_t *tti_tlist; 388*10889SJonathan.Adams@Sun.COM size_t tti_nthreads; 389*10889SJonathan.Adams@Sun.COM size_t tti_idx; 390*10889SJonathan.Adams@Sun.COM 391*10889SJonathan.Adams@Sun.COM kthread_t tti_thread; 392*10889SJonathan.Adams@Sun.COM } taskq_thread_info_t; 393*10889SJonathan.Adams@Sun.COM 394*10889SJonathan.Adams@Sun.COM int 395*10889SJonathan.Adams@Sun.COM taskq_thread_walk_init(mdb_walk_state_t *wsp) 396*10889SJonathan.Adams@Sun.COM { 397*10889SJonathan.Adams@Sun.COM taskq_thread_info_t *tti; 398*10889SJonathan.Adams@Sun.COM taskq_t tq; 399*10889SJonathan.Adams@Sun.COM uintptr_t *tlist; 400*10889SJonathan.Adams@Sun.COM size_t nthreads; 401*10889SJonathan.Adams@Sun.COM 402*10889SJonathan.Adams@Sun.COM tti = wsp->walk_data = mdb_zalloc(sizeof (*tti), UM_SLEEP); 403*10889SJonathan.Adams@Sun.COM tti->tti_addr = wsp->walk_addr; 404*10889SJonathan.Adams@Sun.COM 405*10889SJonathan.Adams@Sun.COM if (wsp->walk_addr != NULL && 406*10889SJonathan.Adams@Sun.COM mdb_vread(&tq, sizeof (tq), wsp->walk_addr) != -1 && 407*10889SJonathan.Adams@Sun.COM !(tq.tq_flags & TASKQ_DYNAMIC)) { 408*10889SJonathan.Adams@Sun.COM 409*10889SJonathan.Adams@Sun.COM nthreads = tq.tq_nthreads; 410*10889SJonathan.Adams@Sun.COM tlist = mdb_alloc(nthreads * sizeof (*tlist), UM_SLEEP); 411*10889SJonathan.Adams@Sun.COM if (tq.tq_nthreads_max == 1) { 412*10889SJonathan.Adams@Sun.COM tlist[0] = (uintptr_t)tq.tq_thread; 413*10889SJonathan.Adams@Sun.COM 414*10889SJonathan.Adams@Sun.COM } else if (mdb_vread(tlist, nthreads * sizeof (*tlist), 415*10889SJonathan.Adams@Sun.COM (uintptr_t)tq.tq_threadlist) == -1) { 416*10889SJonathan.Adams@Sun.COM mdb_warn("unable to read threadlist for taskq_t %p", 417*10889SJonathan.Adams@Sun.COM wsp->walk_addr); 418*10889SJonathan.Adams@Sun.COM mdb_free(tlist, nthreads * sizeof (*tlist)); 419*10889SJonathan.Adams@Sun.COM return (WALK_ERR); 420*10889SJonathan.Adams@Sun.COM } 421*10889SJonathan.Adams@Sun.COM 422*10889SJonathan.Adams@Sun.COM tti->tti_tlist = tlist; 423*10889SJonathan.Adams@Sun.COM tti->tti_nthreads = nthreads; 424*10889SJonathan.Adams@Sun.COM return (WALK_NEXT); 425*10889SJonathan.Adams@Sun.COM } 426*10889SJonathan.Adams@Sun.COM 427*10889SJonathan.Adams@Sun.COM wsp->walk_addr = 0; 428*10889SJonathan.Adams@Sun.COM if (mdb_layered_walk("thread", wsp) == -1) { 429*10889SJonathan.Adams@Sun.COM mdb_warn("can't walk \"thread\""); 430*10889SJonathan.Adams@Sun.COM return (WALK_ERR); 431*10889SJonathan.Adams@Sun.COM } 432*10889SJonathan.Adams@Sun.COM return (0); 433*10889SJonathan.Adams@Sun.COM } 434*10889SJonathan.Adams@Sun.COM 435*10889SJonathan.Adams@Sun.COM int 436*10889SJonathan.Adams@Sun.COM taskq_thread_walk_step(mdb_walk_state_t *wsp) 437*10889SJonathan.Adams@Sun.COM { 438*10889SJonathan.Adams@Sun.COM taskq_thread_info_t *tti = wsp->walk_data; 439*10889SJonathan.Adams@Sun.COM 440*10889SJonathan.Adams@Sun.COM const kthread_t *kt = wsp->walk_layer; 441*10889SJonathan.Adams@Sun.COM taskq_t *tq = (taskq_t *)tti->tti_addr; 442*10889SJonathan.Adams@Sun.COM 443*10889SJonathan.Adams@Sun.COM if (kt == NULL) { 444*10889SJonathan.Adams@Sun.COM uintptr_t addr; 445*10889SJonathan.Adams@Sun.COM 446*10889SJonathan.Adams@Sun.COM if (tti->tti_idx >= tti->tti_nthreads) 447*10889SJonathan.Adams@Sun.COM return (WALK_DONE); 448*10889SJonathan.Adams@Sun.COM 449*10889SJonathan.Adams@Sun.COM addr = tti->tti_tlist[tti->tti_idx]; 450*10889SJonathan.Adams@Sun.COM tti->tti_idx++; 451*10889SJonathan.Adams@Sun.COM 452*10889SJonathan.Adams@Sun.COM if (addr == NULL) 453*10889SJonathan.Adams@Sun.COM return (WALK_NEXT); 454*10889SJonathan.Adams@Sun.COM 455*10889SJonathan.Adams@Sun.COM if (mdb_vread(&tti->tti_thread, sizeof (kthread_t), 456*10889SJonathan.Adams@Sun.COM addr) == -1) { 457*10889SJonathan.Adams@Sun.COM mdb_warn("unable to read kthread_t at %p", addr); 458*10889SJonathan.Adams@Sun.COM return (WALK_ERR); 459*10889SJonathan.Adams@Sun.COM } 460*10889SJonathan.Adams@Sun.COM return (wsp->walk_callback(addr, &tti->tti_thread, 461*10889SJonathan.Adams@Sun.COM wsp->walk_cbdata)); 462*10889SJonathan.Adams@Sun.COM } 463*10889SJonathan.Adams@Sun.COM 464*10889SJonathan.Adams@Sun.COM if (kt->t_taskq == NULL) 465*10889SJonathan.Adams@Sun.COM return (WALK_NEXT); 466*10889SJonathan.Adams@Sun.COM 467*10889SJonathan.Adams@Sun.COM if (tq != NULL && kt->t_taskq != tq) 468*10889SJonathan.Adams@Sun.COM return (WALK_NEXT); 469*10889SJonathan.Adams@Sun.COM 470*10889SJonathan.Adams@Sun.COM return (wsp->walk_callback(wsp->walk_addr, kt, wsp->walk_cbdata)); 471*10889SJonathan.Adams@Sun.COM } 472*10889SJonathan.Adams@Sun.COM 473*10889SJonathan.Adams@Sun.COM void 474*10889SJonathan.Adams@Sun.COM taskq_thread_walk_fini(mdb_walk_state_t *wsp) 475*10889SJonathan.Adams@Sun.COM { 476*10889SJonathan.Adams@Sun.COM taskq_thread_info_t *tti = wsp->walk_data; 477*10889SJonathan.Adams@Sun.COM 478*10889SJonathan.Adams@Sun.COM if (tti->tti_nthreads > 0) { 479*10889SJonathan.Adams@Sun.COM mdb_free(tti->tti_tlist, 480*10889SJonathan.Adams@Sun.COM tti->tti_nthreads * sizeof (*tti->tti_tlist)); 481*10889SJonathan.Adams@Sun.COM } 482*10889SJonathan.Adams@Sun.COM mdb_free(tti, sizeof (*tti)); 483*10889SJonathan.Adams@Sun.COM } 484