"Fossies" - the Fresh Open Source Software Archive

Member "top-3.8beta1/machine/m_macosx.c" (7 May 2008, 21517 Bytes) of package /linux/misc/old/top-3.8beta1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "m_macosx.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.7_vs_3.8beta1.

    1 /*
    2  * Copyright (c) 1984 through 2008, William LeFebvre
    3  * All rights reserved.
    4  * 
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions are met:
    7  * 
    8  *     * Redistributions of source code must retain the above copyright
    9  * notice, this list of conditions and the following disclaimer.
   10  * 
   11  *     * Redistributions in binary form must reproduce the above
   12  * copyright notice, this list of conditions and the following disclaimer
   13  * in the documentation and/or other materials provided with the
   14  * distribution.
   15  * 
   16  *     * Neither the name of William LeFebvre nor the names of other
   17  * contributors may be used to endorse or promote products derived from
   18  * this software without specific prior written permission.
   19  * 
   20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   31  */
   32 
   33 /*
   34  * m_macosx.c
   35  *
   36  * AUTHOR:  Andrew S. Townley
   37  *      based on m_bsd44.c and m_next32.c
   38  *      by Christos Zoulas and Tim Pugh
   39  * CREATED: Tue Aug 11 01:51:35 CDT 1998
   40  * SYNOPSIS:  MacOS X Server (Rhapsody Developer Release 2)
   41  * DESCRIPTION:
   42  *  MacOS X Server (Rhapsody Developer Release 2)
   43  *
   44  * CFLAGS: -DHAVE_STRERROR
   45  * TERMCAP: none
   46  * MATH: none
   47  */
   48 
   49 /*
   50  * normal stuff
   51  */
   52 
   53 #include "config.h"
   54 
   55 #include <stdio.h>
   56 #include <stdarg.h>
   57 #include <errno.h>
   58 #include "os.h"
   59 #include "top.h"
   60 #include "machine.h"
   61 #include "utils.h"
   62 
   63 /*
   64  * MacOS kernel stuff
   65  */
   66 
   67 #include <kvm.h>
   68 #include <fcntl.h>
   69 #include <sys/dkstat.h>
   70 #include <sys/sysctl.h>
   71 #include <mach/message.h>
   72 #include <mach/vm_statistics.h>
   73 #include <mach/mach.h>
   74 #include <mach/host_info.h>
   75 
   76 #define VMUNIX      "/mach_kernel"
   77 #define MEM     "/dev/mem"
   78 #define SWAP        NULL
   79 
   80 #define NUM_AVERAGES    3
   81 #define LOG1024     10
   82 
   83 #define PP(pp, field)   ((pp)->kp_proc . field)
   84 #define EP(pp, field)   ((pp)->kp_eproc . field)
   85 #define VP(pp, field)   ((pp)->kp_eproc.e_vm . field)
   86 #define MPP(mp, field)  (PP((mp)->kproc, field))
   87 #define MEP(mp, field)  (EP((mp)->kproc, field))
   88 #define MVP(mp, field)  (VP((mp)->kproc, field))
   89 #define TP(mp, field)   ((mp)->task_info . field)
   90 #define RP(mp, field)   ((mp)->thread_summary . field)
   91 
   92 /* define what weighted cpu is */
   93 #define weighted_cpu(pct, s) (s == 0 ? 0.0 : \
   94                          ((pct) / (1.0 - exp(s * logcpu)))) 
   95 
   96 /* what we consider to be process size: */
   97 #ifdef notdef
   98 #define PROCSIZE(pp) (VP((pp), vm_tsize) + VP((pp), vm_dsize) + VP((pp), vm_ssize))
   99 #endif
  100 #define PROCSIZE(pp) (EP(pp, e_xsize))
  101 #define TASKSIZE(t) (TP(t, virtual_size) + TP(t, resident_size))
  102 
  103 /* what we consider to be resident set size: */
  104 #ifdef notdef
  105 #define RSSIZE(pp) (MVP((pp), vm_rssize))
  106 #endif
  107 #define RSSIZE(pp) (MEP((pp), e_xrssize))
  108 
  109 #define pctdouble(p) ((double)(p) / FSCALE)
  110 
  111 /*
  112  * globals
  113  */
  114 
  115 static kvm_t        *kd = NULL;
  116 static int      nproc;
  117 static int      onproc = -1;
  118 static int      pref_len;
  119 static int      maxmem;
  120 static char     fmt[MAX_COLS];
  121 static double       logcpu = 1.0;
  122 
  123 /* process array stuff */
  124 
  125 static struct kinfo_proc    *kproc_list = NULL;
  126 static struct macos_proc    *proc_list = NULL;
  127 static struct macos_proc    **proc_ref = NULL;
  128 static int          process_states[7];
  129 static struct handle        handle;
  130 
  131 /*
  132  * The mach information hopefully will not be necessary
  133  * when the kvm_* interfaces are supported completely.
  134  *
  135  * Since we're only concerned with task and thread info
  136  * for 'interesting' processes, we're going to only allocate
  137  * as many task and thread structures as needed.
  138  */
  139 
  140 static struct task_basic_info   *task_list = NULL;
  141 
  142 /* memory statistics */
  143 
  144 static int      pageshift   = 0;
  145 static int      pagesize    = 0;
  146 #define pagetok(size)   ((size) << pageshift)
  147 
  148 static int      swappgsin   = -1;
  149 static int      swappgsout  = -1;
  150 static vm_statistics_data_t vm_stats;
  151 static long     memory_stats[7];
  152 
  153 /* CPU state percentages */
  154 
  155 host_cpu_load_info_data_t cpuload;
  156 
  157 static long cp_time[CPU_STATE_MAX];
  158 static long cp_old[CPU_STATE_MAX];
  159 static long cp_diff[CPU_STATE_MAX];
  160 static int      cpu_states[CPU_STATE_MAX];
  161 
  162 /*
  163  * types
  164  */
  165 
  166 typedef long        pctcpu;
  167 
  168 //struct statics
  169 //{
  170 //  char    **procstate_names;
  171 //  char    **cpustate_names;
  172 //  char    **memory_names;
  173 //  char    **order_names;
  174 //};
  175 //
  176 //struct system_info
  177 //{
  178 //  int last_pid;
  179 //  double  load_avg[NUM_AVERAGES];
  180 //  int p_total;    /* total # of processes */
  181 //  int p_active;   /* number processes considered active */
  182 //  int *procstates;
  183 //  int *cpustates;
  184 //  int *memory;
  185 //};
  186 //
  187 //struct process_select
  188 //{
  189 //  int idle;       /* show idle processes */
  190 //  int system;     /* show system processes */
  191 //  int uid;        /* show only this uid (unless -1) */
  192 //  char    *command;   /* only this command (unless NULL) */
  193 //};
  194 
  195 /*
  196  * We need to declare a hybrid structure which will store all
  197  * of the stuff we care about for each process.
  198  */
  199 
  200 struct macos_proc
  201 {
  202     struct kinfo_proc       *kproc;
  203     task_t              the_task;
  204     struct task_basic_info      task_info;
  205     unsigned int            thread_count;
  206     struct thread_basic_info    thread_summary;
  207 };
  208 
  209 struct handle
  210 {
  211     struct macos_proc       **next_proc;
  212     int             remaining;
  213 };
  214 
  215 static char header[] =
  216   "  PID X        PRI THRD  SIZE   RES STATE   TIME    MEM    CPU COMMAND";
  217 /* 0123456   -- field to fill in starts at header+6 */
  218 #define UNAME_START 6
  219      
  220 #define Proc_format \
  221         "%5d %-8.8s %3d %4d %5s %5s %-5s %6s %5.2f%% %5.2f%% %.16s"
  222 
  223 
  224 int proc_compare(const void *, const void *);
  225 
  226 
  227 /*
  228  * puke()
  229  *
  230  * This function is used to report errors to stderr.
  231  */
  232 
  233 static void puke(const char* fmt, ...)
  234 {
  235     va_list args;
  236     va_start(args, fmt);
  237     vfprintf(stderr, fmt, args);
  238     va_end(args);
  239 
  240     fputc('\n', stderr);
  241     fflush(stderr);
  242 }
  243 
  244 /*
  245  * kread()
  246  *
  247  * This function is a wrapper for the kvm_read() function
  248  * with the addition of a message parameter per kvm_open().
  249  *
  250  * All other behavior is per kvm_read except the error reporting.
  251  */
  252 
  253 static ssize_t kread(u_long addr, void *buf, 
  254     size_t nbytes, const char *errstr)
  255 {
  256     ssize_t s = 0;
  257 
  258     s = kvm_read(kd, addr, buf, nbytes);
  259     if(s == -1)
  260         {
  261         puke("error:  kvm_read() failed for '%s' (%s)\n",
  262             errstr, strerror(errno));
  263         }
  264 
  265     return s;
  266 }
  267 
  268 /*
  269  * prototypes for functions which top needs
  270  */
  271 
  272 char *printable();
  273 
  274 /*
  275  * definitions for offsets
  276  */
  277 
  278 #define X_NPROC     0
  279 #define X_HZ        1
  280 #define X_MAXMEM    2
  281 
  282 #define NLIST_LAST  3
  283 
  284 static struct nlist nlst[] =
  285 {
  286     { "_maxproc" },     /* 0 *** maximum processes */
  287     { "_hz" },      /* 1 */
  288     { "_mem_size" },    /* 2 */
  289     { 0 }
  290 };
  291 
  292 static char *procstates[] =
  293 {
  294     "",
  295     " starting, ",
  296     " running, ",
  297     " sleeping, ",
  298     " stopped, ",
  299     " zombie, ",
  300     " swapped ",
  301     NULL
  302 };
  303 
  304 static char *cpustates[] =
  305 {
  306     "user",
  307     "system",
  308     "idle",
  309     "nice",
  310     NULL
  311 };
  312 
  313 static char *state_abbrev[] =
  314 {
  315     "",
  316     "start",
  317     "run\0\0\0",
  318     "sleep",
  319     "stop",
  320     "zomb"
  321 };
  322 
  323 static char *mach_state[] =
  324 {
  325     "",
  326     "R",
  327     "T",
  328     "S",
  329     "U",
  330     "H"
  331 };
  332 
  333 static char *thread_state[] =
  334 {
  335     "",
  336     "run\0\0\0",
  337     "stop",
  338     "wait",
  339     "uwait",
  340     "halted",
  341 };
  342 
  343 static char *flags_state[] =
  344 {
  345     "",
  346     "W",
  347     "I"
  348 };
  349 
  350 static char *memnames[] =
  351 {
  352     "K Tot, ",
  353     "K Free, ",
  354     "K Act, ",
  355     "K Inact, ",
  356     "K Wired, ",
  357     "K in, ",
  358     "K out ",
  359     NULL
  360 };
  361 
  362 /*
  363  * format_header()
  364  *
  365  * This function is used to add the username into the
  366  * header information.
  367  */
  368 
  369 char *format_header(register char *uname_field)
  370 {
  371     register char *ptr;
  372 
  373     ptr = header + UNAME_START;
  374     while(*uname_field != '\0')
  375         *ptr++ = *uname_field++;
  376 
  377     return(header);
  378 }
  379 
  380 /*
  381  * format_next_process()
  382  *
  383  * This function actuall is responsible for the formatting of
  384  * each row which is displayed.
  385  */
  386 
  387 char *format_next_process(caddr_t handle, char *(*getuserid)())
  388 {
  389     register struct macos_proc  *pp;
  390     register long           cputime;
  391     register double         pct;
  392     register int            vsize;
  393     register int            rsize;
  394     struct handle           *hp;
  395 
  396     /*
  397      * we need to keep track of the next proc structure.
  398      */
  399 
  400     hp = (struct handle*)handle;
  401     pp = *(hp->next_proc++);
  402     hp->remaining--;
  403 
  404     /*
  405      * get the process structure and take care of the cputime
  406      */
  407 
  408     if((MPP(pp, p_flag) & P_INMEM) == 0)
  409         {
  410         /* we want to print swapped processes as <pname> */
  411         char    *comm = MPP(pp, p_comm);
  412 #define COMSIZ  sizeof(MPP(pp, p_comm))
  413         char    buf[COMSIZ];
  414         strncpy(buf, comm, COMSIZ);
  415         comm[0] = '<';
  416         strncpy(&comm[1], buf, COMSIZ - 2);
  417         comm[COMSIZ - 2] = '\0';
  418         strncat(comm, ">", COMSIZ - 1);
  419         comm[COMSIZ - 1] = '\0';
  420         }
  421 
  422     /*
  423      * count the cpu time, but ignore the interrupts
  424      *
  425      * At the present time (DR2 8/1998), MacOS X doesn't
  426      * correctly report this information through the
  427      * kinfo_proc structure.  We need to get it from the
  428      * task threads.
  429      *
  430      * cputime = PP(pp, p_rtime).tv_sec;
  431      */
  432     
  433     cputime = RP(pp, user_time).seconds + RP(pp, system_time).seconds;
  434 
  435     /*
  436      * calculate the base cpu percentages
  437      *
  438      * Again, at the present time, MacOS X doesn't report
  439      * this information through the kinfo_proc.  We need
  440      * to talk to the threads.
  441      */
  442 
  443 //  pct = pctdouble(PP(pp, p_pctcpu));
  444     pct = (double)(RP(pp, cpu_usage))/TH_USAGE_SCALE;
  445 
  446     /*
  447      * format the entry
  448      */
  449 
  450     /*
  451      * In the final version, I would expect this to work correctly,
  452      * but it seems that not all of the fields in the proc
  453      * structure are being used.
  454      *
  455      * For now, we'll attempt to get some of the things we need
  456      * from the mach task info.
  457      */
  458 
  459     sprintf(fmt,
  460         Proc_format,
  461         MPP(pp, p_pid),
  462         (*getuserid)(MEP(pp, e_pcred.p_ruid)),
  463 //      TP(pp, base_priority),
  464         0,
  465         pp->thread_count,
  466         format_k(TASKSIZE(pp) / 1024),
  467         format_k(pagetok(RSSIZE(pp))),
  468         state_abbrev[(u_char)MPP(pp, p_stat)],
  469         format_time(cputime),
  470         100.0 * TP(pp, resident_size) / maxmem,
  471 //      100.0 * weighted_cpu(pct, (RP(pp, user_time).seconds + RP(pp, system_time).seconds)),
  472         100.0 * pct,
  473         printable(MPP(pp, p_comm)));
  474 
  475     return(fmt);
  476 }
  477 
  478 /*
  479  * get_process_info()
  480  *
  481  * This function returns information about the processes
  482  * on the system.
  483  */
  484 
  485 caddr_t get_process_info(struct system_info *si,
  486         struct process_select *sel, int x)
  487 
  488 {
  489     register int                i;
  490     register int                total_procs;
  491     register int                active_procs;
  492     register struct macos_proc      **prefp;
  493     register struct macos_proc      *pp;
  494     register struct kinfo_proc      *pp2;
  495     register struct kinfo_proc      **prefp2;
  496     register struct thread_basic_info   *thread;
  497 
  498     /*
  499      * these are copied out of sel for speed
  500      */
  501 
  502     int show_idle;
  503     int show_system;
  504     int show_uid;
  505     int show_command;
  506 
  507     kproc_list = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nproc);
  508 
  509     if(nproc > onproc)
  510         {
  511         proc_list = (struct macos_proc*)realloc(proc_list, sizeof(struct macos_proc) * nproc);
  512         proc_ref = (struct macos_proc **)realloc(proc_ref, sizeof(struct macos_proc *) * (onproc = nproc));
  513         }
  514 
  515     if(proc_ref == NULL || proc_list == NULL || kproc_list == NULL)
  516         {
  517         puke("error:  out of memory (%s)", strerror(errno));
  518         return(NULL);
  519         }
  520 
  521     /*
  522      * now, our task is to build the array of information we
  523      * need to function correctly.  This involves setting a pointer
  524      * to each real kinfo_proc structure returned by kvm_getprocs()
  525      * in addition to getting the mach information for each of
  526      * those processes.
  527      */
  528 
  529     for(pp2 = kproc_list, i = 0; i < nproc; pp2++, i++)
  530         {
  531         kern_return_t   rc;
  532         u_int       info_count = TASK_BASIC_INFO_COUNT;
  533 
  534         /*
  535          * first, we set the pointer to the reference in
  536          * the kproc list.
  537          */
  538         
  539         proc_list[i].kproc = pp2;
  540 
  541         /*
  542          * then, we load all of the task info for the process
  543          */
  544 
  545         if(PP(pp2, p_stat) != SZOMB)
  546             {
  547             rc = task_for_pid(mach_task_self(), 
  548                 PP(pp2, p_pid), 
  549                 &(proc_list[i].the_task));
  550 
  551             if(rc != KERN_SUCCESS)
  552                 {
  553                 puke("error:  get task info for pid %d failed with rc = %d", PP(pp2, p_pid), rc);
  554                 }
  555 
  556             /*
  557              * load the task information
  558              */
  559 
  560             rc = task_info(proc_list[i].the_task, TASK_BASIC_INFO, 
  561                 (task_info_t)&(proc_list[i].task_info),
  562                 &info_count);
  563 
  564             if(rc != KERN_SUCCESS)
  565                 {
  566                 puke("error:  couldn't get task info (%s); rc = %d", strerror(errno), rc);
  567                 }
  568 
  569             /*
  570              * load the thread summary information
  571              */
  572 
  573             load_thread_info(&proc_list[i]);
  574             }
  575         }
  576 
  577     /* get a pointer to the states summary array */
  578     si->procstates = process_states;
  579 
  580     /* set up flags which define what we are going to select */
  581     show_idle = sel->idle;
  582     show_system = sel->system;
  583     show_uid = sel->uid != -1;
  584     show_command = sel->command != NULL;
  585 
  586     /* count up process states and get pointers to interesting procs */
  587     total_procs = 0;
  588     active_procs = 0;
  589     memset((char *)process_states, 0, sizeof(process_states));
  590     prefp = proc_ref;
  591     for(pp = proc_list, i = 0; i < nproc; pp++, i++)
  592         {
  593         /*
  594          *  Place pointers to each valid proc structure in 
  595          * proc_ref[].  Process slots that are actually in use 
  596          * have a non-zero status field.  Processes with
  597          * P_SYSTEM set are system processes---these get 
  598          * ignored unless show_sysprocs is set.
  599          */
  600         if(MPP(pp, p_stat) != 0 && 
  601                 (show_system || ((MPP(pp, p_flag) & P_SYSTEM) == 0)))
  602             {
  603             total_procs++;
  604             process_states[(unsigned char) MPP(pp, p_stat)]++;
  605             if((MPP(pp, p_stat) != SZOMB) &&
  606                     (show_idle || (MPP(pp, p_pctcpu) != 0) || 
  607                     (MPP(pp, p_stat) == SRUN)) &&
  608                     (!show_uid || MEP(pp, e_pcred.p_ruid) == (uid_t)sel->uid))
  609                 {
  610                 *prefp++ = pp;
  611                 active_procs++;
  612                 }
  613             }
  614         }
  615     
  616     /* 
  617      * if requested, sort the "interesting" processes
  618      */
  619 
  620     qsort((char *)proc_ref, active_procs, sizeof(struct macos_proc *), proc_compare);
  621 
  622     /* remember active and total counts */
  623     si->p_total = total_procs;
  624     si->p_active = pref_len = active_procs;
  625 
  626     /* pass back a handle */
  627     handle.next_proc = proc_ref;
  628     handle.remaining = active_procs;
  629     return((caddr_t)&handle);
  630 }
  631 
  632 /*
  633  * get_system_info()
  634  *
  635  * This function is responsible for geting the periodic
  636  * system information snapshot.
  637  */
  638 
  639 void get_system_info(struct system_info *si)
  640 {
  641     register long   total;
  642     register int    i;
  643     unsigned int count = HOST_CPU_LOAD_INFO_COUNT;
  644 
  645     if (host_statistics(mach_host_self(), HOST_CPU_LOAD_INFO,
  646                 (host_info_t)&cpuload, &count) == KERN_SUCCESS)
  647     {
  648         for (i = 0; i < CPU_STATE_MAX; i++)
  649         {
  650         cp_time[i] = cpuload.cpu_ticks[i];
  651         }
  652     }
  653 
  654 #ifdef MAX_VERBOSE
  655 
  656     /*
  657      * print out the entries
  658      */
  659 
  660     for(i = 0; i < CPU_STATE_MAX; i++)
  661         printf("cp_time[%d] = %d\n", i, cp_time[i]);
  662     fflush(stdout);
  663 
  664 #endif /* MAX_VERBOSE */
  665 
  666     /*
  667      * get the load averages
  668      */
  669 
  670     if(kvm_getloadavg(kd, si->load_avg, NUM_AVERAGES) == -1)
  671         {
  672         puke("error:  kvm_getloadavg() failed (%s)", strerror(errno));
  673         return;
  674         }
  675 
  676 #ifdef MAX_VERBOSE
  677     printf("%-30s%03.2f, %03.2f, %03.2f\n", 
  678             "load averages:", 
  679             si->load_avg[0],
  680             si->load_avg[1],
  681             si->load_avg[2]);
  682 #endif /* MAX_VERBOSE */
  683 
  684     total = percentages(CPU_STATE_MAX, cpu_states, cp_time, cp_old, cp_diff);
  685     /*
  686      * get the memory statistics
  687      */
  688 
  689     {
  690         kern_return_t   status;
  691 
  692         count = HOST_VM_INFO_COUNT;
  693         status = host_statistics(mach_host_self(), HOST_VM_INFO,
  694                      (host_info_t)&vm_stats, &count);
  695 
  696         if(status != KERN_SUCCESS)
  697             {
  698             puke("error:  vm_statistics() failed (%s)", strerror(errno));
  699             return;
  700             }
  701 
  702         /*
  703          * we already have the total memory, we just need
  704          * to get it in the right format.
  705          */
  706 
  707         memory_stats[0] = pagetok(maxmem / pagesize);
  708         memory_stats[1] = pagetok(vm_stats.free_count);
  709         memory_stats[2] = pagetok(vm_stats.active_count);
  710         memory_stats[3] = pagetok(vm_stats.inactive_count);
  711         memory_stats[4] = pagetok(vm_stats.wire_count);
  712 
  713         if(swappgsin < 0)
  714             {
  715             memory_stats[5] = 1;
  716             memory_stats[6] = 1;
  717             }
  718         else
  719             {
  720             memory_stats[5] = pagetok(((vm_stats.pageins - swappgsin)));
  721             memory_stats[6] = pagetok(((vm_stats.pageouts - swappgsout)));
  722             }
  723         swappgsin = vm_stats.pageins;
  724         swappgsout = vm_stats.pageouts;
  725     }
  726     
  727     si->cpustates = cpu_states;
  728     si->memory = memory_stats;
  729     si->last_pid = -1;
  730 
  731     return;
  732 }
  733 
  734 /*
  735  * machine_init()
  736  *
  737  * This function is responsible for filling in the values of the
  738  * statics structure.
  739  */
  740 
  741 int machine_init(struct statics *stat)
  742 {
  743     register int rc = 0;
  744     register int i = 0;
  745     size_t size;
  746 
  747     size = sizeof(maxmem);
  748     sysctlbyname("hw.physmem", &maxmem, &size, NULL, 0);
  749 
  750     size = sizeof(nproc);
  751     sysctlbyname("kern.maxproc", &nproc, &size, NULL, 0);
  752 
  753 #ifdef MAX_VERBOSE
  754     printf("%-30s%10d\n", "total system memory:", maxmem);
  755 #endif /* MAX_VERBOSE */
  756 
  757     /*
  758      * calculate the pageshift from the system page size
  759      */
  760 
  761     pagesize = getpagesize();
  762     pageshift = 0;
  763     while((pagesize >>= 1) > 0)
  764         pageshift++;
  765 
  766     pageshift -= LOG1024;
  767 
  768     /*
  769      * fill in the statics information
  770      */
  771 
  772     stat->procstate_names = procstates;
  773     stat->cpustate_names = cpustates;
  774     stat->memory_names = memnames;
  775 
  776     if ((kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "kvm_open")) == NULL)
  777       return -1;
  778 
  779     return(0);
  780 }
  781 
  782 /* comparison routine for qsort */
  783 
  784 /*
  785  *  proc_compare - comparison function for "qsort"
  786  *  Compares the resource consumption of two processes using five
  787  *      distinct keys.  The keys (in descending order of importance) are:
  788  *      percent cpu, cpu ticks, state, resident set size, total virtual
  789  *      memory usage.  The process states are ordered as follows (from least
  790  *      to most important):  WAIT, zombie, sleep, stop, start, run.  The
  791  *      array declaration below maps a process state index into a number
  792  *      that reflects this ordering.
  793  */
  794 
  795 static unsigned char sorted_state[] =
  796 {
  797     0,  /* not used     */
  798     3,  /* sleep        */
  799     1,  /* ABANDONED (WAIT) */
  800     6,  /* run          */
  801     5,  /* start        */
  802     2,  /* zombie       */
  803     4   /* stop         */
  804 };
  805  
  806 int proc_compare(const void *pp1, const void *pp2)
  807 {
  808     register struct macos_proc *p1;
  809     register struct macos_proc *p2;
  810     register int result;
  811     register pctcpu lresult;
  812 
  813     /* remove one level of indirection */
  814     p1 = *(struct macos_proc **) pp1;
  815     p2 = *(struct macos_proc **) pp2;
  816 
  817     /* compare percent cpu (pctcpu) */
  818     if ((lresult = RP(p2, cpu_usage) - RP(p1, cpu_usage)) == 0)
  819     {
  820     /* use cpticks to break the tie */
  821     if ((result = MPP(p2, p_cpticks) - MPP(p1, p_cpticks)) == 0)
  822     {
  823         /* use process state to break the tie */
  824         if ((result = sorted_state[(unsigned char) MPP(p2, p_stat)] -
  825               sorted_state[(unsigned char) MPP(p1, p_stat)])  == 0)
  826         {
  827         /* use priority to break the tie */
  828         if ((result = MPP(p2, p_priority) - MPP(p1, p_priority)) == 0)
  829         {
  830             /* use resident set size (rssize) to break the tie */
  831             if ((result = RSSIZE(p2) - RSSIZE(p1)) == 0)
  832             {
  833             /* use total memory to break the tie */
  834             result = PROCSIZE(p2->kproc) - PROCSIZE(p1->kproc);
  835             }
  836         }
  837         }
  838     }
  839     }
  840     else
  841     {
  842     result = lresult < 0 ? -1 : 1;
  843     }
  844 
  845     return(result);
  846 }
  847 
  848 
  849 /*
  850  * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
  851  *      the process does not exist.
  852  *      It is EXTREMLY IMPORTANT that this function work correctly.
  853  *      If top runs setuid root (as in SVR4), then this function
  854  *      is the only thing that stands in the way of a serious
  855  *      security problem.  It validates requests for the "kill"
  856  *      and "renice" commands.
  857  */
  858 
  859 int proc_owner(pid)
  860 
  861 int pid;
  862 
  863 {
  864     register int cnt;
  865     register struct macos_proc **prefp;
  866     register struct macos_proc *pp;
  867 
  868     prefp = proc_ref;
  869     cnt = pref_len;
  870     while (--cnt >= 0)
  871     {
  872     pp = *prefp++;  
  873     if (MPP(pp, p_pid) == (pid_t)pid)
  874     {
  875         return((int)MEP(pp, e_pcred.p_ruid));
  876     }
  877     }
  878     return(-1);
  879 }
  880 
  881 /*
  882  * load_thread_info()
  883  *
  884  * This function will attempt to load the thread summary info
  885  * for a Mach task.  The task is located as part of the macos_proc
  886  * structure.
  887  *
  888  * returns the kern_return_t value of any failed call or KERN_SUCCESS
  889  * if everything works.
  890  */
  891 
  892 int load_thread_info(struct macos_proc *mp)
  893 {
  894     register kern_return_t      rc = 0;
  895     register int            i = 0;
  896     register int            t_utime = 0;
  897     register int            t_stime = 0;
  898     register int            t_cpu = 0;
  899     register int            t_state = 0;
  900     register task_t         the_task = mp->the_task;
  901 
  902     thread_array_t          thread_list = NULL;
  903 
  904     /*
  905      * We need to load all of the threads for the 
  906      * given task so we can get the performance 
  907      * data from them.
  908      */
  909 
  910     mp->thread_count = 0;
  911     rc = task_threads(the_task, &thread_list, &(mp->thread_count));
  912 
  913     if(rc != KERN_SUCCESS)
  914         {
  915 //      puke("error:  unable to load threads for task (%s); rc = %d", strerror(errno), rc);
  916         return(rc);
  917         }
  918 
  919     /*
  920      * now, for each of the threads, we need to sum the stats
  921      * so we can present the whole thing to the caller.
  922      */
  923 
  924     for(i = 0; i < mp->thread_count; i++)
  925         {
  926         struct thread_basic_info    t_info;
  927         unsigned int            icount = THREAD_BASIC_INFO_COUNT;
  928         kern_return_t           rc = 0;
  929 
  930         rc = thread_info(thread_list[i], THREAD_BASIC_INFO, 
  931                 (thread_info_t)&t_info, &icount);
  932 
  933         if(rc != KERN_SUCCESS)
  934             {
  935             puke("error:  unable to load thread info for task (%s); rc = %d", strerror(errno), rc);
  936             return(rc);
  937             }
  938 
  939         t_utime += t_info.user_time.seconds;
  940         t_stime += t_info.system_time.seconds;
  941         t_cpu += t_info.cpu_usage;
  942         }
  943 
  944     vm_deallocate(mach_task_self(), (vm_address_t)thread_list, sizeof(thread_array_t)*(mp->thread_count));
  945 
  946     /*
  947      * Now, we load the values in the structure above.
  948      */
  949 
  950     RP(mp, user_time).seconds = t_utime;
  951     RP(mp, system_time).seconds = t_stime;
  952     RP(mp, cpu_usage) = t_cpu;
  953 
  954     return(KERN_SUCCESS);
  955 }
  956