# HG changeset patch # User Jonathan Adams # Date 1256676285 25200 # Node ID 8b6ec68049bda0cfb0fb35fb4201a4a6f8183718 # Parent a32f4a9013e5d0a260cc56e53550c432001cd7e5 6888456 zfs command line utilities should have CTF data 6887356 ::stacks is slow in pipelines on live kernels 6884079 mdb's enum p2 printing should elide common prefixes 6887160 ::offsetof and ::sizeof still can't handle forward decls 6551113 ::taskq would be nice diff -r a32f4a9013e5 -r 8b6ec68049bd usr/src/cmd/Makefile.ctf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/Makefile.ctf Tue Oct 27 13:44:45 2009 -0700 @@ -0,0 +1,31 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +POST_PROCESS += ; $(CTFMERGE) -L VERSION -o $@ $(OBJS) +POST_PROCESS_O += ; $(CTFCONVERT_O) + +CFLAGS += $(CTF_FLAGS) +CFLAGS64 += $(CTF_FLAGS) +NATIVE_CFLAGS += $(CTF_FLAGS) diff -r a32f4a9013e5 -r 8b6ec68049bd usr/src/cmd/cmd-inet/usr.lib/inetd/Makefile --- a/usr/src/cmd/cmd-inet/usr.lib/inetd/Makefile Tue Oct 27 11:26:10 2009 -0700 +++ b/usr/src/cmd/cmd-inet/usr.lib/inetd/Makefile Tue Oct 27 13:44:45 2009 -0700 @@ -19,13 +19,9 @@ # CDDL HEADER END # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "%Z%%M% %I% %E% SMI" -# -# cmd/cmd-inet/usr.lib/inetd/%M% -# PROG = inetd MANIFEST= inetd.xml inetd-upgrade.xml @@ -36,7 +32,7 @@ include ../../../Makefile.cmd include ../../Makefile.cmd-inet -include ../../../svc/Makefile.ctf +include ../../../Makefile.ctf ROOTMANIFESTDIR= $(ROOTSVCNETWORK) @@ -58,7 +54,7 @@ all: $(PROG) $(SVCMETHOD) $(PROG): $(OBJS) - $(LINK.c) $(OBJS) -o $@ $(LDLIBS) $(CTFMERGE_HOOK) + $(LINK.c) $(OBJS) -o $@ $(LDLIBS) $(POST_PROCESS) include ../Makefile.lib diff -r a32f4a9013e5 -r 8b6ec68049bd usr/src/cmd/cmd-inet/usr.lib/inetd/req.flg --- a/usr/src/cmd/cmd-inet/usr.lib/inetd/req.flg Tue Oct 27 11:26:10 2009 -0700 +++ b/usr/src/cmd/cmd-inet/usr.lib/inetd/req.flg Tue Oct 27 13:44:45 2009 -0700 @@ -3,9 +3,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. @@ -21,9 +20,8 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -#ident "%Z%%M% %I% %E% SMI" -echo_file usr/src/cmd/svc/Makefile.ctf +echo_file usr/src/cmd/Makefile.ctf diff -r a32f4a9013e5 -r 8b6ec68049bd usr/src/cmd/mdb/common/mdb/mdb_cmds.c --- a/usr/src/cmd/mdb/common/mdb/mdb_cmds.c Tue Oct 27 11:26:10 2009 -0700 +++ b/usr/src/cmd/mdb/common/mdb/mdb_cmds.c Tue Oct 27 13:44:45 2009 -0700 @@ -2906,7 +2906,8 @@ { "dump", "?[-eqrstu] [-f|-p] [-g bytes] [-w paragraphs]", "dump memory from specified address", cmd_dump, dump_help }, { "echo", "args ...", "echo arguments", cmd_echo }, - { "enum", "?[-x] enum [name]", "print an enumeration", cmd_enum }, + { "enum", "?[-ex] enum [name]", "print an enumeration", cmd_enum, + enum_help }, { "eval", "command", "evaluate the specified command", cmd_eval }, { "events", "[-av]", "list traced software events", cmd_events, events_help }, diff -r a32f4a9013e5 -r 8b6ec68049bd usr/src/cmd/mdb/common/mdb/mdb_ctf.c --- a/usr/src/cmd/mdb/common/mdb/mdb_ctf.c Tue Oct 27 11:26:10 2009 -0700 +++ b/usr/src/cmd/mdb/common/mdb/mdb_ctf.c Tue Oct 27 13:44:45 2009 -0700 @@ -446,6 +446,10 @@ mdb_ctf_impl_t *idp = (mdb_ctf_impl_t *)&id; ssize_t ret; + /* resolve the type in case there's a forward declaration */ + if ((ret = mdb_ctf_type_resolve(id, &id)) != 0) + return (ret); + if ((ret = ctf_type_size(idp->mci_fp, idp->mci_id)) == CTF_ERR) return (set_errno(ctf_to_errno(ctf_errno(idp->mci_fp)))); @@ -586,6 +590,10 @@ mdb_ctf_impl_t *idp = (mdb_ctf_impl_t *)&id; const char *ret; + /* resolve the type in case there's a forward declaration */ + if (mdb_ctf_type_resolve(id, &id) != 0) + return (NULL); + if ((ret = ctf_enum_name(idp->mci_fp, idp->mci_id, value)) == NULL) (void) set_errno(ctf_to_errno(ctf_errno(idp->mci_fp))); @@ -613,6 +621,10 @@ member_iter_t mi; int ret; + /* resolve the type in case there's a forward declaration */ + if ((ret = mdb_ctf_type_resolve(id, &id)) != 0) + return (ret); + mi.mi_cb = cb; mi.mi_arg = data; mi.mi_fp = idp->mci_fp; @@ -629,6 +641,11 @@ mdb_ctf_enum_iter(mdb_ctf_id_t id, mdb_ctf_enum_f *cb, void *data) { mdb_ctf_impl_t *idp = (mdb_ctf_impl_t *)&id; + int ret; + + /* resolve the type in case there's a forward declaration */ + if ((ret = mdb_ctf_type_resolve(id, &id)) != 0) + return (ret); return (ctf_enum_iter(idp->mci_fp, idp->mci_id, cb, data)); } diff -r a32f4a9013e5 -r 8b6ec68049bd usr/src/cmd/mdb/common/mdb/mdb_print.c --- a/usr/src/cmd/mdb/common/mdb/mdb_print.c Tue Oct 27 11:26:10 2009 -0700 +++ b/usr/src/cmd/mdb/common/mdb/mdb_print.c Tue Oct 27 13:44:45 2009 -0700 @@ -217,6 +217,7 @@ mdb_ctf_id_t id; ulong_t off; char tn[MDB_SYM_NAMLEN]; + ssize_t sz; int ret; if (flags & DCMD_ADDRSPEC) @@ -235,35 +236,82 @@ member = argv[1].a_un.a_str; - if (mdb_ctf_offsetof(id, member, &off) != 0) { + if (mdb_ctf_member_info(id, member, &off, &id) != 0) { mdb_warn("failed to find member %s of type %s", member, tn); return (DCMD_ERR); } - if (off % NBBY == 0) - mdb_printf("offsetof (%s, %s) = %#lr\n", - tn, member, off / NBBY); - else - mdb_printf("offsetof (%s, %s) = %#lr bits\n", - tn, member, off); + if (flags & DCMD_PIPE_OUT) { + if (off % NBBY != 0) { + mdb_warn("member %s of type %s is not byte-aligned\n", + member, tn); + return (DCMD_ERR); + } + mdb_printf("%#lr", off / NBBY); + return (DCMD_OK); + } + + mdb_printf("offsetof (%s, %s) = %#lr", + tn, member, off / NBBY); + if (off % NBBY != 0) + mdb_printf(".%lr", off % NBBY); + + if ((sz = mdb_ctf_type_size(id)) > 0) + mdb_printf(", sizeof (...->%s) = %#lr", member, sz); + + mdb_printf("\n"); return (DCMD_OK); } +/*ARGSUSED*/ +static int +enum_prefix_scan_cb(const char *name, int value, void *arg) +{ + char *str = arg; + + /* + * This function is called with every name in the enum. We make + * "arg" be the common prefix, if any. + */ + if (str[0] == 0) { + if (strlcpy(arg, name, MDB_SYM_NAMLEN) >= MDB_SYM_NAMLEN) + return (1); + return (0); + } + + while (*name == *str) { + if (*str == 0) { + if (str != arg) { + str--; /* don't smother a name completely */ + } + break; + } + name++; + str++; + } + *str = 0; + + return (str == arg); /* only continue if prefix is non-empty */ +} + struct enum_p2_info { - int e_value; - char *e_buf; - size_t e_size; - uint_t e_bits; - uint8_t e_found; - uint8_t e_zero; + intmax_t e_value; /* value we're processing */ + char *e_buf; /* buffer for holding names */ + size_t e_size; /* size of buffer */ + size_t e_prefix; /* length of initial prefix */ + uint_t e_allprefix; /* apply prefix to first guy, too */ + uint_t e_bits; /* bits seen */ + uint8_t e_found; /* have we seen anything? */ + uint8_t e_first; /* does buf contain the first one? */ + uint8_t e_zero; /* have we seen a zero value? */ }; static int enum_p2_cb(const char *name, int bit_arg, void *arg) { struct enum_p2_info *eiip = arg; - uint_t bit = bit_arg; + uintmax_t bit = bit_arg; if (bit != 0 && !ISP2(bit)) return (1); /* non-power-of-2; abort processing */ @@ -279,47 +327,84 @@ eiip->e_bits |= bit; if (eiip->e_buf != NULL && (eiip->e_value & bit) != 0) { - if (eiip->e_found) - (void) strlcat(eiip->e_buf, "|", eiip->e_size); + char *buf = eiip->e_buf; + size_t prefix = eiip->e_prefix; + + if (eiip->e_found) { + (void) strlcat(buf, "|", eiip->e_size); - if (strlcat(eiip->e_buf, name, eiip->e_size) >= - eiip->e_size) - return (1); /* overflowed */ + if (eiip->e_first && !eiip->e_allprefix && prefix > 0) { + char c1 = buf[prefix]; + char c2 = buf[prefix + 1]; + buf[prefix] = '{'; + buf[prefix + 1] = 0; + mdb_printf("%s", buf); + buf[prefix] = c1; + buf[prefix + 1] = c2; + mdb_printf("%s", buf + prefix); + } else { + mdb_printf("%s", buf); + } + } + /* skip the common prefix as necessary */ + if ((eiip->e_found || eiip->e_allprefix) && + strlen(name) > prefix) + name += prefix; + + (void) strlcpy(eiip->e_buf, name, eiip->e_size); + eiip->e_first = !eiip->e_found; eiip->e_found = 1; } return (0); } static int -enum_value_to_name_p2(mdb_ctf_id_t id, int v, char *buf, size_t size) +enum_is_p2(mdb_ctf_id_t id) { struct enum_p2_info eii; + bzero(&eii, sizeof (eii)); + + return (mdb_ctf_type_kind(id) == CTF_K_ENUM && + mdb_ctf_enum_iter(id, enum_p2_cb, &eii) == 0 && + eii.e_bits != 0); +} + +static int +enum_value_print_p2(mdb_ctf_id_t id, intmax_t value, uint_t allprefix) +{ + struct enum_p2_info eii; + char prefix[MDB_SYM_NAMLEN + 2]; + intmax_t missed; bzero(&eii, sizeof (eii)); - eii.e_value = v; - eii.e_buf = buf; - eii.e_size = size; + eii.e_value = value; + eii.e_buf = prefix; + eii.e_size = sizeof (prefix); + eii.e_allprefix = allprefix; - if (buf != NULL && size > 0) - buf[0] = '\0'; + prefix[0] = 0; + if (mdb_ctf_enum_iter(id, enum_prefix_scan_cb, prefix) == 0) + eii.e_prefix = strlen(prefix); - if (mdb_ctf_type_kind(id) != CTF_K_ENUM || - mdb_ctf_enum_iter(id, enum_p2_cb, &eii) != 0 || - eii.e_bits == 0) + if (mdb_ctf_enum_iter(id, enum_p2_cb, &eii) != 0 || eii.e_bits == 0) return (-1); - if (buf != NULL && (!eii.e_found || (v & ~eii.e_bits) != 0)) { - char val[16]; + missed = (value & ~(intmax_t)eii.e_bits); - (void) mdb_snprintf(val, sizeof (val), - "0x%x", (v & ~eii.e_bits)); + if (eii.e_found) { + /* push out any final value, with a | if we missed anything */ + if (!eii.e_first) + (void) strlcat(prefix, "}", sizeof (prefix)); + if (missed != 0) + (void) strlcat(prefix, "|", sizeof (prefix)); - if (eii.e_found) - (void) strlcat(buf, "|", size); - if (strlcat(buf, val, size) >= size) - return (-1); + mdb_printf("%s", prefix); + } + + if (!eii.e_found || missed) { + mdb_printf("%#llx", missed); } return (0); @@ -328,24 +413,39 @@ struct enum_cbinfo { uint_t e_flags; const char *e_string; /* NULL for value searches */ - int e_value; + size_t e_prefix; + intmax_t e_value; uint_t e_found; + mdb_ctf_id_t e_id; }; -#define E_PRETTY 0x1 -#define E_HEX 0x2 -#define E_SEARCH_STRING 0x4 -#define E_SEARCH_VALUE 0x8 +#define E_PRETTY 0x01 +#define E_HEX 0x02 +#define E_SEARCH_STRING 0x04 +#define E_SEARCH_VALUE 0x08 +#define E_ELIDE_PREFIX 0x10 static void enum_print(struct enum_cbinfo *info, const char *name, int value) { uint_t flags = info->e_flags; + uint_t elide_prefix = (info->e_flags & E_ELIDE_PREFIX); + + if (name != NULL && info->e_prefix && strlen(name) > info->e_prefix) + name += info->e_prefix; if (flags & E_PRETTY) { - if (flags & E_HEX) - mdb_printf("%-8x %s\n", value, name); - else - mdb_printf("%-11d %s\n", value, name); + uint_t indent = 5 + ((flags & E_HEX) ? 8 : 11); + + mdb_printf((flags & E_HEX)? "%8x " : "%11d ", value); + (void) mdb_inc_indent(indent); + if (name != NULL) { + mdb_iob_puts(mdb.m_out, name); + } else { + (void) enum_value_print_p2(info->e_id, value, + elide_prefix); + } + (void) mdb_dec_indent(indent); + mdb_printf("\n"); } else { mdb_printf("%#r\n", value); } @@ -372,6 +472,23 @@ return (0); } +void +enum_help(void) +{ + mdb_printf("%s", +"Without an address and name, print all values for the enumeration \"enum\".\n" +"With an address, look up a particular value in \"enum\". With a name, look\n" +"up a particular name in \"enum\".\n"); + + (void) mdb_dec_indent(2); + mdb_printf("\n%OPTIONS%\n"); + (void) mdb_inc_indent(2); + + mdb_printf("%s", +" -e remove common prefixes from enum names\n" +" -x report enum values in hexadecimal\n"); +} + /*ARGSUSED*/ int cmd_enum(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) @@ -380,11 +497,13 @@ char type[MDB_SYM_NAMLEN + sizeof ("enum ")]; char tn2[MDB_SYM_NAMLEN + sizeof ("enum ")]; + char prefix[MDB_SYM_NAMLEN]; mdb_ctf_id_t id; mdb_ctf_id_t idr; int i; intmax_t search; + uint_t isp2; info.e_flags = (flags & DCMD_PIPE_OUT)? 0 : E_PRETTY; info.e_string = NULL; @@ -392,6 +511,7 @@ info.e_found = 0; i = mdb_getopts(argc, argv, + 'e', MDB_OPT_SETBITS, E_ELIDE_PREFIX, &info.e_flags, 'x', MDB_OPT_SETBITS, E_HEX, &info.e_flags, NULL); @@ -433,6 +553,8 @@ return (DCMD_ERR); } + info.e_id = idr; + if (argc > 2) return (DCMD_USAGE); @@ -462,25 +584,32 @@ if ((int)search != search) { mdb_warn("value '%lld' out of enumeration range\n", search); - return (DCMD_ERR); } info.e_value = search; } + isp2 = enum_is_p2(idr); + if (isp2) + info.e_flags |= E_HEX; + if (DCMD_HDRSPEC(flags) && (info.e_flags & E_PRETTY)) { if (info.e_flags & E_HEX) - mdb_printf("%%-8s %s%\n", "VALUE", "NAME"); + mdb_printf("%%8s %-64s%\n", "VALUE", "NAME"); else - mdb_printf("%%-11s %s%\n", "VALUE", "NAME"); + mdb_printf("%%11s %-64s%\n", "VALUE", "NAME"); } /* if the enum is a power-of-two one, process it that way */ - if ((info.e_flags & E_SEARCH_VALUE) && - enum_value_to_name_p2(idr, info.e_value, tn2, sizeof (tn2)) == 0) { - enum_print(&info, tn2, info.e_value); + if ((info.e_flags & E_SEARCH_VALUE) && isp2) { + enum_print(&info, NULL, info.e_value); return (DCMD_OK); } + prefix[0] = 0; + if ((info.e_flags & E_ELIDE_PREFIX) && + mdb_ctf_enum_iter(id, enum_prefix_scan_cb, prefix) == 0) + info.e_prefix = strlen(prefix); + if (mdb_ctf_enum_iter(idr, enum_cb, &info) == -1) { mdb_warn("cannot walk '%s' as enum", type); return (DCMD_ERR); @@ -492,7 +621,8 @@ mdb_warn("name \"%s\" not in '%s'\n", info.e_string, type); else - mdb_warn("value %#d not in '%s'\n", info.e_value, type); + mdb_warn("value %#lld not in '%s'\n", info.e_value, + type); return (DCMD_ERR); } @@ -1153,11 +1283,12 @@ mdb_ctf_id_t base, ulong_t off, printarg_t *pap) { mdb_tgt_addr_t addr = pap->pa_addr + off / NBBY; - char vname[MDB_SYM_NAMLEN]; const char *ename; int value; + int isp2 = enum_is_p2(base); + int flags = pap->pa_flags | (isp2 ? PA_INTHEX : 0); - if (!(pap->pa_flags & PA_SHOWVAL)) + if (!(flags & PA_SHOWVAL)) return (0); if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as, @@ -1166,19 +1297,23 @@ return (1); } - if (pap->pa_flags & PA_INTHEX) + if (flags & PA_INTHEX) mdb_printf("%#x", value); else mdb_printf("%#d", value); - ename = mdb_ctf_enum_name(base, value); + (void) mdb_inc_indent(8); + mdb_printf(" ("); - /* If it wasn't an exact match, check if we can do P2 matching */ - if (ename == NULL && - enum_value_to_name_p2(base, value, vname, sizeof (vname)) == 0) - ename = vname; - - mdb_printf(" (%s)", (ename != NULL)? ename : "???"); + if (!isp2 || enum_value_print_p2(base, value, 0) != 0) { + ename = mdb_ctf_enum_name(base, value); + if (ename == NULL) { + ename = "???"; + } + mdb_printf("%s", ename); + } + mdb_printf(")"); + (void) mdb_dec_indent(8); return (0); } diff -r a32f4a9013e5 -r 8b6ec68049bd usr/src/cmd/mdb/common/mdb/mdb_print.h --- a/usr/src/cmd/mdb/common/mdb/mdb_print.h Tue Oct 27 11:26:10 2009 -0700 +++ b/usr/src/cmd/mdb/common/mdb/mdb_print.h Tue Oct 27 13:44:45 2009 -0700 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,15 +19,13 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _MDB_PRINT_H #define _MDB_PRINT_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -36,6 +33,7 @@ #ifdef _MDB extern int cmd_enum(uintptr_t, uint_t, int, const mdb_arg_t *); +extern void enum_help(void); extern int cmd_sizeof(uintptr_t, uint_t, int, const mdb_arg_t *); extern int cmd_offsetof(uintptr_t, uint_t, int, const mdb_arg_t *); extern int cmd_list(uintptr_t, uint_t, int, const mdb_arg_t *); diff -r a32f4a9013e5 -r 8b6ec68049bd usr/src/cmd/mdb/common/modules/genunix/Makefile.files --- a/usr/src/cmd/mdb/common/modules/genunix/Makefile.files Tue Oct 27 11:26:10 2009 -0700 +++ b/usr/src/cmd/mdb/common/modules/genunix/Makefile.files Tue Oct 27 13:44:45 2009 -0700 @@ -66,6 +66,7 @@ sobj.c \ streams.c \ sysevent.c \ + taskq.c \ thread.c \ tsd.c \ tsol.c \ diff -r a32f4a9013e5 -r 8b6ec68049bd usr/src/cmd/mdb/common/modules/genunix/findstack.c --- a/usr/src/cmd/mdb/common/modules/genunix/findstack.c Tue Oct 27 11:26:10 2009 -0700 +++ b/usr/src/cmd/mdb/common/modules/genunix/findstack.c Tue Oct 27 13:44:45 2009 -0700 @@ -690,7 +690,36 @@ } int -stacks_run(int verbose) +stacks_run_tlist(mdb_pipe_t *tlist, stacks_info_t *si) +{ + size_t idx; + size_t found = 0; + kthread_t kt; + int ret; + + for (idx = 0; idx < tlist->pipe_len; idx++) { + uintptr_t addr = tlist->pipe_data[idx]; + + if (mdb_vread(&kt, sizeof (kt), addr) == -1) { + mdb_warn("unable to read kthread_t at %p", addr); + continue; + } + found++; + + ret = stacks_thread_cb(addr, &kt, si); + if (ret == WALK_DONE) + break; + if (ret != WALK_NEXT) + return (-1); + } + + if (found) + return (0); + return (-1); +} + +int +stacks_run(int verbose, mdb_pipe_t *tlist) { stacks_info_t si; findstack_info_t *fsip = &si.si_fsi; @@ -714,9 +743,14 @@ if (verbose) mdb_warn("stacks: processing kernel threads\n"); - if (mdb_walk("thread", stacks_thread_cb, &si) != 0) { - mdb_warn("cannot walk \"thread\""); - return (DCMD_ERR); + if (tlist != NULL) { + if (stacks_run_tlist(tlist, &si)) + return (DCMD_ERR); + } else { + if (mdb_walk("thread", stacks_thread_cb, &si) != 0) { + mdb_warn("cannot walk \"thread\""); + return (DCMD_ERR); + } } if (verbose) @@ -745,7 +779,8 @@ stacks_hash = NULL; mdb_free(si.si_hash, STACKS_HSIZE * sizeof (*si.si_hash)); - stacks_state = STACKS_STATE_DONE; + if (tlist == NULL) + stacks_state = STACKS_STATE_DONE; if (verbose) mdb_warn("stacks: done\n"); @@ -959,6 +994,7 @@ const char *excl_tstate_str = NULL; uint_t tstate = -1U; uint_t excl_tstate = -1U; + uint_t printed = 0; uint_t all = 0; uint_t force = 0; @@ -1066,27 +1102,6 @@ } /* - * Force a cleanup if we're connected to a live system. Never - * do a cleanup after the first invocation around the loop. - */ - force |= (mdb_get_state() == MDB_STATE_RUNNING); - if (force && (flags & (DCMD_LOOPFIRST|DCMD_LOOP)) == DCMD_LOOP) - force = 0; - - stacks_cleanup(force); - - if (stacks_state == STACKS_STATE_CLEAN) { - int res = stacks_run(verbose); - if (res != DCMD_OK) - return (res); - } - - if (!all && DCMD_HDRSPEC(flags) && !(flags & DCMD_PIPE_OUT)) { - mdb_printf("%%-?s %-8s %-?s %8s%\n", - "THREAD", "STATE", "SOBJ", "COUNT"); - } - - /* * If there's an address specified, we're going to further filter * to only entries which have an address in the input. To reduce * overhead (and make the sorted output come out right), we @@ -1120,6 +1135,22 @@ seen = mdb_zalloc(p.pipe_len, UM_SLEEP | UM_GC); } + /* + * Force a cleanup if we're connected to a live system. Never + * do a cleanup after the first invocation around the loop. + */ + force |= (mdb_get_state() == MDB_STATE_RUNNING); + if (force && (flags & (DCMD_LOOPFIRST|DCMD_LOOP)) == DCMD_LOOP) + force = 0; + + stacks_cleanup(force); + + if (stacks_state == STACKS_STATE_CLEAN) { + int res = stacks_run(verbose, addrspec ? &p : NULL); + if (res != DCMD_OK) + return (res); + } + for (idx = 0; idx < stacks_array_size; idx++) { stacks_entry_t *sep = stacks_array[idx]; stacks_entry_t *cur = sep; @@ -1209,9 +1240,10 @@ continue; } - if (all) { + if (all || !printed) { mdb_printf("%%-?s %-8s %-?s %8s%\n", - "THREAD", "STATE", "SOBJTYPE", "COUNT"); + "THREAD", "STATE", "SOBJ", "COUNT"); + printed = 1; } do { diff -r a32f4a9013e5 -r 8b6ec68049bd usr/src/cmd/mdb/common/modules/genunix/genunix.c --- a/usr/src/cmd/mdb/common/modules/genunix/genunix.c Tue Oct 27 11:26:10 2009 -0700 +++ b/usr/src/cmd/mdb/common/modules/genunix/genunix.c Tue Oct 27 13:44:45 2009 -0700 @@ -58,8 +58,6 @@ #include #include #include -#include -#include #include #include #include @@ -101,6 +99,7 @@ #include "sobj.h" #include "streams.h" #include "sysevent.h" +#include "taskq.h" #include "thread.h" #include "tsd.h" #include "tsol.h" @@ -3853,115 +3852,6 @@ return (DCMD_OK); } -/* - * Dump a taskq_ent_t given its address. - */ -/*ARGSUSED*/ -int -taskq_ent(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) -{ - taskq_ent_t taskq_ent; - GElf_Sym sym; - char buf[MDB_SYM_NAMLEN+1]; - - - if (!(flags & DCMD_ADDRSPEC)) { - mdb_warn("expected explicit taskq_ent_t address before ::\n"); - return (DCMD_USAGE); - } - - if (mdb_vread(&taskq_ent, sizeof (taskq_ent_t), addr) == -1) { - mdb_warn("failed to read taskq_ent_t at %p", addr); - return (DCMD_ERR); - } - - if (DCMD_HDRSPEC(flags)) { - mdb_printf("%%-?s %-?s %-s%\n", - "ENTRY", "ARG", "FUNCTION"); - } - - if (mdb_lookup_by_addr((uintptr_t)taskq_ent.tqent_func, MDB_SYM_EXACT, - buf, sizeof (buf), &sym) == -1) { - (void) strcpy(buf, "????"); - } - - mdb_printf("%-?p %-?p %s\n", addr, taskq_ent.tqent_arg, buf); - - return (DCMD_OK); -} - -/* - * Given the address of the (taskq_t) task queue head, walk the queue listing - * the address of every taskq_ent_t. - */ -int -taskq_walk_init(mdb_walk_state_t *wsp) -{ - taskq_t tq_head; - - - if (wsp->walk_addr == NULL) { - mdb_warn("start address required\n"); - return (WALK_ERR); - } - - - /* - * Save the address of the list head entry. This terminates the list. - */ - wsp->walk_data = (void *) - ((size_t)wsp->walk_addr + offsetof(taskq_t, tq_task)); - - - /* - * Read in taskq head, set walk_addr to point to first taskq_ent_t. - */ - if (mdb_vread((void *)&tq_head, sizeof (taskq_t), wsp->walk_addr) == - -1) { - mdb_warn("failed to read taskq list head at %p", - wsp->walk_addr); - } - wsp->walk_addr = (uintptr_t)tq_head.tq_task.tqent_next; - - - /* - * Check for null list (next=head) - */ - if (wsp->walk_addr == (uintptr_t)wsp->walk_data) { - return (WALK_DONE); - } - - return (WALK_NEXT); -} - - -int -taskq_walk_step(mdb_walk_state_t *wsp) -{ - taskq_ent_t tq_ent; - int status; - - - if (mdb_vread((void *)&tq_ent, sizeof (taskq_ent_t), wsp->walk_addr) == - -1) { - mdb_warn("failed to read taskq_ent_t at %p", wsp->walk_addr); - return (DCMD_ERR); - } - - status = wsp->walk_callback(wsp->walk_addr, (void *)&tq_ent, - wsp->walk_cbdata); - - wsp->walk_addr = (uintptr_t)tq_ent.tqent_next; - - - /* Check if we're at the last element (next=head) */ - if (wsp->walk_addr == (uintptr_t)wsp->walk_data) { - return (WALK_DONE); - } - - return (status); -} - int didmatch(uintptr_t addr, const kthread_t *thr, kt_did_t *didp) { @@ -4325,7 +4215,6 @@ "print sysevent subclass list", sysevent_subclass_list}, { "system", NULL, "print contents of /etc/system file", sysfile }, { "task", NULL, "display kernel task(s)", task }, - { "taskq_entry", ":", "display a taskq_ent_t", taskq_ent }, { "vnode2path", ":[-F]", "vnode address to pathname", vnode2path }, { "vnode2smap", ":[offset]", "translate vnode to smap", vnode2smap }, { "whereopen", ":", "given a vnode, dumps procs which have it open", @@ -4571,6 +4460,11 @@ "filter and display STREAM sync queue", syncq, syncq_help }, { "syncq2q", ":", "print queue for a given syncq", syncq2q }, + /* from taskq.c */ + { "taskq", ":[-atT] [-m min_maxq] [-n name]", + "display a taskq", taskq, taskq_help }, + { "taskq_entry", ":", "display a taskq_ent_t", taskq_ent }, + /* from thread.c */ { "thread", "?[-bdfimps]", "display a summarized kthread_t", thread, thread_help }, @@ -4672,8 +4566,6 @@ sysevent_subclass_list_walk_fini}, { "task", "given a task pointer, walk its processes", task_walk_init, task_walk_step, NULL }, - { "taskq_entry", "given a taskq_t*, list all taskq_ent_t in the list", - taskq_walk_init, taskq_walk_step, NULL, NULL }, /* from avl.c */ { AVL_WALK_NAME, AVL_WALK_DESC, @@ -4929,6 +4821,14 @@ { "writeq", "walk write queue side of stdata", str_walk_init, strw_walk_step, str_walk_fini }, + /* from taskq.c */ + { "taskq_thread", "given a taskq_t, list all of its threads", + taskq_thread_walk_init, + taskq_thread_walk_step, + taskq_thread_walk_fini }, + { "taskq_entry", "given a taskq_t*, list all taskq_ent_t in the list", + taskq_ent_walk_init, taskq_ent_walk_step, NULL }, + /* from thread.c */ { "deathrow", "walk threads on both lwp_ and thread_deathrow", deathrow_walk_init, deathrow_walk_step, NULL }, diff -r a32f4a9013e5 -r 8b6ec68049bd usr/src/cmd/mdb/common/modules/genunix/taskq.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/mdb/common/modules/genunix/taskq.c Tue Oct 27 13:44:45 2009 -0700 @@ -0,0 +1,483 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include +#include +#include +#include +#include + +#include "taskq.h" + +typedef struct tqarray_ent { + uintptr_t tq_addr; + char tq_name[TASKQ_NAMELEN + 1]; + int tq_instance; + uint_t tq_flags; +} tqarray_ent_t; + +typedef struct tq_info { + tqarray_ent_t *tqi_array; + size_t tqi_count; + size_t tqi_size; +} tq_info_t; + +/* + * We sort taskqs as follows: + * + * DYNAMIC last + * NOINSTANCE first + * within NOINSTANCE, sort by order of creation (instance #) + * within non-NOINSTANCE, sort by name (case-insensitive) then instance # + */ +int +tqcmp(const void *lhs, const void *rhs) +{ + const tqarray_ent_t *l = lhs; + const tqarray_ent_t *r = rhs; + uint_t lflags = l->tq_flags; + uint_t rflags = r->tq_flags; + int ret; + + if ((lflags & TASKQ_DYNAMIC) && !(rflags & TASKQ_DYNAMIC)) + return (1); + if (!(lflags & TASKQ_DYNAMIC) && (rflags & TASKQ_DYNAMIC)) + return (-1); + + if ((lflags & TASKQ_NOINSTANCE) && !(rflags & TASKQ_NOINSTANCE)) + return (-1); + if (!(lflags & TASKQ_NOINSTANCE) && (rflags & TASKQ_NOINSTANCE)) + return (1); + + if (!(lflags & TASKQ_NOINSTANCE) && + (ret = strcasecmp(l->tq_name, r->tq_name)) != 0) + return (ret); + + if (l->tq_instance < r->tq_instance) + return (-1); + if (l->tq_instance > r->tq_instance) + return (1); + return (0); +} + +/*ARGSUSED*/ +int +tq_count(uintptr_t addr, const void *ignored, void *arg) +{ + tq_info_t *ti = arg; + + ti->tqi_size++; + return (WALK_NEXT); +} + +/*ARGSUSED*/ +int +tq_fill(uintptr_t addr, const void *ignored, tq_info_t *ti) +{ + int idx = ti->tqi_count; + taskq_t tq; + tqarray_ent_t *tqe = &ti->tqi_array[idx]; + + if (idx == ti->tqi_size) { + mdb_warn("taskq: inadequate slop\n"); + return (WALK_ERR); + } + if (mdb_vread(&tq, sizeof (tq), addr) == -1) { + mdb_warn("unable to read taskq_t at %p", addr); + return (WALK_NEXT); + } + + ti->tqi_count++; + tqe->tq_addr = addr; + strncpy(tqe->tq_name, tq.tq_name, TASKQ_NAMELEN); + tqe->tq_instance = tq.tq_instance; + tqe->tq_flags = tq.tq_flags; + + return (WALK_NEXT); +} + +void +taskq_help(void) +{ + mdb_printf("%s", + " -a Only show taskqs with active threads.\n" + " -t Display active thread stacks in each taskq.\n" + " -T Display all thread stacks in each taskq.\n" + " -m min_maxq\n" + " Only show Dynamic taskqs and taskqs with a MAXQ of at\n" + " least min_maxq.\n" + " -n name\n" + " Only show taskqs which contain name somewhere in their\n" + " name.\n"); +} + +int +taskq(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) +{ + taskq_t tq; + + const char *name = NULL; + uintptr_t minmaxq = 0; + uint_t active = FALSE; + uint_t print_threads = FALSE; + uint_t print_threads_all = FALSE; + + size_t tact, tcount, queued, maxq; + + if (mdb_getopts(argc, argv, + 'a', MDB_OPT_SETBITS, TRUE, &active, + 'm', MDB_OPT_UINTPTR, &minmaxq, + 'n', MDB_OPT_STR, &name, + 't', MDB_OPT_SETBITS, TRUE, &print_threads, + 'T', MDB_OPT_SETBITS, TRUE, &print_threads_all, + NULL) != argc) + return (DCMD_USAGE); + + if (!(flags & DCMD_ADDRSPEC)) { + size_t idx; + tq_info_t tqi; + + bzero(&tqi, sizeof (tqi)); + + if (mdb_walk("taskq_cache", tq_count, &tqi) == -1) { + mdb_warn("unable to walk taskq_cache"); + return (DCMD_ERR); + } + tqi.tqi_size += 10; /* slop */ + tqi.tqi_array = mdb_zalloc( + sizeof (*tqi.tqi_array) * tqi.tqi_size, UM_SLEEP|UM_GC); + + if (mdb_walk("taskq_cache", (mdb_walk_cb_t)tq_fill, + &tqi) == -1) { + mdb_warn("unable to walk taskq_cache"); + return (DCMD_ERR); + } + qsort(tqi.tqi_array, tqi.tqi_count, sizeof (*tqi.tqi_array), + tqcmp); + + flags &= ~DCMD_PIPE; + flags |= DCMD_LOOP | DCMD_LOOPFIRST | DCMD_ADDRSPEC; + for (idx = 0; idx < tqi.tqi_count; idx++) { + int ret = taskq(tqi.tqi_array[idx].tq_addr, flags, + argc, argv); + if (ret != DCMD_OK) + return (ret); + flags &= ~DCMD_LOOPFIRST; + } + + return (DCMD_OK); + } + + if (DCMD_HDRSPEC(flags) && !(flags & DCMD_PIPE_OUT)) { + mdb_printf("%%-?s %-31s %4s/%4s %4s %5s %4s%\n", + "ADDR", "NAME", "ACT", "THDS", + "Q'ED", "MAXQ", "INST"); + } + + if (mdb_vread(&tq, sizeof (tq), addr) == -1) { + mdb_warn("failed to read taskq_t at %p", addr); + return (DCMD_ERR); + } + + /* terminate the name, just in case */ + tq.tq_name[sizeof (tq.tq_name) - 1] = 0; + + tact = tq.tq_active; + tcount = tq.tq_nthreads; + queued = tq.tq_tasks - tq.tq_executed; + maxq = tq.tq_maxtasks; + + if (tq.tq_flags & TASKQ_DYNAMIC) { + size_t bsize = tq.tq_nbuckets * sizeof (*tq.tq_buckets); + size_t idx; + taskq_bucket_t *b = mdb_zalloc(bsize, UM_SLEEP | UM_GC); + + if (mdb_vread(b, bsize, (uintptr_t)tq.tq_buckets) == -1) { + mdb_warn("unable to read buckets for taskq %p", addr); + return (DCMD_ERR); + } + + tcount += (tq.tq_tcreates - tq.tq_tdeaths); + + for (idx = 0; idx < tq.tq_nbuckets; idx++) { + tact += b[idx].tqbucket_nalloc; + } + } + + /* filter out taskqs that aren't of interest. */ + if (name != NULL && strstr(tq.tq_name, name) == NULL) + return (DCMD_OK); + if (active && tact == 0 && queued == 0) + return (DCMD_OK); + if (!(tq.tq_flags & TASKQ_DYNAMIC) && maxq < minmaxq) + return (DCMD_OK); + + if (flags & DCMD_PIPE_OUT) { + mdb_printf("%#lr\n", addr); + return (DCMD_OK); + } + + mdb_printf("%?p %-31s %4d/%4d %4d ", + addr, tq.tq_name, tact, tcount, queued); + + if (tq.tq_flags & TASKQ_DYNAMIC) + mdb_printf("%5s ", "-"); + else + mdb_printf("%5d ", maxq); + + if (tq.tq_flags & TASKQ_NOINSTANCE) + mdb_printf("%4s", "-"); + else + mdb_printf("%4x", tq.tq_instance); + + mdb_printf("\n"); + + if (print_threads || print_threads_all) { + int ret; + char strbuf[128]; + const char *arg = + print_threads_all ? "" : "-C \"taskq_thread_wait\""; + + /* + * We can't use mdb_pwalk_dcmd() here, because ::stacks needs + * to get the full pipeline. + */ + mdb_snprintf(strbuf, sizeof (strbuf), + "%p::walk taskq_thread | ::stacks -a %s", + addr, arg); + + (void) mdb_inc_indent(4); + ret = mdb_eval(strbuf); + (void) mdb_dec_indent(4); + + /* abort, since they could have control-Ced the eval */ + if (ret == -1) + return (DCMD_ABORT); + } + + return (DCMD_OK); +} + +/* + * Dump a taskq_ent_t given its address. + */ +/*ARGSUSED*/ +int +taskq_ent(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) +{ + taskq_ent_t taskq_ent; + + if (!(flags & DCMD_ADDRSPEC)) { + return (DCMD_USAGE); + } + + if (mdb_vread(&taskq_ent, sizeof (taskq_ent_t), addr) == -1) { + mdb_warn("failed to read taskq_ent_t at %p", addr); + return (DCMD_ERR); + } + + if (DCMD_HDRSPEC(flags)) { + mdb_printf("%%-?s %-?s %-s%\n", + "ENTRY", "ARG", "FUNCTION"); + } + + mdb_printf("%-?p %-?p %a\n", addr, taskq_ent.tqent_arg, + taskq_ent.tqent_func); + + return (DCMD_OK); +} + + +/* + * Given the address of the (taskq_t) task queue head, walk the queue listing + * the address of every taskq_ent_t. + */ +int +taskq_ent_walk_init(mdb_walk_state_t *wsp) +{ + taskq_t tq_head; + + + if (wsp->walk_addr == NULL) { + mdb_warn("start address required\n"); + return (WALK_ERR); + } + + + /* + * Save the address of the list head entry. This terminates the list. + */ + wsp->walk_data = (void *) + ((size_t)wsp->walk_addr + OFFSETOF(taskq_t, tq_task)); + + + /* + * Read in taskq head, set walk_addr to point to first taskq_ent_t. + */ + if (mdb_vread((void *)&tq_head, sizeof (taskq_t), wsp->walk_addr) == + -1) { + mdb_warn("failed to read taskq list head at %p", + wsp->walk_addr); + } + wsp->walk_addr = (uintptr_t)tq_head.tq_task.tqent_next; + + + /* + * Check for null list (next=head) + */ + if (wsp->walk_addr == (uintptr_t)wsp->walk_data) { + return (WALK_DONE); + } + + return (WALK_NEXT); +} + + +int +taskq_ent_walk_step(mdb_walk_state_t *wsp) +{ + taskq_ent_t tq_ent; + int status; + + + if (mdb_vread((void *)&tq_ent, sizeof (taskq_ent_t), wsp->walk_addr) == + -1) { + mdb_warn("failed to read taskq_ent_t at %p", wsp->walk_addr); + return (DCMD_ERR); + } + + status = wsp->walk_callback(wsp->walk_addr, (void *)&tq_ent, + wsp->walk_cbdata); + + wsp->walk_addr = (uintptr_t)tq_ent.tqent_next; + + + /* Check if we're at the last element (next=head) */ + if (wsp->walk_addr == (uintptr_t)wsp->walk_data) { + return (WALK_DONE); + } + + return (status); +} + +typedef struct taskq_thread_info { + uintptr_t tti_addr; + uintptr_t *tti_tlist; + size_t tti_nthreads; + size_t tti_idx; + + kthread_t tti_thread; +} taskq_thread_info_t; + +int +taskq_thread_walk_init(mdb_walk_state_t *wsp) +{ + taskq_thread_info_t *tti; + taskq_t tq; + uintptr_t *tlist; + size_t nthreads; + + tti = wsp->walk_data = mdb_zalloc(sizeof (*tti), UM_SLEEP); + tti->tti_addr = wsp->walk_addr; + + if (wsp->walk_addr != NULL && + mdb_vread(&tq, sizeof (tq), wsp->walk_addr) != -1 && + !(tq.tq_flags & TASKQ_DYNAMIC)) { + + nthreads = tq.tq_nthreads; + tlist = mdb_alloc(nthreads * sizeof (*tlist), UM_SLEEP); + if (tq.tq_nthreads_max == 1) { + tlist[0] = (uintptr_t)tq.tq_thread; + + } else if (mdb_vread(tlist, nthreads * sizeof (*tlist), + (uintptr_t)tq.tq_threadlist) == -1) { + mdb_warn("unable to read threadlist for taskq_t %p", + wsp->walk_addr); + mdb_free(tlist, nthreads * sizeof (*tlist)); + return (WALK_ERR); + } + + tti->tti_tlist = tlist; + tti->tti_nthreads = nthreads; + return (WALK_NEXT); + } + + wsp->walk_addr = 0; + if (mdb_layered_walk("thread", wsp) == -1) { + mdb_warn("can't walk \"thread\""); + return (WALK_ERR); + } + return (0); +} + +int +taskq_thread_walk_step(mdb_walk_state_t *wsp) +{ + taskq_thread_info_t *tti = wsp->walk_data; + + const kthread_t *kt = wsp->walk_layer; + taskq_t *tq = (taskq_t *)tti->tti_addr; + + if (kt == NULL) { + uintptr_t addr; + + if (tti->tti_idx >= tti->tti_nthreads) + return (WALK_DONE); + + addr = tti->tti_tlist[tti->tti_idx]; + tti->tti_idx++; + + if (addr == NULL) + return (WALK_NEXT); + + if (mdb_vread(&tti->tti_thread, sizeof (kthread_t), + addr) == -1) { + mdb_warn("unable to read kthread_t at %p", addr); + return (WALK_ERR); + } + return (wsp->walk_callback(addr, &tti->tti_thread, + wsp->walk_cbdata)); + } + + if (kt->t_taskq == NULL) + return (WALK_NEXT); + + if (tq != NULL && kt->t_taskq != tq) + return (WALK_NEXT); + + return (wsp->walk_callback(wsp->walk_addr, kt, wsp->walk_cbdata)); +} + +void +taskq_thread_walk_fini(mdb_walk_state_t *wsp) +{ + taskq_thread_info_t *tti = wsp->walk_data; + + if (tti->tti_nthreads > 0) { + mdb_free(tti->tti_tlist, + tti->tti_nthreads * sizeof (*tti->tti_tlist)); + } + mdb_free(tti, sizeof (*tti)); +} diff -r a32f4a9013e5 -r 8b6ec68049bd usr/src/cmd/mdb/common/modules/genunix/taskq.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/mdb/common/modules/genunix/taskq.h Tue Oct 27 13:44:45 2009 -0700 @@ -0,0 +1,49 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _TASKQ_H +#define _TASKQ_H + +#ifdef __cplusplus +extern "C" { +#endif + +extern int taskq(uintptr_t, uint_t, int, const mdb_arg_t *); +extern void taskq_help(void); + +extern int taskq_ent(uintptr_t, uint_t, int, const mdb_arg_t *); + +extern int taskq_ent_walk_init(mdb_walk_state_t *); +extern int taskq_ent_walk_step(mdb_walk_state_t *); + +extern int taskq_thread_walk_init(mdb_walk_state_t *); +extern int taskq_thread_walk_step(mdb_walk_state_t *); +extern void taskq_thread_walk_fini(mdb_walk_state_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* _TASKQ_H */ diff -r a32f4a9013e5 -r 8b6ec68049bd usr/src/cmd/svc/Makefile.ctf --- a/usr/src/cmd/svc/Makefile.ctf Tue Oct 27 11:26:10 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# ident "%Z%%M% %I% %E% SMI" -# - -CTFMERGE_HOOK = && $(CTFMERGE) -L VERSION -o $@ $(OBJS) -CTFCONVERT_HOOK = && $(CTFCONVERT_O) -CFLAGS += $(CTF_FLAGS) -CFLAGS64 += $(CTF_FLAGS) -NATIVE_CFLAGS += $(CTF_FLAGS) diff -r a32f4a9013e5 -r 8b6ec68049bd usr/src/cmd/svc/configd/Makefile --- a/usr/src/cmd/svc/configd/Makefile Tue Oct 27 11:26:10 2009 -0700 +++ b/usr/src/cmd/svc/configd/Makefile Tue Oct 27 13:44:45 2009 -0700 @@ -40,7 +40,7 @@ SRCS = $(MYOBJS:%.o=%.c) include ../../Makefile.cmd -include ../Makefile.ctf +include ../../Makefile.ctf NATIVE_BUILD=$(POUND_SIGN) $(NATIVE_BUILD)PROG = $(MYPROG:%=%-native) @@ -95,11 +95,11 @@ @NATIVE_BUILD= $(MAKE) $(MFLAGS) all $(PROG): $(OBJS) - $(LINK.c) -o $@ $(OBJS) $(LDLIBS) $(CTFMERGE_HOOK) + $(LINK.c) -o $@ $(OBJS) $(LDLIBS) $(POST_PROCESS) %-native.o: %.c - $(COMPILE.c) -o $@ $< $(CTFCONVERT_HOOK) + $(COMPILE.c) -o $@ $< $(POST_PROCESS_O) $(ROOTCMDDIR)/%: %.sh diff -r a32f4a9013e5 -r 8b6ec68049bd usr/src/cmd/svc/prophist/Makefile --- a/usr/src/cmd/svc/prophist/Makefile Tue Oct 27 11:26:10 2009 -0700 +++ b/usr/src/cmd/svc/prophist/Makefile Tue Oct 27 13:44:45 2009 -0700 @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. @@ -20,10 +19,9 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -#ident "%Z%%M% %I% %E% SMI" PROG = prophist OBJS = prophist.o \ @@ -37,7 +35,7 @@ POFILES = $(OBJS:.o=.po) include ../../Makefile.cmd -include ../Makefile.ctf +include ../../Makefile.ctf ROOTCMDDIR= $(ROOT)/lib/svc/bin @@ -56,7 +54,7 @@ all: $(PROG) $(PROG): $(OBJS) - $(LINK.c) -o $@ $(OBJS) $(LDLIBS) $(CTFMERGE_HOOK) + $(LINK.c) -o $@ $(OBJS) $(LDLIBS) $(POST_PROCESS) install: all $(ROOTCMD) $(ROOTPROPHIST) @@ -68,7 +66,7 @@ $(LINT.c) $(LINTFLAGS) $(LNTS) $(LDLIBS) %.o: ../common/%.c - $(COMPILE.c) $(OUTPUT_OPTION) $< $(CTFCONVERT_HOOK) + $(COMPILE.c) $(OUTPUT_OPTION) $< $(POST_PROCESS_O) %.ln: ../common/%.c diff -r a32f4a9013e5 -r 8b6ec68049bd usr/src/cmd/svc/req.flg --- a/usr/src/cmd/svc/req.flg Tue Oct 27 11:26:10 2009 -0700 +++ b/usr/src/cmd/svc/req.flg Tue Oct 27 13:44:45 2009 -0700 @@ -3,9 +3,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. @@ -21,13 +20,11 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "%Z%%M% %I% %E% SMI" -# -echo_file usr/src/cmd/svc/Makefile.ctf +echo_file usr/src/cmd/Makefile.ctf find_files "s.*" \ usr/src/cmd/svc/common \ usr/src/common/svc \ diff -r a32f4a9013e5 -r 8b6ec68049bd usr/src/cmd/svc/servinfo/Makefile --- a/usr/src/cmd/svc/servinfo/Makefile Tue Oct 27 11:26:10 2009 -0700 +++ b/usr/src/cmd/svc/servinfo/Makefile Tue Oct 27 13:44:45 2009 -0700 @@ -29,7 +29,7 @@ POFILES = $(OBJS:.o=.po) include ../../Makefile.cmd -include ../Makefile.ctf +include ../../Makefile.ctf LDLIBS += -lnsl -lsocket @@ -40,7 +40,7 @@ all: $(PROG) $(PROG): $(OBJS) - $(LINK.c) -o $@ $(OBJS) $(LDLIBS) $(CTFMERGE_HOOK) + $(LINK.c) -o $@ $(OBJS) $(LDLIBS) $(POST_PROCESS) install: all $(ROOTLIBPROG) diff -r a32f4a9013e5 -r 8b6ec68049bd usr/src/cmd/svc/startd/Makefile --- a/usr/src/cmd/svc/startd/Makefile Tue Oct 27 11:26:10 2009 -0700 +++ b/usr/src/cmd/svc/startd/Makefile Tue Oct 27 13:44:45 2009 -0700 @@ -52,7 +52,7 @@ POFILES = $(ALLOBJS:%.o=%.po) include ../../Makefile.cmd -include ../Makefile.ctf +include ../../Makefile.ctf ROOTCMDDIR= $(ROOT)/lib/svc/bin @@ -93,7 +93,7 @@ all: $(PROG) $(PROG): $(ALLOBJS) - $(LINK.c) -o $@ $(ALLOBJS) $(LDLIBS) $(CTFMERGE_HOOK) + $(LINK.c) -o $@ $(ALLOBJS) $(LDLIBS) $(POST_PROCESS) $(POFILE): $(POFILES) diff -r a32f4a9013e5 -r 8b6ec68049bd usr/src/cmd/svc/svccfg/Makefile --- a/usr/src/cmd/svc/svccfg/Makefile Tue Oct 27 11:26:10 2009 -0700 +++ b/usr/src/cmd/svc/svccfg/Makefile Tue Oct 27 13:44:45 2009 -0700 @@ -50,7 +50,7 @@ ../common/manifest_hash.po include ../../Makefile.cmd -include ../Makefile.ctf +include ../../Makefile.ctf POFILE = $(PROG)_all.po @@ -120,7 +120,7 @@ @NATIVE_BUILD= $(MAKE) $(MFLAGS) all $(PROG): $(OBJS) $(MAPFILES) - $(LINK.c) -o $@ $(OBJS) $(LDLIBS) $(CTFMERGE_HOOK) + $(LINK.c) -o $@ $(OBJS) $(LDLIBS) $(POST_PROCESS) $(POFILE): $(POFILES) @@ -146,15 +146,15 @@ $(LINT.c) $(LINTFLAGS) $(LNTS) $(LDLIBS) %-native.o: %.c - $(COMPILE.c) -o $@ $< $(CTFCONVERT_HOOK) + $(COMPILE.c) -o $@ $< $(POST_PROCESS_O) %-native.o: ../common/%.c - $(COMPILE.c) -o $@ $< $(CTFCONVERT_HOOK) + $(COMPILE.c) -o $@ $< $(POST_PROCESS_O) %.o: ../common/%.c - $(COMPILE.c) $(OUTPUT_OPTION) $< $(CTFCONVERT_HOOK) + $(COMPILE.c) $(OUTPUT_OPTION) $< $(POST_PROCESS_O) %.ln: ../common/%.c diff -r a32f4a9013e5 -r 8b6ec68049bd usr/src/cmd/svc/svcprop/Makefile --- a/usr/src/cmd/svc/svcprop/Makefile Tue Oct 27 11:26:10 2009 -0700 +++ b/usr/src/cmd/svc/svcprop/Makefile Tue Oct 27 13:44:45 2009 -0700 @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. @@ -20,10 +19,9 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -#ident "%Z%%M% %I% %E% SMI" PROG = svcprop OBJS = svcprop.o @@ -31,7 +29,7 @@ POFILES = $(OBJS:.o=.po) include ../../Makefile.cmd -include ../Makefile.ctf +include ../../Makefile.ctf LDLIBS += -lscf -luutil @@ -42,7 +40,7 @@ all: $(PROG) $(PROG): $(OBJS) - $(LINK.c) -o $@ $(OBJS) $(LDLIBS) $(CTFMERGE_HOOK) + $(LINK.c) -o $@ $(OBJS) $(LDLIBS) $(POST_PROCESS) install: all $(ROOTPROG) diff -r a32f4a9013e5 -r 8b6ec68049bd usr/src/cmd/svc/svcs/Makefile --- a/usr/src/cmd/svc/svcs/Makefile Tue Oct 27 11:26:10 2009 -0700 +++ b/usr/src/cmd/svc/svcs/Makefile Tue Oct 27 13:44:45 2009 -0700 @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. @@ -20,10 +19,9 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -#ident "%Z%%M% %I% %E% SMI" PROG = svcs OBJS = svcs.o explain.o @@ -31,7 +29,7 @@ POFILES = $(OBJS:.o=.po) include ../../Makefile.cmd -include ../Makefile.ctf +include ../../Makefile.ctf POFILE = $(PROG)_all.po LDLIBS += -lcontract -lscf -luutil -lumem @@ -43,7 +41,7 @@ all: $(PROG) $(PROG): $(OBJS) - $(LINK.c) -o $@ $(OBJS) $(LDLIBS) $(CTFMERGE_HOOK) + $(LINK.c) -o $@ $(OBJS) $(LDLIBS) $(POST_PROCESS) $(POFILE): $(POFILES) diff -r a32f4a9013e5 -r 8b6ec68049bd usr/src/cmd/zdb/Makefile.com --- a/usr/src/cmd/zdb/Makefile.com Tue Oct 27 11:26:10 2009 -0700 +++ b/usr/src/cmd/zdb/Makefile.com Tue Oct 27 13:44:45 2009 -0700 @@ -29,6 +29,7 @@ OBJS= $(PROG).o zdb_il.o include ../../Makefile.cmd +include ../../Makefile.ctf INCS += -I../../../lib/libzpool/common INCS += -I../../../uts/common/fs/zfs diff -r a32f4a9013e5 -r 8b6ec68049bd usr/src/cmd/zfs/Makefile --- a/usr/src/cmd/zfs/Makefile Tue Oct 27 11:26:10 2009 -0700 +++ b/usr/src/cmd/zfs/Makefile Tue Oct 27 13:44:45 2009 -0700 @@ -30,6 +30,7 @@ POFILE= zfs.po include ../Makefile.cmd +include ../Makefile.ctf FSTYPE= zfs LINKPROGS= mount umount diff -r a32f4a9013e5 -r 8b6ec68049bd usr/src/cmd/zpool/Makefile --- a/usr/src/cmd/zpool/Makefile Tue Oct 27 11:26:10 2009 -0700 +++ b/usr/src/cmd/zpool/Makefile Tue Oct 27 13:44:45 2009 -0700 @@ -30,6 +30,7 @@ POFILE= zpool.po include ../Makefile.cmd +include ../Makefile.ctf STATCOMMONDIR = $(SRC)/cmd/stat/common diff -r a32f4a9013e5 -r 8b6ec68049bd usr/src/cmd/ztest/Makefile.com --- a/usr/src/cmd/ztest/Makefile.com Tue Oct 27 11:26:10 2009 -0700 +++ b/usr/src/cmd/ztest/Makefile.com Tue Oct 27 13:44:45 2009 -0700 @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. @@ -20,16 +19,16 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "%Z%%M% %I% %E% SMI" -# PROG= ztest -SRCS= ../$(PROG).c +OBJS= $(PROG).o +SRCS= $(OBJS:%.o=../%.c) include ../../Makefile.cmd +include ../../Makefile.ctf INCS += -I../../../lib/libzpool/common INCS += -I../../../uts/common/fs/zfs @@ -50,8 +49,8 @@ all: $(PROG) -$(PROG): $(SRCS) - $(LINK.c) -o $(PROG) $(SRCS) $(LDLIBS) +$(PROG): $(OBJS) + $(LINK.c) -o $(PROG) $(OBJS) $(LDLIBS) $(POST_PROCESS) clean: @@ -59,3 +58,7 @@ lint: lint_SRCS include ../../Makefile.targ + +%.o: ../%.c + $(COMPILE.c) $< + $(POST_PROCESS_O) diff -r a32f4a9013e5 -r 8b6ec68049bd usr/src/uts/common/os/taskq.c --- a/usr/src/uts/common/os/taskq.c Tue Oct 27 11:26:10 2009 -0700 +++ b/usr/src/uts/common/os/taskq.c Tue Oct 27 13:44:45 2009 -0700 @@ -203,7 +203,7 @@ * * taskq: * +-------------+ - * |tq_lock | +---< taskq_ent_free() + * | tq_lock | +---< taskq_ent_free() * +-------------+ | * |... | | tqent: tqent: * +-------------+ | +------------+ +------------+ @@ -1238,16 +1238,29 @@ t->t_taskq = tq; } -static void -taskq_thread_wait(taskq_t *tq, kcondvar_t *cv, callb_cpr_t *cprinfo) +/* + * Common "sleep taskq thread" function, which handles CPR stuff, as well + * as giving a nice common point for debuggers to find inactive threads. + */ +static clock_t +taskq_thread_wait(taskq_t *tq, kmutex_t *mx, kcondvar_t *cv, + callb_cpr_t *cprinfo, clock_t timeout) { - if (tq->tq_flags & TASKQ_CPR_SAFE) { - cv_wait(cv, &tq->tq_lock); - } else { + clock_t ret = 0; + + if (!(tq->tq_flags & TASKQ_CPR_SAFE)) { CALLB_CPR_SAFE_BEGIN(cprinfo); - cv_wait(cv, &tq->tq_lock); - CALLB_CPR_SAFE_END(cprinfo, &tq->tq_lock); } + if (timeout < 0) + cv_wait(cv, mx); + else + ret = cv_timedwait(cv, mx, lbolt + timeout); + + if (!(tq->tq_flags & TASKQ_CPR_SAFE)) { + CALLB_CPR_SAFE_END(cprinfo, mx); + } + + return (ret); } /* @@ -1312,15 +1325,16 @@ break; /* Wait for higher thread_ids to exit */ - taskq_thread_wait(tq, &tq->tq_exit_cv, - &cprinfo); + (void) taskq_thread_wait(tq, &tq->tq_lock, + &tq->tq_exit_cv, &cprinfo, -1); continue; } } if ((tqe = tq->tq_task.tqent_next) == &tq->tq_task) { if (--tq->tq_active == 0) cv_broadcast(&tq->tq_wait_cv); - taskq_thread_wait(tq, &tq->tq_dispatch_cv, &cprinfo); + (void) taskq_thread_wait(tq, &tq->tq_lock, + &tq->tq_dispatch_cv, &cprinfo, -1); tq->tq_active++; continue; } @@ -1441,10 +1455,8 @@ * If a thread is sleeping too long, it dies. */ if (! (bucket->tqbucket_flags & TQBUCKET_CLOSE)) { - CALLB_CPR_SAFE_BEGIN(&cprinfo); - w = cv_timedwait(cv, lock, lbolt + - taskq_thread_timeout * hz); - CALLB_CPR_SAFE_END(&cprinfo, lock); + w = taskq_thread_wait(tq, lock, cv, + &cprinfo, taskq_thread_timeout * hz); } /*