--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using System.Text;
+
+using size_t = System.IntPtr;
+
+// This implements shim for sysctl calls.
+// They are available on BSD systems - FreeBSD, OSX and others.
+// Linux has sysctl() but it is deprecated as well as it is missing sysctlbyname()
+
+internal static partial class Interop
+{
+ internal static partial class Sys
+ {
+
+ [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_Sysctl", SetLastError = true)]
+ private extern static unsafe int Sysctl(int* name, int namelen, void* value, size_t* len);
+
+ // This is 'raw' sysctl call, only wrapped to allocate memory if needed
+ // caller always needs to free returned buffer using Marshal.FreeHGlobal()
+
+ public static unsafe int Sysctl(Span<int> name, ref byte* value, ref int len)
+ {
+ fixed (int * ptr = &name.DangerousGetPinnableReference())
+ {
+ return Sysctl(ptr, name.Length, ref value, ref len);
+ }
+ }
+
+ public static unsafe int Sysctl(int* name, int name_len, ref byte* value, ref int len)
+ {
+ IntPtr bytesLength = (IntPtr)len;
+ byte * pBuffer = value;
+ value = null;
+ int ret=-1;
+
+ if (value == null && len == 0)
+ {
+ // do one try to see how much data we need
+ ret = Sysctl(name, name_len, pBuffer, &bytesLength);
+ if (ret != 0)
+ {
+ throw new InvalidOperationException(string.Format("sysctl returned {0}", ret));
+ }
+ pBuffer = (byte*)Marshal.AllocHGlobal((int)bytesLength);
+ }
+ ret = Sysctl(name, name_len, pBuffer, &bytesLength);
+ if (ret != 0)
+ {
+ if (value == null && len == 0)
+ {
+ // This is case we allocated memory for caller
+ Marshal.FreeHGlobal((IntPtr)pBuffer);
+ }
+ throw new InvalidOperationException(string.Format("sysctl returned {0}", ret));
+ }
+
+ value = pBuffer;
+ len = (int)bytesLength;
+
+ return ret;
+ }
+ }
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+
+
+internal static partial class Interop
+{
+ internal static partial class Process
+ {
+ private const ulong SecondsToNanoSeconds = 1000000000;
+
+ // Constants from sys/syslimits.h
+ private const int PATH_MAX = 1024;
+
+ // 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/_sigset.h
+ private const int _SIG_WORDS = 4;
+
+ // Constants from sys/sysctl.h
+ private const int CTL_KERN = 1;
+ private const int KERN_PROC = 14;
+ private const int KERN_PROC_PATHNAME = 12;
+ private const int KERN_PROC_PROC = 8;
+ private const int KERN_PROC_ALL = 0;
+ private const int KERN_PROC_PID = 1;
+ private const int KERN_PROC_INC_THREAD = 16;
+
+ // Constants from proc_info.h
+ private const int MAXTHREADNAMESIZE = 64;
+ private const int PROC_PIDTASKALLINFO = 2;
+ private const int PROC_PIDTHREADINFO = 5;
+ private const int PROC_PIDLISTTHREADS = 6;
+ private const int PROC_PIDPATHINFO_MAXSIZE = 4 * PATH_MAX;
+
+ internal struct proc_stats
+ {
+ internal long startTime; /* time_t */
+ internal int nice;
+ internal ulong userTime; /* in ticks */
+ internal ulong systemTime; /* in ticks */
+ }
+
+ // 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)]
+ 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>
+ /// Queries the OS for the list of all running processes and returns the PID for each
+ /// </summary>
+ /// <returns>Returns a list of PIDs corresponding to all running processes</returns>
+ internal static unsafe int[] ListAllPids()
+ {
+ int numProcesses = 0;
+ int[] pids;
+ kinfo_proc * entries = null;
+ int idx;
+
+ try
+ {
+ entries = GetProcInfo(0, false, out numProcesses);
+ if (entries == null || numProcesses <= 0)
+ {
+ throw new Win32Exception(SR.CantGetAllPids);
+ }
+
+ Span<kinfo_proc> list = new Span<kinfo_proc>(entries, numProcesses);
+ pids = new int[numProcesses];
+ idx = 0;
+ // walk through process list and skip kernel threads
+ for (int i = 0; i < list.Length; i++)
+ {
+ if (list[i].ki_ppid == 0)
+ {
+ // skip kernel threads
+ numProcesses-=1;
+ }
+ else
+ {
+ pids[idx] = list[i].ki_pid;
+ idx += 1;
+ }
+ }
+ // Remove extra elements
+ Array.Resize<int>(ref pids, numProcesses);
+ }
+ finally
+ {
+ Marshal.FreeHGlobal((IntPtr)entries);
+ }
+ return pids;
+ }
+
+
+ /// <summary>
+ /// 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)
+ {
+ Span<int> sysctlName = stackalloc int[4];
+ byte* pBuffer = null;
+ int bytesLength = 0;
+
+ sysctlName[0] = CTL_KERN;
+ sysctlName[1] = KERN_PROC;
+ sysctlName[2] = KERN_PROC_PATHNAME;
+ sysctlName[3] = pid;
+
+ int ret = Interop.Sys.Sysctl(sysctlName, ref pBuffer, ref bytesLength);
+ if (ret != 0 ) {
+ return null;
+ }
+ return System.Text.Encoding.UTF8.GetString(pBuffer,(int)bytesLength-1);
+ }
+
+ /// <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>
+ 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;
+ }
+
+ /// <summary>
+ /// Gets the process information for a given process
+ /// </summary>
+ /// <param name="pid">The PID (process ID) of the process</param>
+ /// <returns>
+ /// Returns a valid ProcessInfo struct for valid processes that the caller
+ /// has permission to access; otherwise, returns null
+ /// </returns>
+ static public unsafe ProcessInfo GetProcessInfoById(int pid)
+ {
+ kinfo_proc* kinfo = null;
+ int count;
+ ProcessInfo info;
+
+ // Negative PIDs are invalid
+ if (pid < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(pid));
+ }
+
+ try
+ {
+ kinfo = GetProcInfo(pid, true, out count);
+ if (kinfo == null || count < 1)
+ {
+ throw new ArgumentOutOfRangeException(nameof(pid));
+ }
+
+ Span<kinfo_proc> process = new Span<kinfo_proc>(kinfo, count);
+
+ // Get the process information for the specified pid
+ info = new ProcessInfo();
+
+ info.ProcessName = Marshal.PtrToStringAnsi((IntPtr)kinfo->ki_comm);
+ info.BasePriority = kinfo->ki_nice;
+ info.VirtualBytes = (long)kinfo->ki_size;
+ info.WorkingSet = kinfo->ki_rssize;
+ info.SessionId = kinfo ->ki_sid;
+
+ for(int i = 0; i < process.Length; i++)
+ {
+ var ti = new ThreadInfo()
+ {
+ _processId = pid,
+ _threadId = (ulong)process[i].ki_tid,
+ _basePriority = process[i].ki_nice,
+ _startAddress = (IntPtr)process[i].ki_tdaddr
+ };
+ info._threadInfoList.Add(ti);
+ }
+ }
+ finally
+ {
+ Marshal.FreeHGlobal((IntPtr)kinfo);
+ }
+
+ return info;
+ }
+
+ /// <summary>
+ /// Gets the process information for a given process
+ /// </summary>
+ //
+ /// <param name="pid">The PID (process ID) of the process</param>
+ /// <param name="tid">The TID (thread ID) of the process</param>
+ /// <returns>
+ /// Returns basic info about thread. If tis is 0, it will return
+ /// info for process e.g. main thread.
+ /// </returns>
+ public unsafe static proc_stats GetThreadInfo(int pid, int tid)
+ {
+ proc_stats ret = new proc_stats();
+ kinfo_proc* info = null;
+ int count;
+
+ try
+ {
+ info = GetProcInfo(pid, (tid != 0), out count);
+ if (info != null && count >= 1)
+ {
+ if (tid == 0)
+ {
+ ret.startTime = (int)info->ki_start.tv_sec;
+ ret.nice = info->ki_nice;
+ ret.userTime = (ulong)info->ki_rusage.ru_utime.tv_sec * SecondsToNanoSeconds + (ulong)info->ki_rusage.ru_utime.tv_usec;
+ ret.systemTime = (ulong)info->ki_rusage.ru_stime.tv_sec * SecondsToNanoSeconds + (ulong)info->ki_rusage.ru_stime.tv_usec;
+ }
+ else
+ {
+ Span<kinfo_proc> list = new Span<kinfo_proc>(info, count);
+ for(int i = 0; i < list.Length; i++)
+ {
+ if (list[i].ki_tid == tid)
+ {
+ ret.startTime = (int)list[i].ki_start.tv_sec;
+ ret.nice = list[i].ki_nice;
+ ret.userTime = (ulong)list[i].ki_rusage.ru_utime.tv_sec * SecondsToNanoSeconds + (ulong)list[i].ki_rusage.ru_utime.tv_usec;
+ ret.systemTime = (ulong)list[i].ki_rusage.ru_stime.tv_sec * SecondsToNanoSeconds + (ulong)list[i].ki_rusage.ru_stime.tv_usec;
+ break;
+ }
+ }
+ }
+ }
+ }
+ finally
+ {
+ Marshal.FreeHGlobal((IntPtr)info);
+ }
+
+ return ret;
+ }
+ }
+}
public static bool IsInvokingStaticConstructorsSupported { get { throw null; } }
public static bool IsMacOsHighSierraOrHigher { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
public static bool IsNetBSD { get { throw null; } }
+ public static bool IsFreeBSD { get { throw null; } }
public static bool IsNetCore { get { throw null; } }
public static bool IsNetNative { get { throw null; } }
public static bool IsNonZeroLowerBoundArraySupported { get { throw null; } }
public static bool IsNetNative => RuntimeInformation.FrameworkDescription.StartsWith(".NET Native", StringComparison.OrdinalIgnoreCase);
public static bool IsNetCore => RuntimeInformation.FrameworkDescription.StartsWith(".NET Core", StringComparison.OrdinalIgnoreCase);
public static bool IsOSX => RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
+ public static bool IsFreeBSD => RuntimeInformation.IsOSPlatform(OSPlatform.Create("FREEBSD"));
public static bool IsNetBSD => RuntimeInformation.IsOSPlatform(OSPlatform.Create("NETBSD"));
public static bool IsNotWindows8x => !IsWindows8x;
public static bool IsNotWindowsNanoServer => !IsWindowsNanoServer;
pal_time.cpp
pal_uid.cpp
pal_datetime.cpp
+ pal_sysctl.cpp
)
if (CMAKE_SYSTEM_NAME STREQUAL Linux)
target_link_libraries(System.Native rt)
endif ()
+if (CMAKE_SYSTEM_NAME STREQUAL FreeBSD)
+ target_link_libraries(System.Native pthread)
+endif ()
+
install_library_and_symbols (System.Native)
install (TARGETS System.Native-Static DESTINATION .)
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "pal_config.h"
+
+// These functions are only used for platforms which support
+// using sysctl to gather system information.
+
+#if HAVE_SYS_SYSCTL_H
+
+#include "pal_utilities.h"
+#include "pal_sysctl.h"
+#include "pal_errno.h"
+#include "pal_safecrt.h"
+
+#include <errno.h>
+#include <memory>
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+extern "C" int32_t SystemNative_Sysctl(int* name, unsigned int namelen, void* value, size_t* len)
+{
+ void* newp = nullptr;
+ size_t newlen = 0;
+
+#ifdef __linux__
+ return sysctl(name, static_cast<int>(namelen), value, len, newp, newlen);
+#else
+ return sysctl(name, namelen, value, len, newp, newlen);
+#endif
+}
+
+#endif // HAVE_SYSCTL_H
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#pragma once
+
+#include "pal_types.h"
+#include "pal_errno.h"
+
+
+extern "C" int32_t SystemNative_Sysctl(int* name, unsigned int namelen, void* value, size_t* len);
+
)
check_include_files(
- sys/sysctl.h
+ "sys/types.h;sys/sysctl.h"
HAVE_SYS_SYSCTL_H)
check_include_files(
__HostDistroRid="rhel.6-$__HostArch"
fi
fi
+ elif [ "$__HostOS" == "FreeBSD" ]; then
+ __freebsd_version=`sysctl -n kern.osrelease | cut -f1 -d'.'`
+ __HostDistroRid="freebsd.$__freebsd_version-x64"
fi
+
if [ "$__HostDistroRid" == "" ]; then
echo "WARNING: Can not determine runtime id for current distro."
fi
__BuildType=Release
__CMakeArgs=RELEASE
;;
- freebsd|-freebsd)
+ freebsd|FreeBSD|-freebsd|-FreeBSD)
__BuildOS=FreeBSD
;;
linux|-linux)
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<BuildConfigurations>
+ netcoreapp-FreeBSD;
netcoreapp-Linux;
netcoreapp-OSX;
netcoreapp-Windows_NT;
uap-Windows_NT;
</BuildConfigurations>
</PropertyGroup>
-</Project>
\ No newline at end of file
+</Project>
</Compile>
</ItemGroup>
<ItemGroup Condition=" '$(TargetsOSX)' == 'true'">
+ <Compile Include="System\Diagnostics\Process.BSD.cs" />
<Compile Include="System\Diagnostics\Process.OSX.cs" />
+ <Compile Include="System\Diagnostics\ProcessManager.BSD.cs" />
<Compile Include="System\Diagnostics\ProcessManager.OSX.cs" />
<Compile Include="System\Diagnostics\ProcessThread.OSX.cs" />
<Compile Include="$(CommonPath)\Interop\OSX\Interop.libproc.cs">
<Compile Include="System\Diagnostics\ProcessManager.Uap.cs" />
<Compile Include="System\Diagnostics\ProcessStartInfo.Uap.cs" />
</ItemGroup>
- <ItemGroup Condition=" ('$(TargetsFreeBSD)' == 'true' OR '$(TargetsUnknownUnix)' == 'true')">
+ <ItemGroup Condition=" '$(TargetsFreeBSD)' == 'true'">
+ <Compile Include="System\Diagnostics\Process.BSD.cs" />
+ <Compile Include="System\Diagnostics\Process.FreeBSD.cs" />
+ <Compile Include="System\Diagnostics\ProcessManager.BSD.cs" />
+ <Compile Include="System\Diagnostics\ProcessManager.FreeBSD.cs" />
+ <Compile Include="System\Diagnostics\ProcessThread.FreeBSD.cs" />
+ <Compile Include="$(CommonPath)\Interop\BSD\System.Native\Interop.Sysctl.cs">
+ <Link>Common\Interop\BSD\System.Native\Interop.Sysctl.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\FreeBSD\Interop.Process.cs">
+ <Link>Common\Interop\FreeBSD\Interop.Process.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.GetTimestamp.cs">
+ <Link>Common\Unix\System.Native\Interop.GetTimestamp.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.Stat.cs">
+ <Link>Common\Unix\System.Native\Interop.Stat.cs</Link>
+ </Compile>
+ </ItemGroup>
+ <ItemGroup Condition=" ('$(TargetsUnknownUnix)' == 'true')">
<Compile Include="System\Diagnostics\Process.UnknownUnix.cs" />
<Compile Include="System\Diagnostics\ProcessManager.UnknownUnix.cs" />
<Compile Include="System\Diagnostics\ProcessThread.UnknownUnix.cs" />
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.ComponentModel;
+
+namespace System.Diagnostics
+{
+ public partial class Process
+ {
+ /// <summary>
+ /// 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)
+ {
+ if (processName == null)
+ {
+ processName = string.Empty;
+ }
+
+ Process[] procs = GetProcesses(machineName);
+ var list = new List<Process>();
+
+ for (int i = 0; i < procs.Length; i++)
+ {
+ if (string.Equals(processName, procs[i].ProcessName, StringComparison.OrdinalIgnoreCase))
+ {
+ list.Add(procs[i]);
+ }
+ else
+ {
+ procs[i].Dispose();
+ }
+ }
+
+ return list.ToArray();
+ }
+
+ /// <summary>
+ /// Gets or sets which processors the threads in this process can be scheduled to run on.
+ /// </summary>
+ private unsafe IntPtr ProcessorAffinityCore
+ {
+ get
+ {
+ throw new PlatformNotSupportedException(SR.ProcessorAffinityNotSupported);
+ }
+ set
+ {
+ throw new PlatformNotSupportedException(SR.ProcessorAffinityNotSupported);
+ }
+ }
+
+
+ /// <summary>
+ /// Make sure we have obtained the min and max working set limits.
+ /// </summary>
+ private void GetWorkingSetLimits(out IntPtr minWorkingSet, out IntPtr maxWorkingSet)
+ {
+ // We can only do this for the current process on OS X
+ if (_processId != Interop.Sys.GetPid())
+ throw new PlatformNotSupportedException(SR.OsxExternalProcessWorkingSetNotSupported);
+
+ // Minimum working set (or resident set, as it is called on *nix) doesn't exist so set to 0
+ minWorkingSet = IntPtr.Zero;
+
+ // Get the max working set size
+ Interop.Sys.RLimit limit;
+ if (Interop.Sys.GetRLimit(Interop.Sys.RlimitResources.RLIMIT_RSS, out limit) == 0)
+ {
+ maxWorkingSet = limit.CurrentLimit == Interop.Sys.RLIM_INFINITY ?
+ new IntPtr(Int64.MaxValue) :
+ new IntPtr(Convert.ToInt64(limit.CurrentLimit));
+ }
+ else
+ {
+ // The contract specifies that this throws Win32Exception when it failes to retrieve the info
+ throw new Win32Exception();
+ }
+ }
+
+ /// <summary>Sets one or both of the minimum and maximum working set limits.</summary>
+ /// <param name="newMin">The new minimum working set limit, or null not to change it.</param>
+ /// <param name="newMax">The new maximum working set limit, or null not to change it.</param>
+ /// <param name="resultingMin">The resulting minimum working set limit after any changes applied.</param>
+ /// <param name="resultingMax">The resulting maximum working set limit after any changes applied.</param>
+ private void SetWorkingSetLimitsCore(IntPtr? newMin, IntPtr? newMax, out IntPtr resultingMin, out IntPtr resultingMax)
+ {
+ // We can only do this for the current process on OS X
+ if (_processId != Interop.Sys.GetPid())
+ throw new PlatformNotSupportedException(SR.OsxExternalProcessWorkingSetNotSupported);
+
+ // There isn't a way to set the minimum working set, so throw an exception here
+ if (newMin.HasValue)
+ {
+ throw new PlatformNotSupportedException(SR.MinimumWorkingSetNotSupported);
+ }
+
+ // The minimum resident set will always be 0, default the resulting max to 0 until we set it (to make the compiler happy)
+ resultingMin = IntPtr.Zero;
+ resultingMax = IntPtr.Zero;
+
+ // The default hard upper limit is absurdly high (over 9000PB) so just change the soft limit...especially since
+ // if you aren't root and move the upper limit down, you need root to move it back up
+ if (newMax.HasValue)
+ {
+ Interop.Sys.RLimit limits = new Interop.Sys.RLimit() { CurrentLimit = (ulong)newMax.Value.ToInt64() };
+ int result = Interop.Sys.SetRLimit(Interop.Sys.RlimitResources.RLIMIT_RSS, ref limits);
+ if (result != 0)
+ {
+ throw new System.ComponentModel.Win32Exception(SR.RUsageFailure);
+ }
+
+ // Try to grab the actual value, in case the OS decides to fudge the numbers
+ result = Interop.Sys.GetRLimit(Interop.Sys.RlimitResources.RLIMIT_RSS, out limits);
+ if (result == 0) resultingMax = new IntPtr((long)limits.CurrentLimit);
+ }
+ }
+ }
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.ComponentModel;
+
+namespace System.Diagnostics
+{
+ public partial class Process
+ {
+ /// <summary>Gets the time the associated process was started.</summary>
+ internal DateTime StartTimeCore
+ {
+ get
+ {
+ EnsureState(State.HaveId);
+ Interop.Process.proc_stats stat = Interop.Process.GetThreadInfo(_processId, 0);
+
+ return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(stat.startTime);
+ }
+ }
+
+ /// <summary>
+ /// Gets the amount of time the associated process has spent utilizing the CPU.
+ /// It is the sum of the <see cref='System.Diagnostics.Process.UserProcessorTime'/> and
+ /// <see cref='System.Diagnostics.Process.PrivilegedProcessorTime'/>.
+ /// </summary>
+ public TimeSpan TotalProcessorTime
+ {
+ get
+ {
+ EnsureState(State.HaveId);
+ Interop.Process.proc_stats stat = Interop.Process.GetThreadInfo(_processId, 0);
+ return Process.TicksToTimeSpan(stat.userTime + stat.systemTime);
+ }
+ }
+
+ /// <summary>
+ /// Gets the amount of time the associated process has spent running code
+ /// inside the application portion of the process (not the operating system core).
+ /// </summary>
+ public TimeSpan UserProcessorTime
+ {
+ get
+ {
+ EnsureState(State.HaveId);
+
+ Interop.Process.proc_stats stat = Interop.Process.GetThreadInfo(_processId, 0);
+ return Process.TicksToTimeSpan(stat.userTime);
+ }
+ }
+
+ /// <summary>Gets the amount of time the process has spent running code inside the operating system core.</summary>
+ public TimeSpan PrivilegedProcessorTime
+ {
+ get
+ {
+ EnsureState(State.HaveId);
+
+ Interop.Process.proc_stats stat = Interop.Process.GetThreadInfo(_processId, 0);
+ return Process.TicksToTimeSpan(stat.systemTime);
+ }
+ }
+
+ // <summary>Gets execution path</summary>
+ private string GetPathToOpenFile()
+ {
+ Interop.Sys.FileStatus stat;
+ if (Interop.Sys.Stat("/usr/local/bin/open", out stat) == 0 )
+ {
+ return "/usr/local/bin/open";
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ // -----------------------------
+ // ---- 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()
+ {
+ return Interop.Process.GetProcPath(Interop.Sys.GetPid());
+ }
+
+ // ----------------------------------
+ // ---- Unix PAL layer ends here ----
+ // ----------------------------------
+
+
+ }
+}
{
public partial class Process
{
- /// <summary>
- /// 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)
- {
- if (processName == null)
- {
- processName = string.Empty;
- }
-
- Process[] procs = GetProcesses(machineName);
- var list = new List<Process>();
-
- for (int i = 0; i < procs.Length; i++)
- {
- if (string.Equals(processName, procs[i].ProcessName, StringComparison.OrdinalIgnoreCase))
- {
- list.Add(procs[i]);
- }
- else
- {
- procs[i].Dispose();
- }
- }
-
- return list.ToArray();
- }
-
/// <summary>Gets the amount of time the process has spent running code inside the operating system core.</summary>
public TimeSpan PrivilegedProcessorTime
{
}
}
- /// <summary>
- /// Gets or sets which processors the threads in this process can be scheduled to run on.
- /// </summary>
- private unsafe IntPtr ProcessorAffinityCore
- {
- get
- {
- throw new PlatformNotSupportedException(SR.ProcessorAffinityNotSupported);
- }
- set
- {
- throw new PlatformNotSupportedException(SR.ProcessorAffinityNotSupported);
- }
- }
-
-
- /// <summary>
- /// Make sure we have obtained the min and max working set limits.
- /// </summary>
- private void GetWorkingSetLimits(out IntPtr minWorkingSet, out IntPtr maxWorkingSet)
- {
- // We can only do this for the current process on OS X
- if (_processId != Interop.Sys.GetPid())
- throw new PlatformNotSupportedException(SR.OsxExternalProcessWorkingSetNotSupported);
-
- // Minimum working set (or resident set, as it is called on *nix) doesn't exist so set to 0
- minWorkingSet = IntPtr.Zero;
-
- // Get the max working set size
- Interop.Sys.RLimit limit;
- if (Interop.Sys.GetRLimit(Interop.Sys.RlimitResources.RLIMIT_RSS, out limit) == 0)
- {
- maxWorkingSet = limit.CurrentLimit == Interop.Sys.RLIM_INFINITY ?
- new IntPtr(Int64.MaxValue) :
- new IntPtr(Convert.ToInt64(limit.CurrentLimit));
- }
- else
- {
- // The contract specifies that this throws Win32Exception when it failes to retrieve the info
- throw new Win32Exception();
- }
- }
-
- /// <summary>Sets one or both of the minimum and maximum working set limits.</summary>
- /// <param name="newMin">The new minimum working set limit, or null not to change it.</param>
- /// <param name="newMax">The new maximum working set limit, or null not to change it.</param>
- /// <param name="resultingMin">The resulting minimum working set limit after any changes applied.</param>
- /// <param name="resultingMax">The resulting maximum working set limit after any changes applied.</param>
- private void SetWorkingSetLimitsCore(IntPtr? newMin, IntPtr? newMax, out IntPtr resultingMin, out IntPtr resultingMax)
- {
- // We can only do this for the current process on OS X
- if (_processId != Interop.Sys.GetPid())
- throw new PlatformNotSupportedException(SR.OsxExternalProcessWorkingSetNotSupported);
-
- // There isn't a way to set the minimum working set, so throw an exception here
- if (newMin.HasValue)
- {
- throw new PlatformNotSupportedException(SR.MinimumWorkingSetNotSupported);
- }
-
- // The minimum resident set will always be 0, default the resulting max to 0 until we set it (to make the compiler happy)
- resultingMin = IntPtr.Zero;
- resultingMax = IntPtr.Zero;
-
- // The default hard upper limit is absurdly high (over 9000PB) so just change the soft limit...especially since
- // if you aren't root and move the upper limit down, you need root to move it back up
- if (newMax.HasValue)
- {
- Interop.Sys.RLimit limits = new Interop.Sys.RLimit() { CurrentLimit = (ulong)newMax.Value.ToInt64() };
- int result = Interop.Sys.SetRLimit(Interop.Sys.RlimitResources.RLIMIT_RSS, ref limits);
- if (result != 0)
- {
- throw new System.ComponentModel.Win32Exception(SR.RUsageFailure);
- }
-
- // Try to grab the actual value, in case the OS decides to fudge the numbers
- result = Interop.Sys.GetRLimit(Interop.Sys.RlimitResources.RLIMIT_RSS, out limits);
- if (result == 0) resultingMax = new IntPtr((long)limits.CurrentLimit);
- }
- }
-
// -----------------------------
// ---- PAL layer ends here ----
// -----------------------------
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.IO;
+using System.Runtime.InteropServices;
+
+namespace System.Diagnostics
+{
+ internal static partial class ProcessManager
+ {
+ /// <summary>Gets process infos for each process on the specified machine.</summary>
+ /// <param name="machineName">The target machine.</param>
+ /// <returns>An array of process infos, one per found process.</returns>
+ public static ProcessInfo[] GetProcessInfos(string machineName)
+ {
+ ThrowIfRemoteMachine(machineName);
+ int[] procIds = GetProcessIds(machineName);
+
+ // Iterate through all process IDs to load information about each process
+ var processes = new List<ProcessInfo>(procIds.Length);
+ foreach (int pid in procIds)
+ {
+ ProcessInfo pi = CreateProcessInfo(pid);
+ if (pi != null)
+ {
+ processes.Add(pi);
+ }
+ }
+
+ return processes.ToArray();
+ }
+
+ /// <summary>Gets an array of module infos for the specified process.</summary>
+ /// <param name="processId">The ID of the process whose modules should be enumerated.</param>
+ /// <returns>The array of modules.</returns>
+ internal static ProcessModuleCollection GetModules(int processId)
+ {
+ // We don't have a good way of getting all of the modules of the particular process,
+ // but we can at least get the path to the executable file for the process, and
+ // other than for debugging tools, that's the main reason consumers of Modules care about it,
+ // and why MainModule exists.
+ try
+ {
+ string exePath = GetProcPath(processId);
+ if (!string.IsNullOrEmpty(exePath))
+ {
+ return new ProcessModuleCollection(1)
+ {
+ new ProcessModule()
+ {
+ FileName = exePath,
+ ModuleName = Path.GetFileName(exePath)
+ }
+ };
+ }
+ }
+ catch { } // eat all errors
+
+ return new ProcessModuleCollection(0);
+ }
+ }
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.IO;
+using System.Runtime.InteropServices;
+
+namespace System.Diagnostics
+{
+ internal static partial class ProcessManager
+ {
+ /// <summary>Gets the IDs of all processes on the current machine.</summary>
+ public static int[] GetProcessIds()
+ {
+ return Interop.Process.ListAllPids();
+ }
+
+ internal static string GetProcPath(int processId)
+ {
+ return Interop.Process.GetProcPath(processId);
+ }
+
+ private static ProcessInfo CreateProcessInfo(int pid)
+ {
+ // Negative PIDs aren't valid
+ if (pid < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(pid));
+ }
+
+ ProcessInfo procInfo = new ProcessInfo()
+ {
+ ProcessId = pid
+ };
+
+ // Try to get the task info. This can fail if the user permissions don't permit
+ // this user context to query the specified process
+ ProcessInfo iinfo = Interop.Process.GetProcessInfoById(pid);
+
+ procInfo.ProcessName = iinfo.ProcessName;
+ procInfo.BasePriority = iinfo.BasePriority;
+ procInfo.VirtualBytes = iinfo.VirtualBytes;
+ procInfo.WorkingSet = iinfo.WorkingSet;
+ procInfo.SessionId = iinfo.SessionId;
+ foreach (ThreadInfo ti in iinfo._threadInfoList)
+ {
+ procInfo._threadInfoList.Add(ti);
+ }
+
+ return procInfo;
+ }
+
+ // ----------------------------------
+ // ---- Unix PAL layer ends here ----
+ // ----------------------------------
+
+ }
+}
return Interop.libproc.proc_listallpids();
}
- /// <summary>Gets process infos for each process on the specified machine.</summary>
- /// <param name="machineName">The target machine.</param>
- /// <returns>An array of process infos, one per found process.</returns>
- public static ProcessInfo[] GetProcessInfos(string machineName)
+ private static string GetProcPath(int processId)
{
- ThrowIfRemoteMachine(machineName);
- int[] procIds = GetProcessIds(machineName);
-
- // Iterate through all process IDs to load information about each process
- var processes = new List<ProcessInfo>(procIds.Length);
- foreach (int pid in procIds)
- {
- ProcessInfo pi = CreateProcessInfo(pid);
- if (pi != null)
- {
- processes.Add(pi);
- }
- }
-
- return processes.ToArray();
+ return Interop.libproc.proc_pidpath(processId);
}
// -----------------------------
return procInfo;
}
- /// <summary>Gets an array of module infos for the specified process.</summary>
- /// <param name="processId">The ID of the process whose modules should be enumerated.</param>
- /// <returns>The array of modules.</returns>
- internal static ProcessModuleCollection GetModules(int processId)
- {
- // We don't have a good way of getting all of the modules of the particular process,
- // but we can at least get the path to the executable file for the process, and
- // other than for debugging tools, that's the main reason consumers of Modules care about it,
- // and why MainModule exists.
- try
- {
- string exePath = Interop.libproc.proc_pidpath(processId);
- if (!string.IsNullOrEmpty(exePath))
- {
- return new ProcessModuleCollection(1)
- {
- new ProcessModule()
- {
- FileName = exePath,
- ModuleName = Path.GetFileName(exePath)
- }
- };
- }
- }
- catch { } // eat all errors
-
- return new ProcessModuleCollection(0);
- }
-
// ----------------------------------
// ---- Unix PAL layer ends here ----
// ----------------------------------
else
return System.Diagnostics.ThreadWaitReason.Unknown; // There isn't a good mapping for anything else
}
- }
+ }
}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Diagnostics
+{
+ public partial class ProcessThread
+ {
+ /// <summary>
+ /// Returns or sets the priority level of the associated thread. The priority level is
+ /// not an absolute level, but instead contributes to the actual thread priority by
+ /// considering the priority class of the process.
+ /// </summary>
+ private ThreadPriorityLevel PriorityLevelCore
+ {
+ get
+ {
+ Interop.Process.proc_stats stat = Interop.Process.GetThreadInfo(_processId, Id);
+ return Interop.Sys.GetThreadPriorityFromNiceValue((int)stat.nice);
+ }
+ set
+ {
+ throw new PlatformNotSupportedException(); // We can find no API to set this
+ }
+ }
+
+ /// <summary>Returns the time the associated thread was started.</summary>
+ public DateTime StartTime
+ {
+ // kinfo_proc has one entry per thread but ki_start seems to be same for
+ // all threads e.g. reflects process start. This may be re-visited later.
+ get { throw new PlatformNotSupportedException(); }
+ }
+
+ /// <summary>
+ /// Returns the amount of time the associated thread has spent utilizing the CPU.
+ /// It is the sum of the System.Diagnostics.ProcessThread.UserProcessorTime and
+ /// System.Diagnostics.ProcessThread.PrivilegedProcessorTime.
+ /// </summary>
+ public TimeSpan TotalProcessorTime
+ {
+ get
+ {
+ Interop.Process.proc_stats stat = Interop.Process.GetThreadInfo(_processId, Id);
+ return Process.TicksToTimeSpan(stat.userTime + stat.systemTime);
+ }
+ }
+
+ /// <summary>
+ /// Returns the amount of time the associated thread has spent running code
+ /// inside the application (not the operating system core).
+ /// </summary>
+ public TimeSpan UserProcessorTime
+ {
+ get
+ {
+ Interop.Process.proc_stats stat = Interop.Process.GetThreadInfo(_processId, Id);
+ return Process.TicksToTimeSpan(stat.userTime);
+ }
+ }
+
+ /// <summary>
+ /// Returns the amount of time the thread has spent running code inside the operating
+ /// system core.
+ /// </summary>
+ public TimeSpan PrivilegedProcessorTime
+ {
+ get
+ {
+ Interop.Process.proc_stats stat = Interop.Process.GetThreadInfo(_processId, Id);
+ return Process.TicksToTimeSpan(stat.systemTime);
+ }
+
+ }
+ }
+}
{
string path = GetTestFilePath();
File.Create(path).Dispose();
- Assert.Equal(0, chmod(path, 644)); // no execute permissions
+ int mode = Convert.ToInt32("644", 8);
+
+ Assert.Equal(0, chmod(path, mode));
Win32Exception e = Assert.Throws<Win32Exception>(() => Process.Start(path));
Assert.NotEqual(0, e.NativeErrorCode);
{
string path = GetTestFilePath();
File.Create(path).Dispose();
- Assert.Equal(0, chmod(path, 744)); // execute permissions
+ int mode = Convert.ToInt32("744", 8);
+
+ Assert.Equal(0, chmod(path, mode)); // execute permissions
using (Process p = Process.Start(path))
{
}
[Fact]
- [PlatformSpecific(TestPlatforms.OSX)] // OSX throws PNSE from StartTime
+ [PlatformSpecific(TestPlatforms.OSX|TestPlatforms.FreeBSD)] // OSX and FreeBSD throw PNSE from StartTime
public void TestStartTimeProperty_OSX()
{
using (Process p = Process.GetCurrentProcess())
}
[Fact]
- [PlatformSpecific(~TestPlatforms.OSX)] // OSX throws PNSE from StartTime
+ [PlatformSpecific(TestPlatforms.Linux|TestPlatforms.Windows)] // OSX and FreeBSD throw PNSE from StartTime
[SkipOnTargetFramework(TargetFrameworkMonikers.Uap, "Retrieving information about local processes is not supported on uap")]
public async Task TestStartTimeProperty()
{
return;
}
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Create("FREEBSD")))
+ {
+ Assert.Throws<PlatformNotSupportedException>(() => thread.PriorityLevel = ThreadPriorityLevel.AboveNormal);
+ return;
+ }
+
try
{
thread.PriorityLevel = ThreadPriorityLevel.AboveNormal;
{
if (osPlatform == null) throw new ArgumentNullException(nameof(osPlatform));
if (osPlatform.Length == 0) throw new ArgumentException(SR.Argument_EmptyValue, nameof(osPlatform));
-
+
_osPlatform = osPlatform;
}
Assert.Contains("netbsd", RuntimeInformation.OSDescription, StringComparison.OrdinalIgnoreCase);
}
+ [Fact, PlatformSpecific(TestPlatforms.FreeBSD)] // Checks FreeBSD debug name in RuntimeInformation
+ public void VerifyFreeBSDDebugName()
+ {
+ Assert.Contains("FreeBSD", RuntimeInformation.OSDescription, StringComparison.OrdinalIgnoreCase);
+ }
+
[Fact, PlatformSpecific(TestPlatforms.OSX)] // Checks OSX debug name in RuntimeInformation
public void VerifyOSXDebugName()
{
aarch64)
__Arch=arm64
;;
-
+ amd64)
+ __Arch=x64
+ ;;
*)
echo "Unknown CPU $CPUName detected, configuring as if for x64"
__Arch=x64
then
maxProcesses=1;
else
- if [ `uname` = "NetBSD" ]; then
+ if [ `uname` = "NetBSD" ] || [ `uname` = "FreeBSD" ]; then
maxProcesses=$(($(getconf NPROCESSORS_ONLN)+1))
else
maxProcesses=$(($(getconf _NPROCESSORS_ONLN)+1))