Skip to content

Commit

Permalink
Remove reflection from Environment.WorkingSet prop (#43154)
Browse files Browse the repository at this point in the history
  • Loading branch information
am11 authored Oct 12, 2020
1 parent 94c6054 commit 6a59725
Show file tree
Hide file tree
Showing 14 changed files with 595 additions and 514 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Runtime.InteropServices;

#pragma warning disable CA1823 // analyzer incorrectly flags fixed buffer length const (https://github.com/dotnet/roslyn/issues/37593)

internal static partial class Interop
{
internal static partial class Process
{
// Constants from sys/user.h
private const int TDNAMLEN = 16;
private const int WMESGLEN = 8;
private const int LOGNAMELEN = 17;
private const int LOCKNAMELEN = 8;
private const int COMMLEN = 19;
private const int KI_EMULNAMELEN = 16;
private const int LOGINCLASSLEN = 17;
private const int KI_NGROUPS = 16;

private const int KI_NSPARE_INT = 4;
private const int KI_NSPARE_LONG = 12;
private const int KI_NSPARE_PTR = 6;

// Constants from sys/sysctl.h
private const int CTL_KERN = 1;
private const int KERN_PROC = 14;
private const int KERN_PROC_PROC = 8;
private const int KERN_PROC_PID = 1;
private const int KERN_PROC_INC_THREAD = 16;

// From sys/_sigset.h
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct sigset_t
{
private fixed int bits[4];
}

[StructLayout(LayoutKind.Sequential)]
internal struct uid_t
{
public uint id;
}
[StructLayout(LayoutKind.Sequential)]
internal struct gid_t
{
public uint id;
}
[StructLayout(LayoutKind.Sequential)]
public struct timeval
{
public IntPtr tv_sec;
public IntPtr tv_usec;
}

[StructLayout(LayoutKind.Sequential)]
private struct vnode
{
public long tv_sec;
public long tv_usec;
}

// sys/resource.h
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct rusage
{
public timeval ru_utime; /* user time used */
public timeval ru_stime; /* system time used */
public long ru_maxrss; /* max resident set size */
private long ru_ixrss; /* integral shared memory size */
private long ru_idrss; /* integral unshared data " */
private long ru_isrss; /* integral unshared stack " */
private long ru_minflt; /* page reclaims */
private long ru_majflt; /* page faults */
private long ru_nswap; /* swaps */
private long ru_inblock; /* block input operations */
private long ru_oublock; /* block output operations */
private long ru_msgsnd; /* messages sent */
private long ru_msgrcv; /* messages received */
private long ru_nsignals; /* signals received */
private long ru_nvcsw; /* voluntary context switches */
private long ru_nivcsw; /* involuntary " */
}

// From sys/user.h
[StructLayout(LayoutKind.Sequential)]
public unsafe struct kinfo_proc
{
public int ki_structsize; /* size of this structure */
private int ki_layout; /* reserved: layout identifier */
private void* ki_args; /* address of command arguments */
private void* ki_paddr; /* address of proc */
private void* ki_addr; /* kernel virtual addr of u-area */
private vnode* ki_tracep; /* pointer to trace file */
private vnode* ki_textvp; /* pointer to executable file */
private void* ki_fd; /* pointer to open file info */
private void* ki_vmspace; /* pointer to kernel vmspace struct */
private void* ki_wchan; /* sleep address */
public int ki_pid; /* Process identifier */
public int ki_ppid; /* parent process id */
private int ki_pgid; /* process group id */
private int ki_tpgid; /* tty process group id */
public int ki_sid; /* Process session ID */
public int ki_tsid; /* Terminal session ID */
private short ki_jobc; /* job control counter */
private short ki_spare_short1; /* unused (just here for alignment) */
private int ki_tdev; /* controlling tty dev */
private sigset_t ki_siglist; /* Signals arrived but not delivered */
private sigset_t ki_sigmask; /* Current signal mask */
private sigset_t ki_sigignore; /* Signals being ignored */
private sigset_t ki_sigcatch; /* Signals being caught by user */
public uid_t ki_uid; /* effective user id */
private uid_t ki_ruid; /* Real user id */
private uid_t ki_svuid; /* Saved effective user id */
private gid_t ki_rgid; /* Real group id */
private gid_t ki_svgid; /* Saved effective group id */
private short ki_ngroups; /* number of groups */
private short ki_spare_short2; /* unused (just here for alignment) */
private fixed uint ki_groups[KI_NGROUPS]; /* groups */
public ulong ki_size; /* virtual size */
public long ki_rssize; /* current resident set size in pages */
private long ki_swrss; /* resident set size before last swap */
private long ki_tsize; /* text size (pages) XXX */
private long ki_dsize; /* data size (pages) XXX */
private long ki_ssize; /* stack size (pages) */
private ushort ki_xstat; /* Exit status for wait & stop signal */
private ushort ki_acflag; /* Accounting flags */
private uint ki_pctcpu; /* %cpu for process during ki_swtime */
private uint ki_estcpu; /* Time averaged value of ki_cpticks */
private uint ki_slptime; /* Time since last blocked */
private uint ki_swtime; /* Time swapped in or out */
private uint ki_cow; /* number of copy-on-write faults */
private ulong ki_runtime; /* Real time in microsec */
public timeval ki_start; /* starting time */
private timeval ki_childtime; /* time used by process children */
private long ki_flag; /* P_* flags */
private long ki_kiflag; /* KI_* flags (below) */
private int ki_traceflag; /* Kernel trace points */
private byte ki_stat; /* S* process status */
public byte ki_nice; /* Process "nice" value */
private byte ki_lock; /* Process lock (prevent swap) count */
private byte ki_rqindex; /* Run queue index */
private byte ki_oncpu_old; /* Which cpu we are on (legacy) */
private byte ki_lastcpu_old; /* Last cpu we were on (legacy) */
public fixed byte ki_tdname[TDNAMLEN+1]; /* thread name */
private fixed byte ki_wmesg[WMESGLEN+1]; /* wchan message */
private fixed byte ki_login[LOGNAMELEN+1]; /* setlogin name */
private fixed byte ki_lockname[LOCKNAMELEN+1]; /* lock name */
public fixed byte ki_comm[COMMLEN+1]; /* command name */
private fixed byte ki_emul[KI_EMULNAMELEN+1]; /* emulation name */
private fixed byte ki_loginclass[LOGINCLASSLEN+1]; /* login class */
private fixed byte ki_sparestrings[50]; /* spare string space */
private fixed int ki_spareints[KI_NSPARE_INT]; /* spare room for growth */
private int ki_oncpu; /* Which cpu we are on */
private int ki_lastcpu; /* Last cpu we were on */
private int ki_tracer; /* Pid of tracing process */
private int ki_flag2; /* P2_* flags */
private int ki_fibnum; /* Default FIB number */
private uint ki_cr_flags; /* Credential flags */
private int ki_jid; /* Process jail ID */
public int ki_numthreads; /* XXXKSE number of threads in total */
public int ki_tid; /* XXXKSE thread id */
private fixed byte ki_pri[4]; /* process priority */
public rusage ki_rusage; /* process rusage statistics */
/* XXX - most fields in ki_rusage_ch are not (yet) filled in */
private rusage ki_rusage_ch; /* rusage of children processes */
private void* ki_pcb; /* kernel virtual addr of pcb */
private void* ki_kstack; /* kernel virtual addr of stack */
private void* ki_udata; /* User convenience pointer */
public void* ki_tdaddr; /* address of thread */

private fixed long ki_spareptrs[KI_NSPARE_PTR]; /* spare room for growth */
private fixed long ki_sparelongs[KI_NSPARE_LONG]; /* spare room for growth */
private long ki_sflag; /* PS_* flags */
private long ki_tdflags; /* XXXKSE kthread flag */
}

/// <summary>
/// Gets information about process or thread(s)
/// </summary>
/// <param name="pid">The PID of the process. If PID is 0, this will return all processes</param>
/// <param name="threads">Whether to include thread information.</param>
/// <param name="count">The number of kinfo_proc entries returned.</param>
public static unsafe kinfo_proc* GetProcInfo(int pid, bool threads, out int count)
{
Span<int> sysctlName = stackalloc int[4];
int bytesLength = 0;
byte* pBuffer = null;
kinfo_proc* kinfo = null;
int ret;

count = -1;

if (pid == 0)
{
// get all processes
sysctlName[3] = 0;
sysctlName[2] = KERN_PROC_PROC;
}
else
{
// get specific process, possibly with threads
sysctlName[3] = pid;
sysctlName[2] = KERN_PROC_PID | (threads ? KERN_PROC_INC_THREAD : 0);
}
sysctlName[1] = KERN_PROC;
sysctlName[0] = CTL_KERN;

try
{
ret = Interop.Sys.Sysctl(sysctlName, ref pBuffer, ref bytesLength);
if (ret != 0 ) {
throw new ArgumentOutOfRangeException(nameof(pid));
}

kinfo = (kinfo_proc*)pBuffer;
if (kinfo->ki_structsize != sizeof(kinfo_proc))
{
// failed consistency check
throw new ArgumentOutOfRangeException(nameof(pid));
}

count = (int)bytesLength / sizeof(kinfo_proc);
}
catch
{
Marshal.FreeHGlobal((IntPtr)pBuffer);
throw;
}

return kinfo;
}
}
}
Loading

0 comments on commit 6a59725

Please sign in to comment.