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