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
tqcmp(const void * lhs,const void * rhs)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
tq_count(uintptr_t addr,const void * ignored,void * arg)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
tq_fill(uintptr_t addr,const void * ignored,tq_info_t * ti)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
taskq_help(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
taskq(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
taskq_ent(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
taskq_ent_walk_init(mdb_walk_state_t * wsp)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
taskq_ent_walk_step(mdb_walk_state_t * wsp)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
taskq_thread_walk_init(mdb_walk_state_t * wsp)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
taskq_thread_walk_step(mdb_walk_state_t * wsp)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
taskq_thread_walk_fini(mdb_walk_state_t * wsp)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