diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.FreeBSD.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.FreeBSD.cs
index 10171374d39c78..851db8f923bcd9 100644
--- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.FreeBSD.cs
+++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.FreeBSD.cs
@@ -22,15 +22,7 @@ internal DateTime StartTimeCore
}
}
- ///
- /// Gets the amount of time the associated process has spent utilizing the CPU.
- /// It is the sum of the and
- /// .
- ///
- [UnsupportedOSPlatform("ios")]
- [UnsupportedOSPlatform("tvos")]
- [SupportedOSPlatform("maccatalyst")]
- public TimeSpan TotalProcessorTime
+ public partial TimeSpan TotalProcessorTime
{
get
{
@@ -45,14 +37,7 @@ public TimeSpan TotalProcessorTime
}
}
- ///
- /// Gets the amount of time the associated process has spent running code
- /// inside the application portion of the process (not the operating system core).
- ///
- [UnsupportedOSPlatform("ios")]
- [UnsupportedOSPlatform("tvos")]
- [SupportedOSPlatform("maccatalyst")]
- public TimeSpan UserProcessorTime
+ public partial TimeSpan UserProcessorTime
{
get
{
@@ -68,11 +53,7 @@ public TimeSpan UserProcessorTime
}
}
- /// Gets the amount of time the process has spent running code inside the operating system core.
- [UnsupportedOSPlatform("ios")]
- [UnsupportedOSPlatform("tvos")]
- [SupportedOSPlatform("maccatalyst")]
- public TimeSpan PrivilegedProcessorTime
+ public partial TimeSpan PrivilegedProcessorTime
{
get
{
diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Linux.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Linux.cs
index 4b22d5bbd8e088..ce1bd2180efe2e 100644
--- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Linux.cs
+++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Linux.cs
@@ -13,11 +13,7 @@ namespace System.Diagnostics
{
public partial class Process : IDisposable
{
- /// Gets the amount of time the process has spent running code inside the operating system core.
- [UnsupportedOSPlatform("ios")]
- [UnsupportedOSPlatform("tvos")]
- [SupportedOSPlatform("maccatalyst")]
- public TimeSpan PrivilegedProcessorTime
+ public partial TimeSpan PrivilegedProcessorTime
{
get => IsCurrentProcess ? Environment.CpuUsage.PrivilegedTime : TicksToTimeSpan(GetStat().stime);
}
@@ -83,15 +79,7 @@ private static DateTime BootTime
return null;
}
- ///
- /// Gets the amount of time the associated process has spent utilizing the CPU.
- /// It is the sum of the and
- /// .
- ///
- [UnsupportedOSPlatform("ios")]
- [UnsupportedOSPlatform("tvos")]
- [SupportedOSPlatform("maccatalyst")]
- public TimeSpan TotalProcessorTime
+ public partial TimeSpan TotalProcessorTime
{
get
{
@@ -105,14 +93,7 @@ public TimeSpan TotalProcessorTime
}
}
- ///
- /// Gets the amount of time the associated process has spent running code
- /// inside the application portion of the process (not the operating system core).
- ///
- [UnsupportedOSPlatform("ios")]
- [UnsupportedOSPlatform("tvos")]
- [SupportedOSPlatform("maccatalyst")]
- public TimeSpan UserProcessorTime
+ public partial TimeSpan UserProcessorTime
{
get => IsCurrentProcess ? Environment.CpuUsage.UserTime : TicksToTimeSpan(GetStat().utime);
}
diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.OSX.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.OSX.cs
index f3f236b3f93e5b..629335c06e4705 100644
--- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.OSX.cs
+++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.OSX.cs
@@ -14,11 +14,7 @@ public partial class Process
private const int MicrosecondsToSecondsFactor = 1_000_000;
- /// Gets the amount of time the process has spent running code inside the operating system core.
- [UnsupportedOSPlatform("ios")]
- [UnsupportedOSPlatform("tvos")]
- [SupportedOSPlatform("maccatalyst")]
- public TimeSpan PrivilegedProcessorTime
+ public partial TimeSpan PrivilegedProcessorTime
{
get
{
@@ -57,15 +53,7 @@ internal static string GetPathToOpenFile()
return "/usr/bin/open";
}
- ///
- /// Gets the amount of time the associated process has spent utilizing the CPU.
- /// It is the sum of the and
- /// .
- ///
- [UnsupportedOSPlatform("ios")]
- [UnsupportedOSPlatform("tvos")]
- [SupportedOSPlatform("maccatalyst")]
- public TimeSpan TotalProcessorTime
+ public partial TimeSpan TotalProcessorTime
{
get
{
@@ -80,14 +68,7 @@ public TimeSpan TotalProcessorTime
}
}
- ///
- /// Gets the amount of time the associated process has spent running code
- /// inside the application portion of the process (not the operating system core).
- ///
- [UnsupportedOSPlatform("ios")]
- [UnsupportedOSPlatform("tvos")]
- [SupportedOSPlatform("maccatalyst")]
- public TimeSpan UserProcessorTime
+ public partial TimeSpan UserProcessorTime
{
get
{
diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.OpenBSD.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.OpenBSD.cs
index f3ccc9cb35b613..40c2953d90b101 100644
--- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.OpenBSD.cs
+++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.OpenBSD.cs
@@ -22,15 +22,7 @@ internal DateTime StartTimeCore
}
}
- ///
- /// Gets the amount of time the associated process has spent utilizing the CPU.
- /// It is the sum of the and
- /// .
- ///
- [UnsupportedOSPlatform("ios")]
- [UnsupportedOSPlatform("tvos")]
- [SupportedOSPlatform("maccatalyst")]
- public TimeSpan TotalProcessorTime
+ public partial TimeSpan TotalProcessorTime
{
get
{
@@ -45,14 +37,7 @@ public TimeSpan TotalProcessorTime
}
}
- ///
- /// Gets the amount of time the associated process has spent running code
- /// inside the application portion of the process (not the operating system core).
- ///
- [UnsupportedOSPlatform("ios")]
- [UnsupportedOSPlatform("tvos")]
- [SupportedOSPlatform("maccatalyst")]
- public TimeSpan UserProcessorTime
+ public partial TimeSpan UserProcessorTime
{
get
{
@@ -68,11 +53,7 @@ public TimeSpan UserProcessorTime
}
}
- /// Gets the amount of time the process has spent running code inside the operating system core.
- [UnsupportedOSPlatform("ios")]
- [UnsupportedOSPlatform("tvos")]
- [SupportedOSPlatform("maccatalyst")]
- public TimeSpan PrivilegedProcessorTime
+ public partial TimeSpan PrivilegedProcessorTime
{
get
{
diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.SunOS.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.SunOS.cs
index fb515db23e5ccb..cf0ba747869f0c 100644
--- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.SunOS.cs
+++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.SunOS.cs
@@ -41,15 +41,7 @@ internal DateTime StartTimeCore
return ProcessUtils.FindProgramInPath("xdg-open");
}
- ///
- /// Gets the amount of time the associated process has spent utilizing the CPU.
- /// It is the sum of the and
- /// .
- ///
- [UnsupportedOSPlatform("ios")]
- [UnsupportedOSPlatform("tvos")]
- [SupportedOSPlatform("maccatalyst")]
- public TimeSpan TotalProcessorTime
+ public partial TimeSpan TotalProcessorTime
{
get
{
@@ -61,14 +53,7 @@ public TimeSpan TotalProcessorTime
}
}
- ///
- /// Gets the amount of time the associated process has spent running code
- /// inside the application portion of the process (not the operating system core).
- ///
- [UnsupportedOSPlatform("ios")]
- [UnsupportedOSPlatform("tvos")]
- [SupportedOSPlatform("maccatalyst")]
- public TimeSpan UserProcessorTime
+ public partial TimeSpan UserProcessorTime
{
get
{
@@ -79,14 +64,7 @@ public TimeSpan UserProcessorTime
}
}
- ///
- /// Gets the amount of time the process has spent running code inside the operating
- /// system core.
- ///
- [UnsupportedOSPlatform("ios")]
- [UnsupportedOSPlatform("tvos")]
- [SupportedOSPlatform("maccatalyst")]
- public TimeSpan PrivilegedProcessorTime
+ public partial TimeSpan PrivilegedProcessorTime
{
get
{
diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Windows.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Windows.cs
index 8686f53aeb076d..489459e5c00483 100644
--- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Windows.cs
+++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Windows.cs
@@ -192,11 +192,7 @@ private DateTime ExitTimeCore
get { return GetProcessTimes().ExitTime; }
}
- /// Gets the amount of time the process has spent running code inside the operating system core.
- [UnsupportedOSPlatform("ios")]
- [UnsupportedOSPlatform("tvos")]
- [SupportedOSPlatform("maccatalyst")]
- public TimeSpan PrivilegedProcessorTime
+ public partial TimeSpan PrivilegedProcessorTime
{
get => IsCurrentProcess ? Environment.CpuUsage.PrivilegedTime : GetProcessTimes().PrivilegedProcessorTime;
}
@@ -207,27 +203,12 @@ internal DateTime StartTimeCore
get { return GetProcessTimes().StartTime; }
}
- ///
- /// Gets the amount of time the associated process has spent utilizing the CPU.
- /// It is the sum of the and
- /// .
- ///
- [UnsupportedOSPlatform("ios")]
- [UnsupportedOSPlatform("tvos")]
- [SupportedOSPlatform("maccatalyst")]
- public TimeSpan TotalProcessorTime
+ public partial TimeSpan TotalProcessorTime
{
get => IsCurrentProcess ? Environment.CpuUsage.TotalTime : GetProcessTimes().TotalProcessorTime;
}
- ///
- /// Gets the amount of time the associated process has spent running code
- /// inside the application portion of the process (not the operating system core).
- ///
- [UnsupportedOSPlatform("ios")]
- [UnsupportedOSPlatform("tvos")]
- [SupportedOSPlatform("maccatalyst")]
- public TimeSpan UserProcessorTime
+ public partial TimeSpan UserProcessorTime
{
get => IsCurrentProcess ? Environment.CpuUsage.UserTime : GetProcessTimes().UserProcessorTime;
}
diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs
index 7450c980e98069..c088f4226902d8 100644
--- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs
+++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs
@@ -188,6 +188,15 @@ public bool HasExited
}
/// Gets the time the associated process was started.
+ ///
+ /// On Windows, if a handle to the process is available, this property can be read after the process exits.
+ /// On Unix, this property caches its value on first access. A cached value can be read after the process exits,
+ /// but accessing an uncached value after the process exits may throw when the value is unavailable.
+ ///
+ ///
+ /// No process is associated with this object; on Windows, there is no process handle available; or on Unix,
+ /// the value was not cached and is unavailable after the process exited.
+ ///
[UnsupportedOSPlatform("ios")]
[UnsupportedOSPlatform("tvos")]
[SupportedOSPlatform("maccatalyst")]
@@ -203,11 +212,11 @@ public DateTime StartTime
}
}
- ///
- ///
- /// Gets the time that the associated process exited.
- ///
- ///
+ /// Gets the time that the associated process exited.
+ ///
+ /// No process is associated with this object, the process has not exited,
+ /// or there is no process handle available.
+ ///
public DateTime ExitTime
{
get
@@ -222,6 +231,57 @@ public DateTime ExitTime
}
}
+ /// Gets the amount of time the process has spent running code inside the operating system core.
+ ///
+ /// On Windows, if a handle to the process is available, the value can be retrieved after the process exits.
+ /// On Unix, the value is unavailable after the process exits.
+ ///
+ ///
+ /// No process is associated with this object. On Windows, there is no process handle available.
+ /// On Unix, the process has exited.
+ ///
+ /// The operating system could not retrieve process timing information.
+ [UnsupportedOSPlatform("ios")]
+ [UnsupportedOSPlatform("tvos")]
+ [SupportedOSPlatform("maccatalyst")]
+ public partial TimeSpan PrivilegedProcessorTime { get; }
+
+ ///
+ /// Gets the amount of time the associated process has spent utilizing the CPU.
+ /// It is the sum of the and .
+ ///
+ ///
+ /// On Windows, if a handle to the process is available, the value can be retrieved after the process exits.
+ /// On Unix, the value is unavailable after the process exits.
+ ///
+ ///
+ /// No process is associated with this object. On Windows, there is no process handle available.
+ /// On Unix, the process has exited.
+ ///
+ /// The operating system could not retrieve process timing information.
+ [UnsupportedOSPlatform("ios")]
+ [UnsupportedOSPlatform("tvos")]
+ [SupportedOSPlatform("maccatalyst")]
+ public partial TimeSpan TotalProcessorTime { get; }
+
+ ///
+ /// Gets the amount of time the associated process has spent running code
+ /// inside the application portion of the process (not the operating system core).
+ ///
+ ///
+ /// On Windows, if a handle to the process is available, the value can be retrieved after the process exits.
+ /// On Unix, the value is unavailable after the process exits.
+ ///
+ ///
+ /// No process is associated with this object. On Windows, there is no process handle available.
+ /// On Unix, the process has exited.
+ ///
+ /// The operating system could not retrieve process timing information.
+ [UnsupportedOSPlatform("ios")]
+ [UnsupportedOSPlatform("tvos")]
+ [SupportedOSPlatform("maccatalyst")]
+ public partial TimeSpan UserProcessorTime { get; }
+
///
///
/// Gets
diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.iOS.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.iOS.cs
index 2a5d3ddb785291..e2bd120e8e1cc8 100644
--- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.iOS.cs
+++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.iOS.cs
@@ -18,11 +18,7 @@ public void Kill(bool entireProcessTree)
throw new PlatformNotSupportedException();
}
- /// Gets the amount of time the process has spent running code inside the operating system core.
- [UnsupportedOSPlatform("ios")]
- [UnsupportedOSPlatform("tvos")]
- [SupportedOSPlatform("maccatalyst")]
- public TimeSpan PrivilegedProcessorTime
+ public partial TimeSpan PrivilegedProcessorTime
{
get { throw new PlatformNotSupportedException(); }
}
@@ -35,27 +31,12 @@ internal static DateTime StartTimeCore
get { throw new PlatformNotSupportedException(); }
}
- ///
- /// Gets the amount of time the associated process has spent utilizing the CPU.
- /// It is the sum of the and
- /// .
- ///
- [UnsupportedOSPlatform("ios")]
- [UnsupportedOSPlatform("tvos")]
- [SupportedOSPlatform("maccatalyst")]
- public TimeSpan TotalProcessorTime
+ public partial TimeSpan TotalProcessorTime
{
get { throw new PlatformNotSupportedException(); }
}
- ///
- /// Gets the amount of time the associated process has spent running code
- /// inside the application portion of the process (not the operating system core).
- ///
- [UnsupportedOSPlatform("ios")]
- [UnsupportedOSPlatform("tvos")]
- [SupportedOSPlatform("maccatalyst")]
- public TimeSpan UserProcessorTime
+ public partial TimeSpan UserProcessorTime
{
get { throw new PlatformNotSupportedException(); }
}
diff --git a/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs b/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs
index a8f25b6f282d98..d903ced342bc91 100644
--- a/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs
+++ b/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs
@@ -751,6 +751,49 @@ public void TestExitTime()
Assert.InRange(p.ExitTime.ToUniversalTime(), timeBeforeProcessStart, DateTime.MaxValue);
}
+ [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
+ public void TimingProperties_AfterProcessExit()
+ {
+ using Process process = CreateProcess(static () => RemoteExecutor.SuccessExitCode);
+ process.Start();
+ Assert.True(process.WaitForExit(WaitInMS));
+
+ Assert.Equal(RemoteExecutor.SuccessExitCode, process.ExitCode);
+ Assert.NotEqual(default, process.ExitTime);
+
+ if (OperatingSystem.IsWindows())
+ {
+ // Windows process handles retain timing information after the process exits.
+ Assert.NotEqual(default, process.StartTime);
+ Assert.InRange(process.PrivilegedProcessorTime, TimeSpan.Zero, TimeSpan.MaxValue);
+ Assert.InRange(process.TotalProcessorTime, TimeSpan.Zero, TimeSpan.MaxValue);
+ Assert.InRange(process.UserProcessorTime, TimeSpan.Zero, TimeSpan.MaxValue);
+ }
+ else
+ {
+ // Unix reaps child processes after exit. Processor times are unavailable, and StartTime was not
+ // accessed before exit and therefore was not cached.
+ Assert.Throws(() => process.StartTime);
+ Assert.Throws(() => process.PrivilegedProcessorTime);
+ Assert.Throws(() => process.TotalProcessorTime);
+ Assert.Throws(() => process.UserProcessorTime);
+ }
+ }
+
+ [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
+ public void StartTime_AfterProcessExit_WhenCachedBeforeExit_IsAvailable()
+ {
+ using Process process = CreateProcessLong();
+ process.Start();
+ DateTime startTime = process.StartTime;
+
+ process.Kill();
+ Assert.True(process.WaitForExit(WaitInMS));
+
+ Assert.NotEqual(default, startTime);
+ Assert.Equal(startTime, process.StartTime);
+ }
+
[Fact]
[SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "libproc is not supported on iOS/tvOS")]
public void StartTime_GetNotStarted_ThrowsInvalidOperationException()