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