xref: /onnv-gate/usr/src/cmd/perl/contrib/Sun/Solaris/Kstat/Kstat.xs (revision 12607:2bc0f474d551)
11341Sstevel /*
21341Sstevel  * CDDL HEADER START
31341Sstevel  *
41341Sstevel  * The contents of this file are subject to the terms of the
51410Salanbur  * Common Development and Distribution License (the "License").
61410Salanbur  * You may not use this file except in compliance with the License.
71341Sstevel  *
81341Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91341Sstevel  * or http://www.opensolaris.org/os/licensing.
101341Sstevel  * See the License for the specific language governing permissions
111341Sstevel  * and limitations under the License.
121341Sstevel  *
131341Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
141341Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151341Sstevel  * If applicable, add the following below this CDDL HEADER, with the
161341Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
171341Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
181341Sstevel  *
191341Sstevel  * CDDL HEADER END
201341Sstevel  */
211341Sstevel 
221341Sstevel /*
23*12607Sjohn.levon@sun.com  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
241341Sstevel  */
251341Sstevel 
261341Sstevel /*
271341Sstevel  * Kstat.xs is a Perl XS (eXStension module) that makes the Solaris
281341Sstevel  * kstat(3KSTAT) facility available to Perl scripts.  Kstat is a general-purpose
291341Sstevel  * mechanism  for  providing kernel statistics to users.  The Solaris API is
301341Sstevel  * function-based (see the manpage for details), but for ease of use in Perl
311341Sstevel  * scripts this module presents the information as a nested hash data structure.
321341Sstevel  * It would be too inefficient to read every kstat in the system, so this module
331341Sstevel  * uses the Perl TIEHASH mechanism to implement a read-on-demand semantic, which
341341Sstevel  * only reads and updates kstats as and when they are actually accessed.
351341Sstevel  */
361341Sstevel 
371341Sstevel /*
381341Sstevel  * Ignored raw kstats.
391341Sstevel  *
401341Sstevel  * Some raw kstats are ignored by this module, these are listed below.  The
411341Sstevel  * most common reason is that the kstats are stored as arrays and the ks_ndata
421341Sstevel  * and/or ks_data_size fields are invalid.  In this case it is impossible to
431341Sstevel  * know how many records are in the array, so they can't be read.
441341Sstevel  *
451341Sstevel  * unix:*:sfmmu_percpu_stat
461341Sstevel  * This is stored as an array with one entry per cpu.  Each element is of type
471341Sstevel  * struct sfmmu_percpu_stat.  The ks_ndata and ks_data_size fields are bogus.
481341Sstevel  *
491341Sstevel  * ufs directio:*:UFS DirectIO Stats
501341Sstevel  * The structure definition used for these kstats (ufs_directio_kstats) is in a
511341Sstevel  * C file (uts/common/fs/ufs/ufs_directio.c) rather than a header file, so it
521341Sstevel  * isn't accessible.
531341Sstevel  *
541341Sstevel  * qlc:*:statistics
551341Sstevel  * This is a third-party driver for which we don't have source.
561341Sstevel  *
571341Sstevel  * mm:*:phys_installed
581341Sstevel  * This is stored as an array of uint64_t, with each pair of values being the
591341Sstevel  * (address, size) of a memory segment.  The ks_ndata and ks_data_size fields
601341Sstevel  * are both zero.
611341Sstevel  *
621341Sstevel  * sockfs:*:sock_unix_list
631341Sstevel  * This is stored as an array with one entry per active socket.  Each element
641341Sstevel  * is of type struct k_sockinfo.  The ks_ndata and ks_data_size fields are both
651341Sstevel  * zero.
661341Sstevel  *
671341Sstevel  * Note that the ks_ndata and ks_data_size of many non-array raw kstats are
681341Sstevel  * also incorrect.  The relevant assertions are therefore commented out in the
691341Sstevel  * appropriate raw kstat read routines.
701341Sstevel  */
711341Sstevel 
721341Sstevel /* Kstat related includes */
731341Sstevel #include <libgen.h>
741341Sstevel #include <kstat.h>
751341Sstevel #include <sys/var.h>
761341Sstevel #include <sys/utsname.h>
771341Sstevel #include <sys/sysinfo.h>
781341Sstevel #include <sys/flock.h>
791341Sstevel #include <sys/dnlc.h>
801341Sstevel #include <nfs/nfs.h>
811341Sstevel #include <nfs/nfs_clnt.h>
821341Sstevel 
831341Sstevel /* Ultra-specific kstat includes */
841341Sstevel #ifdef __sparc
851341Sstevel #include <vm/hat_sfmmu.h>	/* from /usr/platform/sun4u/include */
861341Sstevel #include <sys/simmstat.h>	/* from /usr/platform/sun4u/include */
871341Sstevel #include <sys/sysctrl.h>	/* from /usr/platform/sun4u/include */
881341Sstevel #include <sys/fhc.h>		/* from /usr/include */
891341Sstevel #endif
901341Sstevel 
911341Sstevel /*
921341Sstevel  * Solaris #defines SP, which conflicts with the perl definition of SP
931341Sstevel  * We don't need the Solaris one, so get rid of it to avoid warnings
941341Sstevel  */
951341Sstevel #undef SP
961341Sstevel 
971341Sstevel /* Perl XS includes */
981341Sstevel #include "EXTERN.h"
991341Sstevel #include "perl.h"
1001341Sstevel #include "XSUB.h"
1011341Sstevel 
1021341Sstevel /* Debug macros */
1031341Sstevel #define	DEBUG_ID "Sun::Solaris::Kstat"
1041341Sstevel #ifdef KSTAT_DEBUG
1051341Sstevel #define	PERL_ASSERT(EXP) \
1061341Sstevel     ((void)((EXP) || (croak("%s: assertion failed at %s:%d: %s", \
1071341Sstevel     DEBUG_ID, __FILE__, __LINE__, #EXP), 0), 0))
1081341Sstevel #define	PERL_ASSERTMSG(EXP, MSG) \
1091341Sstevel     ((void)((EXP) || (croak(DEBUG_ID ": " MSG), 0), 0))
1101341Sstevel #else
1111341Sstevel #define	PERL_ASSERT(EXP)		((void)0)
1121341Sstevel #define	PERL_ASSERTMSG(EXP, MSG)	((void)0)
1131341Sstevel #endif
1141341Sstevel 
1151341Sstevel /* Macros for saving the contents of KSTAT_RAW structures */
1161341Sstevel #if defined(HAS_QUAD) && defined(USE_64_BIT_INT)
1171341Sstevel #define NEW_IV(V) \
1181341Sstevel     (newSViv((IVTYPE) V))
1191341Sstevel #define NEW_UV(V) \
1201341Sstevel     (newSVuv((UVTYPE) V))
1211341Sstevel #else
1221341Sstevel #define NEW_IV(V) \
1231341Sstevel     (V >= IV_MIN && V <= IV_MAX ? newSViv((IVTYPE) V) : newSVnv((NVTYPE) V))
1241341Sstevel #if defined(UVTYPE)
1251341Sstevel #define NEW_UV(V) \
1261341Sstevel     (V <= UV_MAX ? newSVuv((UVTYPE) V) : newSVnv((NVTYPE) V))
1271341Sstevel # else
1281341Sstevel #define NEW_UV(V) \
1291341Sstevel     (V <= IV_MAX ? newSViv((IVTYPE) V) : newSVnv((NVTYPE) V))
1301341Sstevel #endif
1311341Sstevel #endif
1321341Sstevel #define	NEW_HRTIME(V) \
1331341Sstevel     newSVnv((NVTYPE) (V / 1000000000.0))
1341341Sstevel 
1351341Sstevel #define	SAVE_FNP(H, F, K) \
1361341Sstevel     hv_store(H, K, sizeof (K) - 1, newSViv((IVTYPE) &F), 0)
1371341Sstevel #define	SAVE_STRING(H, S, K, SS) \
1381341Sstevel     hv_store(H, #K, sizeof (#K) - 1, \
1391341Sstevel     newSVpvn(S->K, SS ? strlen(S->K) : sizeof(S->K)), 0)
1401341Sstevel #define	SAVE_INT32(H, S, K) \
1411341Sstevel     hv_store(H, #K, sizeof (#K) - 1, NEW_IV(S->K), 0)
1421341Sstevel #define	SAVE_UINT32(H, S, K) \
1431341Sstevel     hv_store(H, #K, sizeof (#K) - 1, NEW_UV(S->K), 0)
1441341Sstevel #define	SAVE_INT64(H, S, K) \
1451341Sstevel     hv_store(H, #K, sizeof (#K) - 1, NEW_IV(S->K), 0)
1461341Sstevel #define	SAVE_UINT64(H, S, K) \
1471341Sstevel     hv_store(H, #K, sizeof (#K) - 1, NEW_UV(S->K), 0)
1481341Sstevel #define	SAVE_HRTIME(H, S, K) \
1491341Sstevel     hv_store(H, #K, sizeof (#K) - 1, NEW_HRTIME(S->K), 0)
1501341Sstevel 
1511341Sstevel /* Private structure used for saving kstat info in the tied hashes */
1521341Sstevel typedef struct {
1531341Sstevel 	char		read;		/* Kstat block has been read before */
1541341Sstevel 	char		valid;		/* Kstat still exists in kstat chain */
1551341Sstevel 	char		strip_str;	/* Strip KSTAT_DATA_CHAR fields */
1561341Sstevel 	kstat_ctl_t	*kstat_ctl;	/* Handle returned by kstat_open */
1571341Sstevel 	kstat_t		*kstat;		/* Handle used by kstat_read */
1581341Sstevel } KstatInfo_t;
1591341Sstevel 
1601341Sstevel /* typedef for apply_to_ties callback functions */
1611341Sstevel typedef int (*ATTCb_t)(HV *, void *);
1621341Sstevel 
1631341Sstevel /* typedef for raw kstat reader functions */
1641341Sstevel typedef void (*kstat_raw_reader_t)(HV *, kstat_t *, int);
1651341Sstevel 
1661341Sstevel /* Hash of "module:name" to KSTAT_RAW read functions */
1671341Sstevel static HV *raw_kstat_lookup;
1681341Sstevel 
1691341Sstevel /*
1701341Sstevel  * Kstats come in two flavours, named and raw.  Raw kstats are just C structs,
1711341Sstevel  * so we need a function per raw kstat to convert the C struct into the
1721341Sstevel  * corresponding perl hash.  All such conversion functions are in the following
1731341Sstevel  * section.
1741341Sstevel  */
1751341Sstevel 
1761341Sstevel /*
1771341Sstevel  * Definitions in /usr/include/sys/cpuvar.h and /usr/include/sys/sysinfo.h
1781341Sstevel  */
1791341Sstevel 
1801341Sstevel static void
save_cpu_stat(HV * self,kstat_t * kp,int strip_str)1811341Sstevel save_cpu_stat(HV *self, kstat_t *kp, int strip_str)
1821341Sstevel {
1831341Sstevel 	cpu_stat_t    *statp;
1841341Sstevel 	cpu_sysinfo_t *sysinfop;
1851341Sstevel 	cpu_syswait_t *syswaitp;
1861341Sstevel 	cpu_vminfo_t  *vminfop;
1871341Sstevel 
1881341Sstevel 	/* PERL_ASSERT(kp->ks_ndata == 1); */
1891341Sstevel 	PERL_ASSERT(kp->ks_data_size == sizeof (cpu_stat_t));
1901341Sstevel 	statp = (cpu_stat_t *)(kp->ks_data);
1911341Sstevel 	sysinfop = &statp->cpu_sysinfo;
1921341Sstevel 	syswaitp = &statp->cpu_syswait;
1931341Sstevel 	vminfop  = &statp->cpu_vminfo;
1941341Sstevel 
1951341Sstevel 	hv_store(self, "idle", 4, NEW_UV(sysinfop->cpu[CPU_IDLE]), 0);
1961341Sstevel 	hv_store(self, "user", 4, NEW_UV(sysinfop->cpu[CPU_USER]), 0);
1971341Sstevel 	hv_store(self, "kernel", 6, NEW_UV(sysinfop->cpu[CPU_KERNEL]), 0);
1981341Sstevel 	hv_store(self, "wait", 4, NEW_UV(sysinfop->cpu[CPU_WAIT]), 0);
1991341Sstevel 	hv_store(self, "wait_io", 7, NEW_UV(sysinfop->wait[W_IO]), 0);
2001341Sstevel 	hv_store(self, "wait_swap", 9, NEW_UV(sysinfop->wait[W_SWAP]), 0);
2011341Sstevel 	hv_store(self, "wait_pio",  8, NEW_UV(sysinfop->wait[W_PIO]), 0);
2021341Sstevel 	SAVE_UINT32(self, sysinfop, bread);
2031341Sstevel 	SAVE_UINT32(self, sysinfop, bwrite);
2041341Sstevel 	SAVE_UINT32(self, sysinfop, lread);
2051341Sstevel 	SAVE_UINT32(self, sysinfop, lwrite);
2061341Sstevel 	SAVE_UINT32(self, sysinfop, phread);
2071341Sstevel 	SAVE_UINT32(self, sysinfop, phwrite);
2081341Sstevel 	SAVE_UINT32(self, sysinfop, pswitch);
2091341Sstevel 	SAVE_UINT32(self, sysinfop, trap);
2101341Sstevel 	SAVE_UINT32(self, sysinfop, intr);
2111341Sstevel 	SAVE_UINT32(self, sysinfop, syscall);
2121341Sstevel 	SAVE_UINT32(self, sysinfop, sysread);
2131341Sstevel 	SAVE_UINT32(self, sysinfop, syswrite);
2141341Sstevel 	SAVE_UINT32(self, sysinfop, sysfork);
2151341Sstevel 	SAVE_UINT32(self, sysinfop, sysvfork);
2161341Sstevel 	SAVE_UINT32(self, sysinfop, sysexec);
2171341Sstevel 	SAVE_UINT32(self, sysinfop, readch);
2181341Sstevel 	SAVE_UINT32(self, sysinfop, writech);
2191341Sstevel 	SAVE_UINT32(self, sysinfop, rcvint);
2201341Sstevel 	SAVE_UINT32(self, sysinfop, xmtint);
2211341Sstevel 	SAVE_UINT32(self, sysinfop, mdmint);
2221341Sstevel 	SAVE_UINT32(self, sysinfop, rawch);
2231341Sstevel 	SAVE_UINT32(self, sysinfop, canch);
2241341Sstevel 	SAVE_UINT32(self, sysinfop, outch);
2251341Sstevel 	SAVE_UINT32(self, sysinfop, msg);
2261341Sstevel 	SAVE_UINT32(self, sysinfop, sema);
2271341Sstevel 	SAVE_UINT32(self, sysinfop, namei);
2281341Sstevel 	SAVE_UINT32(self, sysinfop, ufsiget);
2291341Sstevel 	SAVE_UINT32(self, sysinfop, ufsdirblk);
2301341Sstevel 	SAVE_UINT32(self, sysinfop, ufsipage);
2311341Sstevel 	SAVE_UINT32(self, sysinfop, ufsinopage);
2321341Sstevel 	SAVE_UINT32(self, sysinfop, inodeovf);
2331341Sstevel 	SAVE_UINT32(self, sysinfop, fileovf);
2341341Sstevel 	SAVE_UINT32(self, sysinfop, procovf);
2351341Sstevel 	SAVE_UINT32(self, sysinfop, intrthread);
2361341Sstevel 	SAVE_UINT32(self, sysinfop, intrblk);
2371341Sstevel 	SAVE_UINT32(self, sysinfop, idlethread);
2381341Sstevel 	SAVE_UINT32(self, sysinfop, inv_swtch);
2391341Sstevel 	SAVE_UINT32(self, sysinfop, nthreads);
2401341Sstevel 	SAVE_UINT32(self, sysinfop, cpumigrate);
2411341Sstevel 	SAVE_UINT32(self, sysinfop, xcalls);
2421341Sstevel 	SAVE_UINT32(self, sysinfop, mutex_adenters);
2431341Sstevel 	SAVE_UINT32(self, sysinfop, rw_rdfails);
2441341Sstevel 	SAVE_UINT32(self, sysinfop, rw_wrfails);
2451341Sstevel 	SAVE_UINT32(self, sysinfop, modload);
2461341Sstevel 	SAVE_UINT32(self, sysinfop, modunload);
2471341Sstevel 	SAVE_UINT32(self, sysinfop, bawrite);
2481341Sstevel #ifdef STATISTICS	/* see header file */
2491341Sstevel 	SAVE_UINT32(self, sysinfop, rw_enters);
2501341Sstevel 	SAVE_UINT32(self, sysinfop, win_uo_cnt);
2511341Sstevel 	SAVE_UINT32(self, sysinfop, win_uu_cnt);
2521341Sstevel 	SAVE_UINT32(self, sysinfop, win_so_cnt);
2531341Sstevel 	SAVE_UINT32(self, sysinfop, win_su_cnt);
2541341Sstevel 	SAVE_UINT32(self, sysinfop, win_suo_cnt);
2551341Sstevel #endif
2561341Sstevel 
2571341Sstevel 	SAVE_INT32(self, syswaitp, iowait);
2581341Sstevel 	SAVE_INT32(self, syswaitp, swap);
2591341Sstevel 	SAVE_INT32(self, syswaitp, physio);
2601341Sstevel 
2611341Sstevel 	SAVE_UINT32(self, vminfop, pgrec);
2621341Sstevel 	SAVE_UINT32(self, vminfop, pgfrec);
2631341Sstevel 	SAVE_UINT32(self, vminfop, pgin);
2641341Sstevel 	SAVE_UINT32(self, vminfop, pgpgin);
2651341Sstevel 	SAVE_UINT32(self, vminfop, pgout);
2661341Sstevel 	SAVE_UINT32(self, vminfop, pgpgout);
2671341Sstevel 	SAVE_UINT32(self, vminfop, swapin);
2681341Sstevel 	SAVE_UINT32(self, vminfop, pgswapin);
2691341Sstevel 	SAVE_UINT32(self, vminfop, swapout);
2701341Sstevel 	SAVE_UINT32(self, vminfop, pgswapout);
2711341Sstevel 	SAVE_UINT32(self, vminfop, zfod);
2721341Sstevel 	SAVE_UINT32(self, vminfop, dfree);
2731341Sstevel 	SAVE_UINT32(self, vminfop, scan);
2741341Sstevel 	SAVE_UINT32(self, vminfop, rev);
2751341Sstevel 	SAVE_UINT32(self, vminfop, hat_fault);
2761341Sstevel 	SAVE_UINT32(self, vminfop, as_fault);
2771341Sstevel 	SAVE_UINT32(self, vminfop, maj_fault);
2781341Sstevel 	SAVE_UINT32(self, vminfop, cow_fault);
2791341Sstevel 	SAVE_UINT32(self, vminfop, prot_fault);
2801341Sstevel 	SAVE_UINT32(self, vminfop, softlock);
2811341Sstevel 	SAVE_UINT32(self, vminfop, kernel_asflt);
2821341Sstevel 	SAVE_UINT32(self, vminfop, pgrrun);
2831341Sstevel 	SAVE_UINT32(self, vminfop, execpgin);
2841341Sstevel 	SAVE_UINT32(self, vminfop, execpgout);
2851341Sstevel 	SAVE_UINT32(self, vminfop, execfree);
2861341Sstevel 	SAVE_UINT32(self, vminfop, anonpgin);
2871341Sstevel 	SAVE_UINT32(self, vminfop, anonpgout);
2881341Sstevel 	SAVE_UINT32(self, vminfop, anonfree);
2891341Sstevel 	SAVE_UINT32(self, vminfop, fspgin);
2901341Sstevel 	SAVE_UINT32(self, vminfop, fspgout);
2911341Sstevel 	SAVE_UINT32(self, vminfop, fsfree);
2921341Sstevel }
2931341Sstevel 
2941341Sstevel /*
2951341Sstevel  * Definitions in /usr/include/sys/var.h
2961341Sstevel  */
2971341Sstevel 
2981341Sstevel static void
save_var(HV * self,kstat_t * kp,int strip_str)2991341Sstevel save_var(HV *self, kstat_t *kp, int strip_str)
3001341Sstevel {
3011341Sstevel 	struct var *varp;
3021341Sstevel 
3031341Sstevel 	/* PERL_ASSERT(kp->ks_ndata == 1); */
3041341Sstevel 	PERL_ASSERT(kp->ks_data_size == sizeof (struct var));
3051341Sstevel 	varp = (struct var *)(kp->ks_data);
3061341Sstevel 
3071341Sstevel 	SAVE_INT32(self, varp, v_buf);
3081341Sstevel 	SAVE_INT32(self, varp, v_call);
3091341Sstevel 	SAVE_INT32(self, varp, v_proc);
3101341Sstevel 	SAVE_INT32(self, varp, v_maxupttl);
3111341Sstevel 	SAVE_INT32(self, varp, v_nglobpris);
3121341Sstevel 	SAVE_INT32(self, varp, v_maxsyspri);
3131341Sstevel 	SAVE_INT32(self, varp, v_clist);
3141341Sstevel 	SAVE_INT32(self, varp, v_maxup);
3151341Sstevel 	SAVE_INT32(self, varp, v_hbuf);
3161341Sstevel 	SAVE_INT32(self, varp, v_hmask);
3171341Sstevel 	SAVE_INT32(self, varp, v_pbuf);
3181341Sstevel 	SAVE_INT32(self, varp, v_sptmap);
3191341Sstevel 	SAVE_INT32(self, varp, v_maxpmem);
3201341Sstevel 	SAVE_INT32(self, varp, v_autoup);
3211341Sstevel 	SAVE_INT32(self, varp, v_bufhwm);
3221341Sstevel }
3231341Sstevel 
3241341Sstevel /*
3251341Sstevel  * Definition in /usr/include/sys/dnlc.h
3261341Sstevel  */
3271341Sstevel 
3281341Sstevel static void
save_ncstats(HV * self,kstat_t * kp,int strip_str)3291341Sstevel save_ncstats(HV *self, kstat_t *kp, int strip_str)
3301341Sstevel {
3311341Sstevel 	struct ncstats *ncstatsp;
3321341Sstevel 
3331341Sstevel 	/* PERL_ASSERT(kp->ks_ndata == 1); */
3341341Sstevel 	PERL_ASSERT(kp->ks_data_size == sizeof (struct ncstats));
3351341Sstevel 	ncstatsp = (struct ncstats *)(kp->ks_data);
3361341Sstevel 
3371341Sstevel 	SAVE_INT32(self, ncstatsp, hits);
3381341Sstevel 	SAVE_INT32(self, ncstatsp, misses);
3391341Sstevel 	SAVE_INT32(self, ncstatsp, enters);
3401341Sstevel 	SAVE_INT32(self, ncstatsp, dbl_enters);
3411341Sstevel 	SAVE_INT32(self, ncstatsp, long_enter);
3421341Sstevel 	SAVE_INT32(self, ncstatsp, long_look);
3431341Sstevel 	SAVE_INT32(self, ncstatsp, move_to_front);
3441341Sstevel 	SAVE_INT32(self, ncstatsp, purges);
3451341Sstevel }
3461341Sstevel 
3471341Sstevel /*
3481341Sstevel  * Definition in  /usr/include/sys/sysinfo.h
3491341Sstevel  */
3501341Sstevel 
3511341Sstevel static void
save_sysinfo(HV * self,kstat_t * kp,int strip_str)3521341Sstevel save_sysinfo(HV *self, kstat_t *kp, int strip_str)
3531341Sstevel {
3541341Sstevel 	sysinfo_t *sysinfop;
3551341Sstevel 
3561341Sstevel 	/* PERL_ASSERT(kp->ks_ndata == 1); */
3571341Sstevel 	PERL_ASSERT(kp->ks_data_size == sizeof (sysinfo_t));
3581341Sstevel 	sysinfop = (sysinfo_t *)(kp->ks_data);
3591341Sstevel 
3601341Sstevel 	SAVE_UINT32(self, sysinfop, updates);
3611341Sstevel 	SAVE_UINT32(self, sysinfop, runque);
3621341Sstevel 	SAVE_UINT32(self, sysinfop, runocc);
3631341Sstevel 	SAVE_UINT32(self, sysinfop, swpque);
3641341Sstevel 	SAVE_UINT32(self, sysinfop, swpocc);
3651341Sstevel 	SAVE_UINT32(self, sysinfop, waiting);
3661341Sstevel }
3671341Sstevel 
3681341Sstevel /*
3691341Sstevel  * Definition in  /usr/include/sys/sysinfo.h
3701341Sstevel  */
3711341Sstevel 
3721341Sstevel static void
save_vminfo(HV * self,kstat_t * kp,int strip_str)3731341Sstevel save_vminfo(HV *self, kstat_t *kp, int strip_str)
3741341Sstevel {
3751341Sstevel 	vminfo_t *vminfop;
3761341Sstevel 
3771341Sstevel 	/* PERL_ASSERT(kp->ks_ndata == 1); */
3781341Sstevel 	PERL_ASSERT(kp->ks_data_size == sizeof (vminfo_t));
3791341Sstevel 	vminfop = (vminfo_t *)(kp->ks_data);
3801341Sstevel 
3811341Sstevel 	SAVE_UINT64(self, vminfop, freemem);
3821341Sstevel 	SAVE_UINT64(self, vminfop, swap_resv);
3831341Sstevel 	SAVE_UINT64(self, vminfop, swap_alloc);
3841341Sstevel 	SAVE_UINT64(self, vminfop, swap_avail);
3851341Sstevel 	SAVE_UINT64(self, vminfop, swap_free);
3861341Sstevel }
3871341Sstevel 
3881341Sstevel /*
3891341Sstevel  * Definition in /usr/include/nfs/nfs_clnt.h
3901341Sstevel  */
3911341Sstevel 
3921341Sstevel static void
save_nfs(HV * self,kstat_t * kp,int strip_str)3931341Sstevel save_nfs(HV *self, kstat_t *kp, int strip_str)
3941341Sstevel {
3951341Sstevel 	struct mntinfo_kstat *mntinfop;
3961341Sstevel 
3971341Sstevel 	/* PERL_ASSERT(kp->ks_ndata == 1); */
3981341Sstevel 	PERL_ASSERT(kp->ks_data_size == sizeof (struct mntinfo_kstat));
3991341Sstevel 	mntinfop = (struct mntinfo_kstat *)(kp->ks_data);
4001341Sstevel 
4011341Sstevel 	SAVE_STRING(self, mntinfop, mik_proto, strip_str);
4021341Sstevel 	SAVE_UINT32(self, mntinfop, mik_vers);
4031341Sstevel 	SAVE_UINT32(self, mntinfop, mik_flags);
4041341Sstevel 	SAVE_UINT32(self, mntinfop, mik_secmod);
4051341Sstevel 	SAVE_UINT32(self, mntinfop, mik_curread);
4061341Sstevel 	SAVE_UINT32(self, mntinfop, mik_curwrite);
4071341Sstevel 	SAVE_INT32(self, mntinfop, mik_timeo);
4081341Sstevel 	SAVE_INT32(self, mntinfop, mik_retrans);
4091341Sstevel 	SAVE_UINT32(self, mntinfop, mik_acregmin);
4101341Sstevel 	SAVE_UINT32(self, mntinfop, mik_acregmax);
4111341Sstevel 	SAVE_UINT32(self, mntinfop, mik_acdirmin);
4121341Sstevel 	SAVE_UINT32(self, mntinfop, mik_acdirmax);
4131341Sstevel 	hv_store(self, "lookup_srtt", 11,
4141341Sstevel 	    NEW_UV(mntinfop->mik_timers[0].srtt), 0);
4151341Sstevel 	hv_store(self, "lookup_deviate", 14,
4161341Sstevel 	    NEW_UV(mntinfop->mik_timers[0].deviate), 0);
4171341Sstevel 	hv_store(self, "lookup_rtxcur", 13,
4181341Sstevel 	    NEW_UV(mntinfop->mik_timers[0].rtxcur), 0);
4191341Sstevel 	hv_store(self, "read_srtt", 9,
4201341Sstevel 	    NEW_UV(mntinfop->mik_timers[1].srtt), 0);
4211341Sstevel 	hv_store(self, "read_deviate", 12,
4221341Sstevel 	    NEW_UV(mntinfop->mik_timers[1].deviate), 0);
4231341Sstevel 	hv_store(self, "read_rtxcur", 11,
4241341Sstevel 	    NEW_UV(mntinfop->mik_timers[1].rtxcur), 0);
4251341Sstevel 	hv_store(self, "write_srtt", 10,
4261341Sstevel 	    NEW_UV(mntinfop->mik_timers[2].srtt), 0);
4271341Sstevel 	hv_store(self, "write_deviate", 13,
4281341Sstevel 	    NEW_UV(mntinfop->mik_timers[2].deviate), 0);
4291341Sstevel 	hv_store(self, "write_rtxcur", 12,
4301341Sstevel 	    NEW_UV(mntinfop->mik_timers[2].rtxcur), 0);
4311341Sstevel 	SAVE_UINT32(self, mntinfop, mik_noresponse);
4321341Sstevel 	SAVE_UINT32(self, mntinfop, mik_failover);
4331341Sstevel 	SAVE_UINT32(self, mntinfop, mik_remap);
4341341Sstevel 	SAVE_STRING(self, mntinfop, mik_curserver, strip_str);
4351341Sstevel }
4361341Sstevel 
4371341Sstevel /*
4381341Sstevel  * The following struct => hash functions are all only present on the sparc
4391341Sstevel  * platform, so they are all conditionally compiled depending on __sparc
4401341Sstevel  */
4411341Sstevel 
4421341Sstevel /*
4431341Sstevel  * Definition in /usr/platform/sun4u/include/vm/hat_sfmmu.h
4441341Sstevel  */
4451341Sstevel 
4461341Sstevel #ifdef __sparc
4471341Sstevel static void
save_sfmmu_global_stat(HV * self,kstat_t * kp,int strip_str)4481341Sstevel save_sfmmu_global_stat(HV *self, kstat_t *kp, int strip_str)
4491341Sstevel {
4501341Sstevel 	struct sfmmu_global_stat *sfmmugp;
4511341Sstevel 
4521341Sstevel 	/* PERL_ASSERT(kp->ks_ndata == 1); */
4531341Sstevel 	PERL_ASSERT(kp->ks_data_size == sizeof (struct sfmmu_global_stat));
4541341Sstevel 	sfmmugp = (struct sfmmu_global_stat *)(kp->ks_data);
4551341Sstevel 
4561341Sstevel 	SAVE_INT32(self, sfmmugp, sf_tsb_exceptions);
4571341Sstevel 	SAVE_INT32(self, sfmmugp, sf_tsb_raise_exception);
4581341Sstevel 	SAVE_INT32(self, sfmmugp, sf_pagefaults);
4591341Sstevel 	SAVE_INT32(self, sfmmugp, sf_uhash_searches);
4601341Sstevel 	SAVE_INT32(self, sfmmugp, sf_uhash_links);
4611341Sstevel 	SAVE_INT32(self, sfmmugp, sf_khash_searches);
4621341Sstevel 	SAVE_INT32(self, sfmmugp, sf_khash_links);
4631341Sstevel 	SAVE_INT32(self, sfmmugp, sf_swapout);
4641341Sstevel 	SAVE_INT32(self, sfmmugp, sf_tsb_alloc);
4651341Sstevel 	SAVE_INT32(self, sfmmugp, sf_tsb_allocfail);
4661341Sstevel 	SAVE_INT32(self, sfmmugp, sf_tsb_sectsb_create);
4674528Spaulsan 	SAVE_INT32(self, sfmmugp, sf_scd_1sttsb_alloc);
4684528Spaulsan 	SAVE_INT32(self, sfmmugp, sf_scd_2ndtsb_alloc);
4694528Spaulsan 	SAVE_INT32(self, sfmmugp, sf_scd_1sttsb_allocfail);
4704528Spaulsan 	SAVE_INT32(self, sfmmugp, sf_scd_2ndtsb_allocfail);
4711341Sstevel 	SAVE_INT32(self, sfmmugp, sf_tteload8k);
4721341Sstevel 	SAVE_INT32(self, sfmmugp, sf_tteload64k);
4731341Sstevel 	SAVE_INT32(self, sfmmugp, sf_tteload512k);
4741341Sstevel 	SAVE_INT32(self, sfmmugp, sf_tteload4m);
4751341Sstevel 	SAVE_INT32(self, sfmmugp, sf_tteload32m);
4761341Sstevel 	SAVE_INT32(self, sfmmugp, sf_tteload256m);
4771341Sstevel 	SAVE_INT32(self, sfmmugp, sf_tsb_load8k);
4781341Sstevel 	SAVE_INT32(self, sfmmugp, sf_tsb_load4m);
4791341Sstevel 	SAVE_INT32(self, sfmmugp, sf_hblk_hit);
4801341Sstevel 	SAVE_INT32(self, sfmmugp, sf_hblk8_ncreate);
4811341Sstevel 	SAVE_INT32(self, sfmmugp, sf_hblk8_nalloc);
4821341Sstevel 	SAVE_INT32(self, sfmmugp, sf_hblk1_ncreate);
4831341Sstevel 	SAVE_INT32(self, sfmmugp, sf_hblk1_nalloc);
4841341Sstevel 	SAVE_INT32(self, sfmmugp, sf_hblk_slab_cnt);
4851341Sstevel 	SAVE_INT32(self, sfmmugp, sf_hblk_reserve_cnt);
4861341Sstevel 	SAVE_INT32(self, sfmmugp, sf_hblk_recurse_cnt);
4871341Sstevel 	SAVE_INT32(self, sfmmugp, sf_hblk_reserve_hit);
4881341Sstevel 	SAVE_INT32(self, sfmmugp, sf_get_free_success);
4891341Sstevel 	SAVE_INT32(self, sfmmugp, sf_get_free_throttle);
4901341Sstevel 	SAVE_INT32(self, sfmmugp, sf_get_free_fail);
4911341Sstevel 	SAVE_INT32(self, sfmmugp, sf_put_free_success);
4921341Sstevel 	SAVE_INT32(self, sfmmugp, sf_put_free_fail);
4931341Sstevel 	SAVE_INT32(self, sfmmugp, sf_pgcolor_conflict);
4941341Sstevel 	SAVE_INT32(self, sfmmugp, sf_uncache_conflict);
4951341Sstevel 	SAVE_INT32(self, sfmmugp, sf_unload_conflict);
4961341Sstevel 	SAVE_INT32(self, sfmmugp, sf_ism_uncache);
4971341Sstevel 	SAVE_INT32(self, sfmmugp, sf_ism_recache);
4981341Sstevel 	SAVE_INT32(self, sfmmugp, sf_recache);
4991341Sstevel 	SAVE_INT32(self, sfmmugp, sf_steal_count);
5001341Sstevel 	SAVE_INT32(self, sfmmugp, sf_pagesync);
5011341Sstevel 	SAVE_INT32(self, sfmmugp, sf_clrwrt);
5021341Sstevel 	SAVE_INT32(self, sfmmugp, sf_pagesync_invalid);
5031341Sstevel 	SAVE_INT32(self, sfmmugp, sf_kernel_xcalls);
5041341Sstevel 	SAVE_INT32(self, sfmmugp, sf_user_xcalls);
5051341Sstevel 	SAVE_INT32(self, sfmmugp, sf_tsb_grow);
5061341Sstevel 	SAVE_INT32(self, sfmmugp, sf_tsb_shrink);
5071341Sstevel 	SAVE_INT32(self, sfmmugp, sf_tsb_resize_failures);
5081341Sstevel 	SAVE_INT32(self, sfmmugp, sf_tsb_reloc);
5091341Sstevel 	SAVE_INT32(self, sfmmugp, sf_user_vtop);
5102241Shuah 	SAVE_INT32(self, sfmmugp, sf_ctx_inv);
5111341Sstevel 	SAVE_INT32(self, sfmmugp, sf_tlb_reprog_pgsz);
5124528Spaulsan 	SAVE_INT32(self, sfmmugp, sf_region_remap_demap);
5134528Spaulsan 	SAVE_INT32(self, sfmmugp, sf_create_scd);
5144528Spaulsan 	SAVE_INT32(self, sfmmugp, sf_join_scd);
5154528Spaulsan 	SAVE_INT32(self, sfmmugp, sf_leave_scd);
5164528Spaulsan 	SAVE_INT32(self, sfmmugp, sf_destroy_scd);
5171341Sstevel }
5181341Sstevel #endif
5191341Sstevel 
5201341Sstevel /*
5211341Sstevel  * Definition in /usr/platform/sun4u/include/vm/hat_sfmmu.h
5221341Sstevel  */
5231341Sstevel 
5241341Sstevel #ifdef __sparc
5251341Sstevel static void
save_sfmmu_tsbsize_stat(HV * self,kstat_t * kp,int strip_str)5261341Sstevel save_sfmmu_tsbsize_stat(HV *self, kstat_t *kp, int strip_str)
5271341Sstevel {
5281341Sstevel 	struct sfmmu_tsbsize_stat *sfmmutp;
5291341Sstevel 
5301341Sstevel 	/* PERL_ASSERT(kp->ks_ndata == 1); */
5311341Sstevel 	PERL_ASSERT(kp->ks_data_size == sizeof (struct sfmmu_tsbsize_stat));
5321341Sstevel 	sfmmutp = (struct sfmmu_tsbsize_stat *)(kp->ks_data);
5331341Sstevel 
5341341Sstevel 	SAVE_INT32(self, sfmmutp, sf_tsbsz_8k);
5351341Sstevel 	SAVE_INT32(self, sfmmutp, sf_tsbsz_16k);
5361341Sstevel 	SAVE_INT32(self, sfmmutp, sf_tsbsz_32k);
5371341Sstevel 	SAVE_INT32(self, sfmmutp, sf_tsbsz_64k);
5381341Sstevel 	SAVE_INT32(self, sfmmutp, sf_tsbsz_128k);
5391341Sstevel 	SAVE_INT32(self, sfmmutp, sf_tsbsz_256k);
5401341Sstevel 	SAVE_INT32(self, sfmmutp, sf_tsbsz_512k);
5411341Sstevel 	SAVE_INT32(self, sfmmutp, sf_tsbsz_1m);
5421341Sstevel 	SAVE_INT32(self, sfmmutp, sf_tsbsz_2m);
5431341Sstevel 	SAVE_INT32(self, sfmmutp, sf_tsbsz_4m);
5441341Sstevel }
5451341Sstevel #endif
5461341Sstevel 
5471341Sstevel /*
5481341Sstevel  * Definition in /usr/platform/sun4u/include/sys/simmstat.h
5491341Sstevel  */
5501341Sstevel 
5511341Sstevel #ifdef __sparc
5521341Sstevel static void
save_simmstat(HV * self,kstat_t * kp,int strip_str)5531341Sstevel save_simmstat(HV *self, kstat_t *kp, int strip_str)
5541341Sstevel {
5551341Sstevel 	uchar_t	*simmstatp;
5561341Sstevel 	SV	*list;
5571341Sstevel 	int	i;
5581341Sstevel 
5591341Sstevel 	/* PERL_ASSERT(kp->ks_ndata == 1); */
5601341Sstevel 	PERL_ASSERT(kp->ks_data_size == sizeof (uchar_t) * SIMM_COUNT);
5611341Sstevel 
5621341Sstevel 	list = newSVpv("", 0);
5631341Sstevel 	for (i = 0, simmstatp = (uchar_t *)(kp->ks_data);
5641341Sstevel 	i < SIMM_COUNT - 1; i++, simmstatp++) {
5651341Sstevel 		sv_catpvf(list, "%d,", *simmstatp);
5661341Sstevel 	}
5671341Sstevel 	sv_catpvf(list, "%d", *simmstatp);
5681341Sstevel 	hv_store(self, "status", 6, list, 0);
5691341Sstevel }
5701341Sstevel #endif
5711341Sstevel 
5721341Sstevel /*
5731341Sstevel  * Used by save_temperature to make CSV lists from arrays of
5741341Sstevel  * short temperature values
5751341Sstevel  */
5761341Sstevel 
5771341Sstevel #ifdef __sparc
5781341Sstevel static SV *
short_array_to_SV(short * shortp,int len)5791341Sstevel short_array_to_SV(short *shortp, int len)
5801341Sstevel {
5811341Sstevel 	SV  *list;
5821341Sstevel 
5831341Sstevel 	list = newSVpv("", 0);
5841341Sstevel 	for (; len > 1; len--, shortp++) {
5851341Sstevel 		sv_catpvf(list, "%d,", *shortp);
5861341Sstevel 	}
5871341Sstevel 	sv_catpvf(list, "%d", *shortp);
5881341Sstevel 	return (list);
5891341Sstevel }
5901341Sstevel 
5911341Sstevel /*
5921341Sstevel  * Definition in /usr/platform/sun4u/include/sys/fhc.h
5931341Sstevel  */
5941341Sstevel 
5951341Sstevel static void
save_temperature(HV * self,kstat_t * kp,int strip_str)5961341Sstevel save_temperature(HV *self, kstat_t *kp, int strip_str)
5971341Sstevel {
5981341Sstevel 	struct temp_stats *tempsp;
5991341Sstevel 
6001341Sstevel 	/* PERL_ASSERT(kp->ks_ndata == 1); */
6011341Sstevel 	PERL_ASSERT(kp->ks_data_size == sizeof (struct temp_stats));
6021341Sstevel 	tempsp = (struct temp_stats *)(kp->ks_data);
6031341Sstevel 
6041341Sstevel 	SAVE_UINT32(self, tempsp, index);
6051341Sstevel 	hv_store(self, "l1", 2, short_array_to_SV(tempsp->l1, L1_SZ), 0);
6061341Sstevel 	hv_store(self, "l2", 2, short_array_to_SV(tempsp->l2, L2_SZ), 0);
6071341Sstevel 	hv_store(self, "l3", 2, short_array_to_SV(tempsp->l3, L3_SZ), 0);
6081341Sstevel 	hv_store(self, "l4", 2, short_array_to_SV(tempsp->l4, L4_SZ), 0);
6091341Sstevel 	hv_store(self, "l5", 2, short_array_to_SV(tempsp->l5, L5_SZ), 0);
6101341Sstevel 	SAVE_INT32(self, tempsp, max);
6111341Sstevel 	SAVE_INT32(self, tempsp, min);
6121341Sstevel 	SAVE_INT32(self, tempsp, state);
6131341Sstevel 	SAVE_INT32(self, tempsp, temp_cnt);
6141341Sstevel 	SAVE_INT32(self, tempsp, shutdown_cnt);
6151341Sstevel 	SAVE_INT32(self, tempsp, version);
6161341Sstevel 	SAVE_INT32(self, tempsp, trend);
6171341Sstevel 	SAVE_INT32(self, tempsp, override);
6181341Sstevel }
6191341Sstevel #endif
6201341Sstevel 
6211341Sstevel /*
6221341Sstevel  * Not actually defined anywhere - just a short.  Yuck.
6231341Sstevel  */
6241341Sstevel 
6251341Sstevel #ifdef __sparc
6261341Sstevel static void
save_temp_over(HV * self,kstat_t * kp,int strip_str)6271341Sstevel save_temp_over(HV *self, kstat_t *kp, int strip_str)
6281341Sstevel {
6291341Sstevel 	short *shortp;
6301341Sstevel 
6311341Sstevel 	/* PERL_ASSERT(kp->ks_ndata == 1); */
6321341Sstevel 	PERL_ASSERT(kp->ks_data_size == sizeof (short));
6331341Sstevel 
6341341Sstevel 	shortp = (short *)(kp->ks_data);
6351341Sstevel 	hv_store(self, "override", 8, newSViv(*shortp), 0);
6361341Sstevel }
6371341Sstevel #endif
6381341Sstevel 
6391341Sstevel /*
6401341Sstevel  * Defined in /usr/platform/sun4u/include/sys/sysctrl.h
6411341Sstevel  * (Well, sort of.  Actually there's no structure, just a list of #defines
6421341Sstevel  * enumerating *some* of the array indexes.)
6431341Sstevel  */
6441341Sstevel 
6451341Sstevel #ifdef __sparc
6461341Sstevel static void
save_ps_shadow(HV * self,kstat_t * kp,int strip_str)6471341Sstevel save_ps_shadow(HV *self, kstat_t *kp, int strip_str)
6481341Sstevel {
6491341Sstevel 	uchar_t *ucharp;
6501341Sstevel 
6511341Sstevel 	/* PERL_ASSERT(kp->ks_ndata == 1); */
6521341Sstevel 	PERL_ASSERT(kp->ks_data_size == SYS_PS_COUNT);
6531341Sstevel 
6541341Sstevel 	ucharp = (uchar_t *)(kp->ks_data);
6551341Sstevel 	hv_store(self, "core_0", 6, newSViv(*ucharp++), 0);
6561341Sstevel 	hv_store(self, "core_1", 6, newSViv(*ucharp++), 0);
6571341Sstevel 	hv_store(self, "core_2", 6, newSViv(*ucharp++), 0);
6581341Sstevel 	hv_store(self, "core_3", 6, newSViv(*ucharp++), 0);
6591341Sstevel 	hv_store(self, "core_4", 6, newSViv(*ucharp++), 0);
6601341Sstevel 	hv_store(self, "core_5", 6, newSViv(*ucharp++), 0);
6611341Sstevel 	hv_store(self, "core_6", 6, newSViv(*ucharp++), 0);
6621341Sstevel 	hv_store(self, "core_7", 6, newSViv(*ucharp++), 0);
6631341Sstevel 	hv_store(self, "pps_0", 5, newSViv(*ucharp++), 0);
6641341Sstevel 	hv_store(self, "clk_33", 6, newSViv(*ucharp++), 0);
6651341Sstevel 	hv_store(self, "clk_50", 6, newSViv(*ucharp++), 0);
6661341Sstevel 	hv_store(self, "v5_p", 4, newSViv(*ucharp++), 0);
6671341Sstevel 	hv_store(self, "v12_p", 5, newSViv(*ucharp++), 0);
6681341Sstevel 	hv_store(self, "v5_aux", 6, newSViv(*ucharp++), 0);
6691341Sstevel 	hv_store(self, "v5_p_pch", 8, newSViv(*ucharp++), 0);
6701341Sstevel 	hv_store(self, "v12_p_pch", 9, newSViv(*ucharp++), 0);
6711341Sstevel 	hv_store(self, "v3_pch", 6, newSViv(*ucharp++), 0);
6721341Sstevel 	hv_store(self, "v5_pch", 6, newSViv(*ucharp++), 0);
6731341Sstevel 	hv_store(self, "p_fan", 5, newSViv(*ucharp++), 0);
6741341Sstevel }
6751341Sstevel #endif
6761341Sstevel 
6771341Sstevel /*
6781341Sstevel  * Definition in /usr/platform/sun4u/include/sys/fhc.h
6791341Sstevel  */
6801341Sstevel 
6811341Sstevel #ifdef __sparc
6821341Sstevel static void
save_fault_list(HV * self,kstat_t * kp,int strip_str)6831341Sstevel save_fault_list(HV *self, kstat_t *kp, int strip_str)
6841341Sstevel {
6851341Sstevel 	struct ft_list	*faultp;
6861341Sstevel 	int		i;
6871341Sstevel 	char		name[KSTAT_STRLEN + 7];	/* room for 999999 faults */
6881341Sstevel 
6891341Sstevel 	/* PERL_ASSERT(kp->ks_ndata == 1); */
6901341Sstevel 	/* PERL_ASSERT(kp->ks_data_size == sizeof (struct ft_list)); */
6911341Sstevel 
6921341Sstevel 	for (i = 1, faultp = (struct ft_list *)(kp->ks_data);
6931341Sstevel 	    i <= 999999 && i <= kp->ks_data_size / sizeof (struct ft_list);
6941341Sstevel 	    i++, faultp++) {
6951341Sstevel 		(void) snprintf(name, sizeof (name), "unit_%d", i);
6961341Sstevel 		hv_store(self, name, strlen(name), newSViv(faultp->unit), 0);
6971341Sstevel 		(void) snprintf(name, sizeof (name), "type_%d", i);
6981341Sstevel 		hv_store(self, name, strlen(name), newSViv(faultp->type), 0);
6991341Sstevel 		(void) snprintf(name, sizeof (name), "fclass_%d", i);
7001341Sstevel 		hv_store(self, name, strlen(name), newSViv(faultp->fclass), 0);
7011341Sstevel 		(void) snprintf(name, sizeof (name), "create_time_%d", i);
7021341Sstevel 		hv_store(self, name, strlen(name),
7031341Sstevel 		    NEW_UV(faultp->create_time), 0);
7041341Sstevel 		(void) snprintf(name, sizeof (name), "msg_%d", i);
7051341Sstevel 		hv_store(self, name, strlen(name), newSVpv(faultp->msg, 0), 0);
7061341Sstevel 	}
7071341Sstevel }
7081341Sstevel #endif
7091341Sstevel 
7101341Sstevel /*
7111341Sstevel  * We need to be able to find the function corresponding to a particular raw
7121341Sstevel  * kstat.  To do this we ignore the instance and glue the module and name
7131341Sstevel  * together to form a composite key.  We can then use the data in the kstat
7141341Sstevel  * structure to find the appropriate function.  We use a perl hash to manage the
7151341Sstevel  * lookup, where the key is "module:name" and the value is a pointer to the
7161341Sstevel  * appropriate C function.
7171341Sstevel  *
7181341Sstevel  * Note that some kstats include the instance number as part of the module
7191341Sstevel  * and/or name.  This could be construed as a bug.  However, to work around this
7201341Sstevel  * we omit any digits from the module and name as we build the table in
7211341Sstevel  * build_raw_kstat_loopup(), and we remove any digits from the module and name
7221341Sstevel  * when we look up the functions in lookup_raw_kstat_fn()
7231341Sstevel  */
7241341Sstevel 
7251341Sstevel /*
7261341Sstevel  * This function is called when the XS is first dlopen()ed, and builds the
7271341Sstevel  * lookup table as described above.
7281341Sstevel  */
7291341Sstevel 
7301341Sstevel static void
build_raw_kstat_lookup()7311341Sstevel build_raw_kstat_lookup()
7321341Sstevel 	{
7331341Sstevel 	/* Create new hash */
7341341Sstevel 	raw_kstat_lookup = newHV();
7351341Sstevel 
7361341Sstevel 	SAVE_FNP(raw_kstat_lookup, save_cpu_stat, "cpu_stat:cpu_stat");
7371341Sstevel 	SAVE_FNP(raw_kstat_lookup, save_var, "unix:var");
7381341Sstevel 	SAVE_FNP(raw_kstat_lookup, save_ncstats, "unix:ncstats");
7391341Sstevel 	SAVE_FNP(raw_kstat_lookup, save_sysinfo, "unix:sysinfo");
7401341Sstevel 	SAVE_FNP(raw_kstat_lookup, save_vminfo, "unix:vminfo");
7411341Sstevel 	SAVE_FNP(raw_kstat_lookup, save_nfs, "nfs:mntinfo");
7421341Sstevel #ifdef __sparc
7431341Sstevel 	SAVE_FNP(raw_kstat_lookup, save_sfmmu_global_stat,
7441341Sstevel 	    "unix:sfmmu_global_stat");
7451341Sstevel 	SAVE_FNP(raw_kstat_lookup, save_sfmmu_tsbsize_stat,
7461341Sstevel 	    "unix:sfmmu_tsbsize_stat");
7471341Sstevel 	SAVE_FNP(raw_kstat_lookup, save_simmstat, "unix:simm-status");
7481341Sstevel 	SAVE_FNP(raw_kstat_lookup, save_temperature, "unix:temperature");
7491341Sstevel 	SAVE_FNP(raw_kstat_lookup, save_temp_over, "unix:temperature override");
7501341Sstevel 	SAVE_FNP(raw_kstat_lookup, save_ps_shadow, "unix:ps_shadow");
7511341Sstevel 	SAVE_FNP(raw_kstat_lookup, save_fault_list, "unix:fault_list");
7521341Sstevel #endif
7531341Sstevel }
7541341Sstevel 
7551341Sstevel /*
7561341Sstevel  * This finds and returns the raw kstat reader function corresponding to the
7571341Sstevel  * supplied module and name.  If no matching function exists, 0 is returned.
7581341Sstevel  */
7591341Sstevel 
lookup_raw_kstat_fn(char * module,char * name)7601341Sstevel static kstat_raw_reader_t lookup_raw_kstat_fn(char *module, char *name)
7611341Sstevel 	{
7621341Sstevel 	char			key[KSTAT_STRLEN * 2];
7631341Sstevel 	register char		*f, *t;
7641341Sstevel 	SV			**entry;
7651341Sstevel 	kstat_raw_reader_t	fnp;
7661341Sstevel 
7671341Sstevel 	/* Copy across module & name, removing any digits - see comment above */
7681341Sstevel 	for (f = module, t = key; *f != '\0'; f++, t++) {
7691341Sstevel 		while (*f != '\0' && isdigit(*f)) { f++; }
7701341Sstevel 		*t = *f;
7711341Sstevel 	}
7721341Sstevel 	*t++ = ':';
7731341Sstevel 	for (f = name; *f != '\0'; f++, t++) {
7741341Sstevel 		while (*f != '\0' && isdigit(*f)) {
7751341Sstevel 			f++;
7761341Sstevel 		}
7771341Sstevel 	*t = *f;
7781341Sstevel 	}
7791341Sstevel 	*t = '\0';
7801341Sstevel 
7811341Sstevel 	/* look up & return the function, or teturn 0 if not found */
7821341Sstevel 	if ((entry = hv_fetch(raw_kstat_lookup, key, strlen(key), FALSE)) == 0)
7831341Sstevel 	{
7841341Sstevel 		fnp = 0;
7851341Sstevel 	} else {
7861341Sstevel 		fnp = (kstat_raw_reader_t)(uintptr_t)SvIV(*entry);
7871341Sstevel 	}
7881341Sstevel 	return (fnp);
7891341Sstevel }
7901341Sstevel 
7911341Sstevel /*
7921341Sstevel  * This module converts the flat list returned by kstat_read() into a perl hash
7931341Sstevel  * tree keyed on module, instance, name and statistic.  The following functions
7941341Sstevel  * provide code to create the nested hashes, and to iterate over them.
7951341Sstevel  */
7961341Sstevel 
7971341Sstevel /*
7981341Sstevel  * Given module, instance and name keys return a pointer to the hash tied to
7991341Sstevel  * the bottommost hash.  If the hash already exists, we just return a pointer
8001341Sstevel  * to it, otherwise we create the hash and any others also required above it in
8011341Sstevel  * the hierarchy.  The returned tiehash is blessed into the
8021341Sstevel  * Sun::Solaris::Kstat::_Stat class, so that the appropriate TIEHASH methods are
8031341Sstevel  * called when the bottommost hash is accessed.  If the is_new parameter is
8041341Sstevel  * non-null it will be set to TRUE if a new tie has been created, and FALSE if
8051341Sstevel  * the tie already existed.
8061341Sstevel  */
8071341Sstevel 
8081341Sstevel static HV *
get_tie(SV * self,char * module,int instance,char * name,int * is_new)8091341Sstevel get_tie(SV *self, char *module, int instance, char *name, int *is_new)
8101341Sstevel {
8111341Sstevel 	char str_inst[11];	/* big enough for up to 10^10 instances */
8121341Sstevel 	char *key[3];		/* 3 part key: module, instance, name */
8131341Sstevel 	int  k;
8141341Sstevel 	int  new;
8151341Sstevel 	HV   *hash;
8161341Sstevel 	HV   *tie;
8171341Sstevel 
8181341Sstevel 	/* Create the keys */
8191341Sstevel 	(void) snprintf(str_inst, sizeof (str_inst), "%d", instance);
8201341Sstevel 	key[0] = module;
8211341Sstevel 	key[1] = str_inst;
8221341Sstevel 	key[2] = name;
8231341Sstevel 
8241341Sstevel 	/* Iteratively descend the tree, creating new hashes as required */
8251341Sstevel 	hash = (HV *)SvRV(self);
8261341Sstevel 	for (k = 0; k < 3; k++) {
8271341Sstevel 		SV **entry;
8281341Sstevel 
8291341Sstevel 		SvREADONLY_off(hash);
8301341Sstevel 		entry = hv_fetch(hash, key[k], strlen(key[k]), TRUE);
8311341Sstevel 
8321341Sstevel 		/* If the entry doesn't exist, create it */
8331341Sstevel 		if (! SvOK(*entry)) {
8341341Sstevel 			HV *newhash;
8351341Sstevel 			SV *rv;
8361341Sstevel 
8371341Sstevel 			newhash = newHV();
8381341Sstevel 			rv = newRV_noinc((SV *)newhash);
8391341Sstevel 			sv_setsv(*entry, rv);
8401341Sstevel 			SvREFCNT_dec(rv);
8411341Sstevel 			if (k < 2) {
8421341Sstevel 				SvREADONLY_on(newhash);
8431341Sstevel 			}
8441341Sstevel 			SvREADONLY_on(*entry);
8451341Sstevel 			SvREADONLY_on(hash);
8461341Sstevel 			hash = newhash;
8471341Sstevel 			new = 1;
8481341Sstevel 
8491341Sstevel 		/* Otherwise it already existed */
8501341Sstevel 		} else {
8511341Sstevel 			SvREADONLY_on(hash);
8521341Sstevel 			hash = (HV *)SvRV(*entry);
8531341Sstevel 			new = 0;
8541341Sstevel 		}
8551341Sstevel 	}
8561341Sstevel 
8571341Sstevel 	/* Create and bless a hash for the tie, if necessary */
8581341Sstevel 	if (new) {
8591341Sstevel 		SV *tieref;
8601341Sstevel 		HV *stash;
8611341Sstevel 
8621341Sstevel 		tie = newHV();
8631341Sstevel 		tieref = newRV_noinc((SV *)tie);
8641341Sstevel 		stash = gv_stashpv("Sun::Solaris::Kstat::_Stat", TRUE);
8651341Sstevel 		sv_bless(tieref, stash);
8661341Sstevel 
8671341Sstevel 		/* Add TIEHASH magic */
8681341Sstevel 		hv_magic(hash, (GV *)tieref, 'P');
8691341Sstevel 		SvREADONLY_on(hash);
8701341Sstevel 
8711341Sstevel 	/* Otherwise, just find the existing tied hash */
8721341Sstevel 	} else {
8731341Sstevel 		MAGIC *mg;
8741341Sstevel 
8751341Sstevel 		mg = mg_find((SV *)hash, 'P');
8761341Sstevel 		PERL_ASSERTMSG(mg != 0, "get_tie: lost P magic");
8771341Sstevel 		tie = (HV *)SvRV(mg->mg_obj);
8781341Sstevel 	}
8791341Sstevel 	if (is_new) {
8801341Sstevel 		*is_new = new;
8811341Sstevel 	}
8821341Sstevel 	return (tie);
8831341Sstevel }
8841341Sstevel 
8851341Sstevel /*
8861341Sstevel  * This is an iterator function used to traverse the hash hierarchy and apply
8871341Sstevel  * the passed function to the tied hashes at the bottom of the hierarchy.  If
8881341Sstevel  * any of the callback functions return 0, 0 is returned, otherwise 1
8891341Sstevel  */
8901341Sstevel 
8911341Sstevel static int
apply_to_ties(SV * self,ATTCb_t cb,void * arg)8921341Sstevel apply_to_ties(SV *self, ATTCb_t cb, void *arg)
8931341Sstevel {
8941341Sstevel 	HV	*hash1;
8951341Sstevel 	HE	*entry1;
8961341Sstevel 	long	s;
8971341Sstevel 	int	ret;
8981341Sstevel 
8991341Sstevel 	hash1 = (HV *)SvRV(self);
9001341Sstevel 	hv_iterinit(hash1);
9011341Sstevel 	ret = 1;
9021341Sstevel 
9031341Sstevel 	/* Iterate over each module */
9041341Sstevel 	while (entry1 = hv_iternext(hash1)) {
9051341Sstevel 		HV *hash2;
9061341Sstevel 		HE *entry2;
9071341Sstevel 
9081341Sstevel 		hash2 = (HV *)SvRV(hv_iterval(hash1, entry1));
9091341Sstevel 		hv_iterinit(hash2);
9101341Sstevel 
9111341Sstevel 		/* Iterate over each module:instance */
9121341Sstevel 		while (entry2 = hv_iternext(hash2)) {
9131341Sstevel 			HV *hash3;
9141341Sstevel 			HE *entry3;
9151341Sstevel 
9161341Sstevel 			hash3 = (HV *)SvRV(hv_iterval(hash2, entry2));
9171341Sstevel 			hv_iterinit(hash3);
9181341Sstevel 
9191341Sstevel 			/* Iterate over each module:instance:name */
9201341Sstevel 			while (entry3 = hv_iternext(hash3)) {
9211341Sstevel 				HV    *hash4;
9221341Sstevel 				MAGIC *mg;
9231341Sstevel 				HV    *tie;
9241341Sstevel 
9251341Sstevel 				/* Get the tie */
9261341Sstevel 				hash4 = (HV *)SvRV(hv_iterval(hash3, entry3));
9271341Sstevel 				mg = mg_find((SV *)hash4, 'P');
9281341Sstevel 				PERL_ASSERTMSG(mg != 0,
9291341Sstevel 				    "apply_to_ties: lost P magic");
9301341Sstevel 
9311341Sstevel 				/* Apply the callback */
9321341Sstevel 				if (! cb((HV *)SvRV(mg->mg_obj), arg)) {
9331341Sstevel 					ret = 0;
9341341Sstevel 				}
9351341Sstevel 			}
9361341Sstevel 		}
9371341Sstevel 	}
9381341Sstevel 	return (ret);
9391341Sstevel }
9401341Sstevel 
9411341Sstevel /*
9421341Sstevel  * Mark this HV as valid - used by update() when pruning deleted kstat nodes
9431341Sstevel  */
9441341Sstevel 
9451341Sstevel static int
set_valid(HV * self,void * arg)9461341Sstevel set_valid(HV *self, void *arg)
9471341Sstevel {
9481341Sstevel 	MAGIC *mg;
9491341Sstevel 
9501341Sstevel 	mg = mg_find((SV *)self, '~');
9511341Sstevel 	PERL_ASSERTMSG(mg != 0, "set_valid: lost ~ magic");
9521341Sstevel 	((KstatInfo_t *)SvPVX(mg->mg_obj))->valid = (int)arg;
9531341Sstevel 	return (1);
9541341Sstevel }
9551341Sstevel 
9561341Sstevel /*
9571341Sstevel  * Prune invalid kstat nodes. This is called when kstat_chain_update() detects
9581341Sstevel  * that the kstat chain has been updated.  This removes any hash tree entries
9591341Sstevel  * that no longer have a corresponding kstat.  If del is non-null it will be
9601341Sstevel  * set to the keys of the deleted kstat nodes, if any.  If any entries are
9611341Sstevel  * deleted 1 will be retured, otherwise 0
9621341Sstevel  */
9631341Sstevel 
9641341Sstevel static int
prune_invalid(SV * self,AV * del)9651341Sstevel prune_invalid(SV *self, AV *del)
9661341Sstevel {
9671341Sstevel 	HV	*hash1;
9681341Sstevel 	HE	*entry1;
9691341Sstevel 	STRLEN	klen;
9701341Sstevel 	char	*module, *instance, *name, *key;
9711341Sstevel 	int	ret;
9721341Sstevel 
9731341Sstevel 	hash1 = (HV *)SvRV(self);
9741341Sstevel 	hv_iterinit(hash1);
9751341Sstevel 	ret = 0;
9761341Sstevel 
9771341Sstevel 	/* Iterate over each module */
9781341Sstevel 	while (entry1 = hv_iternext(hash1)) {
9791341Sstevel 		HV *hash2;
9801341Sstevel 		HE *entry2;
9811341Sstevel 
9821341Sstevel 		module = HePV(entry1, PL_na);
9831341Sstevel 		hash2 = (HV *)SvRV(hv_iterval(hash1, entry1));
9841341Sstevel 		hv_iterinit(hash2);
9851341Sstevel 
9861341Sstevel 		/* Iterate over each module:instance */
9871341Sstevel 		while (entry2 = hv_iternext(hash2)) {
9881341Sstevel 			HV *hash3;
9891341Sstevel 			HE *entry3;
9901341Sstevel 
9911341Sstevel 			instance = HePV(entry2, PL_na);
9921341Sstevel 			hash3 = (HV *)SvRV(hv_iterval(hash2, entry2));
9931341Sstevel 			hv_iterinit(hash3);
9941341Sstevel 
9951341Sstevel 			/* Iterate over each module:instance:name */
9961341Sstevel 			while (entry3 = hv_iternext(hash3)) {
9971341Sstevel 				HV    *hash4;
9981341Sstevel 				MAGIC *mg;
9991341Sstevel 				HV    *tie;
10001341Sstevel 
10011341Sstevel 				name = HePV(entry3, PL_na);
10021341Sstevel 				hash4 = (HV *)SvRV(hv_iterval(hash3, entry3));
10031341Sstevel 				mg = mg_find((SV *)hash4, 'P');
10041341Sstevel 				PERL_ASSERTMSG(mg != 0,
10051341Sstevel 				    "prune_invalid: lost P magic");
10061341Sstevel 				tie = (HV *)SvRV(mg->mg_obj);
10071341Sstevel 				mg = mg_find((SV *)tie, '~');
10081341Sstevel 				PERL_ASSERTMSG(mg != 0,
10091341Sstevel 				    "prune_invalid: lost ~ magic");
10101341Sstevel 
10111341Sstevel 				/* If this is marked as invalid, prune it */
10121341Sstevel 				if (((KstatInfo_t *)SvPVX(
10131341Sstevel 				    (SV *)mg->mg_obj))->valid == FALSE) {
10141341Sstevel 					SvREADONLY_off(hash3);
10151341Sstevel 					key = HePV(entry3, klen);
10161341Sstevel 					hv_delete(hash3, key, klen, G_DISCARD);
10171341Sstevel 					SvREADONLY_on(hash3);
10181341Sstevel 					if (del) {
10191341Sstevel 						av_push(del,
10201341Sstevel 						    newSVpvf("%s:%s:%s",
10211341Sstevel 						    module, instance, name));
10221341Sstevel 					}
10231341Sstevel 					ret = 1;
10241341Sstevel 				}
10251341Sstevel 			}
10261341Sstevel 
10271341Sstevel 			/* If the module:instance:name hash is empty prune it */
10281341Sstevel 			if (HvKEYS(hash3) == 0) {
10291341Sstevel 				SvREADONLY_off(hash2);
10301341Sstevel 				key = HePV(entry2, klen);
10311341Sstevel 				hv_delete(hash2, key, klen, G_DISCARD);
10321341Sstevel 				SvREADONLY_on(hash2);
10331341Sstevel 			}
10341341Sstevel 		}
10351341Sstevel 		/* If the module:instance hash is empty prune it */
10361341Sstevel 		if (HvKEYS(hash2) == 0) {
10371341Sstevel 			SvREADONLY_off(hash1);
10381341Sstevel 			key = HePV(entry1, klen);
10391341Sstevel 			hv_delete(hash1, key, klen, G_DISCARD);
10401341Sstevel 			SvREADONLY_on(hash1);
10411341Sstevel 		}
10421341Sstevel 	}
10431341Sstevel 	return (ret);
10441341Sstevel }
10451341Sstevel 
10461341Sstevel /*
10471341Sstevel  * Named kstats are returned as a list of key/values.  This function converts
10481341Sstevel  * such a list into the equivalent perl datatypes, and stores them in the passed
10491341Sstevel  * hash.
10501341Sstevel  */
10511341Sstevel 
10521341Sstevel static void
save_named(HV * self,kstat_t * kp,int strip_str)10531341Sstevel save_named(HV *self, kstat_t *kp, int strip_str)
10541341Sstevel {
10551341Sstevel 	kstat_named_t	*knp;
10561341Sstevel 	int		n;
10571341Sstevel 	SV*		value;
10581341Sstevel 
10591341Sstevel 	for (n = kp->ks_ndata, knp = KSTAT_NAMED_PTR(kp); n > 0; n--, knp++) {
10601341Sstevel 		switch (knp->data_type) {
10611341Sstevel 		case KSTAT_DATA_CHAR:
10621341Sstevel 			value = newSVpv(knp->value.c, strip_str ?
10631341Sstevel 			    strlen(knp->value.c) : sizeof (knp->value.c));
10641341Sstevel 			break;
10651341Sstevel 		case KSTAT_DATA_INT32:
10661341Sstevel 			value = newSViv(knp->value.i32);
10671341Sstevel 			break;
10681341Sstevel 		case KSTAT_DATA_UINT32:
10691341Sstevel 			value = NEW_UV(knp->value.ui32);
10701341Sstevel 			break;
10711341Sstevel 		case KSTAT_DATA_INT64:
10721341Sstevel 			value = NEW_UV(knp->value.i64);
10731341Sstevel 			break;
10741341Sstevel 		case KSTAT_DATA_UINT64:
10751341Sstevel 			value = NEW_UV(knp->value.ui64);
10761341Sstevel 			break;
10771341Sstevel 		case KSTAT_DATA_STRING:
10781341Sstevel 			if (KSTAT_NAMED_STR_PTR(knp) == NULL)
10791341Sstevel 				value = newSVpv("null", sizeof ("null") - 1);
10801341Sstevel 			else
10811341Sstevel 				value = newSVpv(KSTAT_NAMED_STR_PTR(knp),
10821341Sstevel 						KSTAT_NAMED_STR_BUFLEN(knp) -1);
10831341Sstevel 			break;
10841341Sstevel 		default:
10851341Sstevel 			PERL_ASSERTMSG(0, "kstat_read: invalid data type");
10861341Sstevel 			break;
10871341Sstevel 		}
10881341Sstevel 		hv_store(self, knp->name, strlen(knp->name), value, 0);
10891341Sstevel 	}
10901341Sstevel }
10911341Sstevel 
10921341Sstevel /*
10931341Sstevel  * Save kstat interrupt statistics
10941341Sstevel  */
10951341Sstevel 
10961341Sstevel static void
save_intr(HV * self,kstat_t * kp,int strip_str)10971341Sstevel save_intr(HV *self, kstat_t *kp, int strip_str)
10981341Sstevel {
10991341Sstevel 	kstat_intr_t	*kintrp;
11001341Sstevel 	int		i;
11011341Sstevel 	static char	*intr_names[] =
11021341Sstevel 	    { "hard", "soft", "watchdog", "spurious", "multiple_service" };
11031341Sstevel 
11041341Sstevel 	PERL_ASSERT(kp->ks_ndata == 1);
11051341Sstevel 	PERL_ASSERT(kp->ks_data_size == sizeof (kstat_intr_t));
11061341Sstevel 	kintrp = KSTAT_INTR_PTR(kp);
11071341Sstevel 
11081341Sstevel 	for (i = 0; i < KSTAT_NUM_INTRS; i++) {
11091341Sstevel 		hv_store(self, intr_names[i], strlen(intr_names[i]),
11101341Sstevel 		    NEW_UV(kintrp->intrs[i]), 0);
11111341Sstevel 	}
11121341Sstevel }
11131341Sstevel 
11141341Sstevel /*
11151341Sstevel  * Save IO statistics
11161341Sstevel  */
11171341Sstevel 
11181341Sstevel static void
save_io(HV * self,kstat_t * kp,int strip_str)11191341Sstevel save_io(HV *self, kstat_t *kp, int strip_str)
11201341Sstevel {
11211341Sstevel 	kstat_io_t *kiop;
11221341Sstevel 
11231341Sstevel 	PERL_ASSERT(kp->ks_ndata == 1);
11241341Sstevel 	PERL_ASSERT(kp->ks_data_size == sizeof (kstat_io_t));
11251341Sstevel 	kiop = KSTAT_IO_PTR(kp);
11261341Sstevel 	SAVE_UINT64(self, kiop, nread);
11271341Sstevel 	SAVE_UINT64(self, kiop, nwritten);
11281341Sstevel 	SAVE_UINT32(self, kiop, reads);
11291341Sstevel 	SAVE_UINT32(self, kiop, writes);
11301341Sstevel 	SAVE_HRTIME(self, kiop, wtime);
11311341Sstevel 	SAVE_HRTIME(self, kiop, wlentime);
11321341Sstevel 	SAVE_HRTIME(self, kiop, wlastupdate);
11331341Sstevel 	SAVE_HRTIME(self, kiop, rtime);
11341341Sstevel 	SAVE_HRTIME(self, kiop, rlentime);
11351341Sstevel 	SAVE_HRTIME(self, kiop, rlastupdate);
11361341Sstevel 	SAVE_UINT32(self, kiop, wcnt);
11371341Sstevel 	SAVE_UINT32(self, kiop, rcnt);
11381341Sstevel }
11391341Sstevel 
11401341Sstevel /*
11411341Sstevel  * Save timer statistics
11421341Sstevel  */
11431341Sstevel 
11441341Sstevel static void
save_timer(HV * self,kstat_t * kp,int strip_str)11451341Sstevel save_timer(HV *self, kstat_t *kp, int strip_str)
11461341Sstevel {
11471341Sstevel 	kstat_timer_t *ktimerp;
11481341Sstevel 
11491341Sstevel 	PERL_ASSERT(kp->ks_ndata == 1);
11501341Sstevel 	PERL_ASSERT(kp->ks_data_size == sizeof (kstat_timer_t));
11511341Sstevel 	ktimerp = KSTAT_TIMER_PTR(kp);
11521341Sstevel 	SAVE_STRING(self, ktimerp, name, strip_str);
11531341Sstevel 	SAVE_UINT64(self, ktimerp, num_events);
11541341Sstevel 	SAVE_HRTIME(self, ktimerp, elapsed_time);
11551341Sstevel 	SAVE_HRTIME(self, ktimerp, min_time);
11561341Sstevel 	SAVE_HRTIME(self, ktimerp, max_time);
11571341Sstevel 	SAVE_HRTIME(self, ktimerp, start_time);
11581341Sstevel 	SAVE_HRTIME(self, ktimerp, stop_time);
11591341Sstevel }
11601341Sstevel 
11611341Sstevel /*
11621341Sstevel  * Read kstats and copy into the supplied perl hash structure.  If refresh is
11631341Sstevel  * true, this function is being called as part of the update() method.  In this
11641341Sstevel  * case it is only necessary to read the kstats if they have previously been
11651341Sstevel  * accessed (kip->read == TRUE).  If refresh is false, this function is being
11661341Sstevel  * called prior to returning a value to the caller. In this case, it is only
11671341Sstevel  * necessary to read the kstats if they have not previously been read.  If the
11681341Sstevel  * kstat_read() fails, 0 is returned, otherwise 1
11691341Sstevel  */
11701341Sstevel 
11711341Sstevel static int
read_kstats(HV * self,int refresh)11721341Sstevel read_kstats(HV *self, int refresh)
11731341Sstevel {
11741341Sstevel 	MAGIC			*mg;
11751341Sstevel 	KstatInfo_t		*kip;
11761341Sstevel 	kstat_raw_reader_t	fnp;
11771341Sstevel 
11781341Sstevel 	/* Find the MAGIC KstatInfo_t data structure */
11791341Sstevel 	mg = mg_find((SV *)self, '~');
11801341Sstevel 	PERL_ASSERTMSG(mg != 0, "read_kstats: lost ~ magic");
11811341Sstevel 	kip = (KstatInfo_t *)SvPVX(mg->mg_obj);
11821341Sstevel 
11831341Sstevel 	/* Return early if we don't need to actually read the kstats */
11841341Sstevel 	if ((refresh && ! kip->read) || (! refresh && kip->read)) {
11851341Sstevel 		return (1);
11861341Sstevel 	}
11871341Sstevel 
11881341Sstevel 	/* Read the kstats and return 0 if this fails */
11891341Sstevel 	if (kstat_read(kip->kstat_ctl, kip->kstat, NULL) < 0) {
11901341Sstevel 		return (0);
11911341Sstevel 	}
11921341Sstevel 
11931341Sstevel 	/* Save the read data */
11941341Sstevel 	hv_store(self, "snaptime", 8, NEW_HRTIME(kip->kstat->ks_snaptime), 0);
11951341Sstevel 	switch (kip->kstat->ks_type) {
11961341Sstevel 		case KSTAT_TYPE_RAW:
11971341Sstevel 			if ((fnp = lookup_raw_kstat_fn(kip->kstat->ks_module,
11981341Sstevel 			    kip->kstat->ks_name)) != 0) {
11991341Sstevel 				fnp(self, kip->kstat, kip->strip_str);
12001341Sstevel 			}
12011341Sstevel 			break;
12021341Sstevel 		case KSTAT_TYPE_NAMED:
12031341Sstevel 			save_named(self, kip->kstat, kip->strip_str);
12041341Sstevel 			break;
12051341Sstevel 		case KSTAT_TYPE_INTR:
12061341Sstevel 			save_intr(self, kip->kstat, kip->strip_str);
12071341Sstevel 			break;
12081341Sstevel 		case KSTAT_TYPE_IO:
12091341Sstevel 			save_io(self, kip->kstat, kip->strip_str);
12101341Sstevel 			break;
12111341Sstevel 		case KSTAT_TYPE_TIMER:
12121341Sstevel 			save_timer(self, kip->kstat, kip->strip_str);
12131341Sstevel 			break;
12141341Sstevel 		default:
12151341Sstevel 			PERL_ASSERTMSG(0, "read_kstats: illegal kstat type");
12161341Sstevel 			break;
12171341Sstevel 	}
12181341Sstevel 	kip->read = TRUE;
12191341Sstevel 	return (1);
12201341Sstevel }
12211341Sstevel 
12221341Sstevel /*
12231341Sstevel  * The XS code exported to perl is below here.  Note that the XS preprocessor
12241341Sstevel  * has its own commenting syntax, so all comments from this point on are in
12251341Sstevel  * that form.
12261341Sstevel  */
12271341Sstevel 
12281341Sstevel /* The following XS methods are the ABI of the Sun::Solaris::Kstat package */
12291341Sstevel 
12301341Sstevel MODULE = Sun::Solaris::Kstat PACKAGE = Sun::Solaris::Kstat
12311341Sstevel PROTOTYPES: ENABLE
12321341Sstevel 
12331341Sstevel  # Create the raw kstat to store function lookup table on load
12341341Sstevel BOOT:
12351341Sstevel 	build_raw_kstat_lookup();
12361341Sstevel 
12371341Sstevel  #
12381341Sstevel  # The Sun::Solaris::Kstat constructor.  This builds the nested
12391341Sstevel  # name::instance::module hash structure, but doesn't actually read the
12401341Sstevel  # underlying kstats.  This is done on demand by the TIEHASH methods in
12411341Sstevel  # Sun::Solaris::Kstat::_Stat
12421341Sstevel  #
12431341Sstevel 
12441341Sstevel SV*
12451341Sstevel new(class, ...)
12461341Sstevel 	char *class;
12471341Sstevel PREINIT:
12481341Sstevel 	HV		*stash;
12491341Sstevel 	kstat_ctl_t	*kc;
12501341Sstevel 	SV		*kcsv;
12511341Sstevel 	kstat_t		*kp;
12521341Sstevel 	KstatInfo_t	kstatinfo;
12531341Sstevel 	int		sp, strip_str;
12541341Sstevel CODE:
12551341Sstevel 	/* Check we have an even number of arguments, excluding the class */
12561341Sstevel 	sp = 1;
12571341Sstevel 	if (((items - sp) % 2) != 0) {
12581341Sstevel 		croak(DEBUG_ID ": new: invalid number of arguments");
12591341Sstevel 	}
12601341Sstevel 
12611341Sstevel 	/* Process any (name => value) arguments */
12621341Sstevel 	strip_str = 0;
12631341Sstevel 	while (sp < items) {
12641341Sstevel 		SV *name, *value;
12651341Sstevel 
12661341Sstevel 		name = ST(sp);
12671341Sstevel 		sp++;
12681341Sstevel 		value = ST(sp);
12691341Sstevel 		sp++;
12701341Sstevel 		if (strcmp(SvPVX(name), "strip_strings") == 0) {
12711341Sstevel 			strip_str = SvTRUE(value);
12721341Sstevel 		} else {
12731341Sstevel 			croak(DEBUG_ID ": new: invalid parameter name '%s'",
12741341Sstevel 			    SvPVX(name));
12751341Sstevel 		}
12761341Sstevel 	}
12771341Sstevel 
12781341Sstevel 	/* Open the kstats handle */
12791341Sstevel 	if ((kc = kstat_open()) == 0) {
12801341Sstevel 		XSRETURN_UNDEF;
12811341Sstevel 	}
12821341Sstevel 
12831341Sstevel 	/* Create a blessed hash ref */
12841341Sstevel 	RETVAL = (SV *)newRV_noinc((SV *)newHV());
12851341Sstevel 	stash = gv_stashpv(class, TRUE);
12861341Sstevel 	sv_bless(RETVAL, stash);
12871341Sstevel 
12881341Sstevel 	/* Create a place to save the KstatInfo_t structure */
12891341Sstevel 	kcsv = newSVpv((char *)&kc, sizeof (kc));
12901341Sstevel 	sv_magic(SvRV(RETVAL), kcsv, '~', 0, 0);
12911341Sstevel 	SvREFCNT_dec(kcsv);
12921341Sstevel 
12931341Sstevel 	/* Initialise the KstatsInfo_t structure */
12941341Sstevel 	kstatinfo.read = FALSE;
12951341Sstevel 	kstatinfo.valid = TRUE;
12961341Sstevel 	kstatinfo.strip_str = strip_str;
12971341Sstevel 	kstatinfo.kstat_ctl = kc;
12981341Sstevel 
12991341Sstevel 	/* Scan the kstat chain, building hash entries for the kstats */
13001341Sstevel 	for (kp = kc->kc_chain; kp != 0; kp = kp->ks_next) {
13011341Sstevel 		HV *tie;
13021341Sstevel 		SV *kstatsv;
13031341Sstevel 
13041341Sstevel 		/* Don't bother storing the kstat headers */
13051341Sstevel 		if (strncmp(kp->ks_name, "kstat_", 6) == 0) {
13061341Sstevel 			continue;
13071341Sstevel 		}
13081341Sstevel 
13091341Sstevel 		/* Don't bother storing raw stats we don't understand */
13101341Sstevel 		if (kp->ks_type == KSTAT_TYPE_RAW &&
13111341Sstevel 		    lookup_raw_kstat_fn(kp->ks_module, kp->ks_name) == 0) {
13121341Sstevel #ifdef REPORT_UNKNOWN
13131341Sstevel 			(void) fprintf(stderr,
13141341Sstevel 			    "Unknown kstat type %s:%d:%s - %d of size %d\n",
13151341Sstevel 			    kp->ks_module, kp->ks_instance, kp->ks_name,
13161341Sstevel 			    kp->ks_ndata, kp->ks_data_size);
13171341Sstevel #endif
13181341Sstevel 			continue;
13191341Sstevel 		}
13201341Sstevel 
13211341Sstevel 		/* Create a 3-layer hash hierarchy - module.instance.name */
13221341Sstevel 		tie = get_tie(RETVAL, kp->ks_module, kp->ks_instance,
13231341Sstevel 		    kp->ks_name, 0);
13241341Sstevel 
13251341Sstevel 		/* Save the data necessary to read the kstat info on demand */
13261341Sstevel 		hv_store(tie, "class", 5, newSVpv(kp->ks_class, 0), 0);
13271341Sstevel 		hv_store(tie, "crtime", 6, NEW_HRTIME(kp->ks_crtime), 0);
13281341Sstevel 		kstatinfo.kstat = kp;
13291341Sstevel 		kstatsv = newSVpv((char *)&kstatinfo, sizeof (kstatinfo));
13301341Sstevel 		sv_magic((SV *)tie, kstatsv, '~', 0, 0);
13311341Sstevel 		SvREFCNT_dec(kstatsv);
13321341Sstevel 	}
13331341Sstevel 	SvREADONLY_on(SvRV(RETVAL));
13341341Sstevel 	/* SvREADONLY_on(RETVAL); */
13351341Sstevel OUTPUT:
13361341Sstevel 	RETVAL
13371341Sstevel 
13381341Sstevel  #
13391341Sstevel  # Update the perl hash structure so that it is in line with the kernel kstats
13401341Sstevel  # data.  Only kstats athat have previously been accessed are read,
13411341Sstevel  #
13421341Sstevel 
13431341Sstevel  # Scalar context: true/false
13441341Sstevel  # Array context: (\@added, \@deleted)
13451341Sstevel void
13461341Sstevel update(self)
13471341Sstevel 	SV* self;
13481341Sstevel PREINIT:
13491341Sstevel 	MAGIC		*mg;
13501341Sstevel 	kstat_ctl_t	*kc;
13511341Sstevel 	kstat_t		*kp;
13521341Sstevel 	int		ret;
13531341Sstevel 	AV		*add, *del;
13541341Sstevel PPCODE:
13551341Sstevel 	/* Find the hidden KstatInfo_t structure */
13561341Sstevel 	mg = mg_find(SvRV(self), '~');
13571341Sstevel 	PERL_ASSERTMSG(mg != 0, "update: lost ~ magic");
13581341Sstevel 	kc = *(kstat_ctl_t **)SvPVX(mg->mg_obj);
13591341Sstevel 
13601341Sstevel 	/* Update the kstat chain, and return immediately on error. */
13611341Sstevel 	if ((ret = kstat_chain_update(kc)) == -1) {
13621341Sstevel 		if (GIMME_V == G_ARRAY) {
13631341Sstevel 			EXTEND(SP, 2);
13641341Sstevel 			PUSHs(sv_newmortal());
13651341Sstevel 			PUSHs(sv_newmortal());
13661341Sstevel 		} else {
13671341Sstevel 			EXTEND(SP, 1);
13681341Sstevel 			PUSHs(sv_2mortal(newSViv(ret)));
13691341Sstevel 		}
13701341Sstevel 	}
13711341Sstevel 
13721341Sstevel 	/* Create the arrays to be returned if in an array context */
13731341Sstevel 	if (GIMME_V == G_ARRAY) {
13741341Sstevel 		add = newAV();
13751341Sstevel 		del = newAV();
13761341Sstevel 	} else {
13771341Sstevel 		add = 0;
13781341Sstevel 		del = 0;
13791341Sstevel 	}
13801341Sstevel 
13811341Sstevel 	/*
13821341Sstevel 	 * If the kstat chain hasn't changed we can just reread any stats
13831341Sstevel 	 * that have already been read
13841341Sstevel 	 */
13851341Sstevel 	if (ret == 0) {
13861341Sstevel 		if (! apply_to_ties(self, (ATTCb_t)read_kstats, (void *)TRUE)) {
13871341Sstevel 			if (GIMME_V == G_ARRAY) {
13881341Sstevel 				EXTEND(SP, 2);
13891341Sstevel 				PUSHs(sv_2mortal(newRV_noinc((SV *)add)));
13901341Sstevel 				PUSHs(sv_2mortal(newRV_noinc((SV *)del)));
13911341Sstevel 			} else {
13921341Sstevel 				EXTEND(SP, 1);
13931341Sstevel 				PUSHs(sv_2mortal(newSViv(-1)));
13941341Sstevel 			}
13951341Sstevel 		}
13961341Sstevel 
13971341Sstevel 	/*
13981341Sstevel 	 * Otherwise we have to update the Perl structure so that it is in
13991341Sstevel 	 * agreement with the new kstat chain.  We do this in such a way as to
14001341Sstevel 	 * retain all the existing structures, just adding or deleting the
14011341Sstevel 	 * bare minimum.
14021341Sstevel 	 */
14031341Sstevel 	} else {
14041341Sstevel 		KstatInfo_t	kstatinfo;
14051341Sstevel 
14061341Sstevel 		/*
14071341Sstevel 		 * Step 1: set the 'invalid' flag on each entry
14081341Sstevel 		 */
14091341Sstevel 		apply_to_ties(self, &set_valid, (void *)FALSE);
14101341Sstevel 
14111341Sstevel 		/*
14121341Sstevel 		 * Step 2: Set the 'valid' flag on all entries still in the
14131341Sstevel 		 * kernel kstat chain
14141341Sstevel 		 */
14151341Sstevel 		kstatinfo.read		= FALSE;
14161341Sstevel 		kstatinfo.valid		= TRUE;
14171341Sstevel 		kstatinfo.kstat_ctl	= kc;
14181341Sstevel 		for (kp = kc->kc_chain; kp != 0; kp = kp->ks_next) {
14191341Sstevel 			int	new;
14201341Sstevel 			HV	*tie;
14211341Sstevel 
14221341Sstevel 			/* Don't bother storing the kstat headers or types */
14231341Sstevel 			if (strncmp(kp->ks_name, "kstat_", 6) == 0) {
14241341Sstevel 				continue;
14251341Sstevel 			}
14261341Sstevel 
14271341Sstevel 			/* Don't bother storing raw stats we don't understand */
14281341Sstevel 			if (kp->ks_type == KSTAT_TYPE_RAW &&
14291341Sstevel 			    lookup_raw_kstat_fn(kp->ks_module, kp->ks_name)
14301341Sstevel 			    == 0) {
14311341Sstevel #ifdef REPORT_UNKNOWN
14321341Sstevel 				(void) printf("Unknown kstat type %s:%d:%s "
14331341Sstevel 				    "- %d of size %d\n", kp->ks_module,
14341341Sstevel 				    kp->ks_instance, kp->ks_name,
14351341Sstevel 				    kp->ks_ndata, kp->ks_data_size);
14361341Sstevel #endif
14371341Sstevel 				continue;
14381341Sstevel 			}
14391341Sstevel 
14401341Sstevel 			/* Find the tied hash associated with the kstat entry */
14411341Sstevel 			tie = get_tie(self, kp->ks_module, kp->ks_instance,
14421341Sstevel 			    kp->ks_name, &new);
14431341Sstevel 
14441341Sstevel 			/* If newly created store the associated kstat info */
14451341Sstevel 			if (new) {
14461341Sstevel 				SV *kstatsv;
14471341Sstevel 
14481341Sstevel 				/*
14491341Sstevel 				 * Save the data necessary to read the kstat
14501341Sstevel 				 * info on demand
14511341Sstevel 				 */
14521341Sstevel 				hv_store(tie, "class", 5,
14531341Sstevel 				    newSVpv(kp->ks_class, 0), 0);
14541341Sstevel 				hv_store(tie, "crtime", 6,
14551341Sstevel 				    NEW_HRTIME(kp->ks_crtime), 0);
14561341Sstevel 				kstatinfo.kstat = kp;
14571341Sstevel 				kstatsv = newSVpv((char *)&kstatinfo,
14581341Sstevel 				    sizeof (kstatinfo));
14591341Sstevel 				sv_magic((SV *)tie, kstatsv, '~', 0, 0);
14601341Sstevel 				SvREFCNT_dec(kstatsv);
14611341Sstevel 
14621341Sstevel 				/* Save the key on the add list, if required */
14631341Sstevel 				if (GIMME_V == G_ARRAY) {
14641341Sstevel 					av_push(add, newSVpvf("%s:%d:%s",
14651341Sstevel 					    kp->ks_module, kp->ks_instance,
14661341Sstevel 					    kp->ks_name));
14671341Sstevel 				}
14681341Sstevel 
14691341Sstevel 			/* If the stats already exist, just update them */
14701341Sstevel 			} else {
14711341Sstevel 				MAGIC *mg;
14721341Sstevel 				KstatInfo_t *kip;
14731341Sstevel 
14741341Sstevel 				/* Find the hidden KstatInfo_t */
14751341Sstevel 				mg = mg_find((SV *)tie, '~');
14761341Sstevel 				PERL_ASSERTMSG(mg != 0, "update: lost ~ magic");
14771341Sstevel 				kip = (KstatInfo_t *)SvPVX(mg->mg_obj);
14781341Sstevel 
14791341Sstevel 				/* Mark the tie as valid */
14801341Sstevel 				kip->valid = TRUE;
14811341Sstevel 
14821341Sstevel 				/* Re-save the kstat_t pointer.  If the kstat
14831341Sstevel 				 * has been deleted and re-added since the last
14841341Sstevel 				 * update, the address of the kstat structure
14851341Sstevel 				 * will have changed, even though the kstat will
14861341Sstevel 				 * still live at the same place in the perl
14871341Sstevel 				 * hash tree structure.
14881341Sstevel 				 */
14891341Sstevel 				kip->kstat = kp;
14901341Sstevel 
14911341Sstevel 				/* Reread the stats, if read previously */
14921341Sstevel 				read_kstats(tie, TRUE);
14931341Sstevel 			}
14941341Sstevel 		}
14951341Sstevel 
14961341Sstevel 		/*
14971341Sstevel 		 *Step 3: Delete any entries still marked as 'invalid'
14981341Sstevel 		 */
14991341Sstevel 		ret = prune_invalid(self, del);
15001341Sstevel 
15011341Sstevel 	}
15021341Sstevel 	if (GIMME_V == G_ARRAY) {
15031341Sstevel 		EXTEND(SP, 2);
15041341Sstevel 		PUSHs(sv_2mortal(newRV_noinc((SV *)add)));
15051341Sstevel 		PUSHs(sv_2mortal(newRV_noinc((SV *)del)));
15061341Sstevel 	} else {
15071341Sstevel 		EXTEND(SP, 1);
15081341Sstevel 		PUSHs(sv_2mortal(newSViv(ret)));
15091341Sstevel 	}
15101341Sstevel 
15111341Sstevel 
15121341Sstevel  #
15131341Sstevel  # Destructor.  Closes the kstat connection
15141341Sstevel  #
15151341Sstevel 
15161341Sstevel void
15171341Sstevel DESTROY(self)
15181341Sstevel 	SV *self;
15191341Sstevel PREINIT:
15201341Sstevel 	MAGIC		*mg;
15211341Sstevel 	kstat_ctl_t	*kc;
15221341Sstevel CODE:
15231341Sstevel 	mg = mg_find(SvRV(self), '~');
15241341Sstevel 	PERL_ASSERTMSG(mg != 0, "DESTROY: lost ~ magic");
15251341Sstevel 	kc = *(kstat_ctl_t **)SvPVX(mg->mg_obj);
15261341Sstevel 	if (kstat_close(kc) != 0) {
15271341Sstevel 		croak(DEBUG_ID ": kstat_close: failed");
15281341Sstevel 	}
15291341Sstevel 
15301341Sstevel  #
15311341Sstevel  # The following XS methods implement the TIEHASH mechanism used to update the
15321341Sstevel  # kstats hash structure.  These are blessed into a package that isn't
15331341Sstevel  # visible to callers of the Sun::Solaris::Kstat module
15341341Sstevel  #
15351341Sstevel 
15361341Sstevel MODULE = Sun::Solaris::Kstat PACKAGE = Sun::Solaris::Kstat::_Stat
15371341Sstevel PROTOTYPES: ENABLE
15381341Sstevel 
15391341Sstevel  #
15401341Sstevel  # If a value has already been read, return it.  Otherwise read the appropriate
15411341Sstevel  # kstat and then return the value
15421341Sstevel  #
15431341Sstevel 
15441341Sstevel SV*
15451341Sstevel FETCH(self, key)
15461341Sstevel 	SV* self;
15471341Sstevel 	SV* key;
15481341Sstevel PREINIT:
15491341Sstevel 	char	*k;
15501341Sstevel 	STRLEN	klen;
15511341Sstevel 	SV	**value;
15521341Sstevel CODE:
15531341Sstevel 	self = SvRV(self);
15541341Sstevel 	k = SvPV(key, klen);
15551341Sstevel 	if (strNE(k, "class") && strNE(k, "crtime")) {
15561341Sstevel 		read_kstats((HV *)self, FALSE);
15571341Sstevel 	}
15581341Sstevel 	value = hv_fetch((HV *)self, k, klen, FALSE);
15591341Sstevel 	if (value) {
15601341Sstevel 		RETVAL = *value; SvREFCNT_inc(RETVAL);
15611341Sstevel 	} else {
15621341Sstevel 		RETVAL = &PL_sv_undef;
15631341Sstevel 	}
15641341Sstevel OUTPUT:
15651341Sstevel 	RETVAL
15661341Sstevel 
15671341Sstevel  #
15681341Sstevel  # Save the passed value into the kstat hash.  Read the appropriate kstat first,
15691341Sstevel  # if necessary.  Note that this DOES NOT update the underlying kernel kstat
15701341Sstevel  # structure.
15711341Sstevel  #
15721341Sstevel 
15731341Sstevel SV*
15741341Sstevel STORE(self, key, value)
15751341Sstevel 	SV* self;
15761341Sstevel 	SV* key;
15771341Sstevel 	SV* value;
15781341Sstevel PREINIT:
15791341Sstevel 	char	*k;
15801341Sstevel 	STRLEN	klen;
15811341Sstevel CODE:
15821341Sstevel 	self = SvRV(self);
15831341Sstevel 	k = SvPV(key, klen);
15841341Sstevel 	if (strNE(k, "class") && strNE(k, "crtime")) {
15851341Sstevel 		read_kstats((HV *)self, FALSE);
15861341Sstevel 	}
15871341Sstevel 	SvREFCNT_inc(value);
15881341Sstevel 	RETVAL = *(hv_store((HV *)self, k, klen, value, 0));
15891341Sstevel 	SvREFCNT_inc(RETVAL);
15901341Sstevel OUTPUT:
15911341Sstevel 	RETVAL
15921341Sstevel 
15931341Sstevel  #
15941341Sstevel  # Check for the existence of the passed key.  Read the kstat first if necessary
15951341Sstevel  #
15961341Sstevel 
15971341Sstevel bool
15981341Sstevel EXISTS(self, key)
15991341Sstevel 	SV* self;
16001341Sstevel 	SV* key;
16011341Sstevel PREINIT:
16021341Sstevel 	char *k;
16031341Sstevel CODE:
16041341Sstevel 	self = SvRV(self);
16051341Sstevel 	k = SvPV(key, PL_na);
16061341Sstevel 	if (strNE(k, "class") && strNE(k, "crtime")) {
16071341Sstevel 		read_kstats((HV *)self, FALSE);
16081341Sstevel 	}
16091341Sstevel 	RETVAL = hv_exists_ent((HV *)self, key, 0);
16101341Sstevel OUTPUT:
16111341Sstevel 	RETVAL
16121341Sstevel 
16131341Sstevel 
16141341Sstevel  #
16151341Sstevel  # Hash iterator initialisation.  Read the kstats if necessary.
16161341Sstevel  #
16171341Sstevel 
16181341Sstevel SV*
16191341Sstevel FIRSTKEY(self)
16201341Sstevel 	SV* self;
16211341Sstevel PREINIT:
16221341Sstevel 	HE *he;
16231341Sstevel PPCODE:
16241341Sstevel 	self = SvRV(self);
16251341Sstevel 	read_kstats((HV *)self, FALSE);
16261341Sstevel 	hv_iterinit((HV *)self);
16271341Sstevel 	if (he = hv_iternext((HV *)self)) {
16281341Sstevel 		EXTEND(SP, 1);
16291341Sstevel 		PUSHs(hv_iterkeysv(he));
16301341Sstevel 	}
16311341Sstevel 
16321341Sstevel  #
16331341Sstevel  # Return hash iterator next value.  Read the kstats if necessary.
16341341Sstevel  #
16351341Sstevel 
16361341Sstevel SV*
16371341Sstevel NEXTKEY(self, lastkey)
16381341Sstevel 	SV* self;
16391341Sstevel 	SV* lastkey;
16401341Sstevel PREINIT:
16411341Sstevel 	HE *he;
16421341Sstevel PPCODE:
16431341Sstevel 	self = SvRV(self);
16441341Sstevel 	if (he = hv_iternext((HV *)self)) {
16451341Sstevel 		EXTEND(SP, 1);
16461341Sstevel 		PUSHs(hv_iterkeysv(he));
16471341Sstevel 	}
16481341Sstevel 
16491341Sstevel 
16501341Sstevel  #
16511341Sstevel  # Delete the specified hash entry.
16521341Sstevel  #
16531341Sstevel 
16541341Sstevel SV*
16551341Sstevel DELETE(self, key)
16561341Sstevel 	SV *self;
16571341Sstevel 	SV *key;
16581341Sstevel CODE:
16591341Sstevel 	self = SvRV(self);
16601341Sstevel 	RETVAL = hv_delete_ent((HV *)self, key, 0, 0);
16611341Sstevel 	if (RETVAL) {
16621341Sstevel 		SvREFCNT_inc(RETVAL);
16631341Sstevel 	} else {
16641341Sstevel 		RETVAL = &PL_sv_undef;
16651341Sstevel 	}
16661341Sstevel OUTPUT:
16671341Sstevel 	RETVAL
16681341Sstevel 
16691341Sstevel  #
16701341Sstevel  # Clear the entire hash.  This will stop any update() calls rereading this
16711341Sstevel  # kstat until it is accessed again.
16721341Sstevel  #
16731341Sstevel 
16741341Sstevel void
16751341Sstevel CLEAR(self)
16761341Sstevel 	SV* self;
16771341Sstevel PREINIT:
16781341Sstevel 	MAGIC   *mg;
16791341Sstevel 	KstatInfo_t *kip;
16801341Sstevel CODE:
16811341Sstevel 	self = SvRV(self);
16821341Sstevel 	hv_clear((HV *)self);
16831341Sstevel 	mg = mg_find(self, '~');
16841341Sstevel 	PERL_ASSERTMSG(mg != 0, "CLEAR: lost ~ magic");
16851341Sstevel 	kip = (KstatInfo_t *)SvPVX(mg->mg_obj);
16861341Sstevel 	kip->read  = FALSE;
16871341Sstevel 	kip->valid = TRUE;
16881341Sstevel 	hv_store((HV *)self, "class", 5, newSVpv(kip->kstat->ks_class, 0), 0);
16891341Sstevel 	hv_store((HV *)self, "crtime", 6, NEW_HRTIME(kip->kstat->ks_crtime), 0);
1690