File: LocalAppContext.cs

package info (click to toggle)
mono 6.8.0.105%2Bdfsg-3.3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 1,284,512 kB
  • sloc: cs: 11,172,132; xml: 2,850,069; ansic: 671,653; cpp: 122,091; perl: 59,366; javascript: 30,841; asm: 22,168; makefile: 20,093; sh: 15,020; python: 4,827; pascal: 925; sql: 859; sed: 16; php: 1
file content (138 lines) | stat: -rw-r--r-- 5,488 bytes parent folder | download | duplicates (30)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// ==++==
// 
//   Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// ==--==

// There are cases where we have multiple assemblies that are going to import this file and 
// if they are going to also have InternalsVisibleTo between them, there will be a compiler warning
// that the type is found both in the source and in a referenced assembly. The compiler will prefer 
// the version of the type defined in the source
//
// In order to disable the warning for this type we are disabling this warning for this entire file.
#pragma warning disable 436

// NOTE: This file should not be included in mscorlib. This should only be included in FX libraries that need to provide switches
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading;

namespace System
{
    internal static partial class LocalAppContext
    {
        private delegate bool TryGetSwitchDelegate(string switchName, out bool value);

        private static TryGetSwitchDelegate TryGetSwitchFromCentralAppContext;
        private static bool s_canForwardCalls;

        private static Dictionary<string, bool> s_switchMap = new Dictionary<string, bool>();
        private static readonly object s_syncLock = new object();

        private static bool DisableCaching { get; set; }

        static LocalAppContext()
        {
            // Try to setup the callback into the central AppContext
            s_canForwardCalls = SetupDelegate();

            // Populate the default values of the local app context 
            AppContextDefaultValues.PopulateDefaultValues();

            // Cache the value of the switch that help with testing
            DisableCaching = IsSwitchEnabled(@"TestSwitch.LocalAppContext.DisableCaching");
        }

        public static bool IsSwitchEnabled(string switchName)
        {
            if (s_canForwardCalls)
            {
                bool isEnabledCentrally;
                if (TryGetSwitchFromCentralAppContext(switchName, out isEnabledCentrally))
                {
                    // we found the switch, so return whatever value it has
                    return isEnabledCentrally;
                }
                // if we could not get the value from the central authority, try the local storage.
            }

            return IsSwitchEnabledLocal(switchName);
        }

        private static bool IsSwitchEnabledLocal(string switchName)
        {
            // read the value from the set of local defaults
            bool isEnabled, isPresent;
            lock (s_switchMap)
            {
                isPresent = s_switchMap.TryGetValue(switchName, out isEnabled);
            }

            // If the value is in the set of local switches, reutrn the value
            if (isPresent)
            {
                return isEnabled;
            }

            // if we could not find the switch name, we should return 'false'
            // This will preserve the concept of switches been 'off' unless explicitly set to 'on'
            return false;
        }

        private static bool SetupDelegate()
        {
            Type appContextType = typeof(object).Assembly.GetType("System.AppContext");
            if (appContextType == null)
                return false;

            MethodInfo method = appContextType.GetMethod(
                                            "TryGetSwitch",  // the method name
                                            BindingFlags.Static | BindingFlags.Public,  // binding flags
                                            null, // use the default binder
                                            new Type[] { typeof(string), typeof(bool).MakeByRefType() },
                                            null); // parameterModifiers - this is ignored by the default binder 
            if (method == null)
                return false;

            // Create delegate if we found the method.
            TryGetSwitchFromCentralAppContext = (TryGetSwitchDelegate)Delegate.CreateDelegate(typeof(TryGetSwitchDelegate), method);

            return true;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        internal static bool GetCachedSwitchValue(string switchName, ref int switchValue)
        {
            if (switchValue < 0) return false;
            if (switchValue > 0) return true;

            return GetCachedSwitchValueInternal(switchName, ref switchValue);
        }

        private static bool GetCachedSwitchValueInternal(string switchName, ref int switchValue)
        {
            if (LocalAppContext.DisableCaching)
            {
                return LocalAppContext.IsSwitchEnabled(switchName);
            }

            bool isEnabled = LocalAppContext.IsSwitchEnabled(switchName);
            switchValue = isEnabled ? 1 /*true*/ : -1 /*false*/;
            return isEnabled;
        }

        /// <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 initialValue)
        {
            s_switchMap[switchName] = initialValue;
        }
    }
}

#pragma warning restore 436