ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/libstatgrab/src/libstatgrab/process_stats.c
Revision: 1.65
Committed: Wed Apr 7 21:08:40 2004 UTC (20 years, 1 month ago) by tdb
Content type: text/plain
Branch: MAIN
Changes since 1.64: +11 -1 lines
Log Message:
The rest of the error handling stuff (except the vector code).

I've been extremely unimaginative with the string names in error.c, but
they're all in one place so much easier to tidy up. I'm also beginning to
wonder if we actually needed an SG_ERROR_SYSTEM_CALL to indicate some call
into the system failed - because the majority of our errors are those :-)

Still to do, then:
 - vector code
 - better string names in error.c
 - deal with arg string in some way
 - make use of the error status in statgrab/saidar/examples

File Contents

# User Rev Content
1 tdb 1.17 /*
2 tdb 1.57 * i-scream libstatgrab
3 tdb 1.8 * http://www.i-scream.org
4 tdb 1.17 * Copyright (C) 2000-2004 i-scream
5 pajs 1.1 *
6 tdb 1.17 * This library is free software; you can redistribute it and/or
7     * modify it under the terms of the GNU Lesser General Public
8     * License as published by the Free Software Foundation; either
9     * version 2.1 of the License, or (at your option) any later version.
10 pajs 1.1 *
11 tdb 1.17 * This library is distributed in the hope that it will be useful,
12 pajs 1.1 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 tdb 1.17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14     * Lesser General Public License for more details.
15 pajs 1.1 *
16 tdb 1.17 * You should have received a copy of the GNU Lesser General Public
17     * License along with this library; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19     * 02111-1307 USA
20 tdb 1.18 *
21 tdb 1.65 * $Id: process_stats.c,v 1.64 2004/04/07 15:46:34 pajs Exp $
22 pajs 1.1 */
23    
24     #ifdef HAVE_CONFIG_H
25     #include "config.h"
26     #endif
27    
28 pajs 1.6 #include "statgrab.h"
29 ats 1.48 #include "tools.h"
30     #include "vector.h"
31 pajs 1.6 #if defined(SOLARIS) || defined(LINUX)
32 pajs 1.1 #include <stdio.h>
33     #include <stdlib.h>
34 pajs 1.5 #include <sys/types.h>
35     #include <dirent.h>
36     #include <string.h>
37 pajs 1.6 #endif
38 pajs 1.1
39     #ifdef SOLARIS
40     #include <procfs.h>
41     #include <limits.h>
42 pajs 1.5 #define PROC_LOCATION "/proc"
43     #define MAX_FILE_LENGTH PATH_MAX
44     #endif
45     #ifdef LINUX
46 ats 1.16 #include <limits.h>
47 pajs 1.25 #include <unistd.h>
48     #include <sys/stat.h>
49     #include <fcntl.h>
50 pajs 1.1 #define PROC_LOCATION "/proc"
51     #define MAX_FILE_LENGTH PATH_MAX
52     #endif
53 ats 1.13 #ifdef ALLBSD
54 tdb 1.19 #include <stdlib.h>
55 pajs 1.6 #include <sys/param.h>
56     #include <sys/sysctl.h>
57 tdb 1.22 #if defined(FREEBSD) || defined(DFBSD)
58     #include <sys/user.h>
59     #else
60 tdb 1.19 #include <sys/proc.h>
61 ats 1.13 #endif
62 tdb 1.29 #include <string.h>
63     #include <paths.h>
64     #include <fcntl.h>
65     #include <limits.h>
66 tdb 1.41 #if (defined(FREEBSD) && !defined(FREEBSD5)) || defined(DFBSD)
67 tdb 1.29 #include <kvm.h>
68 pajs 1.6 #endif
69 tdb 1.41 #include <unistd.h>
70 tdb 1.55 #ifdef NETBSD2
71     #include <sys/lwp.h>
72     #endif
73 tdb 1.41 #endif
74 pajs 1.1
75 ats 1.52 static void proc_state_init(sg_process_stats *s) {
76 ats 1.48 s->process_name = NULL;
77     s->proctitle = NULL;
78     }
79    
80 ats 1.52 static void proc_state_destroy(sg_process_stats *s) {
81 ats 1.48 free(s->process_name);
82     free(s->proctitle);
83     }
84    
85 ats 1.52 sg_process_stats *sg_get_process_stats(int *entries){
86     VECTOR_DECLARE_STATIC(proc_state, sg_process_stats, 64,
87 tdb 1.63 proc_state_init, proc_state_destroy);
88 ats 1.48 int proc_state_size = 0;
89 ats 1.52 sg_process_stats *proc_state_ptr;
90 tdb 1.26 #ifdef ALLBSD
91 tdb 1.37 int mib[4];
92 tdb 1.26 size_t size;
93     struct kinfo_proc *kp_stats;
94 tdb 1.41 int procs, i;
95 tdb 1.45 char *proctitle;
96 tdb 1.41 #if (defined(FREEBSD) && !defined(FREEBSD5)) || defined(DFBSD)
97 tdb 1.42 kvm_t *kvmd;
98 tdb 1.50 char **args, **argsp;
99     int argslen = 0;
100 tdb 1.41 #else
101 tdb 1.37 long buflen;
102     char *p;
103     #endif
104 tdb 1.55 #ifdef NETBSD2
105     int lwps;
106     struct kinfo_lwp *kl_stats;
107     #endif
108 tdb 1.26 #endif
109 pajs 1.24 #if defined(SOLARIS) || defined(LINUX)
110 tdb 1.63 DIR *proc_dir;
111     struct dirent *dir_entry;
112     char filename[MAX_FILE_LENGTH];
113     FILE *f;
114 pajs 1.24 #ifdef SOLARIS
115 pajs 1.5 psinfo_t process_info;
116 pajs 1.24 #endif
117 pajs 1.25 #ifdef LINUX
118     char s;
119     /* If someone has a executable of 4k filename length, they deserve to get it truncated :) */
120     char ps_name[4096];
121     char *ptr;
122 ats 1.48 VECTOR_DECLARE_STATIC(psargs, char, 128, NULL, NULL);
123 pajs 1.58 unsigned long stime, utime, starttime;
124 pajs 1.25 int x;
125     int fn;
126 ats 1.48 int len;
127     int rc;
128 pajs 1.58 time_t uptime;
129     #endif
130    
131     #ifdef LINUX
132     if ((f=fopen("/proc/uptime", "r")) == NULL) {
133 tdb 1.65 sg_set_error(SG_ERROR_OPEN, "/proc/uptime");
134 pajs 1.58 return NULL;
135     }
136     if((fscanf(f,"%lu %*d",&uptime)) != 1){
137 tdb 1.65 sg_set_error(SG_ERROR_PARSE, NULL);
138 pajs 1.58 return NULL;
139     }
140     fclose(f);
141 pajs 1.25 #endif
142 pajs 1.1
143 tdb 1.63 if((proc_dir=opendir(PROC_LOCATION))==NULL){
144 tdb 1.65 sg_set_error(SG_ERROR_OPENDIR, PROC_LOCATION);
145 tdb 1.63 return NULL;
146     }
147 pajs 1.23
148 tdb 1.63 while((dir_entry=readdir(proc_dir))!=NULL){
149     if(atoi(dir_entry->d_name) == 0) continue;
150 pajs 1.23
151 pajs 1.24 #ifdef SOLARIS
152 tdb 1.63 snprintf(filename, MAX_FILE_LENGTH, "/proc/%s/psinfo", dir_entry->d_name);
153 pajs 1.24 #endif
154 pajs 1.25 #ifdef LINUX
155     snprintf(filename, MAX_FILE_LENGTH, "/proc/%s/stat", dir_entry->d_name);
156     #endif
157 tdb 1.63 if((f=fopen(filename, "r"))==NULL){
158     /* Open failed.. Process since vanished, or the path was too long.
159     * Ah well, move onwards to the next one */
160     continue;
161     }
162 pajs 1.24 #ifdef SOLARIS
163 tdb 1.63 fread(&process_info, sizeof(psinfo_t), 1, f);
164 pajs 1.64 fclose(f);
165 pajs 1.25 #endif
166 pajs 1.1
167 ats 1.48 if (VECTOR_RESIZE(proc_state, proc_state_size + 1) < 0) {
168 ats 1.52 return NULL;
169 ats 1.48 }
170 pajs 1.23 proc_state_ptr = proc_state+proc_state_size;
171 ats 1.48
172 pajs 1.25 #ifdef SOLARIS
173 pajs 1.23 proc_state_ptr->pid = process_info.pr_pid;
174     proc_state_ptr->parent = process_info.pr_ppid;
175     proc_state_ptr->pgid = process_info.pr_pgid;
176     proc_state_ptr->uid = process_info.pr_uid;
177     proc_state_ptr->euid = process_info.pr_euid;
178     proc_state_ptr->gid = process_info.pr_gid;
179     proc_state_ptr->egid = process_info.pr_egid;
180     proc_state_ptr->proc_size = (process_info.pr_size) * 1024;
181     proc_state_ptr->proc_resident = (process_info.pr_rssize) * 1024;
182     proc_state_ptr->time_spent = process_info.pr_time.tv_sec;
183     proc_state_ptr->cpu_percent = (process_info.pr_pctcpu * 100.0) / 0x8000;
184 pajs 1.64 proc_state_ptr->nice = (int)process_info.pr_lwp.pr_nice - 20;
185 ats 1.60 if (sg_update_string(&proc_state_ptr->process_name,
186 tdb 1.63 process_info.pr_fname) < 0) {
187 ats 1.60 return NULL;
188     }
189     if (sg_update_string(&proc_state_ptr->proctitle,
190 tdb 1.63 process_info.pr_psargs) < 0) {
191 ats 1.60 return NULL;
192     }
193 pajs 1.24
194 tdb 1.63 if(process_info.pr_lwp.pr_state==1) proc_state_ptr->state = SG_PROCESS_STATE_SLEEPING;
195     if(process_info.pr_lwp.pr_state==2) proc_state_ptr->state = SG_PROCESS_STATE_RUNNING;
196     if(process_info.pr_lwp.pr_state==3) proc_state_ptr->state = SG_PROCESS_STATE_ZOMBIE;
197     if(process_info.pr_lwp.pr_state==4) proc_state_ptr->state = SG_PROCESS_STATE_STOPPED;
198     if(process_info.pr_lwp.pr_state==6) proc_state_ptr->state = SG_PROCESS_STATE_RUNNING;
199 pajs 1.25 #endif
200     #ifdef LINUX
201 pajs 1.58 x = fscanf(f, "%d %4096s %c %d %d %*d %*d %*d %*u %*u %*u %*u %*u %lu %lu %*d %*d %*d %d %*d %*d %lu %llu %llu %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*d %*d\n", &(proc_state_ptr->pid), ps_name, &s, &(proc_state_ptr->parent), &(proc_state_ptr->pgid), &utime, &stime, &(proc_state_ptr->nice), &starttime, &(proc_state_ptr->proc_size), &(proc_state_ptr->proc_resident));
202     /* +3 becuase man page says "Resident Set Size: number of pages the process has in real memory, minus 3 for administrative purposes." */
203     proc_state_ptr->proc_resident = (proc_state_ptr->proc_resident + 3) * getpagesize();
204 ats 1.52 if(s == 'S') proc_state_ptr->state = SG_PROCESS_STATE_SLEEPING;
205     if(s == 'R') proc_state_ptr->state = SG_PROCESS_STATE_RUNNING;
206     if(s == 'Z') proc_state_ptr->state = SG_PROCESS_STATE_ZOMBIE;
207     if(s == 'T') proc_state_ptr->state = SG_PROCESS_STATE_STOPPED;
208     if(s == 'D') proc_state_ptr->state = SG_PROCESS_STATE_STOPPED;
209 pajs 1.25
210     /* pa_name[0] should = '(' */
211     ptr = strchr(&ps_name[1], ')');
212     if(ptr !=NULL) *ptr='\0';
213 ats 1.48
214 ats 1.52 if (sg_update_string(&proc_state_ptr->process_name,
215 tdb 1.63 &ps_name[1]) < 0) {
216 ats 1.52 return NULL;
217 ats 1.48 }
218 pajs 1.25
219 pajs 1.58 /* cpu */
220     proc_state_ptr->cpu_percent = (100.0 * (utime + stime)) / ((uptime * 100.0) - starttime);
221 pajs 1.25
222 tdb 1.63 fclose(f);
223 pajs 1.62
224     /* uid / gid */
225     snprintf(filename, MAX_FILE_LENGTH, "/proc/%s/status", dir_entry->d_name);
226 tdb 1.63 if ((f=fopen(filename, "r")) == NULL) {
227     /* Open failed.. Process since vanished, or the path was too long.
228     * Ah well, move onwards to the next one */
229     continue;
230     }
231 pajs 1.62
232     if((ptr=sg_f_read_line(f, "Uid:"))==NULL){
233     fclose(f);
234     continue;
235     }
236     sscanf(ptr, "Uid:\t%d\t%d\t%*d\t%*d\n", &(proc_state_ptr->uid), &(proc_state_ptr->euid));
237    
238     if((ptr=sg_f_read_line(f, "Gid:"))==NULL){
239 tdb 1.63 fclose(f);
240     continue;
241     }
242     sscanf(ptr, "Gid:\t%d\t%d\t%*d\t%*d\n", &(proc_state_ptr->gid), &(proc_state_ptr->egid));
243 pajs 1.62
244     fclose(f);
245 ats 1.48
246 pajs 1.25 /* proctitle */
247     snprintf(filename, MAX_FILE_LENGTH, "/proc/%s/cmdline", dir_entry->d_name);
248    
249 tdb 1.63 if((fn=open(filename, O_RDONLY)) == -1){
250     /* Open failed.. Process since vanished, or the path was too long.
251     * Ah well, move onwards to the next one */
252     continue;
253     }
254 ats 1.48
255     #define READ_BLOCK_SIZE 128
256     len = 0;
257     do {
258 ats 1.53 if (VECTOR_RESIZE(psargs, len + READ_BLOCK_SIZE) < 0) {
259 ats 1.52 return NULL;
260 ats 1.48 }
261     rc = read(fn, psargs + len, READ_BLOCK_SIZE);
262     if (rc > 0) {
263     len += rc;
264     }
265     } while (rc == READ_BLOCK_SIZE);
266     close(fn);
267    
268     if (rc == -1) {
269     /* Read failed; move on. */
270     continue;
271 pajs 1.25 }
272    
273 ats 1.48 /* Turn \0s into spaces within the command line. */
274 pajs 1.25 ptr = psargs;
275 ats 1.48 for(x = 0; x < len; x++) {
276 pajs 1.25 if (*ptr == '\0') *ptr = ' ';
277     ptr++;
278     }
279    
280 ats 1.53 if (len == 0) {
281     /* We want psargs to be NULL. */
282     if (VECTOR_RESIZE(psargs, 0) < 0) {
283     return NULL;
284     }
285     } else {
286     /* Not empty, so append a \0. */
287     if (VECTOR_RESIZE(psargs, len + 1) < 0) {
288     return NULL;
289     }
290     psargs[len] = '\0';
291     }
292    
293     if (sg_update_string(&proc_state_ptr->proctitle, psargs) < 0) {
294 ats 1.52 return NULL;
295 ats 1.48 }
296 pajs 1.24 #endif
297 pajs 1.23
298     proc_state_size++;
299 tdb 1.63 }
300     closedir(proc_dir);
301 tdb 1.26 #endif
302    
303     #ifdef ALLBSD
304 tdb 1.36 mib[0] = CTL_KERN;
305     mib[1] = KERN_PROC;
306     mib[2] = KERN_PROC_ALL;
307    
308     if(sysctl(mib, 3, NULL, &size, NULL, 0) < 0) {
309 tdb 1.65 sg_set_error(SG_ERROR_SYSCTL, "CTL_KERN.KERN_PROC.KERN_PROC_ALL");
310 ats 1.52 return NULL;
311 tdb 1.36 }
312    
313     procs = size / sizeof(struct kinfo_proc);
314    
315 ats 1.61 kp_stats = sg_malloc(size);
316 tdb 1.36 if(kp_stats == NULL) {
317 ats 1.52 return NULL;
318 tdb 1.36 }
319 ats 1.54 memset(kp_stats, 0, size);
320 tdb 1.36
321     if(sysctl(mib, 3, kp_stats, &size, NULL, 0) < 0) {
322 tdb 1.65 sg_set_error(SG_ERROR_SYSCTL, "CTL_KERN.KERN_PROC.KERN_PROC_ALL");
323 tdb 1.36 free(kp_stats);
324 ats 1.52 return NULL;
325 tdb 1.36 }
326 tdb 1.33
327 tdb 1.37 #if (defined(FREEBSD) && !defined(FREEBSD5)) || defined(DFBSD)
328 ats 1.52 kvmd = sg_get_kvm2();
329 tdb 1.33 #endif
330 tdb 1.26
331     for (i = 0; i < procs; i++) {
332 ats 1.48 const char *name;
333 ats 1.54
334 tdb 1.55 #ifdef FREEBSD5
335 ats 1.54 if (kp_stats[i].ki_stat == 0) {
336 tdb 1.55 #else
337     if (kp_stats[i].kp_proc.p_stat == 0) {
338     #endif
339 ats 1.54 /* FreeBSD 5 deliberately overallocates the array that
340     * the sysctl returns, so we'll get a few junk
341     * processes on the end that we have to ignore. (Search
342     * for "overestimate by 5 procs" in
343     * src/sys/kern/kern_proc.c for more details.) */
344     continue;
345     }
346 ats 1.48
347     if (VECTOR_RESIZE(proc_state, proc_state_size + 1) < 0) {
348 ats 1.52 return NULL;
349 tdb 1.29 }
350 tdb 1.26 proc_state_ptr = proc_state+proc_state_size;
351 tdb 1.30
352     #ifdef FREEBSD5
353 ats 1.48 name = kp_stats[i].ki_comm;
354 tdb 1.35 #elif defined(DFBSD)
355 ats 1.48 name = kp_stats[i].kp_thread.td_comm;
356 tdb 1.30 #else
357 ats 1.48 name = kp_stats[i].kp_proc.p_comm;
358 tdb 1.30 #endif
359 ats 1.53 if (sg_update_string(&proc_state_ptr->process_name, name) < 0) {
360 ats 1.52 return NULL;
361 ats 1.48 }
362 tdb 1.29
363 tdb 1.37 #if defined(FREEBSD5) || defined(NETBSD) || defined(OPENBSD)
364     size = sizeof(buflen);
365    
366     #ifdef FREEBSD5
367     if(sysctlbyname("kern.ps_arg_cache_limit", &buflen, &size, NULL, 0) < 0) {
368 tdb 1.65 sg_set_error(SG_ERROR_SYSCTLBYNAME, "kern.ps_arg_cache_limit");
369 ats 1.52 return NULL;
370 tdb 1.37 }
371     #else
372 tdb 1.56 /* FIXME - this value can be too large on some of
373     the BSD's, which causes sysctl not to return
374     anything. Maybe we need something smaller? */
375 tdb 1.37 mib[1] = KERN_ARGMAX;
376    
377     if(sysctl(mib, 2, &buflen, &size, NULL, 0) < 0) {
378 tdb 1.65 sg_set_error(SG_ERROR_SYSCTL, "CTL_KERN.KERN_ARGMAX");
379 ats 1.52 return NULL;
380 tdb 1.37 }
381     #endif
382    
383 ats 1.61 proctitle = sg_malloc(buflen);
384 tdb 1.37 if(proctitle == NULL) {
385 ats 1.52 return NULL;
386 tdb 1.37 }
387    
388     size = buflen;
389    
390     #ifdef FREEBSD5
391     mib[2] = KERN_PROC_ARGS;
392     mib[3] = kp_stats[i].ki_pid;
393     #else
394     mib[1] = KERN_PROC_ARGS;
395     mib[2] = kp_stats[i].kp_proc.p_pid;
396     mib[3] = KERN_PROC_ARGV;
397     #endif
398    
399 ats 1.48 free(proc_state_ptr->proctitle);
400 tdb 1.37 if(sysctl(mib, 4, proctitle, &size, NULL, 0) < 0) {
401     free(proctitle);
402     proc_state_ptr->proctitle = NULL;
403     }
404     else if(size > 0) {
405 ats 1.61 proc_state_ptr->proctitle = sg_malloc(size+1);
406 tdb 1.37 if(proc_state_ptr->proctitle == NULL) {
407 ats 1.52 return NULL;
408 tdb 1.29 }
409 tdb 1.37 p = proctitle;
410 ats 1.49 proc_state_ptr->proctitle[0] = '\0';
411 tdb 1.37 do {
412 ats 1.52 sg_strlcat(proc_state_ptr->proctitle, p, size+1);
413     sg_strlcat(proc_state_ptr->proctitle, " ", size+1);
414 tdb 1.37 p += strlen(p) + 1;
415     } while (p < proctitle + size);
416     free(proctitle);
417 tdb 1.45 /* remove trailing space */
418     proc_state_ptr->proctitle[strlen(proc_state_ptr->proctitle)-1] = '\0';
419 tdb 1.37 }
420     else {
421     free(proctitle);
422     proc_state_ptr->proctitle = NULL;
423     }
424     #else
425 ats 1.48 free(proc_state_ptr->proctitle);
426 tdb 1.37 if(kvmd != NULL) {
427     args = kvm_getargv(kvmd, &(kp_stats[i]), 0);
428     if(args != NULL) {
429 tdb 1.50 argsp = args;
430     while(*argsp != NULL) {
431 tdb 1.51 argslen += strlen(*argsp) + 1;
432     argsp++;
433 tdb 1.50 }
434 ats 1.61 proctitle = sg_malloc(argslen + 1);
435 tdb 1.50 proctitle[0] = '\0';
436 tdb 1.37 if(proctitle == NULL) {
437 ats 1.52 return NULL;
438 tdb 1.37 }
439     while(*args != NULL) {
440 ats 1.52 sg_strlcat(proctitle, *args, argslen + 1);
441     sg_strlcat(proctitle, " ", argslen + 1);
442 tdb 1.37 args++;
443 tdb 1.29 }
444 tdb 1.37 /* remove trailing space */
445 tdb 1.45 proctitle[strlen(proctitle)-1] = '\0';
446 tdb 1.37 proc_state_ptr->proctitle = proctitle;
447     }
448     else {
449     proc_state_ptr->proctitle = NULL;
450 tdb 1.29 }
451     }
452     else {
453 tdb 1.37 proc_state_ptr->proctitle = NULL;
454 tdb 1.29 }
455 tdb 1.37 #endif
456 tdb 1.26
457 tdb 1.30 #ifdef FREEBSD5
458 tdb 1.26 proc_state_ptr->pid = kp_stats[i].ki_pid;
459     proc_state_ptr->parent = kp_stats[i].ki_ppid;
460     proc_state_ptr->pgid = kp_stats[i].ki_pgid;
461 tdb 1.30 #else
462     proc_state_ptr->pid = kp_stats[i].kp_proc.p_pid;
463     proc_state_ptr->parent = kp_stats[i].kp_eproc.e_ppid;
464     proc_state_ptr->pgid = kp_stats[i].kp_eproc.e_pgid;
465     #endif
466 tdb 1.26
467 tdb 1.30 #ifdef FREEBSD5
468 tdb 1.26 proc_state_ptr->uid = kp_stats[i].ki_ruid;
469     proc_state_ptr->euid = kp_stats[i].ki_uid;
470     proc_state_ptr->gid = kp_stats[i].ki_rgid;
471     proc_state_ptr->egid = kp_stats[i].ki_svgid;
472 tdb 1.35 #elif defined(DFBSD)
473     proc_state_ptr->uid = kp_stats[i].kp_eproc.e_ucred.cr_ruid;
474     proc_state_ptr->euid = kp_stats[i].kp_eproc.e_ucred.cr_svuid;
475     proc_state_ptr->gid = kp_stats[i].kp_eproc.e_ucred.cr_rgid;
476     proc_state_ptr->egid = kp_stats[i].kp_eproc.e_ucred.cr_svgid;
477 tdb 1.30 #else
478     proc_state_ptr->uid = kp_stats[i].kp_eproc.e_pcred.p_ruid;
479     proc_state_ptr->euid = kp_stats[i].kp_eproc.e_pcred.p_svuid;
480     proc_state_ptr->gid = kp_stats[i].kp_eproc.e_pcred.p_rgid;
481     proc_state_ptr->egid = kp_stats[i].kp_eproc.e_pcred.p_svgid;
482     #endif
483 tdb 1.26
484 tdb 1.30 #ifdef FREEBSD5
485 tdb 1.26 proc_state_ptr->proc_size = kp_stats[i].ki_size;
486     /* This is in pages */
487 tdb 1.30 proc_state_ptr->proc_resident =
488     kp_stats[i].ki_rssize * getpagesize();
489 tdb 1.28 /* This is in microseconds */
490 tdb 1.26 proc_state_ptr->time_spent = kp_stats[i].ki_runtime / 1000000;
491 tdb 1.30 proc_state_ptr->cpu_percent =
492     ((double)kp_stats[i].ki_pctcpu / FSCALE) * 100.0;
493 tdb 1.26 proc_state_ptr->nice = kp_stats[i].ki_nice;
494 tdb 1.30 #else
495     proc_state_ptr->proc_size =
496     kp_stats[i].kp_eproc.e_vm.vm_map.size;
497     /* This is in pages */
498     proc_state_ptr->proc_resident =
499     kp_stats[i].kp_eproc.e_vm.vm_rssize * getpagesize();
500 tdb 1.34 #if defined(NETBSD) || defined(OPENBSD)
501 tdb 1.33 proc_state_ptr->time_spent =
502     kp_stats[i].kp_proc.p_rtime.tv_sec;
503 tdb 1.35 #elif defined(DFBSD)
504     proc_state_ptr->time_spent =
505     ( kp_stats[i].kp_thread.td_uticks +
506     kp_stats[i].kp_thread.td_sticks +
507     kp_stats[i].kp_thread.td_iticks ) / 1000000;
508 tdb 1.33 #else
509 tdb 1.36 /* This is in microseconds */
510 tdb 1.30 proc_state_ptr->time_spent =
511     kp_stats[i].kp_proc.p_runtime / 1000000;
512 tdb 1.33 #endif
513 tdb 1.30 proc_state_ptr->cpu_percent =
514     ((double)kp_stats[i].kp_proc.p_pctcpu / FSCALE) * 100.0;
515     proc_state_ptr->nice = kp_stats[i].kp_proc.p_nice;
516     #endif
517 tdb 1.26
518 tdb 1.55 #ifdef NETBSD2
519     {
520     size_t size;
521     int mib[5];
522    
523     mib[0] = CTL_KERN;
524     mib[1] = KERN_LWP;
525     mib[2] = kp_stats[i].kp_proc.p_pid;
526     mib[3] = sizeof(struct kinfo_lwp);
527     mib[4] = 0;
528    
529     if(sysctl(mib, 5, NULL, &size, NULL, 0) < 0) {
530 tdb 1.65 sg_set_error(SG_ERROR_SYSCTL, "CTL_KERN.KERN_LWP.pid.structsize.0");
531 tdb 1.55 return NULL;
532     }
533    
534     lwps = size / sizeof(struct kinfo_lwp);
535     mib[4] = lwps;
536    
537 ats 1.61 kl_stats = sg_malloc(size);
538 tdb 1.55 if(kl_stats == NULL) {
539     return NULL;
540     }
541    
542     if(sysctl(mib, 5, kl_stats, &size, NULL, 0) < 0) {
543 tdb 1.65 sg_set_error(SG_ERROR_SYSCTL, "CTL_KERN.KERN_LWP.pid.structsize.buffersize");
544 tdb 1.55 return NULL;
545     }
546     }
547    
548     switch(kp_stats[i].kp_proc.p_stat) {
549     case SIDL:
550     proc_state_ptr->state = SG_PROCESS_STATE_RUNNING;
551     break;
552     case SACTIVE:
553     {
554     int i;
555    
556     for(i = 0; i < lwps; i++) {
557     switch(kl_stats[i].l_stat) {
558     case LSONPROC:
559     case LSRUN:
560     proc_state_ptr->state = SG_PROCESS_STATE_RUNNING;
561     goto end;
562     case LSSLEEP:
563     proc_state_ptr->state = SG_PROCESS_STATE_SLEEPING;
564     goto end;
565     case LSSTOP:
566     case LSSUSPENDED:
567     proc_state_ptr->state = SG_PROCESS_STATE_STOPPED;
568     goto end;
569     }
570     proc_state_ptr->state = SG_PROCESS_STATE_UNKNOWN;
571     }
572     end: ;
573     }
574     break;
575     case SSTOP:
576     proc_state_ptr->state = SG_PROCESS_STATE_STOPPED;
577     break;
578     case SZOMB:
579     proc_state_ptr->state = SG_PROCESS_STATE_ZOMBIE;
580     break;
581     default:
582     proc_state_ptr->state = SG_PROCESS_STATE_UNKNOWN;
583     break;
584     }
585     #else
586 tdb 1.30 #ifdef FREEBSD5
587 tdb 1.26 switch (kp_stats[i].ki_stat) {
588 tdb 1.30 #else
589     switch (kp_stats[i].kp_proc.p_stat) {
590     #endif
591 tdb 1.26 case SIDL:
592     case SRUN:
593     #ifdef SONPROC
594     case SONPROC: /* NetBSD */
595     #endif
596 ats 1.52 proc_state_ptr->state = SG_PROCESS_STATE_RUNNING;
597 tdb 1.26 break;
598     case SSLEEP:
599     #ifdef SWAIT
600     case SWAIT: /* FreeBSD 5 */
601     #endif
602     #ifdef SLOCK
603     case SLOCK: /* FreeBSD 5 */
604     #endif
605 ats 1.52 proc_state_ptr->state = SG_PROCESS_STATE_SLEEPING;
606 tdb 1.26 break;
607     case SSTOP:
608 ats 1.52 proc_state_ptr->state = SG_PROCESS_STATE_STOPPED;
609 tdb 1.26 break;
610     case SZOMB:
611     #ifdef SDEAD
612     case SDEAD: /* OpenBSD & NetBSD */
613     #endif
614 ats 1.52 proc_state_ptr->state = SG_PROCESS_STATE_ZOMBIE;
615 tdb 1.31 break;
616     default:
617 ats 1.52 proc_state_ptr->state = SG_PROCESS_STATE_UNKNOWN;
618 tdb 1.26 break;
619     }
620 tdb 1.55 #endif
621 tdb 1.26 proc_state_size++;
622     }
623    
624     free(kp_stats);
625 tdb 1.47 #endif
626    
627     #ifdef CYGWIN
628 tdb 1.65 sg_set_error(SG_ERROR_UNSUPPORTED, "Cygwin");
629 ats 1.52 return NULL;
630 tdb 1.26 #endif
631    
632 ats 1.52 *entries = proc_state_size;
633     return proc_state;
634 tdb 1.27 }
635    
636 ats 1.52 sg_process_count *sg_get_process_count() {
637     static sg_process_count process_stat;
638     sg_process_stats *ps;
639 tdb 1.27 int ps_size, x;
640    
641 tdb 1.30 process_stat.sleeping = 0;
642     process_stat.running = 0;
643     process_stat.zombie = 0;
644     process_stat.stopped = 0;
645     process_stat.total = 0;
646 tdb 1.27
647 ats 1.52 ps = sg_get_process_stats(&ps_size);
648     if (ps == NULL) {
649 tdb 1.32 return NULL;
650     }
651 tdb 1.27
652     for(x = 0; x < ps_size; x++) {
653     switch (ps->state) {
654 ats 1.52 case SG_PROCESS_STATE_RUNNING:
655 tdb 1.27 process_stat.running++;
656     break;
657 ats 1.52 case SG_PROCESS_STATE_SLEEPING:
658 tdb 1.27 process_stat.sleeping++;
659     break;
660 ats 1.52 case SG_PROCESS_STATE_STOPPED:
661 tdb 1.27 process_stat.stopped++;
662     break;
663 ats 1.52 case SG_PROCESS_STATE_ZOMBIE:
664 tdb 1.27 process_stat.zombie++;
665 ats 1.40 break;
666     default:
667 ats 1.52 /* currently no mapping for SG_PROCESS_STATE_UNKNOWN in
668     * sg_process_count */
669 tdb 1.27 break;
670     }
671     ps++;
672     }
673    
674     process_stat.total = ps_size;
675    
676     return &process_stat;
677 pajs 1.23 }