2 #include "utils/mono-proclib.h"
15 /* FIXME: bsds untested */
16 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
17 #include <sys/param.h>
18 #include <sys/types.h>
19 #include <sys/sysctl.h>
21 #ifdef HAVE_SYS_USER_H
24 #ifdef HAVE_STRUCT_KINFO_PROC_KP_PROC
26 # define kinfo_pid_member p_pid
27 # define kinfo_name_member p_comm
29 # define kinfo_pid_member kp_proc.p_pid
30 # define kinfo_name_member kp_proc.p_comm
33 #define kinfo_pid_member ki_pid
34 #define kinfo_name_member ki_comm
41 * @size: a pointer to a location where the size of the returned array is stored
43 * Return an array of pid values for the processes currently running on the system.
44 * The size of the array is stored in @size.
47 mono_process_list (int *size
)
53 size_t data_len
= sizeof (struct kinfo_proc2
) * 400;
54 struct kinfo_proc2
*processes
= malloc (data_len
);
57 size_t data_len
= sizeof (struct kinfo_proc
) * 400;
58 struct kinfo_proc
*processes
= malloc (data_len
);
59 #endif /* KERN_PROC2 */
70 mib
[2] = KERN_PROC_ALL
;
72 mib
[4] = sizeof(struct kinfo_proc2
);
73 mib
[5] = 400; /* XXX */
75 res
= sysctl (mib
, 6, processes
, &data_len
, NULL
, 0);
79 mib
[2] = KERN_PROC_ALL
;
82 res
= sysctl (mib
, 4, processes
, &data_len
, NULL
, 0);
83 #endif /* KERN_PROC2 */
90 res
= data_len
/sizeof (struct kinfo_proc2
);
92 res
= data_len
/sizeof (struct kinfo_proc
);
93 #endif /* KERN_PROC2 */
94 buf
= g_realloc (buf
, res
* sizeof (void*));
95 for (i
= 0; i
< res
; ++i
)
96 buf
[i
] = GINT_TO_POINTER (processes
[i
].kinfo_pid_member
);
106 GDir
*dir
= g_dir_open ("/proc/", 0, NULL
);
112 while ((name
= g_dir_read_name (dir
))) {
115 pid
= strtol (name
, &nend
, 10);
116 if (pid
<= 0 || nend
== name
|| *nend
)
123 buf
= g_realloc (buf
, count
* sizeof (void*));
125 buf
[i
++] = GINT_TO_POINTER (pid
);
135 get_pid_status_item_buf (int pid
, const char *item
, char *rbuf
, int blen
, MonoProcessError
*error
)
140 int len
= strlen (item
);
142 g_snprintf (buf
, sizeof (buf
), "/proc/%d/status", pid
);
143 f
= fopen (buf
, "r");
146 *error
= MONO_PROCESS_ERROR_NOT_FOUND
;
149 while ((s
= fgets (buf
, blen
, f
))) {
152 if (strncmp (buf
, item
, len
))
155 while (g_ascii_isspace (*s
)) s
++;
158 while (g_ascii_isspace (*s
)) s
++;
161 strncpy (rbuf
, s
, MIN (len
, blen
));
162 rbuf
[MIN (len
, blen
) - 1] = 0;
164 *error
= MONO_PROCESS_ERROR_NONE
;
169 *error
= MONO_PROCESS_ERROR_OTHER
;
174 * mono_process_get_name:
175 * @pid: pid of the process
176 * @buf: byte buffer where to store the name of the prcoess
177 * @len: size of the buffer @buf
179 * Return the name of the process identified by @pid, storing it
180 * inside @buf for a maximum of len bytes (including the terminating 0).
183 mono_process_get_name (gpointer pid
, char *buf
, int len
)
189 size_t data_len
= sizeof (struct kinfo_proc2
);
190 struct kinfo_proc2 processi
;
193 size_t data_len
= sizeof (struct kinfo_proc
);
194 struct kinfo_proc processi
;
195 #endif /* KERN_PROC2 */
197 memset (buf
, 0, len
);
201 mib
[1] = KERN_PROC2
;
202 mib
[2] = KERN_PROC_PID
;
203 mib
[3] = GPOINTER_TO_UINT (pid
);
204 mib
[4] = sizeof(struct kinfo_proc2
);
205 mib
[5] = 400; /* XXX */
207 res
= sysctl (mib
, 6, &processi
, &data_len
, NULL
, 0);
209 if (res
< 0 || data_len
!= sizeof (struct kinfo_proc2
)) {
215 mib
[2] = KERN_PROC_PID
;
216 mib
[3] = GPOINTER_TO_UINT (pid
);
218 res
= sysctl (mib
, 4, &processi
, &data_len
, NULL
, 0);
219 if (res
< 0 || data_len
!= sizeof (struct kinfo_proc
)) {
222 #endif /* KERN_PROC2 */
223 strncpy (buf
, processi
.kinfo_name_member
, len
- 1);
230 sprintf (fname
, "/proc/%d/cmdline", GPOINTER_TO_INT (pid
));
232 file
= fopen (fname
, "r");
235 r
= fread (buf
, 1, len
- 1, file
);
238 p
= strrchr (buf
, '/');
242 return get_pid_status_item_buf (GPOINTER_TO_INT (pid
), "Name", buf
, len
, NULL
);
249 * /proc/pid/stat format:
251 * [0] ppid pgid sid tty_nr tty_pgrp flags min_flt cmin_flt maj_flt cmaj_flt
252 * [10] utime stime cutime cstime prio nice threads 0 start_time vsize rss
253 * [20] rss rsslim start_code end_code start_stack esp eip pending blocked sigign
254 * [30] sigcatch wchan 0 0 exit_signal cpu rt_prio policy
257 #define RET_ERROR(err) do { \
258 if (error) *error = (err); \
263 get_process_stat_item (int pid
, int pos
, int sum
, MonoProcessError
*error
)
271 g_snprintf (buf
, sizeof (buf
), "/proc/%d/stat", pid
);
272 f
= fopen (buf
, "r");
274 RET_ERROR (MONO_PROCESS_ERROR_NOT_FOUND
);
275 len
= fread (buf
, 1, sizeof (buf
), f
);
278 RET_ERROR (MONO_PROCESS_ERROR_OTHER
);
279 s
= strchr (buf
, ')');
281 RET_ERROR (MONO_PROCESS_ERROR_OTHER
);
283 while (g_ascii_isspace (*s
)) s
++;
285 RET_ERROR (MONO_PROCESS_ERROR_OTHER
);
286 /* skip the status char */
287 while (*s
&& !g_ascii_isspace (*s
)) s
++;
289 RET_ERROR (MONO_PROCESS_ERROR_OTHER
);
290 for (i
= 0; i
< pos
; ++i
) {
291 while (g_ascii_isspace (*s
)) s
++;
293 RET_ERROR (MONO_PROCESS_ERROR_OTHER
);
294 while (*s
&& !g_ascii_isspace (*s
)) s
++;
296 RET_ERROR (MONO_PROCESS_ERROR_OTHER
);
298 /* we are finally at the needed item */
299 value
= strtoul (s
, &end
, 0);
300 /* add also the following value */
302 while (g_ascii_isspace (*s
)) s
++;
304 RET_ERROR (MONO_PROCESS_ERROR_OTHER
);
305 value
+= strtoul (s
, &end
, 0);
308 *error
= MONO_PROCESS_ERROR_NONE
;
315 static int user_hz
= 0;
318 user_hz
= sysconf (_SC_CLK_TCK
);
327 get_process_stat_time (int pid
, int pos
, int sum
, MonoProcessError
*error
)
329 gint64 val
= get_process_stat_item (pid
, pos
, sum
, error
);
330 /* return 100ns ticks */
331 return (val
* 10000000) / get_user_hz ();
335 get_pid_status_item (int pid
, const char *item
, MonoProcessError
*error
)
340 s
= get_pid_status_item_buf (pid
, item
, buf
, sizeof (buf
), error
);
347 * mono_process_get_data:
348 * @pid: pid of the process
349 * @data: description of data to return
351 * Return a data item of a process like user time, memory use etc,
352 * according to the @data argumet.
355 mono_process_get_data_with_error (gpointer pid
, MonoProcessData data
, MonoProcessError
*error
)
358 int rpid
= GPOINTER_TO_INT (pid
);
361 *error
= MONO_PROCESS_ERROR_OTHER
;
364 case MONO_PROCESS_NUM_THREADS
:
365 return get_pid_status_item (rpid
, "Threads", error
);
366 case MONO_PROCESS_USER_TIME
:
367 return get_process_stat_time (rpid
, 10, FALSE
, error
);
368 case MONO_PROCESS_SYSTEM_TIME
:
369 return get_process_stat_time (rpid
, 11, FALSE
, error
);
370 case MONO_PROCESS_TOTAL_TIME
:
371 return get_process_stat_time (rpid
, 10, TRUE
, error
);
372 case MONO_PROCESS_WORKING_SET
:
373 return get_pid_status_item (rpid
, "VmRSS", error
) * 1024;
374 case MONO_PROCESS_WORKING_SET_PEAK
:
375 val
= get_pid_status_item (rpid
, "VmHWM", error
) * 1024;
377 val
= get_pid_status_item (rpid
, "VmRSS", error
) * 1024;
379 case MONO_PROCESS_PRIVATE_BYTES
:
380 return get_pid_status_item (rpid
, "VmData", error
) * 1024;
381 case MONO_PROCESS_VIRTUAL_BYTES
:
382 return get_pid_status_item (rpid
, "VmSize", error
) * 1024;
383 case MONO_PROCESS_VIRTUAL_BYTES_PEAK
:
384 val
= get_pid_status_item (rpid
, "VmPeak", error
) * 1024;
386 val
= get_pid_status_item (rpid
, "VmSize", error
) * 1024;
388 case MONO_PROCESS_FAULTS
:
389 return get_process_stat_item (rpid
, 6, TRUE
, error
);
390 case MONO_PROCESS_ELAPSED
:
391 return get_process_stat_item (rpid
, 18, FALSE
, error
) / get_user_hz ();
392 case MONO_PROCESS_PPID
:
393 return get_process_stat_time (rpid
, 0, FALSE
, error
);
396 case MONO_PROCESS_END
:
403 mono_process_get_data (gpointer pid
, MonoProcessData data
)
405 MonoProcessError error
;
406 return mono_process_get_data_with_error (pid
, data
, &error
);
412 * Return the number of processors on the system.
415 mono_cpu_count (void)
418 #ifdef _SC_NPROCESSORS_ONLN
419 count
= sysconf (_SC_NPROCESSORS_ONLN
);
426 size_t len
= sizeof (int);
429 if (sysctl (mib
, 2, &count
, &len
, NULL
, 0) == 0)
436 GetSystemInfo (&info
);
437 return info
.dwNumberOfProcessors
;
445 get_cpu_times (int cpu_id
, gint64
*user
, gint64
*systemt
, gint64
*irq
, gint64
*sirq
, gint64
*idle
)
449 int hz
= get_user_hz ();
450 long long unsigned int user_ticks
, nice_ticks
, system_ticks
, idle_ticks
, iowait_ticks
, irq_ticks
, sirq_ticks
;
451 FILE *f
= fopen ("/proc/stat", "r");
455 hz
*= mono_cpu_count ();
456 while ((s
= fgets (buf
, sizeof (buf
), f
))) {
458 if (cpu_id
< 0 && strncmp (s
, "cpu", 3) == 0 && g_ascii_isspace (s
[3])) {
460 } else if (cpu_id
>= 0 && strncmp (s
, "cpu", 3) == 0 && strtol (s
+ 3, &data
, 10) == cpu_id
) {
467 sscanf (data
, "%Lu %Lu %Lu %Lu %Lu %Lu %Lu", &user_ticks
, &nice_ticks
, &system_ticks
, &idle_ticks
, &iowait_ticks
, &irq_ticks
, &sirq_ticks
);
472 *user
= (user_ticks
+ nice_ticks
) * 10000000 / hz
;
474 *systemt
= (system_ticks
) * 10000000 / hz
;
476 *irq
= (irq_ticks
) * 10000000 / hz
;
478 *sirq
= (sirq_ticks
) * 10000000 / hz
;
480 *idle
= (idle_ticks
) * 10000000 / hz
;
485 * @cpu_id: processor number or -1 to get a summary of all the processors
486 * @data: type of data to retrieve
488 * Get data about a processor on the system, like time spent in user space or idle time.
491 mono_cpu_get_data (int cpu_id
, MonoCpuData data
, MonoProcessError
*error
)
496 *error
= MONO_PROCESS_ERROR_NONE
;
498 case MONO_CPU_USER_TIME
:
499 get_cpu_times (cpu_id
, &value
, NULL
, NULL
, NULL
, NULL
);
501 case MONO_CPU_PRIV_TIME
:
502 get_cpu_times (cpu_id
, NULL
, &value
, NULL
, NULL
, NULL
);
504 case MONO_CPU_INTR_TIME
:
505 get_cpu_times (cpu_id
, NULL
, NULL
, &value
, NULL
, NULL
);
507 case MONO_CPU_DCP_TIME
:
508 get_cpu_times (cpu_id
, NULL
, NULL
, NULL
, &value
, NULL
);
510 case MONO_CPU_IDLE_TIME
:
511 get_cpu_times (cpu_id
, NULL
, NULL
, NULL
, NULL
, &value
);