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