[runtime] Fix build for Linux
[mono.git] / mono / utils / mono-proclib.c
index 7971cb09cf37b9dc98bbb252f0ce3ed41d82b93e..3f9ab4c8e92edb3e80d61b788b0de51850dc0a30 100644 (file)
@@ -5,6 +5,7 @@
 
 #include "config.h"
 #include "utils/mono-proclib.h"
+#include "utils/mono-time.h"
 
 #include <stdlib.h>
 #include <stdio.h>
 #ifdef HOST_WIN32
 #include <windows.h>
 #include <process.h>
+#include <Winbase.h>
 #endif
 
-#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
+#if defined(_POSIX_VERSION)
+#include <sys/errno.h>
 #include <sys/param.h>
 #include <sys/types.h>
 #include <sys/sysctl.h>
+#include <sys/resource.h>
+#endif
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
 #include <sys/proc.h>
 #if defined(__APPLE__)
 #include <mach/mach.h>
@@ -61,17 +67,19 @@ mono_process_list (int *size)
        struct kinfo_proc2 *processes = malloc (data_len);
 #else
        int mib [4];
-       size_t data_len = sizeof (struct kinfo_proc) * 400;
-       struct kinfo_proc *processes = malloc (data_len);
+       size_t data_len = sizeof (struct kinfo_proc) * 16;
+       struct kinfo_proc *processes;
+       int limit = 8;
 #endif /* KERN_PROC2 */
        void **buf = NULL;
 
        if (size)
                *size = 0;
+
+#ifdef KERN_PROC2
        if (!processes)
                return NULL;
 
-#ifdef KERN_PROC2
        mib [0] = CTL_KERN;
        mib [1] = KERN_PROC2;
        mib [2] = KERN_PROC_ALL;
@@ -80,19 +88,34 @@ mono_process_list (int *size)
        mib [5] = 400; /* XXX */
 
        res = sysctl (mib, 6, processes, &data_len, NULL, 0);
-#else
-       mib [0] = CTL_KERN;
-       mib [1] = KERN_PROC;
-       mib [2] = KERN_PROC_ALL;
-       mib [3] = 0;
-       
-       res = sysctl (mib, 4, processes, &data_len, NULL, 0);
-#endif /* KERN_PROC2 */
-
        if (res < 0) {
                free (processes);
                return NULL;
        }
+#else
+       processes = NULL;
+       while (limit) {
+               mib [0] = CTL_KERN;
+               mib [1] = KERN_PROC;
+               mib [2] = KERN_PROC_ALL;
+               mib [3] = 0;
+
+               res = sysctl (mib, 4, NULL, &data_len, NULL, 0);
+               if (res)
+                       return NULL;
+               processes = malloc (data_len);
+               res = sysctl (mib, 4, processes, &data_len, NULL, 0);
+               if (res < 0) {
+                       free (processes);
+                       if (errno != ENOMEM)
+                               return NULL;
+                       limit --;
+               } else {
+                       break;
+               }
+       }
+#endif /* KERN_PROC2 */
+
 #ifdef KERN_PROC2
        res = data_len/sizeof (struct kinfo_proc2);
 #else
@@ -105,6 +128,10 @@ mono_process_list (int *size)
        if (size)
                *size = res;
        return buf;
+#elif defined(__HAIKU__)
+       /* FIXME: Add back the code from 9185fcc305e43428d0f40f3ee37c8a405d41c9ae */
+       g_assert_not_reached ();
+       return NULL;
 #else
        const char *name;
        void **buf = NULL;
@@ -408,11 +435,17 @@ get_pid_status_item (int pid, const char *item, MonoProcessError *error, int mul
        struct task_basic_info t_info;
        mach_msg_type_number_t th_count = TASK_BASIC_INFO_COUNT;
 
-       if (task_for_pid (mach_task_self (), pid, &task) != KERN_SUCCESS)
-               RET_ERROR (MONO_PROCESS_ERROR_NOT_FOUND);
+       if (pid == getpid ()) {
+               /* task_for_pid () doesn't work on ios, even for the current process */
+               task = mach_task_self ();
+       } else {
+               if (task_for_pid (mach_task_self (), pid, &task) != KERN_SUCCESS)
+                       RET_ERROR (MONO_PROCESS_ERROR_NOT_FOUND);
+       }
        
        if (task_info (task, TASK_BASIC_INFO, (task_info_t)&t_info, &th_count) != KERN_SUCCESS) {
-               mach_port_deallocate (mach_task_self (), task);
+               if (pid != getpid ())
+                       mach_port_deallocate (mach_task_self (), task);
                RET_ERROR (MONO_PROCESS_ERROR_OTHER);
        }
 
@@ -425,7 +458,8 @@ get_pid_status_item (int pid, const char *item, MonoProcessError *error, int mul
        else
                ret = 0;
 
-       mach_port_deallocate (mach_task_self (), task);
+       if (pid != getpid ())
+               mach_port_deallocate (mach_task_self (), task);
        
        return ret;
 #else
@@ -487,6 +521,8 @@ mono_process_get_data_with_error (gpointer pid, MonoProcessData data, MonoProces
                return get_process_stat_item (rpid, 18, FALSE, error) / get_user_hz ();
        case MONO_PROCESS_PPID:
                return get_process_stat_time (rpid, 0, FALSE, error);
+       case MONO_PROCESS_PAGED_BYTES:
+               return get_pid_status_item (rpid, "VmSwap", error, 1024);
 
                /* Nothing yet */
        case MONO_PROCESS_END:
@@ -653,3 +689,72 @@ mono_cpu_get_data (int cpu_id, MonoCpuData data, MonoProcessError *error)
        return value;
 }
 
+int
+mono_atexit (void (*func)(void))
+{
+#ifdef PLATFORM_ANDROID
+       /* Some versions of android libc doesn't define atexit () */
+       return 0;
+#else
+       return atexit (func);
+#endif
+}
+
+gint32
+mono_cpu_usage (MonoCpuUsageState *prev)
+{
+       gint32 cpu_usage = 0;
+       gint64 cpu_total_time;
+       gint64 cpu_busy_time;
+
+#ifndef HOST_WIN32
+       struct rusage resource_usage;
+       gint64 current_time;
+       gint64 kernel_time;
+       gint64 user_time;
+
+       if (getrusage (RUSAGE_SELF, &resource_usage) == -1) {
+               g_error ("getrusage() failed, errno is %d (%s)\n", errno, strerror (errno));
+               return -1;
+       }
+
+       current_time = mono_100ns_ticks ();
+       kernel_time = resource_usage.ru_stime.tv_sec * 1000 * 1000 * 10 + resource_usage.ru_stime.tv_usec * 10;
+       user_time = resource_usage.ru_utime.tv_sec * 1000 * 1000 * 10 + resource_usage.ru_utime.tv_usec * 10;
+
+       cpu_busy_time = (user_time - (prev ? prev->user_time : 0)) + (kernel_time - (prev ? prev->kernel_time : 0));
+       cpu_total_time = (current_time - (prev ? prev->current_time : 0)) * mono_cpu_count ();
+
+       if (prev) {
+               prev->kernel_time = kernel_time;
+               prev->user_time = user_time;
+               prev->current_time = current_time;
+       }
+#else
+       guint64 idle_time;
+       guint64 kernel_time;
+       guint64 user_time;
+
+       if (!GetSystemTimes ((FILETIME*) &idle_time, (FILETIME*) &kernel_time, (FILETIME*) &user_time)) {
+               g_error ("GetSystemTimes() failed, error code is %d\n", GetLastError ());
+               return -1;
+       }
+
+       cpu_total_time = (gint64)((user_time - (prev ? prev->user_time : 0)) + (kernel_time - (prev ? prev->kernel_time : 0)));
+       cpu_busy_time = (gint64)(cpu_total_time - (idle_time - (prev ? prev->idle_time : 0)));
+
+       if (prev) {
+               prev->idle_time = idle_time;
+               prev->kernel_time = kernel_time;
+               prev->user_time = user_time;
+       }
+#endif
+
+       if (cpu_total_time > 0 && cpu_busy_time > 0)
+               cpu_usage = (gint32)(cpu_busy_time * 100 / cpu_total_time);
+
+       g_assert (cpu_usage >= 0);
+       g_assert (cpu_usage <= 100);
+
+       return cpu_usage;
+}