/* $Id: pack.c,v 1.1 2003/03/31 17:42:16 deschwen Exp $ */

#include "pack.h"

/* herein the various structures (defined in "pack.h") are packed
 * to Perl data structures, mostly hashes. Calls to these functions
 * are generated by xsubpp according to the typemap.
 *
 * see perlguts(1) for some of the Perl magic used here
 */


/* some macros help us to keep the code below understandable */

/* pack the integer value in p->name into hash hv
 * using key "name"
 */
#define PACK_IV(name) \
    sv = newSViv(p->name);\
    if (hv_store(hv, #name, sizeof(#name)-1, sv, 0) == NULL) {\
    warn("__FILE__:__LINE__ failed to pack '" ## #name ## "' elem");\
    }\

/* pack the double value in p->name into hash hv
 * using key "name"
 */
#define PACK_NV(name) \
    sv = newSVnv(p->name);\
    if (hv_store(hv, #name, sizeof(#name)-1, sv, 0) == NULL) {\
    warn("__FILE__:__LINE__ failed to pack '" ## #name ## "' elem");\
    }\

/* pack the string starting at p->name into hash hv
 * using key "name", string length in len (calculated if len == 0)
 */
#define PACK_PV(name, len) \
    sv = newSVpv(p->name, len);\
    if (hv_store(hv, #name, sizeof(#name)-1, sv, 0) == NULL) {\
    warn("__FILE__:__LINE__ failed to pack '" ## #name ## "' elem");\
    }\

/* pack reference to av into hash hv
 * using key "name"
 */
#define PACK_AV(name) \
    sv = newRV_noinc((SV*)av);\
    if (hv_store(hv, #name, sizeof(#name)-1, sv, 0) == NULL) {\
    warn("__FILE__:__LINE__ failed to pack '" ## #name ## "' elem");\
    }\



/* pack struct pst_static into a hash
 * and put a reference to this hash onto Perl stack
 */
void XS_pack_pst_staticPtr(SV* st, pst_static* p)
{
    HV *hv = newHV();
    SV *sv;

    PACK_IV(boot_time);
    PACK_IV(physical_memory);
    PACK_IV(page_size);
    PACK_IV(cpu_states);
    PACK_IV(pst_status_size);
    PACK_IV(pst_static_size);
    PACK_IV(pst_dynamic_size);
    PACK_IV(pst_vminfo_size);
    PACK_IV(command_length);
    PACK_IV(pst_processor_size);
    PACK_IV(pst_diskinfo_size);
    PACK_IV(pst_lvinfo_size);
    PACK_IV(pst_swapinfo_size);
    PACK_IV(pst_maxmem);
    PACK_IV(pst_lotsfree);
    PACK_IV(pst_desfree);
    PACK_IV(pst_minfree);
    PACK_IV(pst_max_ninode);
    PACK_IV(pst_max_nfile);
    PACK_IV(pst_stable_size);

    {   /* pst_supported_pgsize[] */
        AV *av = newAV();
        int i;
        for (i=0; i<PST_N_PG_SIZES; i++) {
            av_push(av, newSViv(p->pst_supported_pgsize[i]));
        }
        PACK_AV(pst_supported_pgsize);
    }

    /* put ref to hv onto stack */
    sv = newSVrv(st, NULL);
    SvREFCNT_dec(sv);
    SvRV(st) = (SV*)hv;
}


/* pack struct pst_dynamic into a hash
 * and put a reference to this hash onto Perl stack
 */
void XS_pack_pst_dynamicPtr(SV* st, pst_dynamic* p)
{
    HV *hv = newHV();
    SV *sv;

    PACK_IV(psd_proc_cnt);	/* MP: number of active processors */
    PACK_IV(psd_max_proc_cnt);  /* MP: max active processors */
    PACK_IV(psd_last_pid);	/* last run process ID */
    PACK_IV(psd_rq);		/* run queue length */
    PACK_IV(psd_dw);		/* jobs in disk wait */
    PACK_IV(psd_pw);		/* jobs in page wait */
    PACK_IV(psd_sl);		/* jobs sleeping in core */
    PACK_IV(psd_sw);		/* swapped out runnable jobs */
    PACK_IV(psd_vm);		/* total virtual memory */
    PACK_IV(psd_avm);		/* active virtual memory */
    PACK_IV(psd_rm);		/* total real memory */
    PACK_IV(psd_arm);		/* active real memory */
    PACK_IV(psd_vmtxt);	        /* virt mem text */
    PACK_IV(psd_avmtxt);	/* active virt mem text */
    PACK_IV(psd_rmtxt);	        /* real mem text */
    PACK_IV(psd_armtxt);	/* active real mem text */
    PACK_IV(psd_free);	        /* free memory pages */
    PACK_NV(psd_avg_1_min);	/* global run queue lengths */
    PACK_NV(psd_avg_5_min);
    PACK_NV(psd_avg_15_min);
    PACK_IV(psd_openlv);	/* # of open Logical Volumes */
    PACK_IV(psd_openvg);	/* # of open LV Volume groups */
    PACK_IV(psd_allocpbuf);	/* # of allocated LV pvol buffers */
    PACK_IV(psd_usedpbuf);	/* # of LV pvol buffers in used */
    PACK_IV(psd_maxpbuf);	/* max # of LV pvol buffers avail. */
    PACK_IV(psd_activeprocs);   /* # of active proc  table entries */
    PACK_IV(psd_activeinodes);  /* # of active inode table entries */
    PACK_IV(psd_activefiles);   /* # of active file  table entries */
    PACK_IV(psd_mpdcnt);	/* # of (bad) memory pages deallocated */
    PACK_IV(psd_procovf);       /* # of times the proc table overflowed */
    PACK_IV(psd_inodeovf);      /* # of times the inode table overflowed */
    PACK_IV(psd_fileovf);       /* # of times the file table overflowed */
    PACK_IV(psd_global_virtual); /* Available global virt space (pages) */
    PACK_IV(psd_valid);	        /* This is a vector that will indicate
			         * if a certain field in is valid */

    { /* global cpu time/state */
        AV *av = newAV();
        int i;
        for (i=0; i<PST_MAX_CPUSTATES; i++) {
            av_push(av, newSViv(p->psd_cpu_time[i]));
        }
        PACK_AV(psd_cpu_time);
    }

    /* put ref to hv onto stack */
    sv = newSVrv(st, NULL);
    SvREFCNT_dec(sv);
    SvRV(st) = (SV*)hv;
}


/* pack struct pst_vminfo into a hash
 * and put a reference to this hash onto Perl stack
 */
void XS_pack_pst_vminfoPtr(SV* st, pst_vminfo* p)
{
    HV *hv = newHV();
    SV *sv;

    PACK_IV(psv_rdfree);	/* rate:	 pages freed by daemon */
    PACK_IV(psv_rintr);	        /* device interrupts */
    PACK_IV(psv_rpgpgin);	/* pages paged in */
    PACK_IV(psv_rpgpgout);	/* pages paged out */
    PACK_IV(psv_rpgrec);	/* total page reclaims */
    PACK_IV(psv_rpgtlb);	/* tlb flushes - 800 only */
    PACK_IV(psv_rscan);	        /* scans in pageout daemon */
    PACK_IV(psv_rswtch);	/* context switches */
    PACK_IV(psv_rsyscall);	/* calls to syscall() */
    PACK_IV(psv_rxifrec);	/* found in freelist rather than in filesys */
    PACK_IV(psv_rxsfrec);	/* found in freelist rather than on swapdev */
    PACK_IV(psv_cfree);	        /* cnt:		free memory pages */
    PACK_IV(psv_sswpin);	/* sum:		swapins */
    PACK_IV(psv_sswpout);	/* swapouts */
    PACK_IV(psv_sdfree);	/* pages freed by daemon */
    PACK_IV(psv_sexfod);	/* pages filled on demand from executables */
    PACK_IV(psv_sfaults);	/* total faults taken */
    PACK_IV(psv_sintr);	        /* device interrupts */
    PACK_IV(psv_sintrans);	/* intransit blocking page faults */
    PACK_IV(psv_snexfod);	/* number of exfod's created */
    PACK_IV(psv_snzfod);	/* number of zero filled on demand */
    PACK_IV(psv_spgfrec);	/* page reclaims from free list */
    PACK_IV(psv_spgin);	        /* pageins */
    PACK_IV(psv_spgout);	/* pageouts */
    PACK_IV(psv_spgpgin);	/* pages paged in */
    PACK_IV(psv_spgpgout);	/* pages paged out */
    PACK_IV(psv_spswpin);	/* pages swapped in */
    PACK_IV(psv_spswpout);	/* pages swapped out */
    PACK_IV(psv_srev);	        /* revolutions of the hand */
    PACK_IV(psv_sseqfree);	/* pages taken from sequential programs */
    PACK_IV(psv_sswtch);	/* context switches */
    PACK_IV(psv_ssyscall);	/* calls to syscall() */
    PACK_IV(psv_strap);	        /* calls to trap */
    PACK_IV(psv_sxifrec);	/* found in free list rather than in filesys */
    PACK_IV(psv_sxsfrec);	/* found on free list rather than on swapdev*/
    PACK_IV(psv_szfod);	        /* pages zero filled on demand */
    PACK_IV(psv_sscan);	        /* scans in pageout daemon */
    PACK_IV(psv_spgrec);	/* total page reclaims */
    PACK_IV(psv_deficit);	/* estimate of needs of new swapped-in procs */
    PACK_IV(psv_tknin);	        /* number of characters read from ttys */
    PACK_IV(psv_tknout);	/* number of characters written to ttys */
    PACK_IV(psv_cntfork);	/* number of forks */
    PACK_IV(psv_sizfork);	/* number of pages forked */
    PACK_IV(psv_lreads);	/* number of disk blk reads issued */
    PACK_IV(psv_lwrites);	/* number of disk blk writes issued */
    PACK_IV(psv_swpocc);	/* # of times swrq occ'd since boot */
    PACK_IV(psv_swpque);	/* cumulative len of swrq since boot */
    PACK_IV(psv_paging_thold);  /* paging threshold, moves between pst_desfree & pst_lotsfree */
    PACK_IV(psv_sysmem);        /* pages of memory unavailable for in-memory backing store */
    PACK_IV(psv_swapspc_cnt);   /* pages of on-disk backing store */
    PACK_IV(psv_swapspc_max);   /* max pages of on-disk backing store */
    PACK_IV(psv_swapmem_cnt);   /* pages of in-memory backing store */
    PACK_IV(psv_swapmem_max);   /* max pages of in-memory backing store */
    PACK_IV(psv_swapper_mem);   /* pages of backing store management */
    PACK_IV(psv_lreadsize);     /* # of char xfer'd by bread */
    PACK_IV(psv_lwritesize);    /* # of char xfer'd by bwrite */
    PACK_IV(psv_swapmem_on);	/* in-memory backing store enabled */

    { /* success by page size of LP fault page size selection  */
        AV *av = newAV();
        int i;
        for (i=0; i<PST_N_PG_SIZES; i++) {
            av_push(av, newSViv(p->psv_select_success[i]));
        }
        PACK_AV(psv_select_success);
    }

    { /* failure by page size of LP fault page size selection */
        AV *av = newAV();
        int i;
        for (i=0; i<PST_N_PG_SIZES; i++) {
            av_push(av, newSViv(p->psv_select_failure[i]));
        }
        PACK_AV(psv_select_failure);
    }

    { /* success by page size of LP allocation */
        AV *av = newAV();
        int i;
        for (i=0; i<PST_N_PG_SIZES; i++) {
            av_push(av, newSViv(p->psv_pgalloc_success[i]));
        }
        PACK_AV(psv_pgalloc_success);
    }

    { /* failure by page size of LP allocation */
        AV *av = newAV();
        int i;
        for (i=0; i<PST_N_PG_SIZES; i++) {
            av_push(av, newSViv(p->psv_pgalloc_failure[i]));
        }
        PACK_AV(psv_pgalloc_failure);
    }

    { /* LP demotions by page size */
        AV *av = newAV();
        int i;
        for (i=0; i<PST_N_PG_SIZES; i++) {
            av_push(av, newSViv(p->psv_demotions[i]));
        }
        PACK_AV(psv_demotions);
    }

    /* put ref to hv onto stack */
    sv = newSVrv(st, NULL);
    SvREFCNT_dec(sv);
    SvRV(st) = (SV*)hv;
}


/* pack a number of (struct pst_swapinfo) into an array of hashes
 * and put a reference to this array onto Perl stack
 */
void XS_pack_my_swapinfoPtr(SV* st, my_swapinfo* q)
{
    AV *av = newAV();
    SV *sv;
    pst_swapinfo *p ;
    int i;

    for (i = 0, p = q->data; i < (q->size); i++, p++) {
        HV *hv = newHV();

        PACK_IV(pss_idx);
        PACK_IV(pss_flags);
        PACK_IV(pss_priority);
        PACK_IV(pss_nfpgs);
        PACK_IV(pss_swapchunk);
        if (p->pss_flags & SW_BLOCK) {
            PACK_IV(pss_major);
            PACK_IV(pss_minor);
            PACK_IV(pss_start);
            PACK_IV(pss_nblksavail);
            PACK_IV(pss_nblksenabled);
        }
        else if (p->pss_flags & SW_FS){
            PACK_IV(pss_allocated);
            PACK_IV(pss_min);
            PACK_IV(pss_limit);
            PACK_IV(pss_reserve);
            PACK_PV(pss_mntpt, 0);
        }
        av_push(av, newRV_noinc((SV*)hv));
    }

    /* put ref to av onto stack */
    sv = newSVrv(st, NULL);
    SvREFCNT_dec(sv);
    SvRV(st) = (SV*)av;
}


/* pack a number of (struct pst_status) into an array of hashes
 * and put a reference to this array onto Perl stack
 */
void XS_pack_my_statusPtr(SV* st, my_status* q)
{
    AV *av = newAV();
    SV *sv;
    pst_status *p ;
    int i;

    for (i = 0, p = q->data; i < (q->size); i++, p++) {
        HV *hv = newHV();

        PACK_IV(pst_idx);          /* Index for further pstat() requests */
        PACK_IV(pst_uid);	   /* Real UID */
        PACK_IV(pst_pid);	   /* Process ID */
        PACK_IV(pst_ppid);	   /* Parent process ID */
        PACK_IV(pst_dsize);	   /* # real pages used for data */
        PACK_IV(pst_tsize);	   /* # real pages used for text */
        PACK_IV(pst_ssize);	   /* # real pages used for stack */
        PACK_IV(pst_nice);	   /* Nice value */
        PACK_IV(pst_pgrp);	   /* Process group of this process */
        PACK_IV(pst_pri);	   /* priority of process */
        PACK_IV(pst_addr);	   /* address of process (in memory) */
        PACK_IV(pst_cpu);	   /* processor utilization for scheduling */
        PACK_IV(pst_utime);	   /* user time spent executing (in seconds) */
        PACK_IV(pst_stime);	   /* system time spent executing (in seconds) */
        PACK_IV(pst_start);	   /* time process started (seconds since epoch) */
        PACK_IV(pst_flag);	   /* flags associated with process */
        PACK_IV(pst_stat);	   /* Current status */
        PACK_IV(pst_wchan);	   /* If state PS_SLEEP, value sleeping on */
        PACK_IV(pst_procnum);	   /* processor this proc last run on */
        PACK_PV(pst_cmd, 0);       /* Command line for the process, if available */
        PACK_IV(pst_time);	   /* resident time for scheduling */
        PACK_IV(pst_cpticks);	   /* ticks of cpu time */
        PACK_IV(pst_cptickstotal); /* total ticks for life of process */
        PACK_IV(pst_fss);	   /* fair share scheduler group id */
        PACK_NV(pst_pctcpu);       /* %cpu for this process during p_time */
        PACK_IV(pst_rssize);       /* resident set size for process (private pages) */
        PACK_IV(pst_suid);         /* saved UID */
        PACK_PV(pst_ucomm, 0);     /* executable basename the process is running */
        PACK_IV(pst_shmsize);	   /* # real pages used for shared memory */
        PACK_IV(pst_mmsize);	   /* # real pages used for memory mapped files */
        PACK_IV(pst_usize);	   /* # real pages used for U-Area & K-Stack */
        PACK_IV(pst_iosize);	   /* # real pages used for I/O device mapping */
        PACK_IV(pst_vtsize);	   /* # virtual pages used for text */
        PACK_IV(pst_vdsize);	   /* # virtual pages used for data */
        PACK_IV(pst_vssize);	   /* # virtual pages used for stack */
        PACK_IV(pst_vshmsize);	   /* # virtual pages used for shared memory */
        PACK_IV(pst_vmmsize);	   /* # virtual pages used for mem-mapped files */
        PACK_IV(pst_vusize);	   /* # virtual pages used for U-Area & K-Stack */
        PACK_IV(pst_viosize);	   /* # virtual pages used for I/O dev mapping */
        PACK_IV(pst_minorfaults);  /* # page reclaims for the process */
        PACK_IV(pst_majorfaults);  /* # page faults needing disk access */
        PACK_IV(pst_nswap);	   /* # of swaps for the process */
        PACK_IV(pst_nsignals);	   /* # signals received by the process */
        PACK_IV(pst_msgrcv);	   /* # socket msgs received by the proc*/
        PACK_IV(pst_msgsnd);	   /* # of socket msgs sent by the proc */
        PACK_IV(pst_maxrss);	   /* highwater mark for proc resident set size */
        PACK_IV(pst_sid);	   /* session ID */
        PACK_IV(pst_schedpolicy);  /* scheduling policy for the process */
        PACK_IV(pst_ticksleft);	   /* clock ticks left in process' RR timeslice */
        PACK_IV(pst_highestfd);	   /* highest file descriptor currently opened */
        PACK_IV(pst_euid);	   /* Effective UID */
        PACK_IV(pst_egid);	   /* Effective GID */
        PACK_IV(pst_ioch);	   /* # of characters read/written */
        PACK_IV(pst_gid);	   /* Real GID */
        PACK_IV(pst_sgid);	   /* saved effective gid */
        PACK_IV(pst_nlwps);	   /* # lwps within this process */
        PACK_IV(pst_lwpid);        /* LWP identifier. NOTE: If this process is
                                    * multi-threaded, this is an lwpid of one of the
                                    * LWPs in the process at this exact moment, which
                                    * LWP is undefined (random) */
        PACK_IV(pst_valid);        /* This is a vector that will indicate if a
                                    * certain field in the structure is valid or not.
                                    */
        PACK_IV(pst_text_size);    /* Page size used for text objects. */
        PACK_IV(pst_data_size);    /* Page size used for data objects. */

        /* push reference to hash into av */
        av_push(av, newRV_noinc((SV*)hv));
    }

    /* put ref to av onto stack */
    sv = newSVrv(st, NULL);
    SvREFCNT_dec(sv);
    SvRV(st) = (SV*)av;
}


/* pack a number of (struct pst_processor) into an array of hashes
 * and put a reference to this array onto Perl stack
 */
void XS_pack_my_processorPtr(SV *st, my_processor *q)
{
    AV *av = newAV();
    SV *sv;
    pst_processor *p ;
    int i;

    for (i = 0, p = q->data; i < (q->size); i++, p++) {
        HV *hv = newHV();

        PACK_IV(psp_idx);	/* Index of the current spu in the
                                 * array of processor statistic entries
                                 */
        PACK_IV(psp_fsreads);	/* # of reads from filesys blocks. */
        PACK_IV(psp_fswrites);	/* # of writes to filesys blocks. */
        PACK_IV(psp_nfsreads);	/* # of nfs disk blk reads issued. */
        PACK_IV(psp_nfswrites);	/* # of nfs disk blk writes issued. */
        PACK_IV(psp_bnfsread);	/* # of bytes read from NFS. */
        PACK_IV(psp_bnfswrite);	/* # of bytes written to NFS. */
        PACK_IV(psp_phread);	/* # of physical reads to raw devs. */
        PACK_IV(psp_phwrite);	/* # of physical writes to raw devs. */
        PACK_IV(psp_runocc);	/* # of times the processor had
                                 * processes waiting to run.  This
                                 * running total is updated once
                                 * a second.
                                 */
        PACK_IV(psp_runque);	/* # of processes the processor had
                                 * waiting to run.  This running total
                                 * is updated once a second.
                                 */
        PACK_IV(psp_sysexec);	/* # of exec system calls. */
        PACK_IV(psp_sysread);	/* # of read system calls. */
        PACK_IV(psp_syswrite);	/* # of write system calls. */
        PACK_IV(psp_sysnami);	/* # of calls to sysnami(). */
        PACK_IV(psp_sysiget);	/* # of calls to sysiget(). */
        PACK_IV(psp_dirblk);	/* # of filesystem blocks read doing
                                 * directory lookup.
                                 */
        PACK_IV(psp_semacnt);	/* # of System V semaphore ops. */
        PACK_IV(psp_msgcnt);	/* # of System V message ops. */
        PACK_IV(psp_muxincnt);	/* # of MUX interrupts received. */
        PACK_IV(psp_muxoutcnt);	/* # of MUX interrupts sent. */
        PACK_IV(psp_ttyrawcnt);	/* # of raw characters read. */
        PACK_IV(psp_ttycanoncnt); /* # of canonical chars processed. */
        PACK_IV(psp_ttyoutcnt);	/* # of characters output. */
        PACK_IV(psp_iticksperclktick); /* interval timer counts (CR16)
                                        * per clock tick,
                                        * see sysconf(_SC_CLK_TCK)
                                        */
        PACK_IV(psp_sysselect);	/* # of select system calls. */
        PACK_NV(psp_avg_1_min);	/* per-processor run queue lengths */
        PACK_NV(psp_avg_5_min);
        PACK_NV(psp_avg_15_min);

        { /* per-processor cpu time/state */
            AV *av = newAV();
            int i;
            for (i=0; i<PST_MAX_CPUSTATES; i++) {
                av_push(av, newSViv(p->psp_cpu_time[i]));
            }
            PACK_AV(psp_cpu_time);
        }

        /* push reference to hash into av */
        av_push(av, newRV_noinc((SV*)hv));
    }

    /* put ref to av onto stack */
    sv = newSVrv(st, NULL);
    SvREFCNT_dec(sv);
    SvRV(st) = (SV*)av;
}


