Merge pull request #1624 from esdrubal/getprocesstimes
authorMarcos Henrich <marcoshenrich@gmail.com>
Mon, 6 Apr 2015 18:46:31 +0000 (19:46 +0100)
committerMarcos Henrich <marcoshenrich@gmail.com>
Mon, 6 Apr 2015 18:46:31 +0000 (19:46 +0100)
[runtime] GetProcessTimes now works with all processes.

mcs/class/System/Test/System.Diagnostics/ProcessTest.cs
mono/io-layer/processes.c
mono/utils/mono-proclib.c
mono/utils/mono-proclib.h
mono/utils/mono-time.c
mono/utils/mono-time.h

index 436e0e1252c835d9aad8d9bb347110344f50261c..de12a43d3cfc5bc82742870ecb5fe81e345725ee 100644 (file)
@@ -52,6 +52,15 @@ namespace MonoTests.System.Diagnostics
                        }
                }
 
+               [Test] // Covers #26363
+               public void GetProcesses_StartTime ()
+               {
+                       foreach (var p in Process.GetProcesses ()) {
+                               if (!p.HasExited && p.StartTime.Year < 1800)
+                                       Assert.Fail ("Process should not be started since the 18th century.");
+                       }
+               }
+
                [Test]
                public void PriorityClass_NotStarted ()
                {
index 913a08570a4706be089a033700e4e79c98011e03..ce7aee14c884732d669200fc8bcbc3a2599d718b 100644 (file)
@@ -90,6 +90,7 @@
 #include <mono/utils/mono-membar.h>
 #include <mono/utils/mono-mutex.h>
 #include <mono/utils/mono-signal-handler.h>
+#include <mono/utils/mono-proclib.h>
 
 /* The process' environment strings */
 #if defined(__APPLE__) && !defined (__arm__) && !defined (__aarch64__)
@@ -1309,11 +1310,19 @@ GetProcessTimes (gpointer process, WapiFileTime *create_time,
                /* Not sure if w32 allows NULLs here or not */
                return FALSE;
        
-       if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process))
-               /* This is a pseudo handle, so just fail for now
-                */
-               return FALSE;
-       
+       if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) {
+               gpointer pid = GINT_TO_POINTER (WAPI_HANDLE_TO_PID(process));
+               gint64 start_ticks, user_ticks, kernel_ticks;
+
+               mono_process_get_times (pid, &start_ticks, &user_ticks, &kernel_ticks);
+
+               _wapi_guint64_to_filetime (start_ticks, create_time);
+               _wapi_guint64_to_filetime (user_ticks, kernel_time);
+               _wapi_guint64_to_filetime (kernel_ticks, user_time);
+
+               return TRUE;
+       }
+
        process_handle = lookup_process_handle (process);
        if (!process_handle) {
                DEBUG ("%s: Can't find process %p", __func__, process);
index 38dea0d5111190982f9e94f21d38772a33436e3c..26d78cccfa59e4b5182e580c1c37056f9bc7f214 100644 (file)
@@ -207,57 +207,67 @@ get_pid_status_item_buf (int pid, const char *item, char *rbuf, int blen, MonoPr
        return NULL;
 }
 
-/**
- * mono_process_get_name:
- * @pid: pid of the process
- * @buf: byte buffer where to store the name of the prcoess
- * @len: size of the buffer @buf
- *
- * Return the name of the process identified by @pid, storing it
- * inside @buf for a maximum of len bytes (including the terminating 0).
- */
-char*
-mono_process_get_name (gpointer pid, char *buf, int len)
-{
 #if USE_SYSCTL
-       int res;
+
 #ifdef KERN_PROC2
-       int mib [6];
-       size_t data_len = sizeof (struct kinfo_proc2);
-       struct kinfo_proc2 processi;
+#define KINFO_PROC struct kinfo_proc2
 #else
-       int mib [4];
-       size_t data_len = sizeof (struct kinfo_proc);
-       struct kinfo_proc processi;
-#endif /* KERN_PROC2 */
+#define KINFO_PROC struct kinfo_proc
+#endif
 
-       memset (buf, 0, len);
+static gboolean
+sysctl_kinfo_proc (gpointer pid, KINFO_PROC* processi)
+{
+       int res;
+       size_t data_len = sizeof (KINFO_PROC);
 
 #ifdef KERN_PROC2
+       int mib [6];
        mib [0] = CTL_KERN;
        mib [1] = KERN_PROC2;
        mib [2] = KERN_PROC_PID;
        mib [3] = GPOINTER_TO_UINT (pid);
-       mib [4] = sizeof(struct kinfo_proc2);
+       mib [4] = sizeof(KINFO_PROC);
        mib [5] = 400; /* XXX */
 
-       res = sysctl (mib, 6, &processi, &data_len, NULL, 0);
-
-       if (res < 0 || data_len != sizeof (struct kinfo_proc2)) {
-               return buf;
-       }
+       res = sysctl (mib, 6, processi, &data_len, NULL, 0);
 #else
+       int mib [4];
        mib [0] = CTL_KERN;
        mib [1] = KERN_PROC;
        mib [2] = KERN_PROC_PID;
        mib [3] = GPOINTER_TO_UINT (pid);
-       
-       res = sysctl (mib, 4, &processi, &data_len, NULL, 0);
-       if (res < 0 || data_len != sizeof (struct kinfo_proc)) {
-               return buf;
-       }
+
+       res = sysctl (mib, 4, processi, &data_len, NULL, 0);
 #endif /* KERN_PROC2 */
-       strncpy (buf, processi.kinfo_name_member, len - 1);
+
+       if (res < 0 || data_len != sizeof (KINFO_PROC))
+               return FALSE;
+
+       return TRUE;
+}
+#endif /* USE_SYSCTL */
+
+/**
+ * mono_process_get_name:
+ * @pid: pid of the process
+ * @buf: byte buffer where to store the name of the prcoess
+ * @len: size of the buffer @buf
+ *
+ * Return the name of the process identified by @pid, storing it
+ * inside @buf for a maximum of len bytes (including the terminating 0).
+ */
+char*
+mono_process_get_name (gpointer pid, char *buf, int len)
+{
+#if USE_SYSCTL
+       KINFO_PROC processi;
+
+       memset (buf, 0, len);
+
+       if (sysctl_kinfo_proc (pid, &processi))
+               strncpy (buf, processi.kinfo_name_member, len - 1);
+
        return buf;
 #else
        char fname [128];
@@ -282,11 +292,42 @@ mono_process_get_name (gpointer pid, char *buf, int len)
 #endif
 }
 
+void
+mono_process_get_times (gpointer pid, gint64 *start_time, gint64 *user_time, gint64 *kernel_time)
+{
+       if (user_time)
+               *user_time = mono_process_get_data (pid, MONO_PROCESS_USER_TIME);
+
+       if (kernel_time)
+               *kernel_time = mono_process_get_data (pid, MONO_PROCESS_SYSTEM_TIME);
+
+       if (start_time) {
+               *start_time = 0;
+
+#if USE_SYSCTL
+               {
+                       KINFO_PROC processi;
+
+                       if (sysctl_kinfo_proc (pid, &processi))
+                               *start_time = mono_100ns_datetime_from_timeval (processi.kp_proc.p_starttime);
+               }
+#endif
+
+               if (*start_time == 0) {
+                       static guint64 boot_time = 0;
+                       if (!boot_time)
+                               boot_time = mono_100ns_datetime () - ((guint64)mono_msec_ticks ()) * 10000;
+
+                       *start_time = boot_time + mono_process_get_data (pid, MONO_PROCESS_ELAPSED);
+               }
+       }
+}
+
 /*
  * /proc/pid/stat format:
  * pid (cmdname) S 
  *     [0] ppid pgid sid tty_nr tty_pgrp flags min_flt cmin_flt maj_flt cmaj_flt
- *     [10] utime stime cutime cstime prio nice threads 0 start_time vsize rss
+ *     [10] utime stime cutime cstime prio nice threads 0 start_time vsize
  *     [20] rss rsslim start_code end_code start_stack esp eip pending blocked sigign
  *     [30] sigcatch wchan 0 0 exit_signal cpu rt_prio policy
  */
@@ -521,7 +562,7 @@ mono_process_get_data_with_error (gpointer pid, MonoProcessData data, MonoProces
        case MONO_PROCESS_FAULTS:
                return get_process_stat_item (rpid, 6, TRUE, error);
        case MONO_PROCESS_ELAPSED:
-               return get_process_stat_item (rpid, 18, FALSE, error) / get_user_hz ();
+               return get_process_stat_time (rpid, 18, FALSE, error);
        case MONO_PROCESS_PPID:
                return get_process_stat_time (rpid, 0, FALSE, error);
        case MONO_PROCESS_PAGED_BYTES:
index 48144a00613e3348b59be04b61b36b35cf31a4b5..67db3f3f31715e57ab0ca97e4dc5364a2d202e3a 100644 (file)
@@ -58,6 +58,8 @@ struct _MonoCpuUsageState {
 
 gpointer* mono_process_list     (int *size);
 
+void      mono_process_get_times (gpointer pid, gint64 *start_time, gint64 *user_time, gint64 *kernel_time);
+
 char*     mono_process_get_name (gpointer pid, char *buf, int len);
 
 gint64    mono_process_get_data (gpointer pid, MonoProcessData data);
index cd347546c207d8b6e72590fcec8060960cd522fd..8fe8f59cfdf4178e70602eb6e81ec14913e6bab4 100644 (file)
@@ -168,9 +168,15 @@ mono_100ns_datetime (void)
 {
        struct timeval tv;
        if (gettimeofday (&tv, NULL) == 0)
-               return (((gint64)tv.tv_sec + EPOCH_ADJUST) * 1000000 + tv.tv_usec) * 10;
+               return mono_100ns_datetime_from_timeval (tv);
        return 0;
 }
 
+gint64
+mono_100ns_datetime_from_timeval (struct timeval tv)
+{
+       return (((gint64)tv.tv_sec + EPOCH_ADJUST) * 1000000 + tv.tv_usec) * 10;
+}
+
 #endif
 
index 6961306c2906f07ddc7c41a26981d27e88994f89..e4b83e3e7b0430e3fa2bf6a75a6ad2793ab2a76a 100644 (file)
@@ -10,9 +10,13 @@ guint32 mono_msec_ticks      (void);
 /* Returns the number of 100ns ticks from unspecified time: this should be monotonic */
 gint64  mono_100ns_ticks     (void);
 
-/* Returns the number of 100ns ticks since 1/1/1, UTC timezone */
+/* Returns the number of 100ns ticks since 1/1/1601, UTC timezone */
 gint64  mono_100ns_datetime  (void);
 
+#ifndef HOST_WIN32
+gint64 mono_100ns_datetime_from_timeval (struct timeval tv);
+#endif
+
 /* Stopwatch class for internal runtime use */
 typedef struct {
        gint64 start, stop;