source: trunk/third/top/machine/m_macosx.c @ 16185

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