File: compmod\system\diagnostics\DiagnosticsConfiguration.cs
Project: ndp\fx\src\System.csproj (System)
//------------------------------------------------------------------------------
// <copyright file="DiagnosticsConfiguration.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
 
namespace System.Diagnostics {
    using System;
    using System.Reflection;
    using System.Collections;
    using System.Configuration;
    using System.Threading;
    using System.Runtime.Versioning;
    
    internal enum InitState {
        NotInitialized,
        Initializing,
        Initialized
    }
 
    internal static class DiagnosticsConfiguration {
        private static volatile SystemDiagnosticsSection configSection;
        private static volatile InitState initState = InitState.NotInitialized;
 
        // setting for Switch.switchSetting
        internal static SwitchElementsCollection SwitchSettings {
            get { 
                Initialize();
                SystemDiagnosticsSection configSectionSav = configSection;
                if (configSectionSav != null)
                    return configSectionSav.Switches;
                else
                    return null;
            }
        }
 
        // setting for DefaultTraceListener.AssertUIEnabled
        internal static bool AssertUIEnabled {
            get { 
                Initialize();
                SystemDiagnosticsSection configSectionSav = configSection;
                if (configSectionSav != null && configSectionSav.Assert != null)
                    return configSectionSav.Assert.AssertUIEnabled;
                else
                    return true; // the default
            }
        }
 
        internal static string ConfigFilePath {
            [ResourceExposure(ResourceScope.Machine)]
            [ResourceConsumption(ResourceScope.Machine)]
            get { 
                Initialize();
                SystemDiagnosticsSection configSectionSav = configSection;
                if (configSectionSav != null) 
                    return configSectionSav.ElementInformation.Source;
                else
                    return string.Empty; // the default
            }
        }
 
        // setting for DefaultTraceListener.LogFileName
        internal static string LogFileName {
            [ResourceExposure(ResourceScope.Machine)]
            [ResourceConsumption(ResourceScope.Machine)]
            get { 
                Initialize();
                SystemDiagnosticsSection configSectionSav = configSection;
                if (configSectionSav != null && configSectionSav.Assert != null)
                    return configSectionSav.Assert.LogFileName;
                else
                    return string.Empty; // the default
            }
        }
 
        // setting for TraceInternal.AutoFlush
        internal static bool AutoFlush {
            get { 
                Initialize();
                SystemDiagnosticsSection configSectionSav = configSection;
                if (configSectionSav != null && configSectionSav.Trace != null)
                    return configSectionSav.Trace.AutoFlush;
                else
                    return false; // the default
            }
        }
 
        // setting for TraceInternal.UseGlobalLock
        internal static bool UseGlobalLock {
            get { 
                Initialize();
                SystemDiagnosticsSection configSectionSav = configSection;
                if (configSectionSav != null && configSectionSav.Trace != null)
                    return configSectionSav.Trace.UseGlobalLock;
                else
                    return true; // the default
            }
        }
 
        // setting for TraceInternal.IndentSize
        internal static int IndentSize {
            get { 
                Initialize();
                SystemDiagnosticsSection configSectionSav = configSection;
                if (configSectionSav != null && configSectionSav.Trace != null)
                    return configSectionSav.Trace.IndentSize;
                else
                    return 4; // the default
            }
        }
 
#if !FEATURE_PAL // perfcounter
        internal static int PerfomanceCountersFileMappingSize {
            get {                                                 
                for (int retryCount = 0; !CanInitialize() && retryCount <= 5; ++retryCount) {
                    if (retryCount == 5)
                        return SharedPerformanceCounter.DefaultCountersFileMappingSize;
                        
                    System.Threading.Thread.Sleep(200);
                }                    
                    
                Initialize();
                SystemDiagnosticsSection configSectionSav = configSection;
                if (configSectionSav != null && configSectionSav.PerfCounters != null) {
                    int size = configSectionSav.PerfCounters.FileMappingSize;
                    if (size < SharedPerformanceCounter.MinCountersFileMappingSize)
                        size = SharedPerformanceCounter.MinCountersFileMappingSize;
                                            
                    if (size > SharedPerformanceCounter.MaxCountersFileMappingSize)
                        size = SharedPerformanceCounter.MaxCountersFileMappingSize;
 
                    return size;
              	} 
                else
                    return SharedPerformanceCounter.DefaultCountersFileMappingSize;
            }                
        }
#endif // !FEATURE_PAL
 
        internal static ListenerElementsCollection SharedListeners {
            get {
                Initialize();
                SystemDiagnosticsSection configSectionSav = configSection;
                if (configSectionSav != null)
                    return configSectionSav.SharedListeners;
                else
                    return null;
            }
        }
 
        internal static SourceElementsCollection  Sources {
            get {
                Initialize();
                SystemDiagnosticsSection configSectionSav = configSection;
                if (configSectionSav != null && configSectionSav.Sources != null)
                    return configSectionSav.Sources;
                else
                    return null;
            }
        }
 
        internal static SystemDiagnosticsSection SystemDiagnosticsSection {
            get {
                Initialize();
                return configSection;
            }
        }
        
        private static SystemDiagnosticsSection GetConfigSection() {
            SystemDiagnosticsSection configSection = (SystemDiagnosticsSection) PrivilegedConfigurationManager.GetSection("system.diagnostics");
            return configSection;
        }
 
        internal static bool IsInitializing() {
            return initState == InitState.Initializing;
        }
 
        internal static bool IsInitialized() {
            return initState == InitState.Initialized;
        }
            
 
        internal static bool CanInitialize() {
            return  (initState != InitState.Initializing) && 
                    !ConfigurationManagerInternalFactory.Instance.SetConfigurationSystemInProgress;
        }
        
        internal static void Initialize() {
            // Initialize() is also called by other components outside of Trace (such as PerformanceCounter)
            // as a result using one lock for this critical section and another for Trace API critical sections  
            // (such as Trace.WriteLine) could potentially lead to deadlock between 2 threads that are 
            // executing these critical sections (and consequently obtaining the 2 locks) in the reverse order. 
            // Using the same lock for DiagnosticsConfiguration as well as TraceInternal avoids this issue. 
            // Sequential locks on TraceInternal.critSec by the same thread is a non issue for this critical section.
            lock (TraceInternal.critSec) {
 
                // because some of the code used to load config also uses diagnostics
                // we can't block them while we initialize from config. Therefore we just
                // return immediately and they just use the default values.
                if (    initState != InitState.NotInitialized || 
                        ConfigurationManagerInternalFactory.Instance.SetConfigurationSystemInProgress) {
 
                    return;
                }
 
                initState = InitState.Initializing; // used for preventing recursion
                try {
                    configSection = GetConfigSection();
                }
                finally {
                    initState = InitState.Initialized;
                }
            }
        }
 
        internal static void Refresh() {
            ConfigurationManager.RefreshSection("system.diagnostics");
 
            // There might still be some persistant state left behind for 
            // ConfigPropertyCollection (for ex, swtichelements), probably for perf. 
            // We need to explicitly cleanup any unrecognized attributes that we 
            // have added during last deserialization, so that they are re-added 
            // during the next Config.GetSection properly and we get a chance to
            // populate the Attributes collection for re-deserialization. 
            // Another alternative could be to expose the properties collection
            // directly as Attributes collection (currently we keep a local 
            // hashtable which we explicitly need to keep in sycn and hence the 
            // cleanup logic below) but the down side of that would be we need to
            // explicitly compute what is recognized Vs unrecognized from that 
            // collection when we expose the unrecognized Attributes publically
            SystemDiagnosticsSection configSectionSav = configSection;
            if (configSectionSav != null) {
 
                if (configSectionSav.Switches != null) {
                    foreach (SwitchElement swelem in configSectionSav.Switches)
                        swelem.ResetProperties();
                }
 
                if (configSectionSav.SharedListeners != null) {
                    foreach (ListenerElement lnelem in configSectionSav.SharedListeners)
                        lnelem.ResetProperties();
                }
 
                if (configSectionSav.Sources != null) {
                    foreach (SourceElement srelem in configSectionSav.Sources)
                        srelem.ResetProperties();
                }
            }
 
            configSection = null;
            
            initState = InitState.NotInitialized;
            Initialize();
        }
    }
}