Skip to content

Commit

Permalink
[corlib] Simplify RuntimeInformation by getting OS name from the runt…
Browse files Browse the repository at this point in the history
…ime (#13164)

We can get the the OS name similar to the architecture from the value that is used by the runtime for DllMaps.

Cached the values into static fields so we only need to do the runtime icall once.

Added all the existing OS names recognized by DllMap to RuntimeInformation.
This also allows us to mark some corlib/System tests that hang the runtime on AIX as non-working.
  • Loading branch information
NattyNarwhal authored and akoeplinger committed Feb 27, 2019
1 parent a3dd8b3 commit a3be248
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 47 deletions.
6 changes: 6 additions & 0 deletions mcs/class/System/Test/System.Diagnostics/ProcessTest.cs
Expand Up @@ -1035,6 +1035,12 @@ public void DisposeWithDisposedStreams ()
[NUnit.Framework.Category ("MobileNotWorking")]
public void StandardInputWrite ()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Create("AIX")))
{
// This test is broken on AIX because the fork child seems to become comatose.
Assert.Ignore ("Skipping on AIX/i");
}

var psi = GetEchoCrossPlatformStartInfo ();
psi.RedirectStandardInput = true;
psi.RedirectStandardOutput = true;
Expand Down
Expand Up @@ -36,13 +36,93 @@ namespace System.Runtime.InteropServices
{
public static class RuntimeInformation
{
/* gets the runtime's arch from the value it uses for DllMap */
static extern string RuntimeArchitecture
static readonly Architecture _osArchitecture;
static readonly Architecture _processArchitecture;
static readonly OSPlatform _osPlatform;

static RuntimeInformation ()
{
[MethodImpl (MethodImplOptions.InternalCall)]
get;
// we can use the runtime's compiled config options for DllMaps here
// process architecure for us is runtime architecture
// see for values: mono-config.c
var runtimeArchitecture = GetRuntimeArchitecture ();
var osName = GetOSName ();

// check OS/process architecture
switch (runtimeArchitecture) {
case "arm":
_osArchitecture = Environment.Is64BitOperatingSystem ? Architecture.Arm64 : Architecture.Arm;
_processArchitecture = Architecture.Arm;
break;
case "armv8":
_osArchitecture = Environment.Is64BitOperatingSystem ? Architecture.Arm64 : Architecture.Arm;
_processArchitecture = Architecture.Arm64;
break;
case "x86":
_osArchitecture = Environment.Is64BitOperatingSystem ? Architecture.X64 : Architecture.X86;
_processArchitecture = Architecture.X86;
break;
case "x86-64":
_osArchitecture = Environment.Is64BitOperatingSystem ? Architecture.X64 : Architecture.X86;
_processArchitecture = Architecture.X64;
break;
// upstream only has these values; try to pretend we're x86 if nothing matches
// want more? bug: https://github.com/dotnet/corefx/issues/30706
default:
_osArchitecture = Environment.Is64BitOperatingSystem ? Architecture.X64 : Architecture.X86;
_processArchitecture = Environment.Is64BitProcess ? Architecture.X64 : Architecture.X86;
break;
}

// check OS platform
switch (osName) {
case "linux":
_osPlatform = OSPlatform.Linux;
break;
case "osx":
_osPlatform = OSPlatform.OSX;
break;
case "windows":
_osPlatform = OSPlatform.Windows;
break;
case "solaris":
_osPlatform = OSPlatform.Create ("SOLARIS");
break;
case "freebsd":
_osPlatform = OSPlatform.Create ("FREEBSD");
break;
case "netbsd":
_osPlatform = OSPlatform.Create ("NETBSD");
break;
case "openbsd":
_osPlatform = OSPlatform.Create ("OPENBSD");
break;
case "aix":
_osPlatform = OSPlatform.Create ("AIX");
break;
case "hpux":
_osPlatform = OSPlatform.Create ("HPUX");
break;
case "haiku":
_osPlatform = OSPlatform.Create ("HAIKU");
break;
case "wasm":
_osPlatform = OSPlatform.Create ("WEBASSEMBLY");
break;
default:
_osPlatform = OSPlatform.Create ("UNKNOWN");
break;
}
}

/* gets the runtime's arch from the value it uses for DllMap */
[MethodImpl (MethodImplOptions.InternalCall)]
static extern string GetRuntimeArchitecture ();

/* gets the runtime's OS from the value it uses for DllMap */
[MethodImpl (MethodImplOptions.InternalCall)]
static extern string GetOSName ();

public static string FrameworkDescription {
get {
return "Mono " + Mono.Runtime.GetDisplayName ();
Expand All @@ -51,20 +131,7 @@ public static class RuntimeInformation

public static bool IsOSPlatform (OSPlatform osPlatform)
{
#if WASM
return osPlatform == OSPlatform.Create ("WEBASSEMBLY");
#else
switch (Environment.Platform) {
case PlatformID.Win32NT:
return osPlatform == OSPlatform.Windows;
case PlatformID.MacOSX:
return osPlatform == OSPlatform.OSX;
case PlatformID.Unix:
return osPlatform == OSPlatform.Linux;
default:
return false;
}
#endif
return _osPlatform == osPlatform;
}

public static string OSDescription
Expand All @@ -83,40 +150,15 @@ public static Architecture OSArchitecture
{
get
{
switch (RuntimeArchitecture) {
case "arm":
case "armv8":
return Environment.Is64BitOperatingSystem ? Architecture.Arm64 : Architecture.Arm;
case "x86":
case "x86-64":
// upstream only has these values; try to pretend we're x86 if nothing matches
// want more? bug: https://github.com/dotnet/corefx/issues/30706
default:
return Environment.Is64BitOperatingSystem ? Architecture.X64 : Architecture.X86;
}
return _osArchitecture;
}
}

public static Architecture ProcessArchitecture
{
get
{
// we can use the runtime's compiled config options for DllMaps here
// process architecure for us is runtime architecture (OS is much harder)
// see for values: mono-config.c
switch (RuntimeArchitecture) {
case "x86":
return Architecture.X86;
case "x86-64":
return Architecture.X64;
case "arm":
return Architecture.Arm;
case "armv8":
return Architecture.Arm64;
// see comment in OSArchiteture default case
default:
return Environment.Is64BitProcess ? Architecture.X64 : Architecture.X86;
}
return _processArchitecture;
}
}
}
Expand Down
28 changes: 28 additions & 0 deletions mcs/class/corlib/Test/System.Threading/InterlockedTest.cs
Expand Up @@ -10,6 +10,7 @@
using NUnit.Framework;
using System;
using System.Threading;
using System.Runtime.InteropServices;

namespace MonoTests.System.Threading
{
Expand Down Expand Up @@ -42,9 +43,19 @@ public class InterlockedTest
readonly IntPtr iptr_2 = (IntPtr)int32_2;
readonly IntPtr iptr_3 = (IntPtr)int32_3;

// The exchange tests are broken on AIX and cause a runtime lockup.
void AssertNotAix()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Create("AIX")))
{
Assert.Ignore ("Skipping on AIX/i");
}
}

[Test]
public void TestExchange_Int32 ()
{
AssertNotAix();
int32 = int32_1;
Assert.AreEqual(int32_1, Interlocked.Exchange(ref int32, int32_2));
Assert.AreEqual(int32_2, int32);
Expand All @@ -53,6 +64,7 @@ public void TestExchange_Int32 ()
[Test]
public void TestExchange_Flt ()
{
AssertNotAix();
flt = flt_1;
Assert.AreEqual(flt_1, Interlocked.Exchange(ref flt, flt_2));
Assert.AreEqual(flt_2, flt);
Expand All @@ -61,6 +73,7 @@ public void TestExchange_Flt ()
[Test]
public void TestExchange_Obj ()
{
AssertNotAix();
obj = obj_1;
Assert.AreEqual(obj_1, Interlocked.Exchange(ref obj, obj_2));
Assert.AreEqual(obj_2, obj);
Expand All @@ -69,6 +82,7 @@ public void TestExchange_Obj ()
[Test]
public void TestExchange_Int64 ()
{
AssertNotAix();
int64 = int64_1;
Assert.AreEqual(int64_1, Interlocked.Exchange(ref int64, int64_2));
Assert.AreEqual(int64_2, int64);
Expand All @@ -77,6 +91,7 @@ public void TestExchange_Int64 ()
[Test]
public void TestExchange_Dbl ()
{
AssertNotAix();
dbl = dbl_1;
Assert.AreEqual(dbl_1, Interlocked.Exchange(ref dbl, dbl_2));
Assert.AreEqual(dbl_2, dbl);
Expand All @@ -85,6 +100,7 @@ public void TestExchange_Dbl ()
[Test]
public void TestExchange_Iptr ()
{
AssertNotAix();
iptr = iptr_1;
Assert.AreEqual(iptr_1, Interlocked.Exchange(ref iptr, iptr_2));
Assert.AreEqual(iptr_2, iptr);
Expand All @@ -93,6 +109,7 @@ public void TestExchange_Iptr ()
[Test]
public void TestCompareExchange_Int32 ()
{
AssertNotAix();
int32 = int32_1;
Assert.AreEqual(int32_1, Interlocked.CompareExchange(ref int32, int32_2, int32_1));
Assert.AreEqual(int32_2, int32);
Expand All @@ -101,6 +118,7 @@ public void TestCompareExchange_Int32 ()
[Test]
public void TestCompareExchange_Flt ()
{
AssertNotAix();
flt = flt_1;
Assert.AreEqual(flt_1, Interlocked.CompareExchange(ref flt, flt_2, flt_1));
Assert.AreEqual(flt_2, flt);
Expand All @@ -109,6 +127,7 @@ public void TestCompareExchange_Flt ()
[Test]
public void TestCompareExchange_Obj ()
{
AssertNotAix();
obj = obj_1;
Assert.AreEqual(obj_1, Interlocked.CompareExchange(ref obj, obj_2, obj_1));
Assert.AreEqual(obj_2, obj);
Expand All @@ -117,6 +136,7 @@ public void TestCompareExchange_Obj ()
[Test]
public void TestCompareExchange_Int64 ()
{
AssertNotAix();
int64 = int64_1;
Assert.AreEqual(int64_1, Interlocked.CompareExchange(ref int64, int64_2, int64_1));
Assert.AreEqual(int64_2, int64);
Expand All @@ -125,6 +145,7 @@ public void TestCompareExchange_Int64 ()
[Test]
public void TestCompareExchange_Dbl ()
{
AssertNotAix();
dbl = dbl_1;
Assert.AreEqual(dbl_1, Interlocked.CompareExchange(ref dbl, dbl_2, dbl_1));
Assert.AreEqual(dbl_2, dbl);
Expand All @@ -133,6 +154,7 @@ public void TestCompareExchange_Dbl ()
[Test]
public void TestCompareExchange_Iptr ()
{
AssertNotAix();
iptr = iptr_1;
Assert.AreEqual(iptr_1, Interlocked.CompareExchange(ref iptr, iptr_2, iptr_1));
Assert.AreEqual(iptr_2, iptr);
Expand All @@ -141,6 +163,7 @@ public void TestCompareExchange_Iptr ()
[Test]
public void TestCompareExchange_Failed_Int32 ()
{
AssertNotAix();
int32 = int32_1;
Assert.AreEqual(int32_1, Interlocked.CompareExchange(ref int32, int32_2, int32_3));
Assert.AreEqual(int32_1, int32);
Expand All @@ -149,6 +172,7 @@ public void TestCompareExchange_Failed_Int32 ()
[Test]
public void TestCompareExchange_Failed_Flt ()
{
AssertNotAix();
flt = flt_1;
Assert.AreEqual(flt_1, Interlocked.CompareExchange(ref flt, flt_2, flt_3));
Assert.AreEqual(flt_1, flt);
Expand All @@ -157,6 +181,7 @@ public void TestCompareExchange_Failed_Flt ()
[Test]
public void TestCompareExchange_Failed_Obj ()
{
AssertNotAix();
obj = obj_1;
Assert.AreEqual(obj_1, Interlocked.CompareExchange(ref obj, obj_2, obj_3));
Assert.AreEqual(obj_1, obj);
Expand All @@ -165,6 +190,7 @@ public void TestCompareExchange_Failed_Obj ()
[Test]
public void TestCompareExchange_Failed_Int64 ()
{
AssertNotAix();
int64 = int64_1;
Assert.AreEqual(int64_1, Interlocked.CompareExchange(ref int64, int64_2, int64_3));
Assert.AreEqual(int64_1, int64);
Expand All @@ -173,6 +199,7 @@ public void TestCompareExchange_Failed_Int64 ()
[Test]
public void TestCompareExchange_Failed_Dbl ()
{
AssertNotAix();
dbl = dbl_1;
Assert.AreEqual(dbl_1, Interlocked.CompareExchange(ref dbl, dbl_2, dbl_3));
Assert.AreEqual(dbl_1, dbl);
Expand All @@ -181,6 +208,7 @@ public void TestCompareExchange_Failed_Dbl ()
[Test]
public void TestCompareExchange_Failed_Iptr ()
{
AssertNotAix();
iptr = iptr_1;
Assert.AreEqual(iptr_1, Interlocked.CompareExchange(ref iptr, iptr_2, iptr_3));
Assert.AreEqual(iptr_1, iptr);
Expand Down
3 changes: 2 additions & 1 deletion mono/metadata/icall-def.h
Expand Up @@ -849,7 +849,8 @@ HANDLES(MARSHAL_41, "copy_from_unmanaged_fixed", ves_icall_System_Runtime_Intero
HANDLES(MARSHAL_42, "copy_to_unmanaged_fixed", ves_icall_System_Runtime_InteropServices_Marshal_copy_to_unmanaged, void, 5, (MonoArray, gint32, gpointer, gint32, gconstpointer))

ICALL_TYPE(RUNTIMEINFO, "System.Runtime.InteropServices.RuntimeInformation", RUNTIMEINFO_1)
HANDLES(RUNTIMEINFO_1, "get_RuntimeArchitecture", ves_icall_System_Runtime_InteropServices_RuntimeInformation_get_RuntimeArchitecture, MonoString, 0, ())
HANDLES(RUNTIMEINFO_1, "GetOSName", ves_icall_System_Runtime_InteropServices_RuntimeInformation_GetOSName, MonoString, 0, ())
HANDLES(RUNTIMEINFO_2, "GetRuntimeArchitecture", ves_icall_System_Runtime_InteropServices_RuntimeInformation_GetRuntimeArchitecture, MonoString, 0, ())

#ifndef DISABLE_COM
ICALL_TYPE(WINDOWSRUNTIME_UNM, "System.Runtime.InteropServices.WindowsRuntime.UnsafeNativeMethods", WINDOWSRUNTIME_UNM_0)
Expand Down
12 changes: 11 additions & 1 deletion mono/metadata/icall.c
Expand Up @@ -7828,12 +7828,22 @@ ves_icall_System_Runtime_InteropServices_Marshal_PrelinkAll (MonoReflectionTypeH
* which use them in different ways for filling in an enum
*/
MonoStringHandle
ves_icall_System_Runtime_InteropServices_RuntimeInformation_get_RuntimeArchitecture (MonoError *error)
ves_icall_System_Runtime_InteropServices_RuntimeInformation_GetRuntimeArchitecture (MonoError *error)
{
error_init (error);
return mono_string_new_handle (mono_domain_get (), mono_config_get_cpu (), error);
}

/*
* used by System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform
*/
MonoStringHandle
ves_icall_System_Runtime_InteropServices_RuntimeInformation_GetOSName (MonoError *error)
{
error_init (error);

This comment has been minimized.

Copy link
@jaykrell

jaykrell Mar 2, 2019

Contributor

This line not needed.

This comment has been minimized.

Copy link
@akoeplinger

akoeplinger Mar 4, 2019

Member

Can you expand on why? I know little about the MonoError semantics but thought we had to always initialize it.

return mono_string_new_handle (mono_domain_get (), mono_config_get_os (), error);
}

int
ves_icall_Interop_Sys_DoubleToString(double value, char *format, char *buffer, int bufferLength)
{
Expand Down

0 comments on commit a3be248

Please sign in to comment.