2 #include "utils/mono-proclib.h"
15 /* FIXME: bsds untested */
16 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
17 #include <sys/types.h>
18 #include <sys/sysctl.h>
20 #ifdef HAVE_SYS_USER_H
23 #ifdef HAVE_STRUCT_KINFO_PROC_KP_PROC
24 #define kinfo_pid_member kp_proc.p_pid
25 #define kinfo_name_member kp_proc.p_comm
27 #define kinfo_pid_member ki_pid
28 #define kinfo_name_member ki_comm
35 * @size: a pointer to a location where the size of the returned array is stored
37 * Return an array of pid values for the processes currently running on the system.
38 * The size of the array is stored in @size.
41 mono_process_list (int *size
)
46 size_t data_len
= sizeof (struct kinfo_proc
) * 400;
47 struct kinfo_proc
*processes
= malloc (data_len
);
57 mib
[2] = KERN_PROC_ALL
;
60 res
= sysctl (mib
, 4, processes
, &data_len
, NULL
, 0);
65 res
= data_len
/sizeof (struct kinfo_proc
);
66 buf
= g_realloc (buf
, res
* sizeof (void*));
67 for (i
= 0; i
< res
; ++i
)
68 buf
[i
] = GINT_TO_POINTER (processes
[i
].kinfo_pid_member
);
78 GDir
*dir
= g_dir_open ("/proc/", 0, NULL
);
84 while ((name
= g_dir_read_name (dir
))) {
87 pid
= strtol (name
, &nend
, 10);
88 if (pid
<= 0 || nend
== name
|| *nend
)
95 buf
= g_realloc (buf
, count
* sizeof (void*));
97 buf
[i
++] = GINT_TO_POINTER (pid
);
107 get_pid_status_item_buf (int pid
, const char *item
, char *rbuf
, int blen
, MonoProcessError
*error
)
112 int len
= strlen (item
);
114 g_snprintf (buf
, sizeof (buf
), "/proc/%d/status", pid
);
115 f
= fopen (buf
, "r");
118 *error
= MONO_PROCESS_ERROR_NOT_FOUND
;
121 while ((s
= fgets (buf
, blen
, f
))) {
124 if (strncmp (buf
, item
, len
))
127 while (g_ascii_isspace (*s
)) s
++;
130 while (g_ascii_isspace (*s
)) s
++;
133 strncpy (rbuf
, s
, MIN (len
, blen
));
136 *error
= MONO_PROCESS_ERROR_NONE
;
141 *error
= MONO_PROCESS_ERROR_OTHER
;
146 * mono_process_get_name:
147 * @pid: pid of the process
148 * @buf: byte buffer where to store the name of the prcoess
149 * @len: size of the buffer @buf
151 * Return the name of the process identified by @pid, storing it
152 * inside @buf for a maximum of len bytes (including the terminating 0).
155 mono_process_get_name (gpointer pid
, char *buf
, int len
)
161 size_t data_len
= sizeof (struct kinfo_proc
);
162 struct kinfo_proc processi
;
164 memset (buf
, 0, len
);
168 mib
[2] = KERN_PROC_PID
;
169 mib
[3] = GPOINTER_TO_UINT (pid
);
171 res
= sysctl (mib
, 4, &processi
, &data_len
, NULL
, 0);
172 if (res
< 0 || data_len
!= sizeof (struct kinfo_proc
)) {
175 strncpy (buf
, processi
.kinfo_name_member
, len
- 1);
182 sprintf (fname
, "/proc/%d/cmdline", GPOINTER_TO_INT (pid
));
184 file
= fopen (fname
, "r");
187 r
= fread (buf
, 1, len
- 1, file
);
190 p
= strrchr (buf
, '/');
194 return get_pid_status_item_buf (GPOINTER_TO_INT (pid
), "Name", buf
, len
, NULL
);
201 * /proc/pid/stat format:
203 * [0] ppid pgid sid tty_nr tty_pgrp flags min_flt cmin_flt maj_flt cmaj_flt
204 * [10] utime stime cutime cstime prio nice threads 0 start_time vsize rss
205 * [20] rss rsslim start_code end_code start_stack esp eip pending blocked sigign
206 * [30] sigcatch wchan 0 0 exit_signal cpu rt_prio policy
209 #define RET_ERROR(err) do { \
210 if (error) *error = (err); \
215 get_process_stat_item (int pid
, int pos
, int sum
, MonoProcessError
*error
)
223 g_snprintf (buf
, sizeof (buf
), "/proc/%d/stat", pid
);
224 f
= fopen (buf
, "r");
226 RET_ERROR (MONO_PROCESS_ERROR_NOT_FOUND
);
227 len
= fread (buf
, 1, sizeof (buf
), f
);
230 RET_ERROR (MONO_PROCESS_ERROR_OTHER
);
231 s
= strchr (buf
, ')');
233 RET_ERROR (MONO_PROCESS_ERROR_OTHER
);
235 while (g_ascii_isspace (*s
)) s
++;
237 RET_ERROR (MONO_PROCESS_ERROR_OTHER
);
238 /* skip the status char */
239 while (*s
&& !g_ascii_isspace (*s
)) s
++;
241 RET_ERROR (MONO_PROCESS_ERROR_OTHER
);
242 for (i
= 0; i
< pos
; ++i
) {
243 while (g_ascii_isspace (*s
)) s
++;
245 RET_ERROR (MONO_PROCESS_ERROR_OTHER
);
246 while (*s
&& !g_ascii_isspace (*s
)) s
++;
248 RET_ERROR (MONO_PROCESS_ERROR_OTHER
);
250 /* we are finally at the needed item */
251 value
= strtoul (s
, &end
, 0);
252 /* add also the following value */
254 while (g_ascii_isspace (*s
)) s
++;
256 RET_ERROR (MONO_PROCESS_ERROR_OTHER
);
257 value
+= strtoul (s
, &end
, 0);
260 *error
= MONO_PROCESS_ERROR_NONE
;
267 static int user_hz
= 0;
270 user_hz
= sysconf (_SC_CLK_TCK
);
279 get_process_stat_time (int pid
, int pos
, int sum
, MonoProcessError
*error
)
281 gint64 val
= get_process_stat_item (pid
, pos
, sum
, error
);
282 /* return milliseconds */
283 return (val
* 1000) / get_user_hz ();
287 get_pid_status_item (int pid
, const char *item
, MonoProcessError
*error
)
292 s
= get_pid_status_item_buf (pid
, item
, buf
, sizeof (buf
), error
);
299 * mono_process_get_data:
300 * @pid: pid of the process
301 * @data: description of data to return
303 * Return a data item of a process like user time, memory use etc,
304 * according to the @data argumet.
307 mono_process_get_data_with_error (gpointer pid
, MonoProcessData data
, MonoProcessError
*error
)
310 int rpid
= GPOINTER_TO_INT (pid
);
313 *error
= MONO_PROCESS_ERROR_OTHER
;
316 case MONO_PROCESS_NUM_THREADS
:
317 return get_pid_status_item (rpid
, "Threads", error
);
318 case MONO_PROCESS_USER_TIME
:
319 return get_process_stat_time (rpid
, 12, FALSE
, error
);
320 case MONO_PROCESS_SYSTEM_TIME
:
321 return get_process_stat_time (rpid
, 13, FALSE
, error
);
322 case MONO_PROCESS_TOTAL_TIME
:
323 return get_process_stat_time (rpid
, 12, TRUE
, error
);
324 case MONO_PROCESS_WORKING_SET
:
325 return get_pid_status_item (rpid
, "VmRSS", error
) * 1024;
326 case MONO_PROCESS_WORKING_SET_PEAK
:
327 val
= get_pid_status_item (rpid
, "VmHWM", error
) * 1024;
329 val
= get_pid_status_item (rpid
, "VmRSS", error
) * 1024;
331 case MONO_PROCESS_PRIVATE_BYTES
:
332 return get_pid_status_item (rpid
, "VmData", error
) * 1024;
333 case MONO_PROCESS_VIRTUAL_BYTES
:
334 return get_pid_status_item (rpid
, "VmSize", error
) * 1024;
335 case MONO_PROCESS_VIRTUAL_BYTES_PEAK
:
336 val
= get_pid_status_item (rpid
, "VmPeak", error
) * 1024;
338 val
= get_pid_status_item (rpid
, "VmSize", error
) * 1024;
340 case MONO_PROCESS_FAULTS
:
341 return get_process_stat_item (rpid
, 6, TRUE
, error
);
342 case MONO_PROCESS_ELAPSED
:
343 return get_process_stat_item (rpid
, 18, FALSE
, error
) / get_user_hz ();
344 case MONO_PROCESS_PPID
:
345 return get_process_stat_time (rpid
, 0, FALSE
, error
);
351 mono_process_get_data (gpointer pid
, MonoProcessData data
)
353 MonoProcessError error
;
354 return mono_process_get_data_with_error (pid
, data
, &error
);
360 * Return the number of processors on the system.
363 mono_cpu_count (void)
366 #ifdef _SC_NPROCESSORS_ONLN
367 count
= sysconf (_SC_NPROCESSORS_ONLN
);
374 size_t len
= sizeof (int);
377 if (sysctl (mib
, 2, &count
, &len
, NULL
, 0) == 0)
381 #ifdef PLATFORM_WIN32
384 GetSystemInfo (&info
);
385 return info
.dwNumberOfProcessors
;
393 get_cpu_times (int cpu_id
, gint64
*user
, gint64
*systemt
, gint64
*irq
, gint64
*sirq
, gint64
*idle
)
397 int hz
= get_user_hz ();
398 long long unsigned int user_ticks
, nice_ticks
, system_ticks
, idle_ticks
, iowait_ticks
, irq_ticks
, sirq_ticks
;
399 FILE *f
= fopen ("/proc/stat", "r");
402 hz
*= mono_cpu_count ();
403 while ((s
= fgets (buf
, sizeof (buf
), f
))) {
405 if (cpu_id
< 0 && strncmp (s
, "cpu", 3) == 0 && g_ascii_isspace (s
[3])) {
407 } else if (cpu_id
>= 0 && strncmp (s
, "cpu", 3) == 0 && strtol (s
+ 3, &data
, 10) == cpu_id
) {
414 sscanf (data
, "%Lu %Lu %Lu %Lu %Lu %Lu %Lu", &user_ticks
, &nice_ticks
, &system_ticks
, &idle_ticks
, &iowait_ticks
, &irq_ticks
, &sirq_ticks
);
419 *user
= (user_ticks
+ nice_ticks
) * 10000000 / hz
;
421 *systemt
= (system_ticks
) * 10000000 / hz
;
423 *irq
= (irq_ticks
) * 10000000 / hz
;
425 *sirq
= (sirq_ticks
) * 10000000 / hz
;
427 *idle
= (idle_ticks
) * 10000000 / hz
;
432 * @cpu_id: processor number or -1 to get a summary of all the processors
433 * @data: type of data to retrieve
435 * Get data about a processor on the system, like time spent in user space or idle time.
438 mono_cpu_get_data (int cpu_id
, MonoCpuData data
, MonoProcessError
*error
)
443 *error
= MONO_PROCESS_ERROR_NONE
;
445 case MONO_CPU_USER_TIME
:
446 get_cpu_times (cpu_id
, &value
, NULL
, NULL
, NULL
, NULL
);
448 case MONO_CPU_PRIV_TIME
:
449 get_cpu_times (cpu_id
, NULL
, &value
, NULL
, NULL
, NULL
);
451 case MONO_CPU_INTR_TIME
:
452 get_cpu_times (cpu_id
, NULL
, NULL
, &value
, NULL
, NULL
);
454 case MONO_CPU_DCP_TIME
:
455 get_cpu_times (cpu_id
, NULL
, NULL
, NULL
, &value
, NULL
);
457 case MONO_CPU_IDLE_TIME
:
458 get_cpu_times (cpu_id
, NULL
, NULL
, NULL
, NULL
, &value
);