1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright (c) 2014 Racktop Systems.
  25  * Copyright 2016 Garrett D'Amore
  26  */
  27 
  28 /*
  29  * Kstat.xs is a Perl XS (eXStension module) that makes the Solaris
  30  * kstat(3KSTAT) facility available to Perl scripts.  Kstat is a general-purpose
  31  * mechanism  for  providing kernel statistics to users.  The Solaris API is
  32  * function-based (see the manpage for details), but for ease of use in Perl
  33  * scripts this module presents the information as a nested hash data structure.
  34  * It would be too inefficient to read every kstat in the system, so this module
  35  * uses the Perl TIEHASH mechanism to implement a read-on-demand semantic, which
  36  * only reads and updates kstats as and when they are actually accessed.
  37  */
  38 
  39 /*
  40  * Ignored raw kstats.
  41  *
  42  * Some raw kstats are ignored by this module, these are listed below.  The
  43  * most common reason is that the kstats are stored as arrays and the ks_ndata
  44  * and/or ks_data_size fields are invalid.  In this case it is impossible to
  45  * know how many records are in the array, so they can't be read.
  46  *
  47  * unix:*:sfmmu_percpu_stat
  48  * This is stored as an array with one entry per cpu.  Each element is of type
  49  * struct sfmmu_percpu_stat.  The ks_ndata and ks_data_size fields are bogus.
  50  *
  51  * ufs directio:*:UFS DirectIO Stats
  52  * The structure definition used for these kstats (ufs_directio_kstats) is in a
  53  * C file (uts/common/fs/ufs/ufs_directio.c) rather than a header file, so it
  54  * isn't accessible.
  55  *
  56  * qlc:*:statistics
  57  * This is a third-party driver for which we don't have source.
  58  *
  59  * mm:*:phys_installed
  60  * This is stored as an array of uint64_t, with each pair of values being the
  61  * (address, size) of a memory segment.  The ks_ndata and ks_data_size fields
  62  * are both zero.
  63  *
  64  * sockfs:*:sock_unix_list
  65  * This is stored as an array with one entry per active socket.  Each element
  66  * is of type struct k_sockinfo.  The ks_ndata and ks_data_size fields are both
  67  * zero.
  68  *
  69  * Note that the ks_ndata and ks_data_size of many non-array raw kstats are
  70  * also incorrect.  The relevant assertions are therefore commented out in the
  71  * appropriate raw kstat read routines.
  72  */
  73 
  74 /* Kstat related includes */
  75 #include <libgen.h>
  76 #include <kstat.h>
  77 #include <sys/var.h>
  78 #include <sys/utsname.h>
  79 #include <sys/sysinfo.h>
  80 #include <sys/flock.h>
  81 #include <sys/dnlc.h>
  82 #include <nfs/nfs.h>
  83 #include <nfs/nfs_clnt.h>
  84 
  85 /* Ultra-specific kstat includes */
  86 #ifdef __sparc
  87 #include <vm/hat_sfmmu.h> /* from /usr/platform/sun4u/include */
  88 #include <sys/simmstat.h> /* from /usr/platform/sun4u/include */
  89 #include <sys/sysctrl.h>  /* from /usr/platform/sun4u/include */
  90 #include <sys/fhc.h>              /* from /usr/include */
  91 #endif
  92 
  93 /*
  94  * Solaris #defines SP, which conflicts with the perl definition of SP
  95  * We don't need the Solaris one, so get rid of it to avoid warnings
  96  */
  97 #undef SP
  98 
  99 /* Perl XS includes */
 100 #include "EXTERN.h"
 101 #include "perl.h"
 102 #include "XSUB.h"
 103 
 104 /* Debug macros */
 105 #define DEBUG_ID "Sun::Solaris::Kstat"
 106 #ifdef KSTAT_DEBUG
 107 #define PERL_ASSERT(EXP) \
 108     ((void)((EXP) || (croak("%s: assertion failed at %s:%d: %s", \
 109     DEBUG_ID, __FILE__, __LINE__, #EXP), 0), 0))
 110 #define PERL_ASSERTMSG(EXP, MSG) \
 111     ((void)((EXP) || (croak(DEBUG_ID ": " MSG), 0), 0))
 112 #else
 113 #define PERL_ASSERT(EXP)                ((void)0)
 114 #define PERL_ASSERTMSG(EXP, MSG)        ((void)0)
 115 #endif
 116 
 117 /* Macros for saving the contents of KSTAT_RAW structures */
 118 #if defined(HAS_QUAD) && defined(USE_64_BIT_INT)
 119 #define NEW_IV(V) \
 120     (newSViv((IVTYPE) V))
 121 #define NEW_UV(V) \
 122     (newSVuv((UVTYPE) V))
 123 #else
 124 #define NEW_IV(V) \
 125     (V >= IV_MIN && V <= IV_MAX ? newSViv((IVTYPE) V) : newSVnv((NVTYPE) V))
 126 #if defined(UVTYPE)
 127 #define NEW_UV(V) \
 128     (V <= UV_MAX ? newSVuv((UVTYPE) V) : newSVnv((NVTYPE) V))
 129 # else
 130 #define NEW_UV(V) \
 131     (V <= IV_MAX ? newSViv((IVTYPE) V) : newSVnv((NVTYPE) V))
 132 #endif
 133 #endif
 134 #define NEW_HRTIME(V) \
 135     newSVnv((NVTYPE) (V / 1000000000.0))
 136 
 137 #define SAVE_FNP(H, F, K) \
 138     hv_store(H, K, sizeof (K) - 1, newSViv((IVTYPE)(uintptr_t)&F), 0)
 139 #define SAVE_STRING(H, S, K, SS) \
 140     hv_store(H, #K, sizeof (#K) - 1, \
 141     newSVpvn(S->K, SS ? strlen(S->K) : sizeof(S->K)), 0)
 142 #define SAVE_INT32(H, S, K) \
 143     hv_store(H, #K, sizeof (#K) - 1, NEW_IV(S->K), 0)
 144 #define SAVE_UINT32(H, S, K) \
 145     hv_store(H, #K, sizeof (#K) - 1, NEW_UV(S->K), 0)
 146 #define SAVE_INT64(H, S, K) \
 147     hv_store(H, #K, sizeof (#K) - 1, NEW_IV(S->K), 0)
 148 #define SAVE_UINT64(H, S, K) \
 149     hv_store(H, #K, sizeof (#K) - 1, NEW_UV(S->K), 0)
 150 #define SAVE_HRTIME(H, S, K) \
 151     hv_store(H, #K, sizeof (#K) - 1, NEW_HRTIME(S->K), 0)
 152 
 153 /* Private structure used for saving kstat info in the tied hashes */
 154 typedef struct {
 155         char            read;           /* Kstat block has been read before */
 156         char            valid;          /* Kstat still exists in kstat chain */
 157         char            strip_str;      /* Strip KSTAT_DATA_CHAR fields */
 158         kstat_ctl_t     *kstat_ctl;     /* Handle returned by kstat_open */
 159         kstat_t         *kstat;         /* Handle used by kstat_read */
 160 } KstatInfo_t;
 161 
 162 /* typedef for apply_to_ties callback functions */
 163 typedef int (*ATTCb_t)(HV *, void *);
 164 
 165 /* typedef for raw kstat reader functions */
 166 typedef void (*kstat_raw_reader_t)(HV *, kstat_t *, int);
 167 
 168 /* Hash of "module:name" to KSTAT_RAW read functions */
 169 static HV *raw_kstat_lookup;
 170 
 171 /*
 172  * Kstats come in two flavours, named and raw.  Raw kstats are just C structs,
 173  * so we need a function per raw kstat to convert the C struct into the
 174  * corresponding perl hash.  All such conversion functions are in the following
 175  * section.
 176  */
 177 
 178 /*
 179  * Definitions in /usr/include/sys/cpuvar.h and /usr/include/sys/sysinfo.h
 180  */
 181 
 182 static void
 183 save_cpu_stat(HV *self, kstat_t *kp, int strip_str)
 184 {
 185         cpu_stat_t    *statp;
 186         cpu_sysinfo_t *sysinfop;
 187         cpu_syswait_t *syswaitp;
 188         cpu_vminfo_t  *vminfop;
 189 
 190         /* PERL_ASSERT(kp->ks_ndata == 1); */
 191         PERL_ASSERT(kp->ks_data_size == sizeof (cpu_stat_t));
 192         statp = (cpu_stat_t *)(kp->ks_data);
 193         sysinfop = &statp->cpu_sysinfo;
 194         syswaitp = &statp->cpu_syswait;
 195         vminfop  = &statp->cpu_vminfo;
 196 
 197         hv_store(self, "idle", 4, NEW_UV(sysinfop->cpu[CPU_IDLE]), 0);
 198         hv_store(self, "user", 4, NEW_UV(sysinfop->cpu[CPU_USER]), 0);
 199         hv_store(self, "kernel", 6, NEW_UV(sysinfop->cpu[CPU_KERNEL]), 0);
 200         hv_store(self, "wait", 4, NEW_UV(sysinfop->cpu[CPU_WAIT]), 0);
 201         hv_store(self, "wait_io", 7, NEW_UV(sysinfop->wait[W_IO]), 0);
 202         hv_store(self, "wait_swap", 9, NEW_UV(sysinfop->wait[W_SWAP]), 0);
 203         hv_store(self, "wait_pio",  8, NEW_UV(sysinfop->wait[W_PIO]), 0);
 204         SAVE_UINT32(self, sysinfop, bread);
 205         SAVE_UINT32(self, sysinfop, bwrite);
 206         SAVE_UINT32(self, sysinfop, lread);
 207         SAVE_UINT32(self, sysinfop, lwrite);
 208         SAVE_UINT32(self, sysinfop, phread);
 209         SAVE_UINT32(self, sysinfop, phwrite);
 210         SAVE_UINT32(self, sysinfop, pswitch);
 211         SAVE_UINT32(self, sysinfop, trap);
 212         SAVE_UINT32(self, sysinfop, intr);
 213         SAVE_UINT32(self, sysinfop, syscall);
 214         SAVE_UINT32(self, sysinfop, sysread);
 215         SAVE_UINT32(self, sysinfop, syswrite);
 216         SAVE_UINT32(self, sysinfop, sysfork);
 217         SAVE_UINT32(self, sysinfop, sysvfork);
 218         SAVE_UINT32(self, sysinfop, sysexec);
 219         SAVE_UINT32(self, sysinfop, readch);
 220         SAVE_UINT32(self, sysinfop, writech);
 221         SAVE_UINT32(self, sysinfop, rcvint);
 222         SAVE_UINT32(self, sysinfop, xmtint);
 223         SAVE_UINT32(self, sysinfop, mdmint);
 224         SAVE_UINT32(self, sysinfop, rawch);
 225         SAVE_UINT32(self, sysinfop, canch);
 226         SAVE_UINT32(self, sysinfop, outch);
 227         SAVE_UINT32(self, sysinfop, msg);
 228         SAVE_UINT32(self, sysinfop, sema);
 229         SAVE_UINT32(self, sysinfop, namei);
 230         SAVE_UINT32(self, sysinfop, ufsiget);
 231         SAVE_UINT32(self, sysinfop, ufsdirblk);
 232         SAVE_UINT32(self, sysinfop, ufsipage);
 233         SAVE_UINT32(self, sysinfop, ufsinopage);
 234         SAVE_UINT32(self, sysinfop, inodeovf);
 235         SAVE_UINT32(self, sysinfop, fileovf);
 236         SAVE_UINT32(self, sysinfop, procovf);
 237         SAVE_UINT32(self, sysinfop, intrthread);
 238         SAVE_UINT32(self, sysinfop, intrblk);
 239         SAVE_UINT32(self, sysinfop, idlethread);
 240         SAVE_UINT32(self, sysinfop, inv_swtch);
 241         SAVE_UINT32(self, sysinfop, nthreads);
 242         SAVE_UINT32(self, sysinfop, cpumigrate);
 243         SAVE_UINT32(self, sysinfop, xcalls);
 244         SAVE_UINT32(self, sysinfop, mutex_adenters);
 245         SAVE_UINT32(self, sysinfop, rw_rdfails);
 246         SAVE_UINT32(self, sysinfop, rw_wrfails);
 247         SAVE_UINT32(self, sysinfop, modload);
 248         SAVE_UINT32(self, sysinfop, modunload);
 249         SAVE_UINT32(self, sysinfop, bawrite);
 250 #ifdef STATISTICS       /* see header file */
 251         SAVE_UINT32(self, sysinfop, rw_enters);
 252         SAVE_UINT32(self, sysinfop, win_uo_cnt);
 253         SAVE_UINT32(self, sysinfop, win_uu_cnt);
 254         SAVE_UINT32(self, sysinfop, win_so_cnt);
 255         SAVE_UINT32(self, sysinfop, win_su_cnt);
 256         SAVE_UINT32(self, sysinfop, win_suo_cnt);
 257 #endif
 258 
 259         SAVE_INT32(self, syswaitp, iowait);
 260         SAVE_INT32(self, syswaitp, swap);
 261         SAVE_INT32(self, syswaitp, physio);
 262 
 263         SAVE_UINT32(self, vminfop, pgrec);
 264         SAVE_UINT32(self, vminfop, pgfrec);
 265         SAVE_UINT32(self, vminfop, pgin);
 266         SAVE_UINT32(self, vminfop, pgpgin);
 267         SAVE_UINT32(self, vminfop, pgout);
 268         SAVE_UINT32(self, vminfop, pgpgout);
 269         SAVE_UINT32(self, vminfop, swapin);
 270         SAVE_UINT32(self, vminfop, pgswapin);
 271         SAVE_UINT32(self, vminfop, swapout);
 272         SAVE_UINT32(self, vminfop, pgswapout);
 273         SAVE_UINT32(self, vminfop, zfod);
 274         SAVE_UINT32(self, vminfop, dfree);
 275         SAVE_UINT32(self, vminfop, scan);
 276         SAVE_UINT32(self, vminfop, rev);
 277         SAVE_UINT32(self, vminfop, hat_fault);
 278         SAVE_UINT32(self, vminfop, as_fault);
 279         SAVE_UINT32(self, vminfop, maj_fault);
 280         SAVE_UINT32(self, vminfop, cow_fault);
 281         SAVE_UINT32(self, vminfop, prot_fault);
 282         SAVE_UINT32(self, vminfop, softlock);
 283         SAVE_UINT32(self, vminfop, kernel_asflt);
 284         SAVE_UINT32(self, vminfop, pgrrun);
 285         SAVE_UINT32(self, vminfop, execpgin);
 286         SAVE_UINT32(self, vminfop, execpgout);
 287         SAVE_UINT32(self, vminfop, execfree);
 288         SAVE_UINT32(self, vminfop, anonpgin);
 289         SAVE_UINT32(self, vminfop, anonpgout);
 290         SAVE_UINT32(self, vminfop, anonfree);
 291         SAVE_UINT32(self, vminfop, fspgin);
 292         SAVE_UINT32(self, vminfop, fspgout);
 293         SAVE_UINT32(self, vminfop, fsfree);
 294 }
 295 
 296 /*
 297  * Definitions in /usr/include/sys/var.h
 298  */
 299 
 300 static void
 301 save_var(HV *self, kstat_t *kp, int strip_str)
 302 {
 303         struct var *varp;
 304 
 305         /* PERL_ASSERT(kp->ks_ndata == 1); */
 306         PERL_ASSERT(kp->ks_data_size == sizeof (struct var));
 307         varp = (struct var *)(kp->ks_data);
 308 
 309         SAVE_INT32(self, varp, v_buf);
 310         SAVE_INT32(self, varp, v_call);
 311         SAVE_INT32(self, varp, v_proc);
 312         SAVE_INT32(self, varp, v_maxupttl);
 313         SAVE_INT32(self, varp, v_nglobpris);
 314         SAVE_INT32(self, varp, v_maxsyspri);
 315         SAVE_INT32(self, varp, v_clist);
 316         SAVE_INT32(self, varp, v_maxup);
 317         SAVE_INT32(self, varp, v_hbuf);
 318         SAVE_INT32(self, varp, v_hmask);
 319         SAVE_INT32(self, varp, v_pbuf);
 320         SAVE_INT32(self, varp, v_sptmap);
 321         SAVE_INT32(self, varp, v_maxpmem);
 322         SAVE_INT32(self, varp, v_autoup);
 323         SAVE_INT32(self, varp, v_bufhwm);
 324 }
 325 
 326 /*
 327  * Definition in /usr/include/sys/dnlc.h
 328  */
 329 
 330 static void
 331 save_ncstats(HV *self, kstat_t *kp, int strip_str)
 332 {
 333         struct ncstats *ncstatsp;
 334 
 335         /* PERL_ASSERT(kp->ks_ndata == 1); */
 336         PERL_ASSERT(kp->ks_data_size == sizeof (struct ncstats));
 337         ncstatsp = (struct ncstats *)(kp->ks_data);
 338 
 339         SAVE_INT32(self, ncstatsp, hits);
 340         SAVE_INT32(self, ncstatsp, misses);
 341         SAVE_INT32(self, ncstatsp, enters);
 342         SAVE_INT32(self, ncstatsp, dbl_enters);
 343         SAVE_INT32(self, ncstatsp, long_enter);
 344         SAVE_INT32(self, ncstatsp, long_look);
 345         SAVE_INT32(self, ncstatsp, move_to_front);
 346         SAVE_INT32(self, ncstatsp, purges);
 347 }
 348 
 349 /*
 350  * Definition in  /usr/include/sys/sysinfo.h
 351  */
 352 
 353 static void
 354 save_sysinfo(HV *self, kstat_t *kp, int strip_str)
 355 {
 356         sysinfo_t *sysinfop;
 357 
 358         /* PERL_ASSERT(kp->ks_ndata == 1); */
 359         PERL_ASSERT(kp->ks_data_size == sizeof (sysinfo_t));
 360         sysinfop = (sysinfo_t *)(kp->ks_data);
 361 
 362         SAVE_UINT32(self, sysinfop, updates);
 363         SAVE_UINT32(self, sysinfop, runque);
 364         SAVE_UINT32(self, sysinfop, runocc);
 365         SAVE_UINT32(self, sysinfop, swpque);
 366         SAVE_UINT32(self, sysinfop, swpocc);
 367         SAVE_UINT32(self, sysinfop, waiting);
 368 }
 369 
 370 /*
 371  * Definition in  /usr/include/sys/sysinfo.h
 372  */
 373 
 374 static void
 375 save_vminfo(HV *self, kstat_t *kp, int strip_str)
 376 {
 377         vminfo_t *vminfop;
 378 
 379         /* PERL_ASSERT(kp->ks_ndata == 1); */
 380         PERL_ASSERT(kp->ks_data_size == sizeof (vminfo_t));
 381         vminfop = (vminfo_t *)(kp->ks_data);
 382 
 383         SAVE_UINT64(self, vminfop, freemem);
 384         SAVE_UINT64(self, vminfop, swap_resv);
 385         SAVE_UINT64(self, vminfop, swap_alloc);
 386         SAVE_UINT64(self, vminfop, swap_avail);
 387         SAVE_UINT64(self, vminfop, swap_free);
 388         SAVE_UINT64(self, vminfop, updates);
 389 }
 390 
 391 /*
 392  * Definition in /usr/include/nfs/nfs_clnt.h
 393  */
 394 
 395 static void
 396 save_nfs(HV *self, kstat_t *kp, int strip_str)
 397 {
 398         struct mntinfo_kstat *mntinfop;
 399 
 400         /* PERL_ASSERT(kp->ks_ndata == 1); */
 401         PERL_ASSERT(kp->ks_data_size == sizeof (struct mntinfo_kstat));
 402         mntinfop = (struct mntinfo_kstat *)(kp->ks_data);
 403 
 404         SAVE_STRING(self, mntinfop, mik_proto, strip_str);
 405         SAVE_UINT32(self, mntinfop, mik_vers);
 406         SAVE_UINT32(self, mntinfop, mik_flags);
 407         SAVE_UINT32(self, mntinfop, mik_secmod);
 408         SAVE_UINT32(self, mntinfop, mik_curread);
 409         SAVE_UINT32(self, mntinfop, mik_curwrite);
 410         SAVE_INT32(self, mntinfop, mik_timeo);
 411         SAVE_INT32(self, mntinfop, mik_retrans);
 412         SAVE_UINT32(self, mntinfop, mik_acregmin);
 413         SAVE_UINT32(self, mntinfop, mik_acregmax);
 414         SAVE_UINT32(self, mntinfop, mik_acdirmin);
 415         SAVE_UINT32(self, mntinfop, mik_acdirmax);
 416         hv_store(self, "lookup_srtt", 11,
 417             NEW_UV(mntinfop->mik_timers[0].srtt), 0);
 418         hv_store(self, "lookup_deviate", 14,
 419             NEW_UV(mntinfop->mik_timers[0].deviate), 0);
 420         hv_store(self, "lookup_rtxcur", 13,
 421             NEW_UV(mntinfop->mik_timers[0].rtxcur), 0);
 422         hv_store(self, "read_srtt", 9,
 423             NEW_UV(mntinfop->mik_timers[1].srtt), 0);
 424         hv_store(self, "read_deviate", 12,
 425             NEW_UV(mntinfop->mik_timers[1].deviate), 0);
 426         hv_store(self, "read_rtxcur", 11,
 427             NEW_UV(mntinfop->mik_timers[1].rtxcur), 0);
 428         hv_store(self, "write_srtt", 10,
 429             NEW_UV(mntinfop->mik_timers[2].srtt), 0);
 430         hv_store(self, "write_deviate", 13,
 431             NEW_UV(mntinfop->mik_timers[2].deviate), 0);
 432         hv_store(self, "write_rtxcur", 12,
 433             NEW_UV(mntinfop->mik_timers[2].rtxcur), 0);
 434         SAVE_UINT32(self, mntinfop, mik_noresponse);
 435         SAVE_UINT32(self, mntinfop, mik_failover);
 436         SAVE_UINT32(self, mntinfop, mik_remap);
 437         SAVE_STRING(self, mntinfop, mik_curserver, strip_str);
 438 }
 439 
 440 /*
 441  * The following struct => hash functions are all only present on the sparc
 442  * platform, so they are all conditionally compiled depending on __sparc
 443  */
 444 
 445 /*
 446  * Definition in /usr/platform/sun4u/include/vm/hat_sfmmu.h
 447  */
 448 
 449 #ifdef __sparc
 450 static void
 451 save_sfmmu_global_stat(HV *self, kstat_t *kp, int strip_str)
 452 {
 453         struct sfmmu_global_stat *sfmmugp;
 454 
 455         /* PERL_ASSERT(kp->ks_ndata == 1); */
 456         PERL_ASSERT(kp->ks_data_size == sizeof (struct sfmmu_global_stat));
 457         sfmmugp = (struct sfmmu_global_stat *)(kp->ks_data);
 458 
 459         SAVE_INT32(self, sfmmugp, sf_tsb_exceptions);
 460         SAVE_INT32(self, sfmmugp, sf_tsb_raise_exception);
 461         SAVE_INT32(self, sfmmugp, sf_pagefaults);
 462         SAVE_INT32(self, sfmmugp, sf_uhash_searches);
 463         SAVE_INT32(self, sfmmugp, sf_uhash_links);
 464         SAVE_INT32(self, sfmmugp, sf_khash_searches);
 465         SAVE_INT32(self, sfmmugp, sf_khash_links);
 466         SAVE_INT32(self, sfmmugp, sf_swapout);
 467         SAVE_INT32(self, sfmmugp, sf_tsb_alloc);
 468         SAVE_INT32(self, sfmmugp, sf_tsb_allocfail);
 469         SAVE_INT32(self, sfmmugp, sf_tsb_sectsb_create);
 470         SAVE_INT32(self, sfmmugp, sf_scd_1sttsb_alloc);
 471         SAVE_INT32(self, sfmmugp, sf_scd_2ndtsb_alloc);
 472         SAVE_INT32(self, sfmmugp, sf_scd_1sttsb_allocfail);
 473         SAVE_INT32(self, sfmmugp, sf_scd_2ndtsb_allocfail);
 474         SAVE_INT32(self, sfmmugp, sf_tteload8k);
 475         SAVE_INT32(self, sfmmugp, sf_tteload64k);
 476         SAVE_INT32(self, sfmmugp, sf_tteload512k);
 477         SAVE_INT32(self, sfmmugp, sf_tteload4m);
 478         SAVE_INT32(self, sfmmugp, sf_tteload32m);
 479         SAVE_INT32(self, sfmmugp, sf_tteload256m);
 480         SAVE_INT32(self, sfmmugp, sf_tsb_load8k);
 481         SAVE_INT32(self, sfmmugp, sf_tsb_load4m);
 482         SAVE_INT32(self, sfmmugp, sf_hblk_hit);
 483         SAVE_INT32(self, sfmmugp, sf_hblk8_ncreate);
 484         SAVE_INT32(self, sfmmugp, sf_hblk8_nalloc);
 485         SAVE_INT32(self, sfmmugp, sf_hblk1_ncreate);
 486         SAVE_INT32(self, sfmmugp, sf_hblk1_nalloc);
 487         SAVE_INT32(self, sfmmugp, sf_hblk_slab_cnt);
 488         SAVE_INT32(self, sfmmugp, sf_hblk_reserve_cnt);
 489         SAVE_INT32(self, sfmmugp, sf_hblk_recurse_cnt);
 490         SAVE_INT32(self, sfmmugp, sf_hblk_reserve_hit);
 491         SAVE_INT32(self, sfmmugp, sf_get_free_success);
 492         SAVE_INT32(self, sfmmugp, sf_get_free_throttle);
 493         SAVE_INT32(self, sfmmugp, sf_get_free_fail);
 494         SAVE_INT32(self, sfmmugp, sf_put_free_success);
 495         SAVE_INT32(self, sfmmugp, sf_put_free_fail);
 496         SAVE_INT32(self, sfmmugp, sf_pgcolor_conflict);
 497         SAVE_INT32(self, sfmmugp, sf_uncache_conflict);
 498         SAVE_INT32(self, sfmmugp, sf_unload_conflict);
 499         SAVE_INT32(self, sfmmugp, sf_ism_uncache);
 500         SAVE_INT32(self, sfmmugp, sf_ism_recache);
 501         SAVE_INT32(self, sfmmugp, sf_recache);
 502         SAVE_INT32(self, sfmmugp, sf_steal_count);
 503         SAVE_INT32(self, sfmmugp, sf_pagesync);
 504         SAVE_INT32(self, sfmmugp, sf_clrwrt);
 505         SAVE_INT32(self, sfmmugp, sf_pagesync_invalid);
 506         SAVE_INT32(self, sfmmugp, sf_kernel_xcalls);
 507         SAVE_INT32(self, sfmmugp, sf_user_xcalls);
 508         SAVE_INT32(self, sfmmugp, sf_tsb_grow);
 509         SAVE_INT32(self, sfmmugp, sf_tsb_shrink);
 510         SAVE_INT32(self, sfmmugp, sf_tsb_resize_failures);
 511         SAVE_INT32(self, sfmmugp, sf_tsb_reloc);
 512         SAVE_INT32(self, sfmmugp, sf_user_vtop);
 513         SAVE_INT32(self, sfmmugp, sf_ctx_inv);
 514         SAVE_INT32(self, sfmmugp, sf_tlb_reprog_pgsz);
 515         SAVE_INT32(self, sfmmugp, sf_region_remap_demap);
 516         SAVE_INT32(self, sfmmugp, sf_create_scd);
 517         SAVE_INT32(self, sfmmugp, sf_join_scd);
 518         SAVE_INT32(self, sfmmugp, sf_leave_scd);
 519         SAVE_INT32(self, sfmmugp, sf_destroy_scd);
 520 }
 521 #endif
 522 
 523 /*
 524  * Definition in /usr/platform/sun4u/include/vm/hat_sfmmu.h
 525  */
 526 
 527 #ifdef __sparc
 528 static void
 529 save_sfmmu_tsbsize_stat(HV *self, kstat_t *kp, int strip_str)
 530 {
 531         struct sfmmu_tsbsize_stat *sfmmutp;
 532 
 533         /* PERL_ASSERT(kp->ks_ndata == 1); */
 534         PERL_ASSERT(kp->ks_data_size == sizeof (struct sfmmu_tsbsize_stat));
 535         sfmmutp = (struct sfmmu_tsbsize_stat *)(kp->ks_data);
 536 
 537         SAVE_INT32(self, sfmmutp, sf_tsbsz_8k);
 538         SAVE_INT32(self, sfmmutp, sf_tsbsz_16k);
 539         SAVE_INT32(self, sfmmutp, sf_tsbsz_32k);
 540         SAVE_INT32(self, sfmmutp, sf_tsbsz_64k);
 541         SAVE_INT32(self, sfmmutp, sf_tsbsz_128k);
 542         SAVE_INT32(self, sfmmutp, sf_tsbsz_256k);
 543         SAVE_INT32(self, sfmmutp, sf_tsbsz_512k);
 544         SAVE_INT32(self, sfmmutp, sf_tsbsz_1m);
 545         SAVE_INT32(self, sfmmutp, sf_tsbsz_2m);
 546         SAVE_INT32(self, sfmmutp, sf_tsbsz_4m);
 547 }
 548 #endif
 549 
 550 /*
 551  * Definition in /usr/platform/sun4u/include/sys/simmstat.h
 552  */
 553 
 554 #ifdef __sparc
 555 static void
 556 save_simmstat(HV *self, kstat_t *kp, int strip_str)
 557 {
 558         uchar_t *simmstatp;
 559         SV      *list;
 560         int     i;
 561 
 562         /* PERL_ASSERT(kp->ks_ndata == 1); */
 563         PERL_ASSERT(kp->ks_data_size == sizeof (uchar_t) * SIMM_COUNT);
 564 
 565         list = newSVpv("", 0);
 566         for (i = 0, simmstatp = (uchar_t *)(kp->ks_data);
 567         i < SIMM_COUNT - 1; i++, simmstatp++) {
 568                 sv_catpvf(list, "%d,", *simmstatp);
 569         }
 570         sv_catpvf(list, "%d", *simmstatp);
 571         hv_store(self, "status", 6, list, 0);
 572 }
 573 #endif
 574 
 575 /*
 576  * Used by save_temperature to make CSV lists from arrays of
 577  * short temperature values
 578  */
 579 
 580 #ifdef __sparc
 581 static SV *
 582 short_array_to_SV(short *shortp, int len)
 583 {
 584         SV  *list;
 585 
 586         list = newSVpv("", 0);
 587         for (; len > 1; len--, shortp++) {
 588                 sv_catpvf(list, "%d,", *shortp);
 589         }
 590         sv_catpvf(list, "%d", *shortp);
 591         return (list);
 592 }
 593 
 594 /*
 595  * Definition in /usr/platform/sun4u/include/sys/fhc.h
 596  */
 597 
 598 static void
 599 save_temperature(HV *self, kstat_t *kp, int strip_str)
 600 {
 601         struct temp_stats *tempsp;
 602 
 603         /* PERL_ASSERT(kp->ks_ndata == 1); */
 604         PERL_ASSERT(kp->ks_data_size == sizeof (struct temp_stats));
 605         tempsp = (struct temp_stats *)(kp->ks_data);
 606 
 607         SAVE_UINT32(self, tempsp, index);
 608         hv_store(self, "l1", 2, short_array_to_SV(tempsp->l1, L1_SZ), 0);
 609         hv_store(self, "l2", 2, short_array_to_SV(tempsp->l2, L2_SZ), 0);
 610         hv_store(self, "l3", 2, short_array_to_SV(tempsp->l3, L3_SZ), 0);
 611         hv_store(self, "l4", 2, short_array_to_SV(tempsp->l4, L4_SZ), 0);
 612         hv_store(self, "l5", 2, short_array_to_SV(tempsp->l5, L5_SZ), 0);
 613         SAVE_INT32(self, tempsp, max);
 614         SAVE_INT32(self, tempsp, min);
 615         SAVE_INT32(self, tempsp, state);
 616         SAVE_INT32(self, tempsp, temp_cnt);
 617         SAVE_INT32(self, tempsp, shutdown_cnt);
 618         SAVE_INT32(self, tempsp, version);
 619         SAVE_INT32(self, tempsp, trend);
 620         SAVE_INT32(self, tempsp, override);
 621 }
 622 #endif
 623 
 624 /*
 625  * Not actually defined anywhere - just a short.  Yuck.
 626  */
 627 
 628 #ifdef __sparc
 629 static void
 630 save_temp_over(HV *self, kstat_t *kp, int strip_str)
 631 {
 632         short *shortp;
 633 
 634         /* PERL_ASSERT(kp->ks_ndata == 1); */
 635         PERL_ASSERT(kp->ks_data_size == sizeof (short));
 636 
 637         shortp = (short *)(kp->ks_data);
 638         hv_store(self, "override", 8, newSViv(*shortp), 0);
 639 }
 640 #endif
 641 
 642 /*
 643  * Defined in /usr/platform/sun4u/include/sys/sysctrl.h
 644  * (Well, sort of.  Actually there's no structure, just a list of #defines
 645  * enumerating *some* of the array indexes.)
 646  */
 647 
 648 #ifdef __sparc
 649 static void
 650 save_ps_shadow(HV *self, kstat_t *kp, int strip_str)
 651 {
 652         uchar_t *ucharp;
 653 
 654         /* PERL_ASSERT(kp->ks_ndata == 1); */
 655         PERL_ASSERT(kp->ks_data_size == SYS_PS_COUNT);
 656 
 657         ucharp = (uchar_t *)(kp->ks_data);
 658         hv_store(self, "core_0", 6, newSViv(*ucharp++), 0);
 659         hv_store(self, "core_1", 6, newSViv(*ucharp++), 0);
 660         hv_store(self, "core_2", 6, newSViv(*ucharp++), 0);
 661         hv_store(self, "core_3", 6, newSViv(*ucharp++), 0);
 662         hv_store(self, "core_4", 6, newSViv(*ucharp++), 0);
 663         hv_store(self, "core_5", 6, newSViv(*ucharp++), 0);
 664         hv_store(self, "core_6", 6, newSViv(*ucharp++), 0);
 665         hv_store(self, "core_7", 6, newSViv(*ucharp++), 0);
 666         hv_store(self, "pps_0", 5, newSViv(*ucharp++), 0);
 667         hv_store(self, "clk_33", 6, newSViv(*ucharp++), 0);
 668         hv_store(self, "clk_50", 6, newSViv(*ucharp++), 0);
 669         hv_store(self, "v5_p", 4, newSViv(*ucharp++), 0);
 670         hv_store(self, "v12_p", 5, newSViv(*ucharp++), 0);
 671         hv_store(self, "v5_aux", 6, newSViv(*ucharp++), 0);
 672         hv_store(self, "v5_p_pch", 8, newSViv(*ucharp++), 0);
 673         hv_store(self, "v12_p_pch", 9, newSViv(*ucharp++), 0);
 674         hv_store(self, "v3_pch", 6, newSViv(*ucharp++), 0);
 675         hv_store(self, "v5_pch", 6, newSViv(*ucharp++), 0);
 676         hv_store(self, "p_fan", 5, newSViv(*ucharp++), 0);
 677 }
 678 #endif
 679 
 680 /*
 681  * Definition in /usr/platform/sun4u/include/sys/fhc.h
 682  */
 683 
 684 #ifdef __sparc
 685 static void
 686 save_fault_list(HV *self, kstat_t *kp, int strip_str)
 687 {
 688         struct ft_list  *faultp;
 689         int             i;
 690         char            name[KSTAT_STRLEN + 7]; /* room for 999999 faults */
 691 
 692         /* PERL_ASSERT(kp->ks_ndata == 1); */
 693         /* PERL_ASSERT(kp->ks_data_size == sizeof (struct ft_list)); */
 694 
 695         for (i = 1, faultp = (struct ft_list *)(kp->ks_data);
 696             i <= 999999 && i <= kp->ks_data_size / sizeof (struct ft_list);
 697             i++, faultp++) {
 698                 (void) snprintf(name, sizeof (name), "unit_%d", i);
 699                 hv_store(self, name, strlen(name), newSViv(faultp->unit), 0);
 700                 (void) snprintf(name, sizeof (name), "type_%d", i);
 701                 hv_store(self, name, strlen(name), newSViv(faultp->type), 0);
 702                 (void) snprintf(name, sizeof (name), "fclass_%d", i);
 703                 hv_store(self, name, strlen(name), newSViv(faultp->fclass), 0);
 704                 (void) snprintf(name, sizeof (name), "create_time_%d", i);
 705                 hv_store(self, name, strlen(name),
 706                     NEW_UV(faultp->create_time), 0);
 707                 (void) snprintf(name, sizeof (name), "msg_%d", i);
 708                 hv_store(self, name, strlen(name), newSVpv(faultp->msg, 0), 0);
 709         }
 710 }
 711 #endif
 712 
 713 /*
 714  * We need to be able to find the function corresponding to a particular raw
 715  * kstat.  To do this we ignore the instance and glue the module and name
 716  * together to form a composite key.  We can then use the data in the kstat
 717  * structure to find the appropriate function.  We use a perl hash to manage the
 718  * lookup, where the key is "module:name" and the value is a pointer to the
 719  * appropriate C function.
 720  *
 721  * Note that some kstats include the instance number as part of the module
 722  * and/or name.  This could be construed as a bug.  However, to work around this
 723  * we omit any digits from the module and name as we build the table in
 724  * build_raw_kstat_loopup(), and we remove any digits from the module and name
 725  * when we look up the functions in lookup_raw_kstat_fn()
 726  */
 727 
 728 /*
 729  * This function is called when the XS is first dlopen()ed, and builds the
 730  * lookup table as described above.
 731  */
 732 
 733 static void
 734 build_raw_kstat_lookup()
 735         {
 736         /* Create new hash */
 737         raw_kstat_lookup = newHV();
 738 
 739         SAVE_FNP(raw_kstat_lookup, save_cpu_stat, "cpu_stat:cpu_stat");
 740         SAVE_FNP(raw_kstat_lookup, save_var, "unix:var");
 741         SAVE_FNP(raw_kstat_lookup, save_ncstats, "unix:ncstats");
 742         SAVE_FNP(raw_kstat_lookup, save_sysinfo, "unix:sysinfo");
 743         SAVE_FNP(raw_kstat_lookup, save_vminfo, "unix:vminfo");
 744         SAVE_FNP(raw_kstat_lookup, save_nfs, "nfs:mntinfo");
 745 #ifdef __sparc
 746         SAVE_FNP(raw_kstat_lookup, save_sfmmu_global_stat,
 747             "unix:sfmmu_global_stat");
 748         SAVE_FNP(raw_kstat_lookup, save_sfmmu_tsbsize_stat,
 749             "unix:sfmmu_tsbsize_stat");
 750         SAVE_FNP(raw_kstat_lookup, save_simmstat, "unix:simm-status");
 751         SAVE_FNP(raw_kstat_lookup, save_temperature, "unix:temperature");
 752         SAVE_FNP(raw_kstat_lookup, save_temp_over, "unix:temperature override");
 753         SAVE_FNP(raw_kstat_lookup, save_ps_shadow, "unix:ps_shadow");
 754         SAVE_FNP(raw_kstat_lookup, save_fault_list, "unix:fault_list");
 755 #endif
 756 }
 757 
 758 /*
 759  * This finds and returns the raw kstat reader function corresponding to the
 760  * supplied module and name.  If no matching function exists, 0 is returned.
 761  */
 762 
 763 static kstat_raw_reader_t lookup_raw_kstat_fn(char *module, char *name)
 764         {
 765         char                    key[KSTAT_STRLEN * 2];
 766         register char           *f, *t;
 767         SV                      **entry;
 768         kstat_raw_reader_t      fnp;
 769 
 770         /* Copy across module & name, removing any digits - see comment above */
 771         for (f = module, t = key; *f != '\0'; f++, t++) {
 772                 while (*f != '\0' && isdigit(*f)) { f++; }
 773                 *t = *f;
 774         }
 775         *t++ = ':';
 776         for (f = name; *f != '\0'; f++, t++) {
 777                 while (*f != '\0' && isdigit(*f)) {
 778                         f++;
 779                 }
 780         *t = *f;
 781         }
 782         *t = '\0';
 783 
 784         /* look up & return the function, or teturn 0 if not found */
 785         if ((entry = hv_fetch(raw_kstat_lookup, key, strlen(key), FALSE)) == 0)
 786         {
 787                 fnp = 0;
 788         } else {
 789                 fnp = (kstat_raw_reader_t)(uintptr_t)SvIV(*entry);
 790         }
 791         return (fnp);
 792 }
 793 
 794 /*
 795  * This module converts the flat list returned by kstat_read() into a perl hash
 796  * tree keyed on module, instance, name and statistic.  The following functions
 797  * provide code to create the nested hashes, and to iterate over them.
 798  */
 799 
 800 /*
 801  * Given module, instance and name keys return a pointer to the hash tied to
 802  * the bottommost hash.  If the hash already exists, we just return a pointer
 803  * to it, otherwise we create the hash and any others also required above it in
 804  * the hierarchy.  The returned tiehash is blessed into the
 805  * Sun::Solaris::Kstat::_Stat class, so that the appropriate TIEHASH methods are
 806  * called when the bottommost hash is accessed.  If the is_new parameter is
 807  * non-null it will be set to TRUE if a new tie has been created, and FALSE if
 808  * the tie already existed.
 809  */
 810 
 811 static HV *
 812 get_tie(SV *self, char *module, int instance, char *name, int *is_new)
 813 {
 814         char str_inst[11];      /* big enough for up to 10^10 instances */
 815         char *key[3];           /* 3 part key: module, instance, name */
 816         int  k;
 817         int  new;
 818         HV   *hash;
 819         HV   *tie;
 820 
 821         /* Create the keys */
 822         (void) snprintf(str_inst, sizeof (str_inst), "%d", instance);
 823         key[0] = module;
 824         key[1] = str_inst;
 825         key[2] = name;
 826 
 827         /* Iteratively descend the tree, creating new hashes as required */
 828         hash = (HV *)SvRV(self);
 829         for (k = 0; k < 3; k++) {
 830                 SV **entry;
 831 
 832                 SvREADONLY_off(hash);
 833                 entry = hv_fetch(hash, key[k], strlen(key[k]), TRUE);
 834 
 835                 /* If the entry doesn't exist, create it */
 836                 if (! SvOK(*entry)) {
 837                         HV *newhash;
 838                         SV *rv;
 839 
 840                         newhash = newHV();
 841                         rv = newRV_noinc((SV *)newhash);
 842                         sv_setsv(*entry, rv);
 843                         SvREFCNT_dec(rv);
 844                         if (k < 2) {
 845                                 SvREADONLY_on(newhash);
 846                         }
 847                         SvREADONLY_on(*entry);
 848                         SvREADONLY_on(hash);
 849                         hash = newhash;
 850                         new = 1;
 851 
 852                 /* Otherwise it already existed */
 853                 } else {
 854                         SvREADONLY_on(hash);
 855                         hash = (HV *)SvRV(*entry);
 856                         new = 0;
 857                 }
 858         }
 859 
 860         /* Create and bless a hash for the tie, if necessary */
 861         if (new) {
 862                 SV *tieref;
 863                 HV *stash;
 864 
 865                 tie = newHV();
 866                 tieref = newRV_noinc((SV *)tie);
 867                 stash = gv_stashpv("Sun::Solaris::Kstat::_Stat", TRUE);
 868                 sv_bless(tieref, stash);
 869 
 870                 /* Add TIEHASH magic */
 871                 hv_magic(hash, (GV *)tieref, 'P');
 872                 SvREADONLY_on(hash);
 873 
 874         /* Otherwise, just find the existing tied hash */
 875         } else {
 876                 MAGIC *mg;
 877 
 878                 mg = mg_find((SV *)hash, 'P');
 879                 PERL_ASSERTMSG(mg != 0, "get_tie: lost P magic");
 880                 tie = (HV *)SvRV(mg->mg_obj);
 881         }
 882         if (is_new) {
 883                 *is_new = new;
 884         }
 885         return (tie);
 886 }
 887 
 888 /*
 889  * This is an iterator function used to traverse the hash hierarchy and apply
 890  * the passed function to the tied hashes at the bottom of the hierarchy.  If
 891  * any of the callback functions return 0, 0 is returned, otherwise 1
 892  */
 893 
 894 static int
 895 apply_to_ties(SV *self, ATTCb_t cb, void *arg)
 896 {
 897         HV      *hash1;
 898         HE      *entry1;
 899         int     ret;
 900 
 901         hash1 = (HV *)SvRV(self);
 902         hv_iterinit(hash1);
 903         ret = 1;
 904 
 905         /* Iterate over each module */
 906         while ((entry1 = hv_iternext(hash1))) {
 907                 HV *hash2;
 908                 HE *entry2;
 909 
 910                 hash2 = (HV *)SvRV(hv_iterval(hash1, entry1));
 911                 hv_iterinit(hash2);
 912 
 913                 /* Iterate over each module:instance */
 914                 while ((entry2 = hv_iternext(hash2))) {
 915                         HV *hash3;
 916                         HE *entry3;
 917 
 918                         hash3 = (HV *)SvRV(hv_iterval(hash2, entry2));
 919                         hv_iterinit(hash3);
 920 
 921                         /* Iterate over each module:instance:name */
 922                         while ((entry3 = hv_iternext(hash3))) {
 923                                 HV    *hash4;
 924                                 MAGIC *mg;
 925 
 926                                 /* Get the tie */
 927                                 hash4 = (HV *)SvRV(hv_iterval(hash3, entry3));
 928                                 mg = mg_find((SV *)hash4, 'P');
 929                                 PERL_ASSERTMSG(mg != 0,
 930                                     "apply_to_ties: lost P magic");
 931 
 932                                 /* Apply the callback */
 933                                 if (! cb((HV *)SvRV(mg->mg_obj), arg)) {
 934                                         ret = 0;
 935                                 }
 936                         }
 937                 }
 938         }
 939         return (ret);
 940 }
 941 
 942 /*
 943  * Mark this HV as valid - used by update() when pruning deleted kstat nodes
 944  */
 945 
 946 static int
 947 set_valid(HV *self, void *arg)
 948 {
 949         MAGIC *mg;
 950 
 951         mg = mg_find((SV *)self, '~');
 952         PERL_ASSERTMSG(mg != 0, "set_valid: lost ~ magic");
 953         ((KstatInfo_t *)SvPVX(mg->mg_obj))->valid = (int)(intptr_t)arg;
 954         return (1);
 955 }
 956 
 957 /*
 958  * Prune invalid kstat nodes. This is called when kstat_chain_update() detects
 959  * that the kstat chain has been updated.  This removes any hash tree entries
 960  * that no longer have a corresponding kstat.  If del is non-null it will be
 961  * set to the keys of the deleted kstat nodes, if any.  If any entries are
 962  * deleted 1 will be retured, otherwise 0
 963  */
 964 
 965 static int
 966 prune_invalid(SV *self, AV *del)
 967 {
 968         HV      *hash1;
 969         HE      *entry1;
 970         STRLEN  klen;
 971         char    *module, *instance, *name, *key;
 972         int     ret;
 973 
 974         hash1 = (HV *)SvRV(self);
 975         hv_iterinit(hash1);
 976         ret = 0;
 977 
 978         /* Iterate over each module */
 979         while ((entry1 = hv_iternext(hash1))) {
 980                 HV *hash2;
 981                 HE *entry2;
 982 
 983                 module = HePV(entry1, PL_na);
 984                 hash2 = (HV *)SvRV(hv_iterval(hash1, entry1));
 985                 hv_iterinit(hash2);
 986 
 987                 /* Iterate over each module:instance */
 988                 while ((entry2 = hv_iternext(hash2))) {
 989                         HV *hash3;
 990                         HE *entry3;
 991 
 992                         instance = HePV(entry2, PL_na);
 993                         hash3 = (HV *)SvRV(hv_iterval(hash2, entry2));
 994                         hv_iterinit(hash3);
 995 
 996                         /* Iterate over each module:instance:name */
 997                         while ((entry3 = hv_iternext(hash3))) {
 998                                 HV    *hash4;
 999                                 MAGIC *mg;
1000                                 HV    *tie;
1001 
1002                                 name = HePV(entry3, PL_na);
1003                                 hash4 = (HV *)SvRV(hv_iterval(hash3, entry3));
1004                                 mg = mg_find((SV *)hash4, 'P');
1005                                 PERL_ASSERTMSG(mg != 0,
1006                                     "prune_invalid: lost P magic");
1007                                 tie = (HV *)SvRV(mg->mg_obj);
1008                                 mg = mg_find((SV *)tie, '~');
1009                                 PERL_ASSERTMSG(mg != 0,
1010                                     "prune_invalid: lost ~ magic");
1011 
1012                                 /* If this is marked as invalid, prune it */
1013                                 if (((KstatInfo_t *)SvPVX(
1014                                     (SV *)mg->mg_obj))->valid == FALSE) {
1015                                         SvREADONLY_off(hash3);
1016                                         key = HePV(entry3, klen);
1017                                         hv_delete(hash3, key, klen, G_DISCARD);
1018                                         SvREADONLY_on(hash3);
1019                                         if (del) {
1020                                                 av_push(del,
1021                                                     newSVpvf("%s:%s:%s",
1022                                                     module, instance, name));
1023                                         }
1024                                         ret = 1;
1025                                 }
1026                         }
1027 
1028                         /* If the module:instance:name hash is empty prune it */
1029                         if (HvKEYS(hash3) == 0) {
1030                                 SvREADONLY_off(hash2);
1031                                 key = HePV(entry2, klen);
1032                                 hv_delete(hash2, key, klen, G_DISCARD);
1033                                 SvREADONLY_on(hash2);
1034                         }
1035                 }
1036                 /* If the module:instance hash is empty prune it */
1037                 if (HvKEYS(hash2) == 0) {
1038                         SvREADONLY_off(hash1);
1039                         key = HePV(entry1, klen);
1040                         hv_delete(hash1, key, klen, G_DISCARD);
1041                         SvREADONLY_on(hash1);
1042                 }
1043         }
1044         return (ret);
1045 }
1046 
1047 /*
1048  * Named kstats are returned as a list of key/values.  This function converts
1049  * such a list into the equivalent perl datatypes, and stores them in the passed
1050  * hash.
1051  */
1052 
1053 static void
1054 save_named(HV *self, kstat_t *kp, int strip_str)
1055 {
1056         kstat_named_t   *knp;
1057         int             n;
1058         SV*             value;
1059 
1060         for (n = kp->ks_ndata, knp = KSTAT_NAMED_PTR(kp); n > 0; n--, knp++) {
1061                 switch (knp->data_type) {
1062                 case KSTAT_DATA_CHAR:
1063                         value = newSVpv(knp->value.c, strip_str ?
1064                             strlen(knp->value.c) : sizeof (knp->value.c));
1065                         break;
1066                 case KSTAT_DATA_INT32:
1067                         value = newSViv(knp->value.i32);
1068                         break;
1069                 case KSTAT_DATA_UINT32:
1070                         value = NEW_UV(knp->value.ui32);
1071                         break;
1072                 case KSTAT_DATA_INT64:
1073                         value = NEW_UV(knp->value.i64);
1074                         break;
1075                 case KSTAT_DATA_UINT64:
1076                         value = NEW_UV(knp->value.ui64);
1077                         break;
1078                 case KSTAT_DATA_TIME:
1079                         value = NEW_HRTIME(knp->value.ui64);
1080                         break;
1081                 case KSTAT_DATA_STRING:
1082                         if (KSTAT_NAMED_STR_PTR(knp) == NULL)
1083                                 value = newSVpv("null", sizeof ("null") - 1);
1084                         else
1085                                 value = newSVpv(KSTAT_NAMED_STR_PTR(knp),
1086                                                 KSTAT_NAMED_STR_BUFLEN(knp) -1);
1087                         break;
1088                 default:
1089                         PERL_ASSERTMSG(0, "kstat_read: invalid data type");
1090                         continue;
1091                 }
1092                 hv_store(self, knp->name, strlen(knp->name), value, 0);
1093         }
1094 }
1095 
1096 /*
1097  * Save kstat interrupt statistics
1098  */
1099 
1100 static void
1101 save_intr(HV *self, kstat_t *kp, int strip_str)
1102 {
1103         kstat_intr_t    *kintrp;
1104         int             i;
1105         static char     *intr_names[] =
1106             { "hard", "soft", "watchdog", "spurious", "multiple_service" };
1107 
1108         PERL_ASSERT(kp->ks_ndata == 1);
1109         PERL_ASSERT(kp->ks_data_size == sizeof (kstat_intr_t));
1110         kintrp = KSTAT_INTR_PTR(kp);
1111 
1112         for (i = 0; i < KSTAT_NUM_INTRS; i++) {
1113                 hv_store(self, intr_names[i], strlen(intr_names[i]),
1114                     NEW_UV(kintrp->intrs[i]), 0);
1115         }
1116 }
1117 
1118 /*
1119  * Save IO statistics
1120  */
1121 
1122 static void
1123 save_io(HV *self, kstat_t *kp, int strip_str)
1124 {
1125         kstat_io_t *kiop;
1126 
1127         PERL_ASSERT(kp->ks_ndata == 1);
1128         PERL_ASSERT(kp->ks_data_size == sizeof (kstat_io_t));
1129         kiop = KSTAT_IO_PTR(kp);
1130         SAVE_UINT64(self, kiop, nread);
1131         SAVE_UINT64(self, kiop, nwritten);
1132         SAVE_UINT32(self, kiop, reads);
1133         SAVE_UINT32(self, kiop, writes);
1134         SAVE_HRTIME(self, kiop, wtime);
1135         SAVE_HRTIME(self, kiop, wlentime);
1136         SAVE_HRTIME(self, kiop, wlastupdate);
1137         SAVE_HRTIME(self, kiop, rtime);
1138         SAVE_HRTIME(self, kiop, rlentime);
1139         SAVE_HRTIME(self, kiop, rlastupdate);
1140         SAVE_UINT32(self, kiop, wcnt);
1141         SAVE_UINT32(self, kiop, rcnt);
1142 }
1143 
1144 /*
1145  * Save timer statistics
1146  */
1147 
1148 static void
1149 save_timer(HV *self, kstat_t *kp, int strip_str)
1150 {
1151         kstat_timer_t *ktimerp;
1152 
1153         PERL_ASSERT(kp->ks_ndata == 1);
1154         PERL_ASSERT(kp->ks_data_size == sizeof (kstat_timer_t));
1155         ktimerp = KSTAT_TIMER_PTR(kp);
1156         SAVE_STRING(self, ktimerp, name, strip_str);
1157         SAVE_UINT64(self, ktimerp, num_events);
1158         SAVE_HRTIME(self, ktimerp, elapsed_time);
1159         SAVE_HRTIME(self, ktimerp, min_time);
1160         SAVE_HRTIME(self, ktimerp, max_time);
1161         SAVE_HRTIME(self, ktimerp, start_time);
1162         SAVE_HRTIME(self, ktimerp, stop_time);
1163 }
1164 
1165 /*
1166  * Read kstats and copy into the supplied perl hash structure.  If refresh is
1167  * true, this function is being called as part of the update() method.  In this
1168  * case it is only necessary to read the kstats if they have previously been
1169  * accessed (kip->read == TRUE).  If refresh is false, this function is being
1170  * called prior to returning a value to the caller. In this case, it is only
1171  * necessary to read the kstats if they have not previously been read.  If the
1172  * kstat_read() fails, 0 is returned, otherwise 1
1173  */
1174 
1175 static int
1176 read_kstats(HV *self, int refresh)
1177 {
1178         MAGIC                   *mg;
1179         KstatInfo_t             *kip;
1180         kstat_raw_reader_t      fnp;
1181 
1182         /* Find the MAGIC KstatInfo_t data structure */
1183         mg = mg_find((SV *)self, '~');
1184         PERL_ASSERTMSG(mg != 0, "read_kstats: lost ~ magic");
1185         kip = (KstatInfo_t *)SvPVX(mg->mg_obj);
1186 
1187         /* Return early if we don't need to actually read the kstats */
1188         if ((refresh && ! kip->read) || (! refresh && kip->read)) {
1189                 return (1);
1190         }
1191 
1192         /* Read the kstats and return 0 if this fails */
1193         if (kstat_read(kip->kstat_ctl, kip->kstat, NULL) < 0) {
1194                 return (0);
1195         }
1196 
1197         /* Save the read data */
1198         hv_store(self, "snaptime", 8, NEW_HRTIME(kip->kstat->ks_snaptime), 0);
1199         switch (kip->kstat->ks_type) {
1200                 case KSTAT_TYPE_RAW:
1201                         if ((fnp = lookup_raw_kstat_fn(kip->kstat->ks_module,
1202                             kip->kstat->ks_name)) != 0) {
1203                                 fnp(self, kip->kstat, kip->strip_str);
1204                         }
1205                         break;
1206                 case KSTAT_TYPE_NAMED:
1207                         save_named(self, kip->kstat, kip->strip_str);
1208                         break;
1209                 case KSTAT_TYPE_INTR:
1210                         save_intr(self, kip->kstat, kip->strip_str);
1211                         break;
1212                 case KSTAT_TYPE_IO:
1213                         save_io(self, kip->kstat, kip->strip_str);
1214                         break;
1215                 case KSTAT_TYPE_TIMER:
1216                         save_timer(self, kip->kstat, kip->strip_str);
1217                         break;
1218                 default:
1219                         PERL_ASSERTMSG(0, "read_kstats: illegal kstat type");
1220                         break;
1221         }
1222         kip->read = TRUE;
1223         return (1);
1224 }
1225 
1226 /*
1227  * The XS code exported to perl is below here.  Note that the XS preprocessor
1228  * has its own commenting syntax, so all comments from this point on are in
1229  * that form.
1230  */
1231 
1232 /* The following XS methods are the ABI of the Sun::Solaris::Kstat package */
1233 
1234 MODULE = Sun::Solaris::Kstat PACKAGE = Sun::Solaris::Kstat
1235 PROTOTYPES: ENABLE
1236 
1237  # Create the raw kstat to store function lookup table on load
1238 BOOT:
1239         build_raw_kstat_lookup();
1240 
1241  #
1242  # The Sun::Solaris::Kstat constructor.  This builds the nested
1243  # name::instance::module hash structure, but doesn't actually read the
1244  # underlying kstats.  This is done on demand by the TIEHASH methods in
1245  # Sun::Solaris::Kstat::_Stat
1246  #
1247 
1248 SV*
1249 new(class, ...)
1250         char *class;
1251 PREINIT:
1252         HV              *stash;
1253         kstat_ctl_t     *kc;
1254         SV              *kcsv;
1255         kstat_t         *kp;
1256         KstatInfo_t     kstatinfo;
1257         int             sp, strip_str;
1258 CODE:
1259         /* Check we have an even number of arguments, excluding the class */
1260         sp = 1;
1261         if (((items - sp) % 2) != 0) {
1262                 croak(DEBUG_ID ": new: invalid number of arguments");
1263         }
1264 
1265         /* Process any (name => value) arguments */
1266         strip_str = 0;
1267         while (sp < items) {
1268                 SV *name, *value;
1269 
1270                 name = ST(sp);
1271                 sp++;
1272                 value = ST(sp);
1273                 sp++;
1274                 if (strcmp(SvPVX(name), "strip_strings") == 0) {
1275                         strip_str = SvTRUE(value);
1276                 } else {
1277                         croak(DEBUG_ID ": new: invalid parameter name '%s'",
1278                             SvPVX(name));
1279                 }
1280         }
1281 
1282         /* Open the kstats handle */
1283         if ((kc = kstat_open()) == 0) {
1284                 XSRETURN_UNDEF;
1285         }
1286 
1287         /* Create a blessed hash ref */
1288         RETVAL = (SV *)newRV_noinc((SV *)newHV());
1289         stash = gv_stashpv(class, TRUE);
1290         sv_bless(RETVAL, stash);
1291 
1292         /* Create a place to save the KstatInfo_t structure */
1293         kcsv = newSVpv((char *)&kc, sizeof (kc));
1294         sv_magic(SvRV(RETVAL), kcsv, '~', 0, 0);
1295         SvREFCNT_dec(kcsv);
1296 
1297         /* Initialise the KstatsInfo_t structure */
1298         kstatinfo.read = FALSE;
1299         kstatinfo.valid = TRUE;
1300         kstatinfo.strip_str = strip_str;
1301         kstatinfo.kstat_ctl = kc;
1302 
1303         /* Scan the kstat chain, building hash entries for the kstats */
1304         for (kp = kc->kc_chain; kp != 0; kp = kp->ks_next) {
1305                 HV *tie;
1306                 SV *kstatsv;
1307 
1308                 /* Don't bother storing the kstat headers */
1309                 if (strncmp(kp->ks_name, "kstat_", 6) == 0) {
1310                         continue;
1311                 }
1312 
1313                 /* Don't bother storing raw stats we don't understand */
1314                 if (kp->ks_type == KSTAT_TYPE_RAW &&
1315                     lookup_raw_kstat_fn(kp->ks_module, kp->ks_name) == 0) {
1316 #ifdef REPORT_UNKNOWN
1317                         (void) fprintf(stderr,
1318                             "Unknown kstat type %s:%d:%s - %d of size %d\n",
1319                             kp->ks_module, kp->ks_instance, kp->ks_name,
1320                             kp->ks_ndata, kp->ks_data_size);
1321 #endif
1322                         continue;
1323                 }
1324 
1325                 /* Create a 3-layer hash hierarchy - module.instance.name */
1326                 tie = get_tie(RETVAL, kp->ks_module, kp->ks_instance,
1327                     kp->ks_name, 0);
1328 
1329                 /* Save the data necessary to read the kstat info on demand */
1330                 hv_store(tie, "class", 5, newSVpv(kp->ks_class, 0), 0);
1331                 hv_store(tie, "crtime", 6, NEW_HRTIME(kp->ks_crtime), 0);
1332                 kstatinfo.kstat = kp;
1333                 kstatsv = newSVpv((char *)&kstatinfo, sizeof (kstatinfo));
1334                 sv_magic((SV *)tie, kstatsv, '~', 0, 0);
1335                 SvREFCNT_dec(kstatsv);
1336         }
1337         SvREADONLY_on(SvRV(RETVAL));
1338         /* SvREADONLY_on(RETVAL); */
1339 OUTPUT:
1340         RETVAL
1341 
1342  #
1343  # Update the perl hash structure so that it is in line with the kernel kstats
1344  # data.  Only kstats athat have previously been accessed are read,
1345  #
1346 
1347  # Scalar context: true/false
1348  # Array context: (\@added, \@deleted)
1349 void
1350 update(self)
1351         SV* self;
1352 PREINIT:
1353         MAGIC           *mg;
1354         kstat_ctl_t     *kc;
1355         kstat_t         *kp;
1356         int             ret;
1357         AV              *add, *del;
1358 PPCODE:
1359         /* Find the hidden KstatInfo_t structure */
1360         mg = mg_find(SvRV(self), '~');
1361         PERL_ASSERTMSG(mg != 0, "update: lost ~ magic");
1362         kc = *(kstat_ctl_t **)SvPVX(mg->mg_obj);
1363 
1364         /* Update the kstat chain, and return immediately on error. */
1365         if ((ret = kstat_chain_update(kc)) == -1) {
1366                 if (GIMME_V == G_ARRAY) {
1367                         EXTEND(SP, 2);
1368                         PUSHs(sv_newmortal());
1369                         PUSHs(sv_newmortal());
1370                 } else {
1371                         EXTEND(SP, 1);
1372                         PUSHs(sv_2mortal(newSViv(ret)));
1373                 }
1374         }
1375 
1376         /* Create the arrays to be returned if in an array context */
1377         if (GIMME_V == G_ARRAY) {
1378                 add = newAV();
1379                 del = newAV();
1380         } else {
1381                 add = 0;
1382                 del = 0;
1383         }
1384 
1385         /*
1386          * If the kstat chain hasn't changed we can just reread any stats
1387          * that have already been read
1388          */
1389         if (ret == 0) {
1390                 if (! apply_to_ties(self, (ATTCb_t)read_kstats, (void *)TRUE)) {
1391                         if (GIMME_V == G_ARRAY) {
1392                                 EXTEND(SP, 2);
1393                                 PUSHs(sv_2mortal(newRV_noinc((SV *)add)));
1394                                 PUSHs(sv_2mortal(newRV_noinc((SV *)del)));
1395                         } else {
1396                                 EXTEND(SP, 1);
1397                                 PUSHs(sv_2mortal(newSViv(-1)));
1398                         }
1399                 }
1400 
1401         /*
1402          * Otherwise we have to update the Perl structure so that it is in
1403          * agreement with the new kstat chain.  We do this in such a way as to
1404          * retain all the existing structures, just adding or deleting the
1405          * bare minimum.
1406          */
1407         } else {
1408                 KstatInfo_t     kstatinfo;
1409 
1410                 /*
1411                  * Step 1: set the 'invalid' flag on each entry
1412                  */
1413                 apply_to_ties(self, &set_valid, (void *)FALSE);
1414 
1415                 /*
1416                  * Step 2: Set the 'valid' flag on all entries still in the
1417                  * kernel kstat chain
1418                  */
1419                 kstatinfo.read          = FALSE;
1420                 kstatinfo.valid         = TRUE;
1421                 kstatinfo.kstat_ctl     = kc;
1422                 for (kp = kc->kc_chain; kp != 0; kp = kp->ks_next) {
1423                         int     new;
1424                         HV      *tie;
1425 
1426                         /* Don't bother storing the kstat headers or types */
1427                         if (strncmp(kp->ks_name, "kstat_", 6) == 0) {
1428                                 continue;
1429                         }
1430 
1431                         /* Don't bother storing raw stats we don't understand */
1432                         if (kp->ks_type == KSTAT_TYPE_RAW &&
1433                             lookup_raw_kstat_fn(kp->ks_module, kp->ks_name)
1434                             == 0) {
1435 #ifdef REPORT_UNKNOWN
1436                                 (void) printf("Unknown kstat type %s:%d:%s "
1437                                     "- %d of size %d\n", kp->ks_module,
1438                                     kp->ks_instance, kp->ks_name,
1439                                     kp->ks_ndata, kp->ks_data_size);
1440 #endif
1441                                 continue;
1442                         }
1443 
1444                         /* Find the tied hash associated with the kstat entry */
1445                         tie = get_tie(self, kp->ks_module, kp->ks_instance,
1446                             kp->ks_name, &new);
1447 
1448                         /* If newly created store the associated kstat info */
1449                         if (new) {
1450                                 SV *kstatsv;
1451 
1452                                 /*
1453                                  * Save the data necessary to read the kstat
1454                                  * info on demand
1455                                  */
1456                                 hv_store(tie, "class", 5,
1457                                     newSVpv(kp->ks_class, 0), 0);
1458                                 hv_store(tie, "crtime", 6,
1459                                     NEW_HRTIME(kp->ks_crtime), 0);
1460                                 kstatinfo.kstat = kp;
1461                                 kstatsv = newSVpv((char *)&kstatinfo,
1462                                     sizeof (kstatinfo));
1463                                 sv_magic((SV *)tie, kstatsv, '~', 0, 0);
1464                                 SvREFCNT_dec(kstatsv);
1465 
1466                                 /* Save the key on the add list, if required */
1467                                 if (GIMME_V == G_ARRAY) {
1468                                         av_push(add, newSVpvf("%s:%d:%s",
1469                                             kp->ks_module, kp->ks_instance,
1470                                             kp->ks_name));
1471                                 }
1472 
1473                         /* If the stats already exist, just update them */
1474                         } else {
1475                                 MAGIC *mg;
1476                                 KstatInfo_t *kip;
1477 
1478                                 /* Find the hidden KstatInfo_t */
1479                                 mg = mg_find((SV *)tie, '~');
1480                                 PERL_ASSERTMSG(mg != 0, "update: lost ~ magic");
1481                                 kip = (KstatInfo_t *)SvPVX(mg->mg_obj);
1482 
1483                                 /* Mark the tie as valid */
1484                                 kip->valid = TRUE;
1485 
1486                                 /* Re-save the kstat_t pointer.  If the kstat
1487                                  * has been deleted and re-added since the last
1488                                  * update, the address of the kstat structure
1489                                  * will have changed, even though the kstat will
1490                                  * still live at the same place in the perl
1491                                  * hash tree structure.
1492                                  */
1493                                 kip->kstat = kp;
1494 
1495                                 /* Reread the stats, if read previously */
1496                                 read_kstats(tie, TRUE);
1497                         }
1498                 }
1499 
1500                 /*
1501                  *Step 3: Delete any entries still marked as 'invalid'
1502                  */
1503                 ret = prune_invalid(self, del);
1504 
1505         }
1506         if (GIMME_V == G_ARRAY) {
1507                 EXTEND(SP, 2);
1508                 PUSHs(sv_2mortal(newRV_noinc((SV *)add)));
1509                 PUSHs(sv_2mortal(newRV_noinc((SV *)del)));
1510         } else {
1511                 EXTEND(SP, 1);
1512                 PUSHs(sv_2mortal(newSViv(ret)));
1513         }
1514 
1515 
1516  #
1517  # Destructor.  Closes the kstat connection
1518  #
1519 
1520 void
1521 DESTROY(self)
1522         SV *self;
1523 PREINIT:
1524         MAGIC           *mg;
1525         kstat_ctl_t     *kc;
1526 CODE:
1527         mg = mg_find(SvRV(self), '~');
1528         PERL_ASSERTMSG(mg != 0, "DESTROY: lost ~ magic");
1529         kc = *(kstat_ctl_t **)SvPVX(mg->mg_obj);
1530         if (kstat_close(kc) != 0) {
1531                 croak(DEBUG_ID ": kstat_close: failed");
1532         }
1533 
1534  #
1535  # The following XS methods implement the TIEHASH mechanism used to update the
1536  # kstats hash structure.  These are blessed into a package that isn't
1537  # visible to callers of the Sun::Solaris::Kstat module
1538  #
1539 
1540 MODULE = Sun::Solaris::Kstat PACKAGE = Sun::Solaris::Kstat::_Stat
1541 PROTOTYPES: ENABLE
1542 
1543  #
1544  # If a value has already been read, return it.  Otherwise read the appropriate
1545  # kstat and then return the value
1546  #
1547 
1548 SV*
1549 FETCH(self, key)
1550         SV* self;
1551         SV* key;
1552 PREINIT:
1553         char    *k;
1554         STRLEN  klen;
1555         SV      **value;
1556 CODE:
1557         self = SvRV(self);
1558         k = SvPV(key, klen);
1559         if (strNE(k, "class") && strNE(k, "crtime")) {
1560                 read_kstats((HV *)self, FALSE);
1561         }
1562         value = hv_fetch((HV *)self, k, klen, FALSE);
1563         if (value) {
1564                 RETVAL = *value; SvREFCNT_inc(RETVAL);
1565         } else {
1566                 RETVAL = &PL_sv_undef;
1567         }
1568 OUTPUT:
1569         RETVAL
1570 
1571  #
1572  # Save the passed value into the kstat hash.  Read the appropriate kstat first,
1573  # if necessary.  Note that this DOES NOT update the underlying kernel kstat
1574  # structure.
1575  #
1576 
1577 SV*
1578 STORE(self, key, value)
1579         SV* self;
1580         SV* key;
1581         SV* value;
1582 PREINIT:
1583         char    *k;
1584         STRLEN  klen;
1585 CODE:
1586         self = SvRV(self);
1587         k = SvPV(key, klen);
1588         if (strNE(k, "class") && strNE(k, "crtime")) {
1589                 read_kstats((HV *)self, FALSE);
1590         }
1591         SvREFCNT_inc(value);
1592         RETVAL = *(hv_store((HV *)self, k, klen, value, 0));
1593         SvREFCNT_inc(RETVAL);
1594 OUTPUT:
1595         RETVAL
1596 
1597  #
1598  # Check for the existence of the passed key.  Read the kstat first if necessary
1599  #
1600 
1601 bool
1602 EXISTS(self, key)
1603         SV* self;
1604         SV* key;
1605 PREINIT:
1606         char *k;
1607 CODE:
1608         self = SvRV(self);
1609         k = SvPV(key, PL_na);
1610         if (strNE(k, "class") && strNE(k, "crtime")) {
1611                 read_kstats((HV *)self, FALSE);
1612         }
1613         RETVAL = hv_exists_ent((HV *)self, key, 0);
1614 OUTPUT:
1615         RETVAL
1616 
1617 
1618  #
1619  # Hash iterator initialisation.  Read the kstats if necessary.
1620  #
1621 
1622 SV*
1623 FIRSTKEY(self)
1624         SV* self;
1625 PREINIT:
1626         HE *he;
1627 PPCODE:
1628         self = SvRV(self);
1629         read_kstats((HV *)self, FALSE);
1630         hv_iterinit((HV *)self);
1631         if ((he = hv_iternext((HV *)self))) {
1632                 EXTEND(SP, 1);
1633                 PUSHs(hv_iterkeysv(he));
1634         }
1635 
1636  #
1637  # Return hash iterator next value.  Read the kstats if necessary.
1638  #
1639 
1640 SV*
1641 NEXTKEY(self, lastkey)
1642         SV* self;
1643         SV* lastkey;
1644 PREINIT:
1645         HE *he;
1646 PPCODE:
1647         self = SvRV(self);
1648         if ((he = hv_iternext((HV *)self))) {
1649                 EXTEND(SP, 1);
1650                 PUSHs(hv_iterkeysv(he));
1651         }
1652 
1653 
1654  #
1655  # Delete the specified hash entry.
1656  #
1657 
1658 SV*
1659 DELETE(self, key)
1660         SV *self;
1661         SV *key;
1662 CODE:
1663         self = SvRV(self);
1664         RETVAL = hv_delete_ent((HV *)self, key, 0, 0);
1665         if (RETVAL) {
1666                 SvREFCNT_inc(RETVAL);
1667         } else {
1668                 RETVAL = &PL_sv_undef;
1669         }
1670 OUTPUT:
1671         RETVAL
1672 
1673  #
1674  # Clear the entire hash.  This will stop any update() calls rereading this
1675  # kstat until it is accessed again.
1676  #
1677 
1678 void
1679 CLEAR(self)
1680         SV* self;
1681 PREINIT:
1682         MAGIC   *mg;
1683         KstatInfo_t *kip;
1684 CODE:
1685         self = SvRV(self);
1686         hv_clear((HV *)self);
1687         mg = mg_find(self, '~');
1688         PERL_ASSERTMSG(mg != 0, "CLEAR: lost ~ magic");
1689         kip = (KstatInfo_t *)SvPVX(mg->mg_obj);
1690         kip->read  = FALSE;
1691         kip->valid = TRUE;
1692         hv_store((HV *)self, "class", 5, newSVpv(kip->kstat->ks_class, 0), 0);
1693         hv_store((HV *)self, "crtime", 6, NEW_HRTIME(kip->kstat->ks_crtime), 0);