/// Gets executable name for process given it's PID
/// </summary>
/// <param name="pid">The PID of the process</param>
- public static unsafe string GetProcPath(int pid)
+ public static unsafe string? GetProcPath(int pid)
{
Span<int> sysctlName = stackalloc int[4];
byte* pBuffer = null;
// Get the process information for the specified pid
info = new ProcessInfo();
- info.ProcessName = Marshal.PtrToStringAnsi((IntPtr)kinfo->ki_comm);
+ info.ProcessName = Marshal.PtrToStringAnsi((IntPtr)kinfo->ki_comm)!;
info.BasePriority = kinfo->ki_nice;
info.VirtualBytes = (long)kinfo->ki_size;
info.WorkingSet = kinfo->ki_rssize;
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+#nullable enable
using System;
using System.Buffers.Text;
using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
using System.IO;
internal static partial class Interop
private const string ProcCGroupFilePath = "/proc/self/cgroup";
/// <summary>Path to the found cgroup memory limit path, or null if it couldn't be found.</summary>
- internal static readonly string s_cgroupMemoryLimitPath = FindCGroupMemoryLimitPath();
+ internal static readonly string? s_cgroupMemoryLimitPath = FindCGroupMemoryLimitPath();
/// <summary>Tries to read the memory limit from the cgroup memory location.</summary>
/// <param name="limit">The read limit, or 0 if it couldn't be read.</param>
/// <returns>true if the limit was read successfully; otherwise, false.</returns>
public static bool TryGetMemoryLimit(out ulong limit)
{
- string path = s_cgroupMemoryLimitPath;
+ string? path = s_cgroupMemoryLimitPath;
if (path != null &&
TryReadMemoryValueFromFile(path, out limit))
/// <summary>Find the cgroup memory limit path.</summary>
/// <returns>The limit path if found; otherwise, null.</returns>
- private static string FindCGroupMemoryLimitPath()
+ private static string? FindCGroupMemoryLimitPath()
{
- string cgroupMemoryPath = FindCGroupPath("memory", out CGroupVersion version);
+ string? cgroupMemoryPath = FindCGroupPath("memory", out CGroupVersion version);
if (cgroupMemoryPath != null)
{
if (version == CGroupVersion.CGroup1)
/// <summary>Find the cgroup path for the specified subsystem.</summary>
/// <param name="subsystem">The subsystem, e.g. "memory".</param>
/// <returns>The cgroup path if found; otherwise, null.</returns>
- private static string FindCGroupPath(string subsystem, out CGroupVersion version)
+ private static string? FindCGroupPath(string subsystem, out CGroupVersion version)
{
- if (TryFindHierarchyMount(subsystem, out version, out string hierarchyRoot, out string hierarchyMount) &&
- TryFindCGroupPathForSubsystem(subsystem, out string cgroupPathRelativeToMount))
+ if (TryFindHierarchyMount(subsystem, out version, out string? hierarchyRoot, out string? hierarchyMount) &&
+ TryFindCGroupPathForSubsystem(subsystem, out string? cgroupPathRelativeToMount))
{
// For a host cgroup, we need to append the relative path.
// In a docker container, the root and relative path are the same and we don't need to append.
/// <param name="root">The path of the directory in the filesystem which forms the root of this mount; null if not found.</param>
/// <param name="path">The path of the mount point relative to the process's root directory; null if not found.</param>
/// <returns>true if the mount was found; otherwise, null.</returns>
- private static bool TryFindHierarchyMount(string subsystem, out CGroupVersion version, out string root, out string path)
+ private static bool TryFindHierarchyMount(string subsystem, out CGroupVersion version, [NotNullWhen(true)] out string? root, [NotNullWhen(true)] out string? path)
{
return TryFindHierarchyMount(ProcMountInfoFilePath, subsystem, out version, out root, out path);
}
- internal static bool TryFindHierarchyMount(string mountInfoFilePath, string subsystem, out CGroupVersion version, out string root, out string path)
+ internal static bool TryFindHierarchyMount(string mountInfoFilePath, string subsystem, out CGroupVersion version, [NotNullWhen(true)] out string? root, [NotNullWhen(true)] out string? path)
{
if (File.Exists(mountInfoFilePath))
{
{
using (var reader = new StreamReader(mountInfoFilePath))
{
- string line;
+ string? line;
while ((line = reader.ReadLine()) != null)
{
// Look for an entry that has cgroup as the "filesystem type"
/// <param name="subsystem">The subsystem, e.g. "memory".</param>
/// <param name="path">The found path, or null if it couldn't be found.</param>
/// <returns></returns>
- private static bool TryFindCGroupPathForSubsystem(string subsystem, out string path)
+ private static bool TryFindCGroupPathForSubsystem(string subsystem, [NotNullWhen(true)] out string? path)
{
return TryFindCGroupPathForSubsystem(ProcCGroupFilePath, subsystem, out path);
}
- internal static bool TryFindCGroupPathForSubsystem(string procCGroupFilePath, string subsystem, out string path)
+ internal static bool TryFindCGroupPathForSubsystem(string procCGroupFilePath, string subsystem, [NotNullWhen(true)] out string? path)
{
if (File.Exists(procCGroupFilePath))
{
{
using (var reader = new StreamReader(procCGroupFilePath))
{
- string line;
+ string? line;
while ((line = reader.ReadLine()) != null)
{
string[] lineParts = line.Split(':');
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Text;
internal static bool TryParseStatFile(string statFilePath, out ParsedStat result, ReusableTextReader reusableReader)
{
- if (!TryReadFile(statFilePath, reusableReader, out string statFileContents))
+ if (!TryReadFile(statFilePath, reusableReader, out string? statFileContents))
{
// Between the time that we get an ID and the time that we try to read the associated stat
// file(s), the process could be gone.
internal static bool TryParseStatusFile(string statusFilePath, out ParsedStatus result, ReusableTextReader reusableReader)
{
- if (!TryReadFile(statusFilePath, reusableReader, out string fileContents))
+ if (!TryReadFile(statusFilePath, reusableReader, out string? fileContents))
{
// Between the time that we get an ID and the time that we try to read the associated stat
// file(s), the process could be gone.
return true;
}
- private static bool TryReadFile(string filePath, ReusableTextReader reusableReader, out string fileContents)
+ private static bool TryReadFile(string filePath, ReusableTextReader reusableReader, [NotNullWhen(true)] out string? fileContents)
{
try
{
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+#nullable enable
+
using System;
using System.Collections.Generic;
using System.ComponentModel;
int result = 0;
int size = 20; // start assuming 20 threads is enough
- ulong[] threadIds = null;
+ ulong[]? threadIds = null;
var threads = new List<KeyValuePair<ulong, proc_threadinfo?>>();
// We have no way of knowing how many threads the process has (and therefore how big our buffer should be)
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+#nullable enable
+
using System;
using System.ComponentModel;
using System.Diagnostics;
internal static partial class Sys
{
internal static unsafe int ForkAndExecProcess(
- string filename, string[] argv, string[] envp, string cwd,
+ string filename, string[] argv, string[] envp, string? cwd,
bool redirectStdin, bool redirectStdout, bool redirectStderr,
- bool setUser, uint userId, uint groupId, uint[] groups,
+ bool setUser, uint userId, uint groupId, uint[]? groups,
out int lpChildPid, out int stdinFd, out int stdoutFd, out int stderrFd, bool shouldThrow = true)
{
byte** argvPtr = null, envpPtr = null;
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_ForkAndExecProcess", SetLastError = true)]
private static extern unsafe int ForkAndExecProcess(
- string filename, byte** argv, byte** envp, string cwd,
+ string filename, byte** argv, byte** envp, string? cwd,
int redirectStdin, int redirectStdout, int redirectStderr,
int setUser, uint userId, uint groupId, uint* groups, int groupsLength,
out int lpChildPid, out int stdinFd, out int stdoutFd, out int stderrFd);
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+#nullable enable
+
using System;
using System.Runtime.InteropServices;
{
internal static partial class Sys
{
- internal static unsafe uint[] GetGroupList(string userName, uint primaryGroupId)
+ internal static unsafe uint[]? GetGroupList(string userName, uint primaryGroupId)
{
const int InitialGroupsLength =
#if DEBUG
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+#nullable enable
+
using System;
using System.Runtime.InteropServices;
using System.Text;
string domain,
IntPtr password,
LogonFlags logonFlags,
- string appName,
+ string? appName,
[In] StringBuilder cmdLine,
int creationFlags,
IntPtr environmentBlock,
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+#nullable enable
+
using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;
{
[DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, SetLastError = true, BestFitMapping = false, EntryPoint = "CreateProcessW")]
internal static extern bool CreateProcess(
- string lpApplicationName,
+ string? lpApplicationName,
[In] StringBuilder lpCommandLine,
ref SECURITY_ATTRIBUTES procSecAttrs,
ref SECURITY_ATTRIBUTES threadSecAttrs,
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+#nullable enable
using Microsoft.Win32.SafeHandles;
using System.Runtime.InteropServices;
using System.Threading;
{
internal ProcessWaitHandle(SafeProcessHandle processHandle)
{
- SafeWaitHandle waitHandle = null;
+ SafeWaitHandle? waitHandle;
SafeProcessHandle currentProcHandle = Interop.Kernel32.GetCurrentProcess();
bool succeeded = Interop.Kernel32.DuplicateHandle(
currentProcHandle,
internal static partial class SerializationGuard
{
private delegate void ThrowIfDeserializationInProgressWithSwitchDel(string switchName, ref int cachedValue);
- private static readonly ThrowIfDeserializationInProgressWithSwitchDel s_throwIfDeserializationInProgressWithSwitch = CreateThrowIfDeserializationInProgressWithSwitchDelegate();
+ private static readonly ThrowIfDeserializationInProgressWithSwitchDel? s_throwIfDeserializationInProgressWithSwitch = CreateThrowIfDeserializationInProgressWithSwitchDelegate();
/// <summary>
/// Builds a wrapper delegate for SerializationInfo.ThrowIfDeserializationInProgress(string, ref int),
/// since it is not exposed via contracts.
/// </summary>
- private static ThrowIfDeserializationInProgressWithSwitchDel CreateThrowIfDeserializationInProgressWithSwitchDelegate()
+ private static ThrowIfDeserializationInProgressWithSwitchDel? CreateThrowIfDeserializationInProgressWithSwitchDelegate()
{
- ThrowIfDeserializationInProgressWithSwitchDel throwIfDeserializationInProgressDelegate = null;
- MethodInfo throwMethod = typeof(SerializationInfo).GetMethod("ThrowIfDeserializationInProgress",
+ ThrowIfDeserializationInProgressWithSwitchDel? throwIfDeserializationInProgressDelegate = null;
+ MethodInfo? throwMethod = typeof(SerializationInfo).GetMethod("ThrowIfDeserializationInProgress",
BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, null, new Type[] { typeof(string), typeof(int).MakeByRefType() }, Array.Empty<ParameterModifier>());
if (throwMethod != null)
using System.IO;
+#nullable enable
+
namespace System.Text
{
/// <summary>Provides a reusable reader for reading all of the text from streams.</summary>
/// <summary>Initializes a new reusable reader.</summary>
/// <param name="encoding">The Encoding to use. Defaults to UTF8.</param>
/// <param name="bufferSize">The size of the buffer to use when reading from the stream.</param>
- public ReusableTextReader(Encoding encoding = null, int bufferSize = 1024)
+ public ReusableTextReader(Encoding? encoding = null, int bufferSize = 1024)
{
if (encoding == null)
{
public sealed partial class SafeProcessHandle : Microsoft.Win32.SafeHandles.SafeHandleZeroOrMinusOneIsInvalid
{
public SafeProcessHandle(System.IntPtr existingHandle, bool ownsHandle) : base (default(bool)) { }
- public override bool IsInvalid { get { throw null; } }
protected override bool ReleaseHandle() { throw null; }
}
}
public partial class DataReceivedEventArgs : System.EventArgs
{
internal DataReceivedEventArgs() { }
- public string Data { get { throw null; } }
+ public string? Data { get { throw null; } }
}
public delegate void DataReceivedEventHandler(object sender, System.Diagnostics.DataReceivedEventArgs e);
[System.AttributeUsageAttribute(System.AttributeTargets.All)]
public MonitoringDescriptionAttribute(string description) { }
public override string Description { get { throw null; } }
}
- public partial class Process : System.ComponentModel.Component
+ public partial class Process : System.ComponentModel.Component, System.IDisposable
{
public Process() { }
public int BasePriority { get { throw null; } }
public bool HasExited { get { throw null; } }
public int Id { get { throw null; } }
public string MachineName { get { throw null; } }
- public System.Diagnostics.ProcessModule MainModule { get { throw null; } }
+ public System.Diagnostics.ProcessModule? MainModule { get { throw null; } }
public System.IntPtr MainWindowHandle { get { throw null; } }
public string MainWindowTitle { get { throw null; } }
public System.IntPtr MaxWorkingSet { get { throw null; } set { } }
public System.IO.StreamReader StandardOutput { get { throw null; } }
public System.Diagnostics.ProcessStartInfo StartInfo { get { throw null; } set { } }
public System.DateTime StartTime { get { throw null; } }
- public System.ComponentModel.ISynchronizeInvoke SynchronizingObject { get { throw null; } set { } }
+ public System.ComponentModel.ISynchronizeInvoke? SynchronizingObject { get { throw null; } set { } }
public System.Diagnostics.ProcessThreadCollection Threads { get { throw null; } }
public System.TimeSpan TotalProcessorTime { get { throw null; } }
public System.TimeSpan UserProcessorTime { get { throw null; } }
[System.ObsoleteAttribute("This property has been deprecated. Please use System.Diagnostics.Process.WorkingSet64 instead. https://go.microsoft.com/fwlink/?linkid=14202")]
public int WorkingSet { get { throw null; } }
public long WorkingSet64 { get { throw null; } }
- public event System.Diagnostics.DataReceivedEventHandler ErrorDataReceived { add { } remove { } }
+ public event System.Diagnostics.DataReceivedEventHandler? ErrorDataReceived { add { } remove { } }
public event System.EventHandler Exited { add { } remove { } }
- public event System.Diagnostics.DataReceivedEventHandler OutputDataReceived { add { } remove { } }
+ public event System.Diagnostics.DataReceivedEventHandler? OutputDataReceived { add { } remove { } }
public void BeginErrorReadLine() { }
public void BeginOutputReadLine() { }
public void CancelErrorRead() { }
public static System.Diagnostics.Process GetProcessById(int processId, string machineName) { throw null; }
public static System.Diagnostics.Process[] GetProcesses() { throw null; }
public static System.Diagnostics.Process[] GetProcesses(string machineName) { throw null; }
- public static System.Diagnostics.Process[] GetProcessesByName(string processName) { throw null; }
- public static System.Diagnostics.Process[] GetProcessesByName(string processName, string machineName) { throw null; }
+ public static System.Diagnostics.Process[] GetProcessesByName(string? processName) { throw null; }
+ public static System.Diagnostics.Process[] GetProcessesByName(string? processName, string machineName) { throw null; }
public void Kill() { }
public void Kill(bool entireProcessTree) { }
public static void LeaveDebugMode() { }
protected void OnExited() { }
public void Refresh() { }
public bool Start() { throw null; }
- public static System.Diagnostics.Process Start(System.Diagnostics.ProcessStartInfo startInfo) { throw null; }
+ public static System.Diagnostics.Process? Start(System.Diagnostics.ProcessStartInfo startInfo) { throw null; }
public static System.Diagnostics.Process Start(string fileName) { throw null; }
public static System.Diagnostics.Process Start(string fileName, string arguments) { throw null; }
[System.CLSCompliantAttribute(false)]
internal ProcessModule() { }
public System.IntPtr BaseAddress { get { throw null; } }
public System.IntPtr EntryPointAddress { get { throw null; } }
- public string FileName { get { throw null; } }
+ public string? FileName { get { throw null; } }
public System.Diagnostics.FileVersionInfo FileVersionInfo { get { throw null; } }
public int ModuleMemorySize { get { throw null; } }
- public string ModuleName { get { throw null; } }
+ public string? ModuleName { get { throw null; } }
public override string ToString() { throw null; }
}
public partial class ProcessModuleCollection : System.Collections.ReadOnlyCollectionBase
public string Arguments { get { throw null; } set { } }
public bool CreateNoWindow { get { throw null; } set { } }
public string Domain { get { throw null; } set { } }
- public System.Collections.Generic.IDictionary<string, string> Environment { get { throw null; } }
+ public System.Collections.Generic.IDictionary<string, string?> Environment { get { throw null; } }
public System.Collections.Specialized.StringDictionary EnvironmentVariables { get { throw null; } }
public bool ErrorDialog { get { throw null; } set { } }
public System.IntPtr ErrorDialogParentHandle { get { throw null; } set { } }
public string FileName { get { throw null; } set { } }
public bool LoadUserProfile { get { throw null; } set { } }
[System.CLSCompliantAttribute(false)]
- public System.Security.SecureString Password { get { throw null; } set { } }
- public string PasswordInClearText { get { throw null; } set { } }
+ public System.Security.SecureString? Password { get { throw null; } set { } }
+ public string? PasswordInClearText { get { throw null; } set { } }
public bool RedirectStandardError { get { throw null; } set { } }
public bool RedirectStandardInput { get { throw null; } set { } }
public bool RedirectStandardOutput { get { throw null; } set { } }
- public System.Text.Encoding StandardErrorEncoding { get { throw null; } set { } }
- public System.Text.Encoding StandardInputEncoding { get { throw null; } set { } }
- public System.Text.Encoding StandardOutputEncoding { get { throw null; } set { } }
+ public System.Text.Encoding? StandardErrorEncoding { get { throw null; } set { } }
+ public System.Text.Encoding? StandardInputEncoding { get { throw null; } set { } }
+ public System.Text.Encoding? StandardOutputEncoding { get { throw null; } set { } }
public string UserName { get { throw null; } set { } }
public bool UseShellExecute { get { throw null; } set { } }
[System.ComponentModel.DefaultValueAttribute("")]
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>$(NetCoreAppCurrent)</TargetFrameworks>
+ <Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Compile Include="System.Diagnostics.Process.cs" />
// Process.{Safe}Handle to initalize and use a WaitHandle to successfully use it on
// Unix as well to wait for the process to complete.
- private readonly SafeWaitHandle _handle;
+ private readonly SafeWaitHandle _handle = null!;
private readonly bool _releaseRef;
internal SafeProcessHandle(int processId, SafeWaitHandle handle) :
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<NoWarn>$(NoWarn);CS1573</NoWarn>
<TargetFrameworks>$(NetCoreAppCurrent)-FreeBSD;$(NetCoreAppCurrent)-Linux;$(NetCoreAppCurrent)-OSX;$(NetCoreAppCurrent)-Windows_NT</TargetFrameworks>
+ <Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetsFreeBSD)' == 'true' or '$(TargetsUnknownUnix)' == 'true' ">
<!-- Suppress unused field warnings when using PlatformNotSupportedException stubs -->
namespace System.Collections.Specialized
{
- internal sealed class DictionaryWrapper : IDictionary<string, string>, IDictionary
+ internal sealed class DictionaryWrapper : IDictionary<string, string?>, IDictionary
{
- private readonly Dictionary<string, string> _contents;
+ private readonly Dictionary<string, string?> _contents;
- public DictionaryWrapper(Dictionary<string, string> contents)
+ public DictionaryWrapper(Dictionary<string, string?> contents)
{
_contents = contents;
}
- public string this[string key]
+ public string? this[string key]
{
get => _contents[key];
set => _contents[key] = value;
}
- public object this[object key]
+ public object? this[object key]
{
get => this[(string)key];
- set => this[(string)key] = (string)value;
+ set => this[(string)key] = (string?)value;
}
public ICollection<string> Keys => _contents.Keys;
- public ICollection<string> Values => _contents.Values;
+ public ICollection<string?> Values => _contents.Values;
ICollection IDictionary.Keys => _contents.Keys;
ICollection IDictionary.Values => _contents.Values;
public bool IsFixedSize => ((IDictionary)_contents).IsFixedSize;
public object SyncRoot => ((IDictionary)_contents).SyncRoot;
- public void Add(string key, string value) => this[key] = value;
+ public void Add(string key, string? value) => this[key] = value;
- public void Add(KeyValuePair<string, string> item) => Add(item.Key, item.Value);
+ public void Add(KeyValuePair<string, string?> item) => Add(item.Key, item.Value);
- public void Add(object key, object value) => Add((string)key, (string)value);
+ public void Add(object key, object? value) => Add((string)key, (string?)value);
public void Clear() => _contents.Clear();
- public bool Contains(KeyValuePair<string, string> item)
+ public bool Contains(KeyValuePair<string, string?> item)
{
return _contents.ContainsKey(item.Key) && _contents[item.Key] == item.Value;
}
public bool Contains(object key) => ContainsKey((string)key);
public bool ContainsKey(string key) => _contents.ContainsKey(key);
- public bool ContainsValue(string value) => _contents.ContainsValue(value);
+ public bool ContainsValue(string? value) => _contents.ContainsValue(value);
- public void CopyTo(KeyValuePair<string, string>[] array, int arrayIndex)
+ public void CopyTo(KeyValuePair<string, string?>[] array, int arrayIndex)
{
- ((IDictionary<string, string>)_contents).CopyTo(array, arrayIndex);
+ ((IDictionary<string, string?>)_contents).CopyTo(array, arrayIndex);
}
public void CopyTo(Array array, int index) => ((IDictionary)_contents).CopyTo(array, index);
public bool Remove(string key) => _contents.Remove(key);
public void Remove(object key) => Remove((string)key);
- public bool Remove(KeyValuePair<string, string> item)
+ public bool Remove(KeyValuePair<string, string?> item)
{
if (!Contains(item))
{
return Remove(item.Key);
}
- public bool TryGetValue(string key, out string value) => _contents.TryGetValue(key, out value);
+ public bool TryGetValue(string key, out string? value) => _contents.TryGetValue(key, out value);
- public IEnumerator<KeyValuePair<string, string>> GetEnumerator() => _contents.GetEnumerator();
+ public IEnumerator<KeyValuePair<string, string?>> GetEnumerator() => _contents.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => _contents.GetEnumerator();
IDictionaryEnumerator IDictionary.GetEnumerator() => _contents.GetEnumerator();
}
_contents = contents;
}
- public override string this[string key]
+ public override string? this[string key]
{
get { return _contents[key]; }
set { _contents[key] = value; }
public override object SyncRoot => _contents.SyncRoot;
- public override void Add(string key, string value)
+ public override void Add(string key, string? value)
{
if (_contents.ContainsKey(key))
{
public override bool ContainsKey(string key) => _contents.ContainsKey(key);
- public override bool ContainsValue(string value) => _contents.ContainsValue(value);
+ public override bool ContainsValue(string? value) => _contents.ContainsValue(value);
public override void CopyTo(Array array, int index) => _contents.CopyTo(array, index);
public override IEnumerator GetEnumerator()
{
- foreach (KeyValuePair<string, string> keyValuePair in _contents)
+ foreach (KeyValuePair<string, string?> keyValuePair in _contents)
{
yield return new DictionaryEntry(keyValuePair.Key, keyValuePair.Value);
}
public override void Remove(string key) => _contents.Remove(key);
}
-}
\ No newline at end of file
+}
private readonly char[] _charBuffer;
// Delegate to call user function.
- private readonly Action<string> _userCallBack;
+ private readonly Action<string?> _userCallBack;
private readonly CancellationTokenSource _cts;
- private Task _readToBufferTask;
- private readonly Queue<string> _messageQueue;
- private StringBuilder _sb;
+ private Task? _readToBufferTask;
+ private readonly Queue<string?> _messageQueue;
+ private StringBuilder? _sb;
private bool _bLastCarriageReturn;
private bool _cancelOperation;
// Creates a new AsyncStreamReader for the given stream. The
// character encoding is set by encoding and the buffer size,
// in number of 16-bit characters, is set by bufferSize.
- internal AsyncStreamReader(Stream stream, Action<string> callback, Encoding encoding)
+ internal AsyncStreamReader(Stream stream, Action<string?> callback, Encoding encoding)
{
Debug.Assert(stream != null && encoding != null && callback != null, "Invalid arguments!");
Debug.Assert(stream.CanRead, "Stream must be readable!");
_charBuffer = new char[maxCharsPerBuffer];
_cts = new CancellationTokenSource();
- _messageQueue = new Queue<string>();
+ _messageQueue = new Queue<string?>();
}
// User calls BeginRead to start the asynchronous read
break;
int charLen = _decoder.GetChars(_byteBuffer, 0, bytesRead, _charBuffer, 0);
- _sb.Append(_charBuffer, 0, charLen);
+ _sb!.Append(_charBuffer, 0, charLen);
MoveLinesFromStringBuilderToMessageQueue();
}
catch (IOException)
// We're at EOF, process current buffer content and flush message queue.
lock (_messageQueue)
{
- if (_sb.Length != 0)
+ if (_sb!.Length != 0)
{
_messageQueue.Enqueue(_sb.ToString());
_sb.Length = 0;
{
int currentIndex = _currentLinePos;
int lineStart = 0;
- int len = _sb.Length;
+ int len = _sb!.Length;
// skip a beginning '\n' character of new block if last block ended
// with '\r'
{
// Get the next line (if there isn't one, we're done) and
// invoke the user's callback with it.
- string line;
+ string? line;
lock (_messageQueue)
{
if (_messageQueue.Count == 0)
// Otherwise, let the exception propagate.
if (rethrowInNewThread)
{
- ThreadPool.QueueUserWorkItem(edi => ((ExceptionDispatchInfo)edi).Throw(), ExceptionDispatchInfo.Capture(e));
+ ThreadPool.QueueUserWorkItem(edi => ((ExceptionDispatchInfo)edi!).Throw(), ExceptionDispatchInfo.Capture(e));
return true;
}
throw;
public class DataReceivedEventArgs : EventArgs
{
- private readonly string _data;
+ private readonly string? _data;
- internal DataReceivedEventArgs(string data)
+ internal DataReceivedEventArgs(string? data)
{
_data = data;
}
- public string Data
+ public string? Data
{
get { return _data; }
}
{
internal sealed class PerformanceCounterLib
{
- private static string s_computerName;
+ private static string? s_computerName;
- private PerformanceMonitor _performanceMonitor;
+ private PerformanceMonitor? _performanceMonitor;
private readonly string _machineName;
private readonly string _perfLcid;
- private static ConcurrentDictionary<(string machineName, string lcidString), PerformanceCounterLib> s_libraryTable;
- private Dictionary<int, string> _nameTable;
+ private static ConcurrentDictionary<(string machineName, string lcidString), PerformanceCounterLib>? s_libraryTable;
+ private Dictionary<int, string>? _nameTable;
private readonly object _nameTableLock = new object();
- private static object s_internalSyncObject;
+ private static object? s_internalSyncObject;
internal PerformanceCounterLib(string machineName, string lcid)
{
}
/// <internalonly/>
- internal static string ComputerName => LazyInitializer.EnsureInitialized(ref s_computerName, ref s_internalSyncObject, () => Interop.Kernel32.GetComputerName());
+ internal static string ComputerName => LazyInitializer.EnsureInitialized<string>(ref s_computerName, ref s_internalSyncObject, () => Interop.Kernel32.GetComputerName() ?? "");
internal Dictionary<int, string> NameTable
{
internal string GetCounterName(int index)
{
- string result;
+ string? result;
return NameTable.TryGetValue(index, out result) ? result : "";
}
try
{
- string[] names = null;
+ string[]? names = null;
int waitRetries = 14; //((2^13)-1)*10ms == approximately 1.4mins
int waitSleep = 0;
internal class PerformanceMonitor
{
#if FEATURE_REGISTRY
- private RegistryKey _perfDataKey = null;
+ private RegistryKey _perfDataKey = null!; // will be initialized by Init() method
#endif
private readonly string _machineName;
#if FEATURE_REGISTRY
int waitRetries = 17; //2^16*10ms == approximately 10mins
int waitSleep = 0;
- byte[] data = null;
+ byte[]? data = null;
int error = 0;
while (waitRetries > 0)
/// Creates an array of <see cref="Process"/> components that are associated with process resources on a
/// remote computer. These process resources share the specified process name.
/// </summary>
- public static Process[] GetProcessesByName(string processName, string machineName)
+ public static Process[] GetProcessesByName(string? processName, string machineName)
{
if (processName == null)
{
}
// <summary>Gets execution path</summary>
- private string GetPathToOpenFile()
+ private string? GetPathToOpenFile()
{
Interop.Sys.FileStatus stat;
if (Interop.Sys.Stat("/usr/local/bin/open", out stat) == 0)
// ---- PAL layer ends here ----
// -----------------------------
/// <summary>Gets the path to the current executable, or null if it could not be retrieved.</summary>
- private static string GetExePath()
+ private static string? GetExePath()
{
return Interop.Process.GetProcPath(Interop.Sys.GetPid());
}
/// Creates an array of <see cref="Process"/> components that are associated with process resources on a
/// remote computer. These process resources share the specified process name.
/// </summary>
- public static Process[] GetProcessesByName(string processName, string machineName)
+ public static Process[] GetProcessesByName(string? processName, string machineName)
{
ProcessManager.ThrowIfRemoteMachine(machineName);
if (processName == null)
GetStat().ppid;
/// <summary>Gets execution path</summary>
- private string GetPathToOpenFile()
+ private string? GetPathToOpenFile()
{
string[] allowedProgramsToRun = { "xdg-open", "gnome-open", "kfmclient" };
foreach (var program in allowedProgramsToRun)
{
- string pathToProgram = FindProgramInPath(program);
+ string? pathToProgram = FindProgramInPath(program);
if (!string.IsNullOrEmpty(pathToProgram))
{
return pathToProgram;
partial void EnsureHandleCountPopulated()
{
- if (_processInfo.HandleCount <= 0 && _haveProcessId)
+ if (_processInfo!.HandleCount <= 0 && _haveProcessId)
{
// Don't get information for a PID that exited and has possibly been recycled.
if (GetHasExited(refresh: false))
/// <summary>Gets the path to the executable for the process, or null if it could not be retrieved.</summary>
/// <param name="processId">The pid for the target process, or -1 for the current process.</param>
- internal static string GetExePath(int processId = -1)
+ internal static string? GetExePath(int processId = -1)
{
string exeFilePath = processId == -1 ?
Interop.procfs.SelfExeFilePath :
{
string cmdLineFilePath = Interop.procfs.GetCmdLinePathForProcess(stat.pid);
- byte[] rentedArray = null;
+ byte[]? rentedArray = null;
try
{
// bufferSize == 1 used to avoid unnecessary buffer in FileStream
byte[] tmp = ArrayPool<byte>.Shared.Rent((int)newLength);
buffer.CopyTo(tmp);
- byte[] toReturn = rentedArray;
+ byte[]? toReturn = rentedArray;
buffer = rentedArray = tmp;
if (toReturn != null)
{
if (argEnd != -1)
{
// Check if argv[0] has the process name.
- string name = GetUntruncatedNameFromArg(argRemainder.Slice(0, argEnd), prefix: stat.comm);
+ string? name = GetUntruncatedNameFromArg(argRemainder.Slice(0, argEnd), prefix: stat.comm);
if (name != null)
{
return name;
}
}
- string GetUntruncatedNameFromArg(Span<byte> arg, string prefix)
+ string? GetUntruncatedNameFromArg(Span<byte> arg, string prefix)
{
// Strip directory names from arg.
int nameStart = arg.LastIndexOf((byte)'/') + 1;
try
{
var descendantProcesses = new Queue<Process>();
- Process current = this;
+ Process? current = this;
do
{
/// <summary>
/// Returns all immediate child processes.
/// </summary>
- private IReadOnlyList<Process> GetChildProcesses(Process[] processes = null)
+ private IReadOnlyList<Process> GetChildProcesses(Process[]? processes = null)
{
bool internallyInitializedProcesses = processes == null;
processes = processes ?? GetProcesses();
private IEnumerable<Exception> KillTree()
{
- List<Exception> exceptions = null;
+ List<Exception>? exceptions = null;
KillTree(ref exceptions);
return exceptions ?? Enumerable.Empty<Exception>();
}
- private void KillTree(ref List<Exception> exceptions)
+ private void KillTree(ref List<Exception>? exceptions)
{
// If the process has exited, we can no longer determine its children.
// If we know the process has exited, stop already.
childProcess.Dispose();
}
- void AddException(ref List<Exception> list, Exception e)
+ void AddException(ref List<Exception>? list, Exception e)
{
if (list == null)
{
}
/// <summary>Gets the main module for the associated process.</summary>
- public ProcessModule MainModule
+ public ProcessModule? MainModule
{
get
{
{
ThrowIfExited(refresh: true);
- return _processHandle;
+ return _processHandle!;
}
EnsureState(State.HaveNonExitedId | State.IsLocal);
{
EnsureInitialized();
- string filename;
+ string? filename;
string[] argv;
if (startInfo.UseShellExecute)
int stdinFd = -1, stdoutFd = -1, stderrFd = -1;
string[] envp = CreateEnvp(startInfo);
- string cwd = !string.IsNullOrWhiteSpace(startInfo.WorkingDirectory) ? startInfo.WorkingDirectory : null;
+ string? cwd = !string.IsNullOrWhiteSpace(startInfo.WorkingDirectory) ? startInfo.WorkingDirectory : null;
bool setCredentials = !string.IsNullOrEmpty(startInfo.UserName);
uint userId = 0;
uint groupId = 0;
- uint[] groups = null;
+ uint[]? groups = null;
if (setCredentials)
{
(userId, groupId, groups) = GetUserAndGroupIds(startInfo);
}
private bool ForkAndExecProcess(
- string filename, string[] argv, string[] envp, string cwd,
+ string? filename, string[] argv, string[] envp, string? cwd,
bool redirectStdin, bool redirectStdout, bool redirectStderr,
- bool setCredentials, uint userId, uint groupId, uint[] groups,
+ bool setCredentials, uint userId, uint groupId, uint[]? groups,
out int stdinFd, out int stdoutFd, out int stderrFd,
bool usesTerminal, bool throwOnNoExec = true)
{
// -----------------------------
/// <summary>Finalizable holder for the underlying shared wait state object.</summary>
- private ProcessWaitState.Holder _waitStateHolder;
+ private ProcessWaitState.Holder? _waitStateHolder;
/// <summary>Size to use for redirect streams and stream readers/writers.</summary>
private const int StreamBufferSize = 4096;
/// <param name="resolvedExe">Resolved executable to open ProcessStartInfo.FileName</param>
/// <param name="ignoreArguments">Don't pass ProcessStartInfo.Arguments</param>
/// <returns>The argv array.</returns>
- private static string[] ParseArgv(ProcessStartInfo psi, string resolvedExe = null, bool ignoreArguments = false)
+ private static string[] ParseArgv(ProcessStartInfo psi, string? resolvedExe = null, bool ignoreArguments = false)
{
if (string.IsNullOrEmpty(resolvedExe) &&
(ignoreArguments || (string.IsNullOrEmpty(psi.Arguments) && psi.ArgumentList.Count == 0)))
return envp;
}
- private static string ResolveExecutableForShellExecute(string filename, string workingDirectory)
+ private static string? ResolveExecutableForShellExecute(string filename, string? workingDirectory)
{
// Determine if filename points to an executable file.
// filename may be an absolute path, a relative path or a uri.
- string resolvedFilename = null;
+ string? resolvedFilename = null;
// filename is an absolute path
if (Path.IsPathRooted(filename))
{
}
}
// filename is a uri
- else if (Uri.TryCreate(filename, UriKind.Absolute, out Uri uri))
+ else if (Uri.TryCreate(filename, UriKind.Absolute, out Uri? uri))
{
if (uri.IsFile && uri.Host == "" && File.Exists(uri.LocalPath))
{
/// <summary>Resolves a path to the filename passed to ProcessStartInfo. </summary>
/// <param name="filename">The filename.</param>
/// <returns>The resolved path. It can return null in case of URLs.</returns>
- private static string ResolvePath(string filename)
+ private static string? ResolvePath(string filename)
{
// Follow the same resolution that Windows uses with CreateProcess:
// 1. First try the exact path provided
}
// Then check the executable's directory
- string path = GetExePath();
+ string? path = GetExePath();
if (path != null)
{
try
{
- path = Path.Combine(Path.GetDirectoryName(path), filename);
+ path = Path.Combine(Path.GetDirectoryName(path)!, filename);
if (File.Exists(path))
{
return path;
/// </summary>
/// <param name="program"></param>
/// <returns></returns>
- private static string FindProgramInPath(string program)
+ private static string? FindProgramInPath(string program)
{
string path;
- string pathEnvVar = Environment.GetEnvironmentVariable("PATH");
+ string? pathEnvVar = Environment.GetEnvironmentVariable("PATH");
if (pathEnvVar != null)
{
var pathParser = new StringParser(pathEnvVar, ':', skipEmpty: true);
throw new Win32Exception(SR.Format(SR.UserDoesNotExist, startInfo.UserName));
}
- uint[] groups = Interop.Sys.GetGroupList(startInfo.UserName, groupId.Value);
+ uint[]? groups = Interop.Sys.GetGroupList(startInfo.UserName, groupId!.Value);
if (groups == null)
{
throw new Win32Exception(SR.Format(SR.UserGroupsCannotBeDetermined, startInfo.UserName));
{
private bool _haveMainWindow;
private IntPtr _mainWindowHandle;
- private string _mainWindowTitle;
+ private string? _mainWindowTitle;
private bool _haveResponding;
private bool _responding;
/// Creates an array of <see cref="Process"/> components that are associated with process resources on a
/// remote computer. These process resources share the specified process name.
/// </summary>
- public static Process[] GetProcessesByName(string processName, string machineName)
+ public static Process[] GetProcessesByName(string? processName, string machineName)
{
if (processName == null)
{
}
[CLSCompliant(false)]
- public static Process Start(string fileName, string userName, SecureString password, string domain)
+ public static Process? Start(string fileName, string userName, SecureString password, string domain)
{
ProcessStartInfo startInfo = new ProcessStartInfo(fileName);
startInfo.UserName = userName;
}
[CLSCompliant(false)]
- public static Process Start(string fileName, string arguments, string userName, SecureString password, string domain)
+ public static Process? Start(string fileName, string arguments, string userName, SecureString password, string domain)
{
ProcessStartInfo startInfo = new ProcessStartInfo(fileName, arguments);
startInfo.UserName = userName;
/// </summary>
private bool WaitForExitCore(int milliseconds)
{
- SafeProcessHandle handle = null;
+ SafeProcessHandle? handle = null;
try
{
handle = GetProcessHandle(Interop.Advapi32.ProcessOptions.SYNCHRONIZE, false);
}
/// <summary>Gets the main module for the associated process.</summary>
- public ProcessModule MainModule
+ public ProcessModule? MainModule
{
get
{
SafeThreadHandle threadSH = new SafeThreadHandle();
// handles used in parent process
- SafeFileHandle parentInputPipeHandle = null;
- SafeFileHandle childInputPipeHandle = null;
- SafeFileHandle parentOutputPipeHandle = null;
- SafeFileHandle childOutputPipeHandle = null;
- SafeFileHandle parentErrorPipeHandle = null;
- SafeFileHandle childErrorPipeHandle = null;
+ SafeFileHandle? parentInputPipeHandle = null;
+ SafeFileHandle? childInputPipeHandle = null;
+ SafeFileHandle? parentOutputPipeHandle = null;
+ SafeFileHandle? childOutputPipeHandle = null;
+ SafeFileHandle? parentErrorPipeHandle = null;
+ SafeFileHandle? childErrorPipeHandle = null;
// Take a global lock to synchronize all redirect pipe handle creations and CreateProcess
// calls. We do not want one process to inherit the handles created concurrently for another
if (startInfo.CreateNoWindow) creationFlags |= Interop.Advapi32.StartupInfoOptions.CREATE_NO_WINDOW;
// set up the environment block parameter
- string environmentBlock = null;
+ string? environmentBlock = null;
if (startInfo._environmentVariables != null)
{
creationFlags |= Interop.Advapi32.StartupInfoOptions.CREATE_UNICODE_ENVIRONMENT;
- environmentBlock = GetEnvironmentVariablesBlock(startInfo._environmentVariables);
+ environmentBlock = GetEnvironmentVariablesBlock(startInfo._environmentVariables!);
}
string workingDirectory = startInfo.WorkingDirectory;
if (workingDirectory == string.Empty)
if (startInfo.RedirectStandardInput)
{
Encoding enc = startInfo.StandardInputEncoding ?? GetEncoding((int)Interop.Kernel32.GetConsoleCP());
- _standardInput = new StreamWriter(new FileStream(parentInputPipeHandle, FileAccess.Write, 4096, false), enc, 4096);
+ _standardInput = new StreamWriter(new FileStream(parentInputPipeHandle!, FileAccess.Write, 4096, false), enc, 4096);
_standardInput.AutoFlush = true;
}
if (startInfo.RedirectStandardOutput)
{
Encoding enc = startInfo.StandardOutputEncoding ?? GetEncoding((int)Interop.Kernel32.GetConsoleOutputCP());
- _standardOutput = new StreamReader(new FileStream(parentOutputPipeHandle, FileAccess.Read, 4096, false), enc, true, 4096);
+ _standardOutput = new StreamReader(new FileStream(parentOutputPipeHandle!, FileAccess.Read, 4096, false), enc, true, 4096);
}
if (startInfo.RedirectStandardError)
{
Encoding enc = startInfo.StandardErrorEncoding ?? GetEncoding((int)Interop.Kernel32.GetConsoleOutputCP());
- _standardError = new StreamReader(new FileStream(parentErrorPipeHandle, FileAccess.Read, 4096, false), enc, true, 4096);
+ _standardError = new StreamReader(new FileStream(parentErrorPipeHandle!, FileAccess.Read, 4096, false), enc, true, 4096);
}
if (procSH.IsInvalid)
// this is only a "pseudo handle" to the current process - no need to close it later
SafeProcessHandle processHandle = Interop.Kernel32.GetCurrentProcess();
- SafeTokenHandle hToken = null;
+ SafeTokenHandle? hToken = null;
try
{
// Since haveProcessHandle is true, we know we have the process handle
// open with at least SYNCHRONIZE access, so we can wait on it with
// zero timeout to see if the process has exited.
- using (Interop.Kernel32.ProcessWaitHandle waitHandle = new Interop.Kernel32.ProcessWaitHandle(_processHandle))
+ using (Interop.Kernel32.ProcessWaitHandle waitHandle = new Interop.Kernel32.ProcessWaitHandle(_processHandle!))
{
if (waitHandle.WaitOne(0))
{
// If we dispose of our contained handle we'll be in a bad state. .NET Framework dealt with this
// by doing a try..finally around every usage of GetProcessHandle and only disposed if
// it wasn't our handle.
- return new SafeProcessHandle(_processHandle.DangerousGetHandle(), ownsHandle: false);
+ return new SafeProcessHandle(_processHandle!.DangerousGetHandle(), ownsHandle: false);
}
else
{
Interop.Kernel32.SECURITY_ATTRIBUTES securityAttributesParent = default;
securityAttributesParent.bInheritHandle = Interop.BOOL.TRUE;
- SafeFileHandle hTmp = null;
+ SafeFileHandle? hTmp = null;
try
{
if (parentInputs)
private bool _haveProcessId;
private int _processId;
private bool _haveProcessHandle;
- private SafeProcessHandle _processHandle;
+ private SafeProcessHandle? _processHandle;
private bool _isRemoteMachine;
private string _machineName;
- private ProcessInfo _processInfo;
+ private ProcessInfo? _processInfo;
- private ProcessThreadCollection _threads;
- private ProcessModuleCollection _modules;
+ private ProcessThreadCollection? _threads;
+ private ProcessModuleCollection? _modules;
private bool _haveWorkingSetLimits;
private IntPtr _minWorkingSet;
private bool _havePriorityClass;
private ProcessPriorityClass _priorityClass;
- private ProcessStartInfo _startInfo;
+ private ProcessStartInfo? _startInfo;
private bool _watchForExit;
private bool _watchingForExit;
- private EventHandler _onExited;
+ private EventHandler? _onExited;
private bool _exited;
private int _exitCode;
private bool _havePriorityBoostEnabled;
private bool _raisedOnExited;
- private RegisteredWaitHandle _registeredWaitHandle;
- private WaitHandle _waitHandle;
- private StreamReader _standardOutput;
- private StreamWriter _standardInput;
- private StreamReader _standardError;
+ private RegisteredWaitHandle? _registeredWaitHandle;
+ private WaitHandle? _waitHandle;
+ private StreamReader? _standardOutput;
+ private StreamWriter? _standardInput;
+ private StreamReader? _standardError;
private bool _disposed;
private bool _standardInputAccessed;
private StreamReadMode _errorStreamReadMode;
// Support for asynchronously reading streams
- public event DataReceivedEventHandler OutputDataReceived;
- public event DataReceivedEventHandler ErrorDataReceived;
+ public event DataReceivedEventHandler? OutputDataReceived;
+ public event DataReceivedEventHandler? ErrorDataReceived;
// Abstract the stream details
- internal AsyncStreamReader _output;
- internal AsyncStreamReader _error;
+ internal AsyncStreamReader? _output;
+ internal AsyncStreamReader? _error;
internal bool _pendingOutputRead;
internal bool _pendingErrorRead;
_errorStreamReadMode = StreamReadMode.Undefined;
}
- private Process(string machineName, bool isRemoteMachine, int processId, ProcessInfo processInfo)
+ private Process(string machineName, bool isRemoteMachine, int processId, ProcessInfo? processInfo)
{
GC.SuppressFinalize(this);
_processInfo = processInfo;
get
{
EnsureState(State.HaveProcessInfo);
- return _processInfo.BasePriority;
+ return _processInfo!.BasePriority;
}
}
get
{
EnsureState(State.HaveProcessInfo);
- return _processInfo.PoolNonPagedBytes;
+ return _processInfo!.PoolNonPagedBytes;
}
}
get
{
EnsureState(State.HaveProcessInfo);
- return unchecked((int)_processInfo.PoolNonPagedBytes);
+ return unchecked((int)_processInfo!.PoolNonPagedBytes);
}
}
get
{
EnsureState(State.HaveProcessInfo);
- return _processInfo.PageFileBytes;
+ return _processInfo!.PageFileBytes;
}
}
get
{
EnsureState(State.HaveProcessInfo);
- return unchecked((int)_processInfo.PageFileBytes);
+ return unchecked((int)_processInfo!.PageFileBytes);
}
}
get
{
EnsureState(State.HaveProcessInfo);
- return _processInfo.PoolPagedBytes;
+ return _processInfo!.PoolPagedBytes;
}
}
get
{
EnsureState(State.HaveProcessInfo);
- return unchecked((int)_processInfo.PoolPagedBytes);
+ return unchecked((int)_processInfo!.PoolPagedBytes);
}
}
get
{
EnsureState(State.HaveProcessInfo);
- return _processInfo.PageFileBytesPeak;
+ return _processInfo!.PageFileBytesPeak;
}
}
get
{
EnsureState(State.HaveProcessInfo);
- return unchecked((int)_processInfo.PageFileBytesPeak);
+ return unchecked((int)_processInfo!.PageFileBytesPeak);
}
}
get
{
EnsureState(State.HaveProcessInfo);
- return _processInfo.WorkingSetPeak;
+ return _processInfo!.WorkingSetPeak;
}
}
get
{
EnsureState(State.HaveProcessInfo);
- return unchecked((int)_processInfo.WorkingSetPeak);
+ return unchecked((int)_processInfo!.WorkingSetPeak);
}
}
get
{
EnsureState(State.HaveProcessInfo);
- return _processInfo.VirtualBytesPeak;
+ return _processInfo!.VirtualBytesPeak;
}
}
get
{
EnsureState(State.HaveProcessInfo);
- return unchecked((int)_processInfo.VirtualBytesPeak);
+ return unchecked((int)_processInfo!.VirtualBytesPeak);
}
}
get
{
EnsureState(State.HaveProcessInfo);
- return _processInfo.PrivateBytes;
+ return _processInfo!.PrivateBytes;
}
}
get
{
EnsureState(State.HaveProcessInfo);
- return unchecked((int)_processInfo.PrivateBytes);
+ return unchecked((int)_processInfo!.PrivateBytes);
}
}
get
{
EnsureState(State.HaveProcessInfo);
- return _processInfo.ProcessName;
+ return _processInfo!.ProcessName;
}
}
get
{
EnsureState(State.HaveProcessInfo);
- return _processInfo.SessionId;
+ return _processInfo!.SessionId;
}
}
if (_threads == null)
{
EnsureState(State.HaveProcessInfo);
- int count = _processInfo._threadInfoList.Count;
+ int count = _processInfo!._threadInfoList.Count;
ProcessThread[] newThreadsArray = new ProcessThread[count];
for (int i = 0; i < count; i++)
{
{
EnsureState(State.HaveProcessInfo);
EnsureHandleCountPopulated();
- return _processInfo.HandleCount;
+ return _processInfo!.HandleCount;
}
}
get
{
EnsureState(State.HaveProcessInfo);
- return _processInfo.VirtualBytes;
+ return _processInfo!.VirtualBytes;
}
}
get
{
EnsureState(State.HaveProcessInfo);
- return unchecked((int)_processInfo.VirtualBytes);
+ return unchecked((int)_processInfo!.VirtualBytes);
}
}
get
{
EnsureState(State.HaveProcessInfo);
- return _processInfo.WorkingSet;
+ return _processInfo!.WorkingSet;
}
}
get
{
EnsureState(State.HaveProcessInfo);
- return unchecked((int)_processInfo.WorkingSet);
+ return unchecked((int)_processInfo!.WorkingSet);
}
}
/// This is called from the threadpool when a process exits.
/// </devdoc>
/// <internalonly/>
- private void CompletionCallback(object waitHandleContext, bool wasSignaled)
+ private void CompletionCallback(object? waitHandleContext, bool wasSignaled)
{
Debug.Assert(waitHandleContext != null, "Process.CompletionCallback called with no waitHandleContext");
lock (this)
return WaitForInputIdleCore(milliseconds);
}
- public ISynchronizeInvoke SynchronizingObject { get; set; }
+ public ISynchronizeInvoke? SynchronizingObject { get; set; }
/// <devdoc>
/// <para>
if (_haveProcessHandle)
{
- _processHandle.Dispose();
+ _processHandle!.Dispose();
_processHandle = null;
_haveProcessHandle = false;
}
{
if (_haveProcessHandle)
{
- SetProcessId(ProcessManager.GetProcessIdFromHandle(_processHandle));
+ SetProcessId(ProcessManager.GetProcessIdFromHandle(_processHandle!));
}
else
{
/// local computer. These process resources share the specified process name.
/// </para>
/// </devdoc>
- public static Process[] GetProcessesByName(string processName)
+ public static Process[] GetProcessesByName(string? processName)
{
return GetProcessesByName(processName, ".");
}
/// </devdoc>
protected void OnExited()
{
- EventHandler exited = _onExited;
+ EventHandler? exited = _onExited;
if (exited != null)
{
exited(this, EventArgs.Empty);
SetProcessHandle(GetProcessHandle());
}
- return _processHandle;
+ return _processHandle!;
}
/// <devdoc>
/// </devdoc>
public static Process Start(string fileName)
{
- return Start(new ProcessStartInfo(fileName));
+ // the underlying Start method can only return null on Windows platforms,
+ // when the ProcessStartInfo.UseShellExecute property is set to true.
+ // We can thus safely assert non-nullability for tihs overload.
+ return Start(new ProcessStartInfo(fileName))!;
}
/// <devdoc>
/// </devdoc>
public static Process Start(string fileName, string arguments)
{
- return Start(new ProcessStartInfo(fileName, arguments));
+ // the underlying Start method can only return null on Windows platforms,
+ // when the ProcessStartInfo.UseShellExecute property is set to true.
+ // We can thus safely assert non-nullability for tihs overload.
+ return Start(new ProcessStartInfo(fileName, arguments))!;
}
/// <devdoc>
/// component.
/// </para>
/// </devdoc>
- public static Process Start(ProcessStartInfo startInfo)
+ public static Process? Start(ProcessStartInfo startInfo)
{
Process process = new Process();
if (startInfo == null)
{
if (_watchingForExit)
{
- RegisteredWaitHandle rwh = null;
- WaitHandle wh = null;
+ RegisteredWaitHandle? rwh = null;
+ WaitHandle? wh = null;
lock (this)
{
_pendingErrorRead = false;
}
- internal void OutputReadNotifyUser(string data)
+ internal void OutputReadNotifyUser(string? data)
{
// To avoid race between remove handler and raising the event
- DataReceivedEventHandler outputDataReceived = OutputDataReceived;
+ DataReceivedEventHandler? outputDataReceived = OutputDataReceived;
if (outputDataReceived != null)
{
DataReceivedEventArgs e = new DataReceivedEventArgs(data);
}
}
- internal void ErrorReadNotifyUser(string data)
+ internal void ErrorReadNotifyUser(string? data)
{
// To avoid race between remove handler and raising the event
- DataReceivedEventHandler errorDataReceived = ErrorDataReceived;
+ DataReceivedEventHandler? errorDataReceived = ErrorDataReceived;
if (errorDataReceived != null)
{
DataReceivedEventArgs e = new DataReceivedEventArgs(data);
// and why MainModule exists.
try
{
- string exePath = GetProcPath(processId);
+ string? exePath = GetProcPath(processId);
if (!string.IsNullOrEmpty(exePath))
{
return new ProcessModuleCollection(1)
return Interop.Process.ListAllPids();
}
- internal static string GetProcPath(int processId)
+ internal static string? GetProcPath(int processId)
{
return Interop.Process.GetProcPath(processId);
}
var processes = new List<ProcessInfo>(procIds.Length);
foreach (int pid in procIds)
{
- ProcessInfo pi = CreateProcessInfo(pid, reusableReader);
+ ProcessInfo? pi = CreateProcessInfo(pid, reusableReader);
if (pi != null)
{
processes.Add(pi);
}
// Move the main executable module to be the first in the list if it's not already
- string exePath = Process.GetExePath(processId);
+ string? exePath = Process.GetExePath(processId);
for (int i = 0; i < modules.Count; i++)
{
ProcessModule module = modules[i];
/// <summary>
/// Creates a ProcessInfo from the specified process ID.
/// </summary>
- internal static ProcessInfo CreateProcessInfo(int pid, ReusableTextReader reusableReader = null)
+ internal static ProcessInfo? CreateProcessInfo(int pid, ReusableTextReader? reusableReader = null)
{
reusableReader ??= new ReusableTextReader();
if (Interop.procfs.TryReadStatFile(pid, out Interop.procfs.ParsedStat stat, reusableReader))
/// <summary>
/// Creates a ProcessInfo from the data parsed from a /proc/pid/stat file and the associated tasks directory.
/// </summary>
- internal static ProcessInfo CreateProcessInfo(ref Interop.procfs.ParsedStat procFsStat, ref Interop.procfs.ParsedStatus procFsStatus, ReusableTextReader reusableReader, string processName = null)
+ internal static ProcessInfo CreateProcessInfo(ref Interop.procfs.ParsedStat procFsStat, ref Interop.procfs.ParsedStatus procFsStatus, ReusableTextReader reusableReader, string? processName = null)
{
int pid = procFsStat.pid;
{
// Set the values we have; all the other values don't have meaning or don't exist on OSX
Interop.libproc.proc_taskallinfo temp = info.Value;
- unsafe { procInfo.ProcessName = Marshal.PtrToStringAnsi(new IntPtr(temp.pbsd.pbi_comm)); }
+ unsafe { procInfo.ProcessName = Marshal.PtrToStringAnsi(new IntPtr(temp.pbsd.pbi_comm))!; }
procInfo.BasePriority = temp.pbsd.pbi_nice;
procInfo.VirtualBytes = (long)temp.ptinfo.pti_virtual_size;
procInfo.WorkingSet = (long)temp.ptinfo.pti_resident_size;
/// <param name="processId">The process ID.</param>
/// <param name="machineName">The machine name.</param>
/// <returns>The ProcessInfo for the process if it could be found; otherwise, null.</returns>
- public static ProcessInfo GetProcessInfo(int processId, string machineName)
+ public static ProcessInfo? GetProcessInfo(int processId, string machineName)
{
ThrowIfRemoteMachine(machineName);
return CreateProcessInfo(processId);
internal static class NtProcessInfoHelper
{
// Cache a single buffer for use in GetProcessInfos().
- private static long[] CachedBuffer;
+ private static long[]? CachedBuffer;
// Use a smaller buffer size on debug to ensure we hit the retry path.
#if DEBUG
private const int DefaultCachedBufferSize = 128 * 1024;
#endif
- internal static ProcessInfo[] GetProcessInfos(Predicate<int> processIdFilter = null)
+ internal static ProcessInfo[] GetProcessInfos(Predicate<int>? processIdFilter = null)
{
ProcessInfo[] processInfos;
int bufferSize = DefaultCachedBufferSize;
// Get the cached buffer.
- long[] buffer = Interlocked.Exchange(ref CachedBuffer, null);
+ long[]? buffer = Interlocked.Exchange(ref CachedBuffer, null);
try
{
return newSize;
}
- private static unsafe ProcessInfo[] GetProcessInfos(ReadOnlySpan<byte> data, Predicate<int> processIdFilter)
+ private static unsafe ProcessInfo[] GetProcessInfos(ReadOnlySpan<byte> data, Predicate<int>? processIdFilter)
{
// Use a dictionary to avoid duplicate entries if any
// 60 is a reasonable number for processes on a normal machine.
/// <param name="processId">The process ID.</param>
/// <param name="machineName">The machine name.</param>
/// <returns>The ProcessInfo for the process if it could be found; otherwise, null.</returns>
- public static ProcessInfo GetProcessInfo(int processId, string machineName)
+ public static ProcessInfo? GetProcessInfo(int processId, string machineName)
{
if (IsRemoteMachine(machineName))
{
return;
}
- SafeTokenHandle tokenHandle = null;
+ SafeTokenHandle? tokenHandle = null;
try
{
if (!Interop.Advapi32.OpenProcessToken(
return GetModules(processId, firstModuleOnly: false);
}
- public static ProcessModule GetFirstModule(int processId)
+ public static ProcessModule? GetFirstModule(int processId)
{
ProcessModuleCollection modules = GetModules(processId, firstModuleOnly: true);
return modules.Count == 0 ? null : modules[0];
public static ProcessInfo[] GetProcessInfos(string machineName, bool isRemoteMachine)
{
- PerformanceCounterLib library = null;
+ PerformanceCounterLib? library = null;
try
{
library = PerformanceCounterLib.GetPerformanceCounterLib(machineName, new CultureInfo("en"));
for (int i = 0; i < threadInfos.Count; i++)
{
ThreadInfo threadInfo = threadInfos[i];
- if (processInfos.TryGetValue(threadInfo._processId, out ProcessInfo processInfo))
+ if (processInfos.TryGetValue(threadInfo._processId, out ProcessInfo? processInfo))
{
processInfo._threadInfoList.Add(threadInfo);
}
/// </devdoc>
public class ProcessModule : Component
{
- private FileVersionInfo _fileVersionInfo;
+ private FileVersionInfo? _fileVersionInfo;
internal ProcessModule() { }
/// <devdoc>
/// Returns the name of the Module.
/// </devdoc>
- public string ModuleName { get; internal set; }
+ public string? ModuleName { get; internal set; }
/// <devdoc>
/// Returns the full file path for the location of the module.
/// </devdoc>
- public string FileName { get; internal set; }
+ public string? FileName { get; internal set; }
/// <devdoc>
/// Returns the memory address that the module was loaded at.
/// <devdoc>
/// Returns version information about the module.
/// </devdoc>
- public FileVersionInfo FileVersionInfo => _fileVersionInfo ?? (_fileVersionInfo = FileVersionInfo.GetVersionInfo(FileName));
+ public FileVersionInfo FileVersionInfo => _fileVersionInfo ?? (_fileVersionInfo = FileVersionInfo.GetVersionInfo(FileName!));
public override string ToString() => $"{base.ToString()} ({ModuleName})";
}
internal void RemoveAt(int index) => InnerList.RemoveAt(index);
- public ProcessModule this[int index] => (ProcessModule)InnerList[index];
+ public ProcessModule this[int index] => (ProcessModule)InnerList[index]!;
public int IndexOf(ProcessModule module) => InnerList.IndexOf(module);
if (key == null)
return Array.Empty<string>();
- string value = key.GetValue(string.Empty) as string;
+ string? value = key.GetValue(string.Empty) as string;
if (string.IsNullOrEmpty(value))
return Array.Empty<string>();
{
public sealed partial class ProcessStartInfo
{
- private string _domain;
+ private string? _domain;
private const bool CaseSensitiveEnvironmentVariables = false;
- public string PasswordInClearText { get; set; }
+ public string? PasswordInClearText { get; set; }
public string Domain
{
public bool LoadUserProfile { get; set; }
[CLSCompliant(false)]
- public SecureString Password { get; set; }
+ public SecureString? Password { get; set; }
}
}
/// </devdoc>
public sealed partial class ProcessStartInfo
{
- private string _fileName;
- private string _arguments;
- private string _directory;
- private string _userName;
- private string _verb;
- private Collection<string> _argumentList;
+ private string? _fileName;
+ private string? _arguments;
+ private string? _directory;
+ private string? _userName;
+ private string? _verb;
+ private Collection<string>? _argumentList;
private ProcessWindowStyle _windowStyle;
- internal DictionaryWrapper _environmentVariables;
+ internal DictionaryWrapper? _environmentVariables;
/// <devdoc>
/// Default constructor. At least the <see cref='System.Diagnostics.ProcessStartInfo.FileName'/>
public bool CreateNoWindow { get; set; }
- public StringDictionary EnvironmentVariables => new StringDictionaryWrapper(Environment as DictionaryWrapper);
+ public StringDictionary EnvironmentVariables => new StringDictionaryWrapper((Environment as DictionaryWrapper)!);
- public IDictionary<string, string> Environment
+ public IDictionary<string, string?> Environment
{
get
{
IDictionary envVars = System.Environment.GetEnvironmentVariables();
#pragma warning disable 0429 // CaseSensitiveEnvironmentVaribles is constant but varies depending on if we build for Unix or Windows
- _environmentVariables = new DictionaryWrapper(new Dictionary<string, string>(
+ _environmentVariables = new DictionaryWrapper(new Dictionary<string, string?>(
envVars.Count,
CaseSensitiveEnvironmentVariables ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase));
#pragma warning restore 0429
while (e.MoveNext())
{
DictionaryEntry entry = e.Entry;
- _environmentVariables.Add((string)entry.Key, (string)entry.Value);
+ _environmentVariables.Add((string)entry.Key, (string?)entry.Value);
}
}
return _environmentVariables;
public bool RedirectStandardOutput { get; set; }
public bool RedirectStandardError { get; set; }
- public Encoding StandardInputEncoding { get; set; }
+ public Encoding? StandardInputEncoding { get; set; }
- public Encoding StandardErrorEncoding { get; set; }
+ public Encoding? StandardErrorEncoding { get; set; }
- public Encoding StandardOutputEncoding { get; set; }
+ public Encoding? StandardOutputEncoding { get; set; }
/// <devdoc>
/// <para>
/// </devdoc>
public ProcessThread this[int index]
{
- get { return (ProcessThread)InnerList[index]; }
+ get { return (ProcessThread)InnerList[index]!; }
}
/// <devdoc>
{
GC.SuppressFinalize(this);
_state.ReleaseRef();
- _state = null;
+ _state = null!;
}
}
}
{
lock (s_childProcessWaitStates)
{
- ProcessWaitState pws;
+ ProcessWaitState? pws;
if (isNewChild)
{
// When the PID is recycled for a new child, we remove the old child.
/// </summary>
internal void ReleaseRef()
{
- ProcessWaitState pws;
+ ProcessWaitState? pws;
Dictionary<int, ProcessWaitState> waitStates = _isChild ? s_childProcessWaitStates : s_processWaitStates;
lock (waitStates)
{
private readonly bool _usesTerminal;
/// <summary>If a wait operation is in progress, the Task that represents it; otherwise, null.</summary>
- private Task _waitInProgress;
+ private Task? _waitInProgress;
/// <summary>The number of alive users of this object.</summary>
private int _outstandingRefCount;
/// </summary>
private DateTime _exitTime;
/// <summary>A lazily-initialized event set when the process exits.</summary>
- private ManualResetEvent _exitedEvent;
+ private ManualResetEvent? _exitedEvent;
/// <summary>Initialize the wait state object.</summary>
/// <param name="processId">The associated process' ID.</param>
// another operation underway, then we'll just tack ours onto the end of it.
_waitInProgress = _waitInProgress == null ?
WaitForExitAsync() :
- _waitInProgress.ContinueWith((_, state) => ((ProcessWaitState)state).WaitForExitAsync(),
+ _waitInProgress.ContinueWith((_, state) => ((ProcessWaitState)state!).WaitForExitAsync(),
this, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Default).Unwrap();
}
}
while (true)
{
bool createdTask = false;
- CancellationTokenSource cts = null;
+ CancellationTokenSource? cts = null;
Task waitTask;
// We're in a polling loop... determine how much time remains
pid = Interop.Sys.WaitIdAnyExitedNoHangNoWait();
if (pid > 0)
{
- if (s_childProcessWaitStates.TryGetValue(pid, out ProcessWaitState pws))
+ if (s_childProcessWaitStates.TryGetValue(pid, out ProcessWaitState? pws))
{
// Known Process.
if (pws.TryReapChild())
if (checkAll)
{
// We track things to unref so we don't invalidate our iterator by changing s_childProcessWaitStates.
- ProcessWaitState firstToRemove = null;
- List<ProcessWaitState> additionalToRemove = null;
+ ProcessWaitState? firstToRemove = null;
+ List<ProcessWaitState>? additionalToRemove = null;
foreach (KeyValuePair<int, ProcessWaitState> kv in s_childProcessWaitStates)
{
ProcessWaitState pws = kv.Value;