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