2using System.Diagnostics;
4using System.Threading.Tasks;
6using Microsoft.Extensions.Logging;
7using Microsoft.Win32.SafeHandles;
17 public int Id {
get; }
30 logger.LogWarning(ex,
"Failed to get PID {pid}'s memory usage!",
Id);
49 return handle.PrivateMemorySize64;
53 logger.LogWarning(ex,
"Failed to get PID {pid}'s memory usage!",
Id);
72 readonly global::System.Diagnostics.Process
handle;
126 global::System.Diagnostics.Process
handle,
127 CancellationTokenSource? readerCts,
132 this.handle =
handle ??
throw new ArgumentNullException(nameof(
handle));
144 this.logger =
logger ??
throw new ArgumentNullException(nameof(
logger));
156 Startup = Task.Factory.StartNew(
161 handle.WaitForInputIdle();
165 logger.LogTrace(ex,
"WaitForInputIdle() failed, this is normal.");
168 CancellationToken.None,
170 TaskScheduler.Current);
178 logger.LogTrace(ex,
"Failed to measure initial process time.");
184 logger.LogTrace(
"Created process ID: {pid}",
Id);
190 if (Interlocked.Exchange(ref
disposed, 1) != 0)
193 logger.LogTrace(
"Disposing PID {pid}...",
Id);
209 throw new InvalidOperationException(
"Output/Error stream reading was not enabled!");
211 return readTask.WaitAsync(cancellationToken);
220 logger.LogTrace(
"PID {pid} already exited",
Id);
226 logger.LogTrace(
"Terminating PID {pid}...",
Id);
228 if (!
handle.WaitForExit(5000))
229 logger.LogWarning(
"WaitForExit() on PID {pid} timed out!",
Id);
233 logger.LogDebug(e,
"PID {pid} termination exception!",
Id);
241 var targetPriority = higher ? ProcessPriorityClass.AboveNormal : ProcessPriorityClass.BelowNormal;
244 handle.PriorityClass = targetPriority;
245 logger.LogTrace(
"Set PID {pid} to {targetPriority} priority",
Id, targetPriority);
249 logger.LogWarning(ex,
"Unable to set priority for PID {id} to {targetPriority}!",
Id, targetPriority);
260 logger.LogTrace(
"Suspended PID {pid}",
Id);
264 logger.LogError(e,
"Failed to suspend PID {pid}!",
Id);
276 logger.LogTrace(
"Resumed PID {pid}",
Id);
280 logger.LogError(e,
"Failed to resume PID {pid}!",
Id);
290 logger.LogTrace(
"PID {pid} Username: {username}",
Id, result);
295 public ValueTask
CreateDump(
string outputFile,
bool minidump, CancellationToken cancellationToken)
297 ArgumentNullException.ThrowIfNull(outputFile);
300 logger.LogTrace(
"Dumping PID {pid} to {dumpFilePath}...",
Id, outputFile);
311 var now = DateTimeOffset.UtcNow;
312 var newTime =
handle.TotalProcessorTime;
320 if (timeDelta != TimeSpan.Zero)
325 logger.LogWarning(ex,
"Error measuring processor time delta!");
344 catch (OperationCanceledException ex)
346 logger.LogTrace(ex,
"Process lifetime task cancelled!");
347 hasExited =
handle.HasExited;
353 var exitCode =
handle.ExitCode;
354 logger.LogTrace(
"PID {pid} exited with code {exitCode}",
Id, exitCode);
IIOManager that resolves paths to Environment.CurrentDirectory.
const TaskCreationOptions BlockingTaskCreationOptions
The TaskCreationOptions used to spawn Tasks for potentially long running, blocking operations.
readonly object processTimeMeasureLock
lock object for measuring processor time usage.
Process(IProcessFeatures processFeatures, global::System.Diagnostics.Process handle, CancellationTokenSource? readerCts, Task< string?>? readTask, ILogger< Process > logger, bool preExisting)
Initializes a new instance of the Process class.
DateTimeOffset lastProcessorMeasureTime
The last time MeasureProcessorTimeDelta was called.
void CheckDisposed()
Throws an ObjectDisposedException if a method of the Process was called after DisposeAsync.
async ValueTask DisposeAsync()
DateTimeOffset? LaunchTime
When the process was started.
readonly global::System.Diagnostics.Process handle
The global::System.Diagnostics.Process object.
Task< int?> Lifetime
The Task<TResult> resulting in the exit code of the process or null if the process was detached.
Task< string?> GetCombinedOutput(CancellationToken cancellationToken)
Get the stderr and stdout output of the IProcess.A Task<TResult> resulting in the stderr and stdout o...
void AdjustPriority(bool higher)
Set's the owned global::System.Diagnostics.Process.PriorityClass to a non-normal value.
ValueTask CreateDump(string outputFile, bool minidump, CancellationToken cancellationToken)
Create a dump file of the process.A ValueTask representing the running operation.
double MeasureProcessorTimeDelta()
Gets the estimated CPU usage fraction of the process based on the last time this was called....
double lastProcessorUsageEstimation
The last valid return value of MeasureProcessorTimeDelta.
TimeSpan lastProcessorUsageTime
The last value of global::System.Diagnostics.Process.TotalProcessorTime.
void Terminate()
Asycnhronously terminates the process.To ensure the IProcess has ended, use the IProcessBase....
readonly ILogger< Process > logger
The ILogger for the Process.
void SuspendProcess()
Suspends the process.
readonly CancellationTokenSource cancellationTokenSource
The CancellationTokenSource used to shutdown the readTask and Lifetime.
string GetExecutingUsername()
Get the name of the account executing the IProcess.The name of the account executing the IProcess.
void ResumeProcess()
Resumes the process.
readonly SafeProcessHandle safeHandle
The global::System.Diagnostics.Process.SafeHandle.
readonly IProcessFeatures processFeatures
The IProcessFeatures for the Process.
Task Startup
The Task representing the time until the IProcess becomes "idle".
long? MemoryUsage
Gets the process' memory usage in bytes.
readonly? Task< string?> readTask
The Task<TResult> resulting in the process' standard output/error text.
int disposed
If the Process was disposed.
async Task< int?> WrapLifetimeTask()
Attaches a log message to the process' exit event.
Abstraction for suspending and resuming processes.
string GetExecutingUsername(global::System.Diagnostics.Process process)
Get the name of the user executing a given process .
ValueTask CreateDump(global::System.Diagnostics.Process process, string outputFile, bool minidump, CancellationToken cancellationToken)
Create a dump file for a given process .
void SuspendProcess(global::System.Diagnostics.Process process)
Suspend a given process .
void ResumeProcess(global::System.Diagnostics.Process process)
Resume a given suspended global::System.Diagnostics.Process.
Abstraction over a global::System.Diagnostics.Process.