From a3be248d3fbc278398c1937788ebce2a7b0c211d Mon Sep 17 00:00:00 2001 From: Calvin Buckley Date: Wed, 27 Feb 2019 18:21:34 -0400 Subject: [PATCH] [corlib] Simplify RuntimeInformation by getting OS name from the runtime (#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. --- .../Test/System.Diagnostics/ProcessTest.cs | 6 + .../RuntimeInformation.cs | 132 ++++++++++++------ .../Test/System.Threading/InterlockedTest.cs | 28 ++++ mono/metadata/icall-def.h | 3 +- mono/metadata/icall.c | 12 +- 5 files changed, 134 insertions(+), 47 deletions(-) diff --git a/mcs/class/System/Test/System.Diagnostics/ProcessTest.cs b/mcs/class/System/Test/System.Diagnostics/ProcessTest.cs index fd382999eb18c..b1fc4962cb6be 100644 --- a/mcs/class/System/Test/System.Diagnostics/ProcessTest.cs +++ b/mcs/class/System/Test/System.Diagnostics/ProcessTest.cs @@ -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; diff --git a/mcs/class/corlib/System.Runtime.InteropServices.RuntimeInformation/RuntimeInformation.cs b/mcs/class/corlib/System.Runtime.InteropServices.RuntimeInformation/RuntimeInformation.cs index 7b11484ead012..8e2c82b19efa0 100644 --- a/mcs/class/corlib/System.Runtime.InteropServices.RuntimeInformation/RuntimeInformation.cs +++ b/mcs/class/corlib/System.Runtime.InteropServices.RuntimeInformation/RuntimeInformation.cs @@ -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 (); @@ -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 @@ -83,17 +150,7 @@ 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; } } @@ -101,22 +158,7 @@ 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; } } } diff --git a/mcs/class/corlib/Test/System.Threading/InterlockedTest.cs b/mcs/class/corlib/Test/System.Threading/InterlockedTest.cs index ac4d7d6647962..20ed84b0a197e 100644 --- a/mcs/class/corlib/Test/System.Threading/InterlockedTest.cs +++ b/mcs/class/corlib/Test/System.Threading/InterlockedTest.cs @@ -10,6 +10,7 @@ using NUnit.Framework; using System; using System.Threading; +using System.Runtime.InteropServices; namespace MonoTests.System.Threading { @@ -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); @@ -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); @@ -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); @@ -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); @@ -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); @@ -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); @@ -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); @@ -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); @@ -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); @@ -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); @@ -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); @@ -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); @@ -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); @@ -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); @@ -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); @@ -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); @@ -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); @@ -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); diff --git a/mono/metadata/icall-def.h b/mono/metadata/icall-def.h index aab80ee99a30c..af214218d3e0c 100644 --- a/mono/metadata/icall-def.h +++ b/mono/metadata/icall-def.h @@ -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) diff --git a/mono/metadata/icall.c b/mono/metadata/icall.c index 1ae3b6f64ef4b..d8a37befd773d 100644 --- a/mono/metadata/icall.c +++ b/mono/metadata/icall.c @@ -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); + 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) {