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