-
Notifications
You must be signed in to change notification settings - Fork 330
Consolidate OS detection to OsConstants #4255
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,13 +13,13 @@ | |
| using System.IO; | ||
| using System.Runtime.CompilerServices; | ||
| using System.Security; | ||
| using Microsoft.Data.SqlClient; | ||
| using System.Security.Authentication; | ||
| using System.Text; | ||
| using System.Threading; | ||
| using System.Threading.Tasks; | ||
| using System.Transactions; | ||
| using Microsoft.Data.Common.ConnectionString; | ||
| using Microsoft.Data.SqlClient; | ||
| using Microsoft.Data.SqlClient.Connection; | ||
| using Microsoft.SqlServer.Server; | ||
| using Microsoft.Win32; | ||
|
|
@@ -65,22 +65,6 @@ internal static partial class ADP | |
| /// </summary> | ||
| internal const int MaxBufferAccessTokenExpiry = 600; | ||
|
|
||
| /// <summary> | ||
| /// This member returns true if the current OS platform is Windows. | ||
| /// </summary> | ||
| /// <remarks> | ||
| /// This is a const on .NET Framework, and a property on .NET Core, because of differing API availability and JIT requirements. | ||
| /// .NET Framework will perform basic dead branch elimination when a const value is encountered, while .NET Core can trim Windows-specific | ||
| /// code when published to non-Windows platforms. | ||
| /// .NET Core's trimming is very limited though, so this must be used inline within methods to throw PlatformNotSupportedException, | ||
| /// rather than in a throw helper. | ||
| /// </remarks> | ||
| #if NETFRAMEWORK | ||
| public const bool IsWindows = true; | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This isn't strictly true - you can run .NET Framework on non-Windows. We're conflating .NET Framework and Windows elsewhere, and we will deal with that later. |
||
| #else | ||
| public static bool IsWindows => OperatingSystem.IsWindows(); | ||
| #endif | ||
|
|
||
| #region UDT | ||
|
|
||
| #if NETFRAMEWORK | ||
|
|
@@ -159,10 +143,10 @@ internal static Timer UnsafeCreateTimer( | |
| state, | ||
| TimeSpan.FromMilliseconds(dueTimeMilliseconds), | ||
| TimeSpan.FromMilliseconds(periodMilliseconds)); | ||
|
|
||
| internal static Timer UnsafeCreateTimer(TimerCallback callback, object state, TimeSpan dueTime, TimeSpan period) | ||
| { | ||
| // Don't capture the current ExecutionContext and its AsyncLocals onto | ||
| // Don't capture the current ExecutionContext and its AsyncLocals onto | ||
| // a global timer causing them to live forever | ||
| bool restoreFlow = false; | ||
| try | ||
|
|
@@ -184,7 +168,7 @@ internal static Timer UnsafeCreateTimer(TimerCallback callback, object state, Ti | |
| } | ||
| } | ||
| } | ||
|
|
||
|
|
||
| #region COM+ exceptions | ||
| internal static ArgumentException Argument(string error) | ||
|
|
@@ -451,7 +435,7 @@ internal static ArgumentOutOfRangeException InvalidCommandBehavior(CommandBehavi | |
| internal static object LocalMachineRegistryValue(string subkey, string queryvalue) | ||
| { | ||
| #if NET | ||
| if (!IsWindows) | ||
| if (OsConstants.IsUnix) | ||
|
paulmedynski marked this conversation as resolved.
Outdated
|
||
| { | ||
| // No registry in non-Windows environments | ||
| return null; | ||
|
|
@@ -639,7 +623,7 @@ internal static string BuildMultiPartName(string[] strings) | |
| { | ||
| StringBuilder bld = new(); | ||
| // Assume we want to build a full multi-part name with all parts except trimming separators for | ||
| // leading empty names (null or empty strings, but not whitespace). Separators in the middle | ||
| // leading empty names (null or empty strings, but not whitespace). Separators in the middle | ||
| // should be added, even if the name part is null/empty, to maintain proper location of the parts. | ||
| for (int i = 0; i < strings.Length; i++) | ||
| { | ||
|
|
@@ -839,14 +823,14 @@ internal static Version GetAssemblyVersion() | |
| /// Represents a collection of Azure SQL Server endpoint URLs for various regions and environments. | ||
| /// </summary> | ||
| /// <remarks>This array includes endpoint URLs for Azure SQL in global, Germany, US Government, | ||
| /// China, and Fabric environments. These endpoints are used to identify and interact with Azure SQL services | ||
| /// China, and Fabric environments. These endpoints are used to identify and interact with Azure SQL services | ||
| /// in their respective regions or environments.</remarks> | ||
| internal static readonly List<string> s_azureSqlServerEndpoints = new() { AZURE_SQL, | ||
| AZURE_SQL_GERMANY, | ||
| AZURE_SQL_USGOV, | ||
| AZURE_SQL_CHINA, | ||
| AZURE_SQL_FABRIC }; | ||
|
|
||
| /// <summary> | ||
| /// Contains endpoint strings for Azure SQL Server on-demand services. | ||
| /// Each entry is a combination of the ONDEMAND_PREFIX and a specific Azure SQL endpoint string. | ||
|
|
@@ -872,9 +856,9 @@ internal static Version GetAssemblyVersion() | |
| internal static bool IsAzureSynapseOnDemandEndpoint(string dataSource) | ||
| { | ||
| return IsEndpoint(dataSource, s_azureSynapseOnDemandEndpoints) | ||
| || dataSource.IndexOf(AZURE_SYNAPSE, StringComparison.OrdinalIgnoreCase) >= 0; | ||
| || dataSource.IndexOf(AZURE_SYNAPSE, StringComparison.OrdinalIgnoreCase) >= 0; | ||
| } | ||
|
|
||
| internal static bool IsAzureSqlServerEndpoint(string dataSource) | ||
| { | ||
| return IsEndpoint(dataSource, s_azureSqlServerEndpoints); | ||
|
|
@@ -1088,7 +1072,7 @@ internal enum InternalErrorCode | |
|
|
||
| SqlDependencyObtainProcessDispatcherFailureObjectHandle = 50, | ||
| SqlDependencyProcessDispatcherFailureCreateInstance = 51, | ||
|
|
||
| SqlDependencyCommandHashIsNotAssociatedWithNotification = 53, | ||
|
|
||
| UnknownTransactionFailure = 60, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| // 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.Runtime.InteropServices; | ||
|
|
||
| namespace Microsoft.Data.SqlClient; | ||
|
|
||
| /// <summary> | ||
| /// Provides platform detection flags for OS-specific code paths. | ||
| /// </summary> | ||
| /// <remarks> | ||
| /// These constants are computed at runtime and cached as static readonly fields. This design | ||
| /// allows the JIT compiler to elide branches in hot paths based on whether the OS flags are known | ||
| /// constants at JIT compilation time. | ||
| /// </remarks> | ||
| internal static class OsConstants | ||
| { | ||
| /// <summary> | ||
| /// Gets a value indicating whether the runtime is executing on Windows. | ||
| /// </summary> | ||
| internal static readonly bool IsWindows; | ||
|
|
||
| /// <summary> | ||
| /// Gets a value indicating whether the runtime is executing on Linux. | ||
| /// </summary> | ||
| internal static readonly bool IsLinux; | ||
|
|
||
| /// <summary> | ||
| /// Gets a value indicating whether the runtime is executing on macOS. | ||
| /// </summary> | ||
| internal static readonly bool IsMacOS; | ||
|
|
||
| #if NET | ||
|
paulmedynski marked this conversation as resolved.
Outdated
|
||
| /// <summary> | ||
| /// Gets a value indicating whether the runtime is executing on FreeBSD. | ||
| /// </summary> | ||
| /// <remarks> | ||
| /// FreeBSD support is only available in .NET 5+ and later. This field will be | ||
| /// <c>false</c> on .NET Framework or if the runtime does not support FreeBSD detection. | ||
| /// </remarks> | ||
| internal static readonly bool IsFreeBSD; | ||
| #endif | ||
|
|
||
| /// <summary> | ||
| /// Gets a value indicating whether the runtime is executing on a Unix-like operating system. | ||
| /// </summary> | ||
| /// <remarks> | ||
| /// This is <c>true</c> for Linux, macOS, FreeBSD, and other Unix-like platforms. | ||
| /// It is <c>false</c> only on Windows. | ||
| /// </remarks> | ||
| internal static readonly bool IsUnix; | ||
|
paulmedynski marked this conversation as resolved.
Outdated
|
||
|
|
||
| /// <summary> | ||
| /// Initializes platform detection flags by querying <see cref="RuntimeInformation"/>. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This impacts IL trimming, which runs at publish time. The IL trimmer needs to be able to statically see that I've linked against the CI artifacts and confirmed that the IL trimmer can't analyze the static constructor, so I think this rules out everything besides exposing properties which returns the value of Incidentally, exposing it as a field or a property also blocks .NET Framework from removing dead code paths (which in turn can consume the inlining budget), which is why IsWindows is currently a |
||
| /// </summary> | ||
| /// <remarks> | ||
| /// We use a static constructor instead of a module initializer ([ModuleInitializer]) to avoid | ||
| /// the CA2255 security concern. Module initializers can be problematic because: 1. They run in | ||
| /// an unpredictable order relative to other initialization code. 2. They run before the app | ||
| /// initialization sequence, potentially before security policies are set. 3. They can | ||
| /// complicate debugging and profiling. | ||
| /// | ||
| /// Using a static constructor ensures initialization happens in a well-defined, type-safe | ||
| /// manner that is compatible with the CLR's type loading guarantees. | ||
| /// | ||
| /// The trade-off is that the OS flags won't be initialized until the OsConstants type is first | ||
| /// accessed, which may cause a slight delay in a hot path, but only once. | ||
| /// </remarks> | ||
| static OsConstants() | ||
| { | ||
| IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); | ||
| IsLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux); | ||
| IsMacOS = RuntimeInformation.IsOSPlatform(OSPlatform.OSX); | ||
| #if NET | ||
| IsFreeBSD = RuntimeInformation.IsOSPlatform(OSPlatform.FreeBSD); | ||
| IsUnix = IsLinux || IsMacOS || IsFreeBSD; | ||
| #else | ||
| IsUnix = IsLinux || IsMacOS; | ||
| #endif | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.