xref: /illumos-gate/usr/src/cmd/perl/contrib/Sun/Solaris/Kstat/Kstat.xs (revision f52943a93040563107b95bccb9db87d9971ef47d)
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 2019 OmniOS Community Edition (OmniOSce) Association.
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 sockinfo.  ks_ndata is the number of elements of that
67  * array and ks_data_size is the total size of the array.
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_STRING:
1079 			if (KSTAT_NAMED_STR_PTR(knp) == NULL)
1080 				value = newSVpv("null", sizeof ("null") - 1);
1081 			else
1082 				value = newSVpv(KSTAT_NAMED_STR_PTR(knp),
1083 						KSTAT_NAMED_STR_BUFLEN(knp) -1);
1084 			break;
1085 		default:
1086 			PERL_ASSERTMSG(0, "kstat_read: invalid data type");
1087 			continue;
1088 		}
1089 		hv_store(self, knp->name, strlen(knp->name), value, 0);
1090 	}
1091 }
1092 
1093 /*
1094  * Save kstat interrupt statistics
1095  */
1096 
1097 static void
1098 save_intr(HV *self, kstat_t *kp, int strip_str)
1099 {
1100 	kstat_intr_t	*kintrp;
1101 	int		i;
1102 	static char	*intr_names[] =
1103 	    { "hard", "soft", "watchdog", "spurious", "multiple_service" };
1104 
1105 	PERL_ASSERT(kp->ks_ndata == 1);
1106 	PERL_ASSERT(kp->ks_data_size == sizeof (kstat_intr_t));
1107 	kintrp = KSTAT_INTR_PTR(kp);
1108 
1109 	for (i = 0; i < KSTAT_NUM_INTRS; i++) {
1110 		hv_store(self, intr_names[i], strlen(intr_names[i]),
1111 		    NEW_UV(kintrp->intrs[i]), 0);
1112 	}
1113 }
1114 
1115 /*
1116  * Save IO statistics
1117  */
1118 
1119 static void
1120 save_io(HV *self, kstat_t *kp, int strip_str)
1121 {
1122 	kstat_io_t *kiop;
1123 
1124 	PERL_ASSERT(kp->ks_ndata == 1);
1125 	PERL_ASSERT(kp->ks_data_size == sizeof (kstat_io_t));
1126 	kiop = KSTAT_IO_PTR(kp);
1127 	SAVE_UINT64(self, kiop, nread);
1128 	SAVE_UINT64(self, kiop, nwritten);
1129 	SAVE_UINT32(self, kiop, reads);
1130 	SAVE_UINT32(self, kiop, writes);
1131 	SAVE_HRTIME(self, kiop, wtime);
1132 	SAVE_HRTIME(self, kiop, wlentime);
1133 	SAVE_HRTIME(self, kiop, wlastupdate);
1134 	SAVE_HRTIME(self, kiop, rtime);
1135 	SAVE_HRTIME(self, kiop, rlentime);
1136 	SAVE_HRTIME(self, kiop, rlastupdate);
1137 	SAVE_UINT32(self, kiop, wcnt);
1138 	SAVE_UINT32(self, kiop, rcnt);
1139 }
1140 
1141 /*
1142  * Save timer statistics
1143  */
1144 
1145 static void
1146 save_timer(HV *self, kstat_t *kp, int strip_str)
1147 {
1148 	kstat_timer_t *ktimerp;
1149 
1150 	PERL_ASSERT(kp->ks_ndata == 1);
1151 	PERL_ASSERT(kp->ks_data_size == sizeof (kstat_timer_t));
1152 	ktimerp = KSTAT_TIMER_PTR(kp);
1153 	SAVE_STRING(self, ktimerp, name, strip_str);
1154 	SAVE_UINT64(self, ktimerp, num_events);
1155 	SAVE_HRTIME(self, ktimerp, elapsed_time);
1156 	SAVE_HRTIME(self, ktimerp, min_time);
1157 	SAVE_HRTIME(self, ktimerp, max_time);
1158 	SAVE_HRTIME(self, ktimerp, start_time);
1159 	SAVE_HRTIME(self, ktimerp, stop_time);
1160 }
1161 
1162 /*
1163  * Read kstats and copy into the supplied perl hash structure.  If refresh is
1164  * true, this function is being called as part of the update() method.  In this
1165  * case it is only necessary to read the kstats if they have previously been
1166  * accessed (kip->read == TRUE).  If refresh is false, this function is being
1167  * called prior to returning a value to the caller. In this case, it is only
1168  * necessary to read the kstats if they have not previously been read.  If the
1169  * kstat_read() fails, 0 is returned, otherwise 1
1170  */
1171 
1172 static int
1173 read_kstats(HV *self, int refresh)
1174 {
1175 	MAGIC			*mg;
1176 	KstatInfo_t		*kip;
1177 	kstat_raw_reader_t	fnp;
1178 
1179 	/* Find the MAGIC KstatInfo_t data structure */
1180 	mg = mg_find((SV *)self, '~');
1181 	PERL_ASSERTMSG(mg != 0, "read_kstats: lost ~ magic");
1182 	kip = (KstatInfo_t *)SvPVX(mg->mg_obj);
1183 
1184 	/* Return early if we don't need to actually read the kstats */
1185 	if ((refresh && ! kip->read) || (! refresh && kip->read)) {
1186 		return (1);
1187 	}
1188 
1189 	/* Read the kstats and return 0 if this fails */
1190 	if (kstat_read(kip->kstat_ctl, kip->kstat, NULL) < 0) {
1191 		return (0);
1192 	}
1193 
1194 	/* Save the read data */
1195 	hv_store(self, "snaptime", 8, NEW_HRTIME(kip->kstat->ks_snaptime), 0);
1196 	switch (kip->kstat->ks_type) {
1197 		case KSTAT_TYPE_RAW:
1198 			if ((fnp = lookup_raw_kstat_fn(kip->kstat->ks_module,
1199 			    kip->kstat->ks_name)) != 0) {
1200 				fnp(self, kip->kstat, kip->strip_str);
1201 			}
1202 			break;
1203 		case KSTAT_TYPE_NAMED:
1204 			save_named(self, kip->kstat, kip->strip_str);
1205 			break;
1206 		case KSTAT_TYPE_INTR:
1207 			save_intr(self, kip->kstat, kip->strip_str);
1208 			break;
1209 		case KSTAT_TYPE_IO:
1210 			save_io(self, kip->kstat, kip->strip_str);
1211 			break;
1212 		case KSTAT_TYPE_TIMER:
1213 			save_timer(self, kip->kstat, kip->strip_str);
1214 			break;
1215 		default:
1216 			PERL_ASSERTMSG(0, "read_kstats: illegal kstat type");
1217 			break;
1218 	}
1219 	kip->read = TRUE;
1220 	return (1);
1221 }
1222 
1223 static int
1224 read_kstats_wrap(HV *self, void *ptr)
1225 {
1226 	int refresh = (intptr_t)ptr;
1227 
1228 	return (read_kstats(self, refresh));
1229 }
1230 
1231 /*
1232  * The XS code exported to perl is below here.  Note that the XS preprocessor
1233  * has its own commenting syntax, so all comments from this point on are in
1234  * that form.
1235  */
1236 
1237 /* The following XS methods are the ABI of the Sun::Solaris::Kstat package */
1238 
1239 MODULE = Sun::Solaris::Kstat PACKAGE = Sun::Solaris::Kstat
1240 PROTOTYPES: ENABLE
1241 
1242  # Create the raw kstat to store function lookup table on load
1243 BOOT:
1244 	build_raw_kstat_lookup();
1245 
1246  #
1247  # The Sun::Solaris::Kstat constructor.  This builds the nested
1248  # name::instance::module hash structure, but doesn't actually read the
1249  # underlying kstats.  This is done on demand by the TIEHASH methods in
1250  # Sun::Solaris::Kstat::_Stat
1251  #
1252 
1253 SV*
1254 new(class, ...)
1255 	char *class;
1256 PREINIT:
1257 	HV		*stash;
1258 	kstat_ctl_t	*kc;
1259 	SV		*kcsv;
1260 	kstat_t		*kp;
1261 	KstatInfo_t	kstatinfo;
1262 	int		sp, strip_str;
1263 CODE:
1264 	/* Check we have an even number of arguments, excluding the class */
1265 	sp = 1;
1266 	if (((items - sp) % 2) != 0) {
1267 		croak(DEBUG_ID ": new: invalid number of arguments");
1268 	}
1269 
1270 	/* Process any (name => value) arguments */
1271 	strip_str = 0;
1272 	while (sp < items) {
1273 		SV *name, *value;
1274 
1275 		name = ST(sp);
1276 		sp++;
1277 		value = ST(sp);
1278 		sp++;
1279 		if (strcmp(SvPVX(name), "strip_strings") == 0) {
1280 			strip_str = SvTRUE(value);
1281 		} else {
1282 			croak(DEBUG_ID ": new: invalid parameter name '%s'",
1283 			    SvPVX(name));
1284 		}
1285 	}
1286 
1287 	/* Open the kstats handle */
1288 	if ((kc = kstat_open()) == 0) {
1289 		XSRETURN_UNDEF;
1290 	}
1291 
1292 	/* Create a blessed hash ref */
1293 	RETVAL = (SV *)newRV_noinc((SV *)newHV());
1294 	stash = gv_stashpv(class, TRUE);
1295 	sv_bless(RETVAL, stash);
1296 
1297 	/* Create a place to save the KstatInfo_t structure */
1298 	kcsv = newSVpv((char *)&kc, sizeof (kc));
1299 	sv_magic(SvRV(RETVAL), kcsv, '~', 0, 0);
1300 	SvREFCNT_dec(kcsv);
1301 
1302 	/* Initialise the KstatsInfo_t structure */
1303 	kstatinfo.read = FALSE;
1304 	kstatinfo.valid = TRUE;
1305 	kstatinfo.strip_str = strip_str;
1306 	kstatinfo.kstat_ctl = kc;
1307 
1308 	/* Scan the kstat chain, building hash entries for the kstats */
1309 	for (kp = kc->kc_chain; kp != 0; kp = kp->ks_next) {
1310 		HV *tie;
1311 		SV *kstatsv;
1312 
1313 		/* Don't bother storing the kstat headers */
1314 		if (strncmp(kp->ks_name, "kstat_", 6) == 0) {
1315 			continue;
1316 		}
1317 
1318 		/* Don't bother storing raw stats we don't understand */
1319 		if (kp->ks_type == KSTAT_TYPE_RAW &&
1320 		    lookup_raw_kstat_fn(kp->ks_module, kp->ks_name) == 0) {
1321 #ifdef REPORT_UNKNOWN
1322 			(void) fprintf(stderr,
1323 			    "Unknown kstat type %s:%d:%s - %d of size %d\n",
1324 			    kp->ks_module, kp->ks_instance, kp->ks_name,
1325 			    kp->ks_ndata, kp->ks_data_size);
1326 #endif
1327 			continue;
1328 		}
1329 
1330 		/* Create a 3-layer hash hierarchy - module.instance.name */
1331 		tie = get_tie(RETVAL, kp->ks_module, kp->ks_instance,
1332 		    kp->ks_name, 0);
1333 
1334 		/* Save the data necessary to read the kstat info on demand */
1335 		hv_store(tie, "class", 5, newSVpv(kp->ks_class, 0), 0);
1336 		hv_store(tie, "crtime", 6, NEW_HRTIME(kp->ks_crtime), 0);
1337 		kstatinfo.kstat = kp;
1338 		kstatsv = newSVpv((char *)&kstatinfo, sizeof (kstatinfo));
1339 		sv_magic((SV *)tie, kstatsv, '~', 0, 0);
1340 		SvREFCNT_dec(kstatsv);
1341 	}
1342 	SvREADONLY_on(SvRV(RETVAL));
1343 	/* SvREADONLY_on(RETVAL); */
1344 OUTPUT:
1345 	RETVAL
1346 
1347  #
1348  # Update the perl hash structure so that it is in line with the kernel kstats
1349  # data.  Only kstats athat have previously been accessed are read,
1350  #
1351 
1352  # Scalar context: true/false
1353  # Array context: (\@added, \@deleted)
1354 void
1355 update(self)
1356 	SV* self;
1357 PREINIT:
1358 	MAGIC		*mg;
1359 	kstat_ctl_t	*kc;
1360 	kstat_t		*kp;
1361 	int		ret;
1362 	AV		*add, *del;
1363 PPCODE:
1364 	/* Find the hidden KstatInfo_t structure */
1365 	mg = mg_find(SvRV(self), '~');
1366 	PERL_ASSERTMSG(mg != 0, "update: lost ~ magic");
1367 	kc = *(kstat_ctl_t **)SvPVX(mg->mg_obj);
1368 
1369 	/* Update the kstat chain, and return immediately on error. */
1370 	if ((ret = kstat_chain_update(kc)) == -1) {
1371 		if (GIMME_V == G_ARRAY) {
1372 			EXTEND(SP, 2);
1373 			PUSHs(sv_newmortal());
1374 			PUSHs(sv_newmortal());
1375 		} else {
1376 			EXTEND(SP, 1);
1377 			PUSHs(sv_2mortal(newSViv(ret)));
1378 		}
1379 	}
1380 
1381 	/* Create the arrays to be returned if in an array context */
1382 	if (GIMME_V == G_ARRAY) {
1383 		add = newAV();
1384 		del = newAV();
1385 	} else {
1386 		add = 0;
1387 		del = 0;
1388 	}
1389 
1390 	/*
1391 	 * If the kstat chain hasn't changed we can just reread any stats
1392 	 * that have already been read
1393 	 */
1394 	if (ret == 0) {
1395 		if (! apply_to_ties(self, read_kstats_wrap, (void *)TRUE)) {
1396 			if (GIMME_V == G_ARRAY) {
1397 				EXTEND(SP, 2);
1398 				PUSHs(sv_2mortal(newRV_noinc((SV *)add)));
1399 				PUSHs(sv_2mortal(newRV_noinc((SV *)del)));
1400 			} else {
1401 				EXTEND(SP, 1);
1402 				PUSHs(sv_2mortal(newSViv(-1)));
1403 			}
1404 		}
1405 
1406 	/*
1407 	 * Otherwise we have to update the Perl structure so that it is in
1408 	 * agreement with the new kstat chain.  We do this in such a way as to
1409 	 * retain all the existing structures, just adding or deleting the
1410 	 * bare minimum.
1411 	 */
1412 	} else {
1413 		KstatInfo_t	kstatinfo;
1414 
1415 		/*
1416 		 * Step 1: set the 'invalid' flag on each entry
1417 		 */
1418 		apply_to_ties(self, &set_valid, (void *)FALSE);
1419 
1420 		/*
1421 		 * Step 2: Set the 'valid' flag on all entries still in the
1422 		 * kernel kstat chain
1423 		 */
1424 		kstatinfo.read		= FALSE;
1425 		kstatinfo.valid		= TRUE;
1426 		kstatinfo.kstat_ctl	= kc;
1427 		for (kp = kc->kc_chain; kp != 0; kp = kp->ks_next) {
1428 			int	new;
1429 			HV	*tie;
1430 
1431 			/* Don't bother storing the kstat headers or types */
1432 			if (strncmp(kp->ks_name, "kstat_", 6) == 0) {
1433 				continue;
1434 			}
1435 
1436 			/* Don't bother storing raw stats we don't understand */
1437 			if (kp->ks_type == KSTAT_TYPE_RAW &&
1438 			    lookup_raw_kstat_fn(kp->ks_module, kp->ks_name)
1439 			    == 0) {
1440 #ifdef REPORT_UNKNOWN
1441 				(void) printf("Unknown kstat type %s:%d:%s "
1442 				    "- %d of size %d\n", kp->ks_module,
1443 				    kp->ks_instance, kp->ks_name,
1444 				    kp->ks_ndata, kp->ks_data_size);
1445 #endif
1446 				continue;
1447 			}
1448 
1449 			/* Find the tied hash associated with the kstat entry */
1450 			tie = get_tie(self, kp->ks_module, kp->ks_instance,
1451 			    kp->ks_name, &new);
1452 
1453 			/* If newly created store the associated kstat info */
1454 			if (new) {
1455 				SV *kstatsv;
1456 
1457 				/*
1458 				 * Save the data necessary to read the kstat
1459 				 * info on demand
1460 				 */
1461 				hv_store(tie, "class", 5,
1462 				    newSVpv(kp->ks_class, 0), 0);
1463 				hv_store(tie, "crtime", 6,
1464 				    NEW_HRTIME(kp->ks_crtime), 0);
1465 				kstatinfo.kstat = kp;
1466 				kstatsv = newSVpv((char *)&kstatinfo,
1467 				    sizeof (kstatinfo));
1468 				sv_magic((SV *)tie, kstatsv, '~', 0, 0);
1469 				SvREFCNT_dec(kstatsv);
1470 
1471 				/* Save the key on the add list, if required */
1472 				if (GIMME_V == G_ARRAY) {
1473 					av_push(add, newSVpvf("%s:%d:%s",
1474 					    kp->ks_module, kp->ks_instance,
1475 					    kp->ks_name));
1476 				}
1477 
1478 			/* If the stats already exist, just update them */
1479 			} else {
1480 				MAGIC *mg;
1481 				KstatInfo_t *kip;
1482 
1483 				/* Find the hidden KstatInfo_t */
1484 				mg = mg_find((SV *)tie, '~');
1485 				PERL_ASSERTMSG(mg != 0, "update: lost ~ magic");
1486 				kip = (KstatInfo_t *)SvPVX(mg->mg_obj);
1487 
1488 				/* Mark the tie as valid */
1489 				kip->valid = TRUE;
1490 
1491 				/* Re-save the kstat_t pointer.  If the kstat
1492 				 * has been deleted and re-added since the last
1493 				 * update, the address of the kstat structure
1494 				 * will have changed, even though the kstat will
1495 				 * still live at the same place in the perl
1496 				 * hash tree structure.
1497 				 */
1498 				kip->kstat = kp;
1499 
1500 				/* Reread the stats, if read previously */
1501 				read_kstats(tie, TRUE);
1502 			}
1503 		}
1504 
1505 		/*
1506 		 *Step 3: Delete any entries still marked as 'invalid'
1507 		 */
1508 		ret = prune_invalid(self, del);
1509 
1510 	}
1511 	if (GIMME_V == G_ARRAY) {
1512 		EXTEND(SP, 2);
1513 		PUSHs(sv_2mortal(newRV_noinc((SV *)add)));
1514 		PUSHs(sv_2mortal(newRV_noinc((SV *)del)));
1515 	} else {
1516 		EXTEND(SP, 1);
1517 		PUSHs(sv_2mortal(newSViv(ret)));
1518 	}
1519 
1520 
1521  #
1522  # Destructor.  Closes the kstat connection
1523  #
1524 
1525 void
1526 DESTROY(self)
1527 	SV *self;
1528 PREINIT:
1529 	MAGIC		*mg;
1530 	kstat_ctl_t	*kc;
1531 CODE:
1532 	mg = mg_find(SvRV(self), '~');
1533 	PERL_ASSERTMSG(mg != 0, "DESTROY: lost ~ magic");
1534 	kc = *(kstat_ctl_t **)SvPVX(mg->mg_obj);
1535 	if (kstat_close(kc) != 0) {
1536 		croak(DEBUG_ID ": kstat_close: failed");
1537 	}
1538 
1539  #
1540  # The following XS methods implement the TIEHASH mechanism used to update the
1541  # kstats hash structure.  These are blessed into a package that isn't
1542  # visible to callers of the Sun::Solaris::Kstat module
1543  #
1544 
1545 MODULE = Sun::Solaris::Kstat PACKAGE = Sun::Solaris::Kstat::_Stat
1546 PROTOTYPES: ENABLE
1547 
1548  #
1549  # If a value has already been read, return it.  Otherwise read the appropriate
1550  # kstat and then return the value
1551  #
1552 
1553 SV*
1554 FETCH(self, key)
1555 	SV* self;
1556 	SV* key;
1557 PREINIT:
1558 	char	*k;
1559 	STRLEN	klen;
1560 	SV	**value;
1561 CODE:
1562 	self = SvRV(self);
1563 	k = SvPV(key, klen);
1564 	if (strNE(k, "class") && strNE(k, "crtime")) {
1565 		read_kstats((HV *)self, FALSE);
1566 	}
1567 	value = hv_fetch((HV *)self, k, klen, FALSE);
1568 	if (value) {
1569 		RETVAL = *value; SvREFCNT_inc(RETVAL);
1570 	} else {
1571 		RETVAL = &PL_sv_undef;
1572 	}
1573 OUTPUT:
1574 	RETVAL
1575 
1576  #
1577  # Save the passed value into the kstat hash.  Read the appropriate kstat first,
1578  # if necessary.  Note that this DOES NOT update the underlying kernel kstat
1579  # structure.
1580  #
1581 
1582 SV*
1583 STORE(self, key, value)
1584 	SV* self;
1585 	SV* key;
1586 	SV* value;
1587 PREINIT:
1588 	char	*k;
1589 	STRLEN	klen;
1590 CODE:
1591 	self = SvRV(self);
1592 	k = SvPV(key, klen);
1593 	if (strNE(k, "class") && strNE(k, "crtime")) {
1594 		read_kstats((HV *)self, FALSE);
1595 	}
1596 	SvREFCNT_inc(value);
1597 	RETVAL = *(hv_store((HV *)self, k, klen, value, 0));
1598 	SvREFCNT_inc(RETVAL);
1599 OUTPUT:
1600 	RETVAL
1601 
1602  #
1603  # Check for the existence of the passed key.  Read the kstat first if necessary
1604  #
1605 
1606 bool
1607 EXISTS(self, key)
1608 	SV* self;
1609 	SV* key;
1610 PREINIT:
1611 	char *k;
1612 CODE:
1613 	self = SvRV(self);
1614 	k = SvPV(key, PL_na);
1615 	if (strNE(k, "class") && strNE(k, "crtime")) {
1616 		read_kstats((HV *)self, FALSE);
1617 	}
1618 	RETVAL = hv_exists_ent((HV *)self, key, 0);
1619 OUTPUT:
1620 	RETVAL
1621 
1622 
1623  #
1624  # Hash iterator initialisation.  Read the kstats if necessary.
1625  #
1626 
1627 SV*
1628 FIRSTKEY(self)
1629 	SV* self;
1630 PREINIT:
1631 	HE *he;
1632 PPCODE:
1633 	self = SvRV(self);
1634 	read_kstats((HV *)self, FALSE);
1635 	hv_iterinit((HV *)self);
1636 	if ((he = hv_iternext((HV *)self))) {
1637 		EXTEND(SP, 1);
1638 		PUSHs(hv_iterkeysv(he));
1639 	}
1640 
1641  #
1642  # Return hash iterator next value.  Read the kstats if necessary.
1643  #
1644 
1645 SV*
1646 NEXTKEY(self, lastkey)
1647 	SV* self;
1648 	SV* lastkey;
1649 PREINIT:
1650 	HE *he;
1651 PPCODE:
1652 	self = SvRV(self);
1653 	if ((he = hv_iternext((HV *)self))) {
1654 		EXTEND(SP, 1);
1655 		PUSHs(hv_iterkeysv(he));
1656 	}
1657 
1658 
1659  #
1660  # Delete the specified hash entry.
1661  #
1662 
1663 SV*
1664 DELETE(self, key)
1665 	SV *self;
1666 	SV *key;
1667 CODE:
1668 	self = SvRV(self);
1669 	RETVAL = hv_delete_ent((HV *)self, key, 0, 0);
1670 	if (RETVAL) {
1671 		SvREFCNT_inc(RETVAL);
1672 	} else {
1673 		RETVAL = &PL_sv_undef;
1674 	}
1675 OUTPUT:
1676 	RETVAL
1677 
1678  #
1679  # Clear the entire hash.  This will stop any update() calls rereading this
1680  # kstat until it is accessed again.
1681  #
1682 
1683 void
1684 CLEAR(self)
1685 	SV* self;
1686 PREINIT:
1687 	MAGIC   *mg;
1688 	KstatInfo_t *kip;
1689 CODE:
1690 	self = SvRV(self);
1691 	hv_clear((HV *)self);
1692 	mg = mg_find(self, '~');
1693 	PERL_ASSERTMSG(mg != 0, "CLEAR: lost ~ magic");
1694 	kip = (KstatInfo_t *)SvPVX(mg->mg_obj);
1695 	kip->read  = FALSE;
1696 	kip->valid = TRUE;
1697 	hv_store((HV *)self, "class", 5, newSVpv(kip->kstat->ks_class, 0), 0);
1698 	hv_store((HV *)self, "crtime", 6, NEW_HRTIME(kip->kstat->ks_crtime), 0);
1699