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