Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions src/Common/src/Interop/Linux/procfs/Interop.ProcFsStat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@ internal static partial class Interop
internal static partial class procfs
{
internal const string RootPath = "/proc/";
internal const string SelfExeFilePath = RootPath + "self/exe";
internal const string ProcUptimeFilePath = RootPath + "uptime";
private const string ExeFileName = "/exe";
private const string StatFileName = "/stat";
private const string MapsFileName = "/maps";
private const string FileDescriptorDirectoryName = "/fd/";
private const string TaskDirectoryName = "/task/";

internal const string SelfExeFilePath = RootPath + "self" + ExeFileName;
internal const string ProcUptimeFilePath = RootPath + "uptime";

internal struct ParsedStat
{
// Commented out fields are available in the stat data file but
Expand Down Expand Up @@ -80,6 +82,11 @@ internal struct ParsedMapsModule
internal KeyValuePair<long, long> AddressRange;
}

internal static string GetExeFilePathForProcess(int pid)
{
return RootPath + pid.ToString(CultureInfo.InvariantCulture) + ExeFileName;
}

internal static string GetStatFilePathForProcess(int pid)
{
return RootPath + pid.ToString(CultureInfo.InvariantCulture) + StatFileName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,9 +186,14 @@ private void SetWorkingSetLimitsCore(IntPtr? newMin, IntPtr? newMax, out IntPtr
// ---- 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()
/// <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)
{
string exeFilePath = processId == -1 ?
Interop.procfs.SelfExeFilePath :
Interop.procfs.GetExeFilePathForProcess(processId);

// Determine the maximum size of a path
int maxPath = Interop.Sys.MaxPath;

Expand All @@ -197,7 +202,7 @@ private static string GetExePath()
{
// Read from procfs the symbolic link to this process' executable
byte[] buffer = new byte[pathLen + 1]; // +1 for null termination
int resultLength = Interop.Sys.ReadLink(Interop.procfs.SelfExeFilePath, buffer, pathLen);
int resultLength = Interop.Sys.ReadLink(exeFilePath, buffer, pathLen);

// If we got one, null terminate it (readlink doesn't do this) and return the string
if (resultLength > 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,22 @@ internal static ProcessModuleCollection GetModules(int processId)
}
}

// Move the main executable module to be the first in the list if it's not already
string exePath = Process.GetExePath(processId);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A nit - what if we didn't add the main module in the loop above and just stored it in a local? Then we would not have to loop here over all at modules and we could just insert that module to the first position of the list.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That causes complications if the module is split across multiple entries. And in the vast majority of cases (all we've seen thus far until Alpine in docker), the extra loop will just check the first entry and exit as the main module will already be first.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, right, I've forgotten about that.

for (int i = 0; i < modules.Count; i++)
{
ProcessModule module = modules[i];
if (module.FileName == exePath)
{
if (i > 0)
{
modules.RemoveAt(i);
modules.Insert(0, module);
}
break;
}
}

// Return the set of modules found
return modules;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ internal ProcessModuleCollection(int capacity)

internal void Add(ProcessModule module) => InnerList.Add(module);

internal void Insert(int index, ProcessModule module) => InnerList.Insert(index, module);

internal void RemoveAt(int index) => InnerList.RemoveAt(index);

public ProcessModule this[int index] => (ProcessModule)InnerList[index];

public int IndexOf(ProcessModule module) => InnerList.IndexOf(module);
Expand Down