diff options
Diffstat (limited to 'src/mscorlib/src/System/AppContext/AppContext.cs')
-rw-r--r-- | src/mscorlib/src/System/AppContext/AppContext.cs | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/src/mscorlib/src/System/AppContext/AppContext.cs b/src/mscorlib/src/System/AppContext/AppContext.cs new file mode 100644 index 0000000000..d1416f7af1 --- /dev/null +++ b/src/mscorlib/src/System/AppContext/AppContext.cs @@ -0,0 +1,169 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + + +using System.Collections.Generic; + +namespace System +{ + public static class AppContext + { + [Flags] + private enum SwitchValueState + { + HasFalseValue = 0x1, + HasTrueValue = 0x2, + HasLookedForOverride = 0x4, + UnknownValue = 0x8 // Has no default and could not find an override + } + private static Dictionary<string, SwitchValueState> s_switchMap = new Dictionary<string, SwitchValueState>(); + private static readonly object s_syncLock = new object(); + + public static string BaseDirectory + { +#if FEATURE_CORECLR + [System.Security.SecuritySafeCritical] +#endif + get + { + return AppDomain.CurrentDomain.BaseDirectory; + } + } + + #region Switch APIs + + static AppContext() + { + // populate the AppContext with the default set of values + AppContextDefaultValues.PopulateDefaultValues(); + } + + /// <summary> + /// Try to get the value of the switch. + /// </summary> + /// <param name="switchName">The name of the switch</param> + /// <param name="isEnabled">A variable where to place the value of the switch</param> + /// <returns>A return value of true represents that the switch was set and <paramref name="isEnabled"/> contains the value of the switch</returns> + public static bool TryGetSwitch(string switchName, out bool isEnabled) + { + if (switchName == null) + throw new ArgumentNullException("switchName"); + if (switchName.Length == 0) + throw new ArgumentException(Environment.GetResourceString("Argument_EmptyName"), "switchName"); + + // By default, the switch is not enabled. + isEnabled = false; + + SwitchValueState switchValue; + lock (s_switchMap) + { + if (s_switchMap.TryGetValue(switchName, out switchValue)) + { + // The value is in the dictionary. + // There are 3 cases here: + // 1. The value of the switch is 'unknown'. This means that the switch name is not known to the system (either via defaults or checking overrides). + // Example: This is the case when, during a servicing event, a switch is added to System.Xml which ships before mscorlib. The value of the switch + // Will be unknown to mscorlib.dll and we want to prevent checking the overrides every time we check this switch + // 2. The switch has a valid value AND we have read the overrides for it + // Example: TryGetSwitch is called for a switch set via SetSwitch + // 3. The switch has the default value and we need to check for overrides + // Example: TryGetSwitch is called for the first time for a switch that has a default value + + // 1. The value is unknown + if (switchValue == SwitchValueState.UnknownValue) + { + isEnabled = false; + return false; + } + + // We get the value of isEnabled from the value that we stored in the dictionary + isEnabled = (switchValue & SwitchValueState.HasTrueValue) == SwitchValueState.HasTrueValue; + + // 2. The switch has a valid value AND we have checked for overrides + if ((switchValue & SwitchValueState.HasLookedForOverride) == SwitchValueState.HasLookedForOverride) + { + return true; + } + + // 3. The switch has a valid value, but we need to check for overrides. + // Regardless of whether or not the switch has an override, we need to update the value to reflect + // the fact that we checked for overrides. + bool overrideValue; + if (AppContextDefaultValues.TryGetSwitchOverride(switchName, out overrideValue)) + { + // we found an override! + isEnabled = overrideValue; + } + + // Update the switch in the dictionary to mark it as 'checked for override' + s_switchMap[switchName] = (isEnabled ? SwitchValueState.HasTrueValue : SwitchValueState.HasFalseValue) + | SwitchValueState.HasLookedForOverride; + + return true; + } + else + { + // The value is NOT in the dictionary + // In this case we need to see if we have an override defined for the value. + // There are 2 cases: + // 1. The value has an override specified. In this case we need to add the value to the dictionary + // and mark it as checked for overrides + // Example: In a servicing event, System.Xml introduces a switch and an override is specified. + // The value is not found in mscorlib (as System.Xml ships independent of mscorlib) + // 2. The value does not have an override specified + // In this case, we want to capture the fact that we looked for a value and found nothing by adding + // an entry in the dictionary with the 'sentinel' value of 'SwitchValueState.UnknownValue'. + // Example: This will prevent us from trying to find overrides for values that we don't have in the dictionary + + // 1. The value has an override specified. + bool overrideValue; + if (AppContextDefaultValues.TryGetSwitchOverride(switchName, out overrideValue)) + { + isEnabled = overrideValue; + + // Update the switch in the dictionary to mark it as 'checked for override' + s_switchMap[switchName] = (isEnabled ? SwitchValueState.HasTrueValue : SwitchValueState.HasFalseValue) + | SwitchValueState.HasLookedForOverride; + + return true; + } + + // 2. The value does not have an override. + s_switchMap[switchName] = SwitchValueState.UnknownValue; + } + } + return false; // we did not find a value for the switch + } + + /// <summary> + /// Assign a switch a value + /// </summary> + /// <param name="switchName">The name of the switch</param> + /// <param name="isEnabled">The value to assign</param> + public static void SetSwitch(string switchName, bool isEnabled) + { + if (switchName == null) + throw new ArgumentNullException("switchName"); + if (switchName.Length == 0) + throw new ArgumentException(Environment.GetResourceString("Argument_EmptyName"), "switchName"); + + lock (s_syncLock) + { + // Store the new value and the fact that we checked in the dictionary + s_switchMap[switchName] = (isEnabled ? SwitchValueState.HasTrueValue : SwitchValueState.HasFalseValue) + | SwitchValueState.HasLookedForOverride; + } + } + + /// <summary> + /// This method is going to be called from the AppContextDefaultValues class when setting up the + /// default values for the switches. !!!! This method is called during the static constructor so it does not + /// take a lock !!!! If you are planning to use this outside of that, please ensure proper locking. + /// </summary> + internal static void DefineSwitchDefault(string switchName, bool isEnabled) + { + s_switchMap[switchName] = isEnabled ? SwitchValueState.HasTrueValue : SwitchValueState.HasFalseValue; + } + #endregion + } +}
\ No newline at end of file |