File: system\threading\executioncontext.cs
Project: ndp\clr\src\bcl\mscorlib.csproj (mscorlib)
// ==++==
// 
//   Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//
// <OWNER>Microsoft</OWNER>
/*============================================================
**
** Class:  ExecutionContext
**
**
** Purpose: Capture execution  context for a thread
**
** 
===========================================================*/
namespace System.Threading
{    
    using System;
    using System.Security;
    using System.Runtime.Remoting;
    using System.Security.Principal;
    using System.Collections;
    using System.Collections.Generic;
    using System.Reflection;
    using System.Runtime.ExceptionServices;
    using System.Runtime.Serialization;
    using System.Security.Permissions;
#if FEATURE_REMOTING
    using System.Runtime.Remoting.Messaging;
#endif // FEATURE_REMOTING
    using System.Runtime.InteropServices;
    using System.Runtime.CompilerServices;
    using System.Runtime.ConstrainedExecution;
    using System.Diagnostics.Contracts;
    using System.Diagnostics.CodeAnalysis;
 
#if FEATURE_CORECLR
    [System.Security.SecurityCritical] // auto-generated
#endif
    [System.Runtime.InteropServices.ComVisible(true)]
    public delegate void ContextCallback(Object state);
 
#if FEATURE_CORECLR

    [SecurityCritical]
    internal struct ExecutionContextSwitcher
    {
        internal ExecutionContext m_ec;
        internal SynchronizationContext m_sc;
 
        internal void Undo()
        {
            SynchronizationContext.SetSynchronizationContext(m_sc);
            ExecutionContext.Restore(m_ec);
        }
    }
 
    public sealed class ExecutionContext : IDisposable
    {
        public static readonly ExecutionContext Default = new ExecutionContext();
 
        [ThreadStatic]
        [SecurityCritical]
        static ExecutionContext t_currentMaybeNull;
 
        private readonly Dictionary<IAsyncLocal, object> m_localValues;
        private readonly List<IAsyncLocal> m_localChangeNotifications;
 
        private ExecutionContext()
        {
            m_localValues = new Dictionary<IAsyncLocal, object>();
            m_localChangeNotifications = new List<IAsyncLocal>();
        }
 
        private ExecutionContext(ExecutionContext other)
        {
            m_localValues = new Dictionary<IAsyncLocal, object>(other.m_localValues);
            m_localChangeNotifications = new List<IAsyncLocal>(other.m_localChangeNotifications);
        }
 
        [SecuritySafeCritical]
        public static ExecutionContext Capture()
        {
            return t_currentMaybeNull ?? ExecutionContext.Default;
        }
 
        [SecurityCritical]
        [HandleProcessCorruptedStateExceptions]
        public static void Run(ExecutionContext executionContext, ContextCallback callback, Object state)
        {
            ExecutionContextSwitcher ecsw = default(ExecutionContextSwitcher);
            try
            {
                EstablishCopyOnWriteScope(ref ecsw);
 
                ExecutionContext.Restore(executionContext);
                callback(state);
            }
            catch
            {
                // Note: we have a "catch" rather than a "finally" because we want
                // to stop the first pass of EH here.  That way we can restore the previous
                // context before any of our callers' EH filters run.  That means we need to 
                // end the scope separately in the non-exceptional case below.
                ecsw.Undo();
                throw;
            }
            ecsw.Undo();
        }
 
        [SecurityCritical]
        internal static void Restore(ExecutionContext executionContext)
        {
            if (executionContext == null)
                throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NullContext"));
 
            ExecutionContext previous = t_currentMaybeNull ?? Default;
            t_currentMaybeNull = executionContext;
 
            if (previous != executionContext)
                OnContextChanged(previous, executionContext);
        }
 
        [SecurityCritical]
        static internal void EstablishCopyOnWriteScope(ref ExecutionContextSwitcher ecsw)
        {
            ecsw.m_ec = Capture();
            ecsw.m_sc = SynchronizationContext.CurrentNoFlow;
        }
 
        [SecurityCritical]
        [HandleProcessCorruptedStateExceptions]
        private static void OnContextChanged(ExecutionContext previous, ExecutionContext current)
        {
            previous = previous ?? Default;
 
            foreach (IAsyncLocal local in previous.m_localChangeNotifications)
            {
                object previousValue;
                object currentValue;
                previous.m_localValues.TryGetValue(local, out previousValue);
                current.m_localValues.TryGetValue(local, out currentValue);
 
                if (previousValue != currentValue)
                    local.OnValueChanged(previousValue, currentValue, true);
            }
 
            if (current.m_localChangeNotifications != previous.m_localChangeNotifications)
            {
                try
                {
                    foreach (IAsyncLocal local in current.m_localChangeNotifications)
                    {
                        // If the local has a value in the previous context, we already fired the event for that local
                        // in the code above.
                        object previousValue;
                        if (!previous.m_localValues.TryGetValue(local, out previousValue))
                        {
                            object currentValue;
                            current.m_localValues.TryGetValue(local, out currentValue);
 
                            if (previousValue != currentValue)
                                local.OnValueChanged(previousValue, currentValue, true);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Environment.FailFast(
                        Environment.GetResourceString("ExecutionContext_ExceptionInAsyncLocalNotification"), 
                        ex);
                }
            }        
        }
 
        [SecurityCritical]
        internal static object GetLocalValue(IAsyncLocal local)
        {
            ExecutionContext current = t_currentMaybeNull;
            if (current == null)
                return null;
 
            object value;
            current.m_localValues.TryGetValue(local, out value);
            return value;
        }
 
        [SecurityCritical]
        internal static void SetLocalValue(IAsyncLocal local, object newValue, bool needChangeNotifications)
        {
            ExecutionContext current = t_currentMaybeNull ?? ExecutionContext.Default;
 
            object previousValue;
            bool hadPreviousValue = current.m_localValues.TryGetValue(local, out previousValue);
 
            if (previousValue == newValue)
                return;
 
            current = new ExecutionContext(current);
            current.m_localValues[local] = newValue;
 
            t_currentMaybeNull = current;
 
            if (needChangeNotifications)
            {
                if (hadPreviousValue)
                    Contract.Assert(current.m_localChangeNotifications.Contains(local));
                else
                    current.m_localChangeNotifications.Add(local);
 
                local.OnValueChanged(previousValue, newValue, false);
            }
        }
 
    #region Wrappers for CLR compat, to avoid ifdefs all over the BCL

        [Flags]
        internal enum CaptureOptions
        {
            None = 0x00,
            IgnoreSyncCtx = 0x01,
            OptimizeDefaultCase = 0x02,
        }
 
        [SecurityCritical]
        internal static ExecutionContext Capture(ref StackCrawlMark stackMark, CaptureOptions captureOptions)
        {
            return Capture();
        }
 
        [SecuritySafeCritical]
        [FriendAccessAllowed]
        internal static ExecutionContext FastCapture()
        {
            return Capture();
        }
 
        [SecurityCritical]
        [FriendAccessAllowed]
        internal static void Run(ExecutionContext executionContext, ContextCallback callback, Object state, bool preserveSyncCtx)
        {
            Run(executionContext, callback, state);
        }
 
        [SecurityCritical]
        internal bool IsDefaultFTContext(bool ignoreSyncCtx)
        {
            ExecutionContext current = t_currentMaybeNull;
            return current == null || current == Default;
        }
 
        [SecuritySafeCritical]
        public ExecutionContext CreateCopy()
        {
            return this; // since CoreCLR's ExecutionContext is immutable, we don't need to create copies.
        }
 
        public void Dispose()
        {
            // For CLR compat only
        }
 
        public static bool IsFlowSuppressed()
        {
            return false;
        }
 
        internal static ExecutionContext PreAllocatedDefault
        {
            [SecuritySafeCritical]
            get { return ExecutionContext.Default; }
        }
 
        internal bool IsPreAllocatedDefault
        {
            get { return this == ExecutionContext.Default; }
        }
 
    #endregion
    }
 
#else // FEATURE_CORECLR
 
    // Legacy desktop ExecutionContext implementation
 
    internal struct ExecutionContextSwitcher
    {
        internal ExecutionContext.Reader outerEC; // previous EC we need to restore on Undo
        internal bool outerECBelongsToScope;
#if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK        
        internal SecurityContextSwitcher scsw;
#endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
        internal Object hecsw;
#if !FEATURE_PAL && FEATURE_IMPERSONATION
        internal WindowsIdentity wi;
        internal bool cachedAlwaysFlowImpersonationPolicy;
        internal bool wiIsValid;
#endif
        internal Thread thread;
 
        [System.Security.SecurityCritical]  // auto-generated
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
#if FEATURE_CORRUPTING_EXCEPTIONS
        [HandleProcessCorruptedStateExceptions] // 
        [SuppressMessage("Microsoft.Security", "CA2153:DoNotCatchCorruptedStateExceptionsInGeneralHandlers", Justification = "Reviewed for security")]
#endif // FEATURE_CORRUPTING_EXCEPTIONS
        internal bool UndoNoThrow()
        {
            try
            {
                Undo();
            }
            catch (Exception ex)
            {
                if (!AppContextSwitches.UseLegacyExecutionContextBehaviorUponUndoFailure)
                {
                    // Fail fast since we can't continue safely
                    Environment.FailFast(Environment.GetResourceString("ExecutionContext_UndoFailed"), ex);
                }
                return false;
            }
            return true;
        }
        
        [System.Security.SecurityCritical]  // auto-generated
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
        internal void Undo()
        {
            //
            // Don't use an uninitialized switcher, or one that's already been used.
            //
            if (thread == null)
                return; // Don't do anything
 
            Contract.Assert(Thread.CurrentThread == this.thread);
            Thread currentThread = this.thread;
 
            // 
            // Restore the HostExecutionContext before restoring the ExecutionContext.
            //
#if FEATURE_CAS_POLICY                
            if (hecsw != null)
                HostExecutionContextSwitcher.Undo(hecsw);
#endif // FEATURE_CAS_POLICY
 
            //
            // restore the saved Execution Context.  Note that this will also restore the 
            // SynchronizationContext, Logical/IllogicalCallContext, etc.
            //
            ExecutionContext.Reader innerEC = currentThread.GetExecutionContextReader();
            currentThread.SetExecutionContext(outerEC, outerECBelongsToScope);
 
#if DEBUG
            try
            {
                currentThread.ForbidExecutionContextMutation = true;
#endif
 
                //
                // Tell the SecurityContext to do the side-effects of restoration.
                //
#if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
                if (scsw.currSC != null)
                {
                    // Any critical failure inside scsw will cause FailFast
                    scsw.Undo();
                }
#endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
 
#if !FEATURE_PAL && FEATURE_IMPERSONATION
                if (wiIsValid)
                    SecurityContext.RestoreCurrentWI(outerEC, innerEC, wi, cachedAlwaysFlowImpersonationPolicy);
#endif
 
                thread = null; // this will prevent the switcher object being used again
#if DEBUG
            }
            finally
            {
                currentThread.ForbidExecutionContextMutation = false;
            }
#endif
            ExecutionContext.OnAsyncLocalContextChanged(innerEC.DangerousGetRawExecutionContext(), outerEC.DangerousGetRawExecutionContext());
        }
    }
 
 
    public struct AsyncFlowControl: IDisposable
    {
        private bool useEC;
        private ExecutionContext _ec;
#if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
        private SecurityContext _sc;
#endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
        private Thread _thread;
#if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
        [SecurityCritical]
        internal void Setup(SecurityContextDisableFlow flags)
        {
            useEC = false;
            Thread currentThread = Thread.CurrentThread;
            _sc = currentThread.GetMutableExecutionContext().SecurityContext;
            _sc._disableFlow = flags;
            _thread = currentThread;
        }
#endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
        [SecurityCritical]
        internal void Setup()
        {
            useEC = true;
            Thread currentThread = Thread.CurrentThread;
            _ec = currentThread.GetMutableExecutionContext();
            _ec.isFlowSuppressed = true;
            _thread = currentThread;
        }
        
        public void Dispose()
        {
            Undo();
        }
        
        [SecuritySafeCritical]
        public void Undo()
        {
            if (_thread == null)
            {
                throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CannotUseAFCMultiple"));
            }  
            if (_thread != Thread.CurrentThread)
            {
                throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CannotUseAFCOtherThread"));
            }
            if (useEC) 
            {
                if (Thread.CurrentThread.GetMutableExecutionContext() != _ec)
                {
                    throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_AsyncFlowCtrlCtxMismatch"));
                }      
                ExecutionContext.RestoreFlow();
            }
#if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK            
            else
            {
                if (!Thread.CurrentThread.GetExecutionContextReader().SecurityContext.IsSame(_sc))
                {
                    throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_AsyncFlowCtrlCtxMismatch"));
                }      
                SecurityContext.RestoreFlow();
            }
#endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK            
            _thread = null;
        }
        
        public override int GetHashCode()
        {
            // review - Microsoft
            return _thread == null ? ToString().GetHashCode() : _thread.GetHashCode();
        }
        
        public override bool Equals(Object obj)
        {
            if (obj is AsyncFlowControl)
                return Equals((AsyncFlowControl)obj);
            else
                return false;
        }
    
        public bool Equals(AsyncFlowControl obj)
        {
            return obj.useEC == useEC && obj._ec == _ec &&
#if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK                            
                obj._sc == _sc && 
#endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
                obj._thread == _thread;
        }
    
        public static bool operator ==(AsyncFlowControl a, AsyncFlowControl b)
        {
            return a.Equals(b);
        }
        
        public static bool operator !=(AsyncFlowControl a, AsyncFlowControl b)
        {
            return !(a == b);
        }
        
    }
    
 
    [Serializable] 
    public sealed class ExecutionContext : IDisposable, ISerializable
    {
        /*=========================================================================
        ** Data accessed from managed code that needs to be defined in 
        ** ExecutionContextObject  to maintain alignment between the two classes.
        ** DON'T CHANGE THESE UNLESS YOU MODIFY ExecutionContextObject in vm\object.h
        =========================================================================*/
#if FEATURE_CAS_POLICY        
        private HostExecutionContext _hostExecutionContext;
#endif // FEATURE_CAS_POLICY
        private SynchronizationContext _syncContext;
        private SynchronizationContext _syncContextNoFlow;
#if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
        private SecurityContext     _securityContext;
#endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
#if FEATURE_REMOTING
        [System.Security.SecurityCritical] // auto-generated
        private LogicalCallContext  _logicalCallContext;
        private IllogicalCallContext _illogicalCallContext;  // this call context follows the physical thread
#endif // #if FEATURE_REMOTING
 
        enum Flags
        {
            None = 0x0,
            IsNewCapture = 0x1,
            IsFlowSuppressed = 0x2,
            IsPreAllocatedDefault = 0x4
        }
        private Flags _flags;
 
        private IAsyncLocalValueMap _localValues;
        private IAsyncLocal[] _localChangeNotifications;
 
        internal bool isNewCapture 
        { 
            get
            { 
                return (_flags & (Flags.IsNewCapture | Flags.IsPreAllocatedDefault)) != Flags.None; 
            }
            set
            {
                Contract.Assert(!IsPreAllocatedDefault);
                if (value)
                    _flags |= Flags.IsNewCapture;
                else
                    _flags &= ~Flags.IsNewCapture;
            }
        }
        internal bool isFlowSuppressed 
        { 
            get 
            { 
                return (_flags & Flags.IsFlowSuppressed) != Flags.None; 
            }
            set
            {
                Contract.Assert(!IsPreAllocatedDefault);
                if (value)
                    _flags |= Flags.IsFlowSuppressed;
                else
                    _flags &= ~Flags.IsFlowSuppressed;
            }
        }
       
 
        private static readonly ExecutionContext s_dummyDefaultEC = new ExecutionContext(isPreAllocatedDefault: true);
 
        static internal ExecutionContext PreAllocatedDefault
        {
            [SecuritySafeCritical]
            get { return s_dummyDefaultEC; }
        }
 
        internal bool IsPreAllocatedDefault
        {
            get
            {
                // we use _flags instead of a direct comparison w/ s_dummyDefaultEC to avoid the static access on 
                // hot code paths.
                if ((_flags & Flags.IsPreAllocatedDefault) != Flags.None)
                {
                    Contract.Assert(this == s_dummyDefaultEC);
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }
 
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        internal ExecutionContext()
        {            
        }
 
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        internal ExecutionContext(bool isPreAllocatedDefault)
        {
            if (isPreAllocatedDefault)
                _flags = Flags.IsPreAllocatedDefault;
        }
 
        // Read-only wrapper around ExecutionContext.  This enables safe reading of an ExecutionContext without accidentally modifying it.
        internal struct Reader
        {
            ExecutionContext m_ec;
 
            public Reader(ExecutionContext ec) { m_ec = ec; }
 
            public ExecutionContext DangerousGetRawExecutionContext() { return m_ec; }
 
            public bool IsNull { get { return m_ec == null; } }
            [SecurityCritical]
            public bool IsDefaultFTContext(bool ignoreSyncCtx) { return m_ec.IsDefaultFTContext(ignoreSyncCtx); }
            public bool IsFlowSuppressed 
            {
                [MethodImpl(MethodImplOptions.AggressiveInlining)]
                get { return IsNull ? false : m_ec.isFlowSuppressed; } 
            }
            //public Thread Thread { get { return m_ec._thread; } }
            public bool IsSame(ExecutionContext.Reader other) { return m_ec == other.m_ec; }
 
            public SynchronizationContext SynchronizationContext { get { return IsNull ? null : m_ec.SynchronizationContext; } }
            public SynchronizationContext SynchronizationContextNoFlow { get { return IsNull ? null : m_ec.SynchronizationContextNoFlow; } }
 
#if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
            public SecurityContext.Reader SecurityContext 
            {
                [SecurityCritical]
                [MethodImpl(MethodImplOptions.AggressiveInlining)]
                get { return new SecurityContext.Reader(IsNull ? null : m_ec.SecurityContext); } 
            }
#endif
 
#if FEATURE_REMOTING
            public LogicalCallContext.Reader LogicalCallContext 
            {
                [SecurityCritical]
                get { return new LogicalCallContext.Reader(IsNull ? null : m_ec.LogicalCallContext); } 
            }
 
            public IllogicalCallContext.Reader IllogicalCallContext 
            {
                [SecurityCritical]
                get { return new IllogicalCallContext.Reader(IsNull ? null : m_ec.IllogicalCallContext); } 
            }
#endif
 
            [SecurityCritical]
            public object GetLocalValue(IAsyncLocal local)
            {
                if (IsNull)
                    return null;
 
                if (m_ec._localValues == null)
                    return null;
 
                object value;
                m_ec._localValues.TryGetValue(local, out value);
                return value;
            }
 
            [SecurityCritical]
            public bool HasSameLocalValues(ExecutionContext other)
            {
                var thisLocalValues = IsNull ? null : m_ec._localValues;
                var otherLocalValues = other == null ? null : other._localValues;
                return thisLocalValues == otherLocalValues;
            }
 
            [SecurityCritical]
            public bool HasLocalValues()
            {
                return !this.IsNull && m_ec._localValues != null;
            }
        }
 
        [SecurityCritical]
        internal static object GetLocalValue(IAsyncLocal local)
        {
            return Thread.CurrentThread.GetExecutionContextReader().GetLocalValue(local);
        }
 
        [SecurityCritical]
        internal static void SetLocalValue(IAsyncLocal local, object newValue, bool needChangeNotifications)
        {
            ExecutionContext current = Thread.CurrentThread.GetMutableExecutionContext();
 
            object previousValue = null;
            bool hadPreviousValue = current._localValues != null && current._localValues.TryGetValue(local, out previousValue);
 
            if (previousValue == newValue)
                return;
 
            // Regarding 'treatNullValueAsNonexistent: !needChangeNotifications' below:
            // - When change notifications are not necessary for this IAsyncLocal, there is no observable difference between
            //   storing a null value and removing the IAsyncLocal from 'm_localValues'
            // - When change notifications are necessary for this IAsyncLocal, the IAsyncLocal's absence in 'm_localValues'
            //   indicates that this is the first value change for the IAsyncLocal and it needs to be registered for change
            //   notifications. So in this case, a null value must be stored in 'm_localValues' to indicate that the IAsyncLocal
            //   is already registered for change notifications.
            IAsyncLocalValueMap newValues = current._localValues;
            if (newValues == null)
            {
                newValues = AsyncLocalValueMap.Create(local, newValue, treatNullValueAsNonexistent: !needChangeNotifications);
            }
            else
            {
                newValues = newValues.Set(local, newValue, treatNullValueAsNonexistent: !needChangeNotifications);
            }
            current._localValues = newValues;
 
            if (needChangeNotifications)
            {
                //
                // Either copy the change notification array, or create a new one, depending on whether we need to add a new item.
                //
                if (hadPreviousValue)
                {
                    Contract.Assert(current._localChangeNotifications != null);
                    Contract.Assert(Array.IndexOf(current._localChangeNotifications, local) >= 0);
                }
                else
                {
                    IAsyncLocal[] newChangeNotifications = current._localChangeNotifications;
                    if (newChangeNotifications == null)
                    {
                        newChangeNotifications = new IAsyncLocal[1] { local };
                    }
                    else
                    {
                        int newNotificationIndex = newChangeNotifications.Length;
                        Array.Resize(ref newChangeNotifications, newNotificationIndex + 1);
                        newChangeNotifications[newNotificationIndex] = local;
                    }
                    current._localChangeNotifications = newChangeNotifications;
                }
 
                local.OnValueChanged(previousValue, newValue, false);
            }
        }
 
        [SecurityCritical]
        [HandleProcessCorruptedStateExceptions]
        internal static void OnAsyncLocalContextChanged(ExecutionContext previous, ExecutionContext current)
        {
            IAsyncLocal[] previousLocalChangeNotifications = (previous == null) ? null : previous._localChangeNotifications;
            if (previousLocalChangeNotifications != null)
            {
                foreach (IAsyncLocal local in previousLocalChangeNotifications)
                {
                    object previousValue = null;
                    if (previous != null && previous._localValues != null)
                        previous._localValues.TryGetValue(local, out previousValue);
 
                    object currentValue = null;
                    if (current != null && current._localValues != null)
                        current._localValues.TryGetValue(local, out currentValue);
 
                    if (previousValue != currentValue)
                        local.OnValueChanged(previousValue, currentValue, true);
                }
            }
 
            IAsyncLocal[] currentLocalChangeNotifications = (current == null) ? null : current._localChangeNotifications;
            if (currentLocalChangeNotifications != null && currentLocalChangeNotifications != previousLocalChangeNotifications)
            {
                try
                {
                    foreach (IAsyncLocal local in currentLocalChangeNotifications)
                    {
                        // If the local has a value in the previous context, we already fired the event for that local
                        // in the code above.
                        object previousValue = null;
                        if (previous == null ||
                            previous._localValues == null ||
                            !previous._localValues.TryGetValue(local, out previousValue))
                        {
                            object currentValue = null;
                            if (current != null && current._localValues != null)
                                current._localValues.TryGetValue(local, out currentValue);
 
                            if (previousValue != currentValue)
                                local.OnValueChanged(previousValue, currentValue, true);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Environment.FailFast(
                        Environment.GetResourceString("ExecutionContext_ExceptionInAsyncLocalNotification"),
                        ex);
                }
            }
        }
 
 
#if FEATURE_REMOTING
        internal LogicalCallContext LogicalCallContext
        {
            [System.Security.SecurityCritical]  // auto-generated
            get
            {
                if (_logicalCallContext == null)
                {
                _logicalCallContext = new LogicalCallContext();
                }
                return _logicalCallContext;
            }
            [System.Security.SecurityCritical]  // auto-generated
            set
            {
                Contract.Assert(this != s_dummyDefaultEC);
                _logicalCallContext = value;
            }
        }
 
        internal IllogicalCallContext IllogicalCallContext
        {
            get
            {
                if (_illogicalCallContext == null)
                {
                _illogicalCallContext = new IllogicalCallContext();
                }
                return _illogicalCallContext;
            }
            set
            {
                Contract.Assert(this != s_dummyDefaultEC);
                _illogicalCallContext = value;
            }
        }
#endif // #if FEATURE_REMOTING
 
        internal SynchronizationContext SynchronizationContext
        {
            [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
            get
            {
                return _syncContext;
            }
            [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
            set
            {
                Contract.Assert(this != s_dummyDefaultEC);
                _syncContext = value;
            }
        }
 
        internal SynchronizationContext SynchronizationContextNoFlow
        {
            [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
            get
            {
                return _syncContextNoFlow;
            }
            [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
            set
            {
                Contract.Assert(this != s_dummyDefaultEC);
                _syncContextNoFlow = value;
            }
        }
 
#if FEATURE_CAS_POLICY
    internal HostExecutionContext HostExecutionContext
    {
            get 
            {
                return _hostExecutionContext;
            }
            set 
            {
                Contract.Assert(this != s_dummyDefaultEC);
                _hostExecutionContext = value;
            }
    }
#endif // FEATURE_CAS_POLICY
#if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
        internal  SecurityContext SecurityContext
        {
            [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
            get
            {
                return _securityContext;
            }
            [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
            set
            {
                Contract.Assert(this != s_dummyDefaultEC);
                        // store the new security context 
                        _securityContext = value;
                        // perform the reverse link too
                        if (value != null)
                            _securityContext.ExecutionContext = this;
            }
        }
#endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
 
 
        public void Dispose()
        {
            if(this.IsPreAllocatedDefault)
                return; //Do nothing if this is the default context
#if FEATURE_CAS_POLICY
            if (_hostExecutionContext != null)
                _hostExecutionContext.Dispose();
#endif // FEATURE_CAS_POLICY
#if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
            if (_securityContext != null)
                _securityContext.Dispose();
#endif //FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
        }
        
        [DynamicSecurityMethod]
        [System.Security.SecurityCritical]  // auto-generated_required
        public static void Run(ExecutionContext executionContext, ContextCallback callback, Object state)
        {
            if (executionContext == null)
                throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NullContext"));
            if (!executionContext.isNewCapture)
                throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NotNewCaptureContext"));
            
            Run(executionContext, callback, state, false);
        }
 
        // This method is special from a security perspective - the VM will not allow a stack walk to
        // continue past the call to ExecutionContext.Run.  If you change the signature to this method, make
        // sure to update SecurityStackWalk::IsSpecialRunFrame in the VM to search for the new signature.
        [DynamicSecurityMethod]
        [SecurityCritical]
        [FriendAccessAllowed]
        internal static void Run(ExecutionContext executionContext, ContextCallback callback, Object state, bool preserveSyncCtx)
        {
            RunInternal(executionContext, callback, state, preserveSyncCtx);
        }
 
        // Actual implementation of Run is here, in a non-DynamicSecurityMethod, because the JIT seems to refuse to inline callees into
        // a DynamicSecurityMethod.
        [SecurityCritical]
        [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "Reviewed for thread safety")]
        [HandleProcessCorruptedStateExceptions]
        internal static void RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, bool preserveSyncCtx)
        {
            Contract.Assert(executionContext != null);
            if (executionContext.IsPreAllocatedDefault)
            {
                Contract.Assert(executionContext.IsDefaultFTContext(preserveSyncCtx));
            }
            else
            {
                Contract.Assert(executionContext.isNewCapture);
                executionContext.isNewCapture = false;
            }
 
            Thread currentThread = Thread.CurrentThread;
            ExecutionContextSwitcher ecsw = default(ExecutionContextSwitcher);
 
            RuntimeHelpers.PrepareConstrainedRegions();
            try
            {
                ExecutionContext.Reader ec = currentThread.GetExecutionContextReader();
                if ( (ec.IsNull || ec.IsDefaultFTContext(preserveSyncCtx)) && 
    #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK                
                    SecurityContext.CurrentlyInDefaultFTSecurityContext(ec) && 
    #endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK                
                    executionContext.IsDefaultFTContext(preserveSyncCtx) &&
                    ec.HasSameLocalValues(executionContext)
                    )
                {
                    // Neither context is interesting, so we don't need to set the context.
                    // We do need to reset any changes made by the user's callback,
                    // so here we establish a "copy-on-write scope".  Any changes will
                    // result in a copy of the context being made, preserving the original
                    // context.
                    EstablishCopyOnWriteScope(currentThread, true, ref ecsw);
                }
                else
                {
                    if (executionContext.IsPreAllocatedDefault)
                        executionContext = new ExecutionContext();
                    ecsw = SetExecutionContext(executionContext, preserveSyncCtx);
                }
 
                //
                // Call the user's callback
                //
                callback(state);
            }
            finally
            {
                ecsw.Undo();
            }
        }
 
        [SecurityCritical]
        static internal void EstablishCopyOnWriteScope(ref ExecutionContextSwitcher ecsw)
        {
            EstablishCopyOnWriteScope(Thread.CurrentThread, false, ref ecsw);
        }
 
        [SecurityCritical]
        static private void EstablishCopyOnWriteScope(Thread currentThread, bool knownNullWindowsIdentity, ref ExecutionContextSwitcher ecsw)
        {
            Contract.Assert(currentThread == Thread.CurrentThread);
 
            ecsw.outerEC = currentThread.GetExecutionContextReader();
            ecsw.outerECBelongsToScope = currentThread.ExecutionContextBelongsToCurrentScope;
 
#if !FEATURE_PAL && FEATURE_IMPERSONATION
            ecsw.cachedAlwaysFlowImpersonationPolicy = SecurityContext.AlwaysFlowImpersonationPolicy;
            if (knownNullWindowsIdentity)
                Contract.Assert(SecurityContext.GetCurrentWI(ecsw.outerEC, ecsw.cachedAlwaysFlowImpersonationPolicy) == null);
            else
                ecsw.wi = SecurityContext.GetCurrentWI(ecsw.outerEC, ecsw.cachedAlwaysFlowImpersonationPolicy);
            ecsw.wiIsValid = true;
#endif
            currentThread.ExecutionContextBelongsToCurrentScope = false;
            ecsw.thread = currentThread;
        }
 
            
        // Sets the given execution context object on the thread.
        // Returns the previous one.
        [System.Security.SecurityCritical]  // auto-generated
        [DynamicSecurityMethodAttribute()]
        [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
#if FEATURE_CORRUPTING_EXCEPTIONS
        [HandleProcessCorruptedStateExceptions] // 
#endif // FEATURE_CORRUPTING_EXCEPTIONS
        internal  static ExecutionContextSwitcher SetExecutionContext(ExecutionContext executionContext, bool preserveSyncCtx)
        {
#if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK                        
            StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
#endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
 
            Contract.Assert(executionContext != null);
            Contract.Assert(executionContext != s_dummyDefaultEC);
 
            // Set up the switcher object to return;
            ExecutionContextSwitcher ecsw = new ExecutionContextSwitcher();
            
            Thread currentThread = Thread.CurrentThread;
            ExecutionContext.Reader outerEC = currentThread.GetExecutionContextReader();
 
            ecsw.thread = currentThread;
            ecsw.outerEC = outerEC;
            ecsw.outerECBelongsToScope = currentThread.ExecutionContextBelongsToCurrentScope;
 
            if (preserveSyncCtx)
                executionContext.SynchronizationContext = outerEC.SynchronizationContext;
            executionContext.SynchronizationContextNoFlow = outerEC.SynchronizationContextNoFlow;
 
            currentThread.SetExecutionContext(executionContext, belongsToCurrentScope: true);
 
            RuntimeHelpers.PrepareConstrainedRegions();
            try
            {
                OnAsyncLocalContextChanged(outerEC.DangerousGetRawExecutionContext(), executionContext);
 
#if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK                    
                //set the security context
                SecurityContext sc = executionContext.SecurityContext;
                if (sc != null)
                {
                    // non-null SC: needs to be set
                    SecurityContext.Reader prevSeC = outerEC.SecurityContext;
                    ecsw.scsw = SecurityContext.SetSecurityContext(sc, prevSeC, false, ref stackMark);
                }
                else if (!SecurityContext.CurrentlyInDefaultFTSecurityContext(ecsw.outerEC))
                {
                    // null incoming SC, but we're currently not in FT: use static FTSC to set
                    SecurityContext.Reader prevSeC = outerEC.SecurityContext;
                    ecsw.scsw = SecurityContext.SetSecurityContext(SecurityContext.FullTrustSecurityContext, prevSeC, false, ref stackMark);
                }
#endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
#if FEATURE_CAS_POLICY                
                // set the Host Context
                HostExecutionContext hostContext = executionContext.HostExecutionContext;
                if (hostContext != null)
                {
                    ecsw.hecsw = HostExecutionContextManager.SetHostExecutionContextInternal(hostContext);
                } 
#endif // FEATURE_CAS_POLICY
            }
            catch
            {
                ecsw.UndoNoThrow();
                throw;
            }
            return ecsw;    
        }
 
        //
        // Public CreateCopy.  Used to copy captured ExecutionContexts so they can be reused multiple times.
        // This should only copy the portion of the context that we actually capture.
        //
        [SecuritySafeCritical]
        public ExecutionContext CreateCopy()
        {
            if (!isNewCapture)
            {
                throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CannotCopyUsedContext"));
            }
            ExecutionContext ec = new ExecutionContext();
            ec.isNewCapture = true;
            ec._syncContext = _syncContext == null ? null : _syncContext.CreateCopy();
            ec._localValues = _localValues;
            ec._localChangeNotifications = _localChangeNotifications;
#if FEATURE_CAS_POLICY
            // capture the host execution context
            ec._hostExecutionContext = _hostExecutionContext == null ? null : _hostExecutionContext.CreateCopy();
#endif // FEATURE_CAS_POLICY
#if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
            if (_securityContext != null)
            {
                ec._securityContext = _securityContext.CreateCopy();
                ec._securityContext.ExecutionContext = ec;
            }
#endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
 
#if FEATURE_REMOTING
            if (this._logicalCallContext != null)
                ec.LogicalCallContext = (LogicalCallContext)this.LogicalCallContext.Clone();
 
            Contract.Assert(this._illogicalCallContext == null);
#endif // #if FEATURE_REMOTING
 
            return ec;
        }
 
        //
        // Creates a complete copy, used for copy-on-write.
        //
        [SecuritySafeCritical]
        internal ExecutionContext CreateMutableCopy()
        {
            Contract.Assert(!this.isNewCapture);
 
            ExecutionContext ec = new ExecutionContext();
 
            // We don't deep-copy the SyncCtx, since we're still in the same context after copy-on-write.
            ec._syncContext = this._syncContext;
            ec._syncContextNoFlow = this._syncContextNoFlow;
 
#if FEATURE_CAS_POLICY
            // capture the host execution context
            ec._hostExecutionContext = this._hostExecutionContext == null ? null : _hostExecutionContext.CreateCopy();
#endif // FEATURE_CAS_POLICY
 
#if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
            if (_securityContext != null)
            {
                ec._securityContext = this._securityContext.CreateMutableCopy();
                ec._securityContext.ExecutionContext = ec;
            }
#endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
 
#if FEATURE_REMOTING
            if (this._logicalCallContext != null)
                ec.LogicalCallContext = (LogicalCallContext)this.LogicalCallContext.Clone();
 
            if (this._illogicalCallContext != null)
                ec.IllogicalCallContext = (IllogicalCallContext)this.IllogicalCallContext.CreateCopy();
#endif // #if FEATURE_REMOTING
 
            ec._localValues = this._localValues;
            ec._localChangeNotifications = this._localChangeNotifications;
            ec.isFlowSuppressed = this.isFlowSuppressed;
 
            return ec;
        }
 
        [System.Security.SecurityCritical]  // auto-generated_required
        public static AsyncFlowControl SuppressFlow()
        {
            if (IsFlowSuppressed())
            {
                throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CannotSupressFlowMultipleTimes"));
            }
            Contract.EndContractBlock();
            AsyncFlowControl afc = new AsyncFlowControl();
            afc.Setup();
            return afc;
        }
 
        [SecuritySafeCritical]
        public static void RestoreFlow()
        {
            ExecutionContext ec = Thread.CurrentThread.GetMutableExecutionContext();
            if (!ec.isFlowSuppressed)
            {
                throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CannotRestoreUnsupressedFlow"));
            }
            ec.isFlowSuppressed = false;
        }
 
        [Pure]
        public static bool IsFlowSuppressed()
        {
            return Thread.CurrentThread.GetExecutionContextReader().IsFlowSuppressed;
        }
 
        [System.Security.SecuritySafeCritical]  // auto-generated
        [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
        public static ExecutionContext Capture()
        {
            // set up a stack mark for finding the caller
            StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
            return ExecutionContext.Capture(ref stackMark, CaptureOptions.None);            
        }
 
        //
        // Captures an ExecutionContext with optimization for the "default" case, and captures a "null" synchronization context.
        // When calling ExecutionContext.Run on the returned context, specify ignoreSyncCtx = true
        //
        [System.Security.SecuritySafeCritical]  // auto-generated
        [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
        [FriendAccessAllowed]
        internal static ExecutionContext FastCapture()
        {
            // set up a stack mark for finding the caller
            StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
            return ExecutionContext.Capture(ref stackMark, CaptureOptions.IgnoreSyncCtx | CaptureOptions.OptimizeDefaultCase);
        }
 
 
        [Flags]
        internal enum CaptureOptions
        {
            None = 0x00,
 
            IgnoreSyncCtx = 0x01,       //Don't flow SynchronizationContext
 
            OptimizeDefaultCase = 0x02, //Faster in the typical case, but can't show the result to users
                                        // because they could modify the shared default EC.
                                        // Use this only if you won't be exposing the captured EC to users.
        }
 
    // internal helper to capture the current execution context using a passed in stack mark
        [System.Security.SecurityCritical]  // auto-generated
        static internal ExecutionContext Capture(ref StackCrawlMark stackMark, CaptureOptions options)
        {
            ExecutionContext.Reader ecCurrent = Thread.CurrentThread.GetExecutionContextReader();
 
            // check to see if Flow is suppressed
            if (ecCurrent.IsFlowSuppressed) 
                return null;
 
            //
            // Attempt to capture context.  There may be nothing to capture...
            //
 
#if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK            
            // capture the security context
            SecurityContext secCtxNew = SecurityContext.Capture(ecCurrent, ref stackMark);
#endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
#if FEATURE_CAS_POLICY
             // capture the host execution context
            HostExecutionContext hostCtxNew = HostExecutionContextManager.CaptureHostExecutionContext();    		 
#endif // FEATURE_CAS_POLICY
 
            SynchronizationContext syncCtxNew = null;
 
#if FEATURE_REMOTING
            LogicalCallContext logCtxNew = null;
#endif
 
            if (!ecCurrent.IsNull)
            {
                // capture the sync context
                if (0 == (options & CaptureOptions.IgnoreSyncCtx))
                    syncCtxNew = (ecCurrent.SynchronizationContext == null) ? null : ecCurrent.SynchronizationContext.CreateCopy();
 
#if FEATURE_REMOTING
                // copy over the Logical Call Context
                if (ecCurrent.LogicalCallContext.HasInfo)
                    logCtxNew = ecCurrent.LogicalCallContext.Clone();
#endif // #if FEATURE_REMOTING
            }
 
            IAsyncLocalValueMap localValues = null;
            IAsyncLocal[] localChangeNotifications = null;
            if (!ecCurrent.IsNull)
            {
                localValues = ecCurrent.DangerousGetRawExecutionContext()._localValues;
                localChangeNotifications = ecCurrent.DangerousGetRawExecutionContext()._localChangeNotifications;
            }
 
            //
            // If we didn't get anything but defaults, and we're allowed to return the 
            // dummy default EC, don't bother allocating a new context.
            //
            if (0 != (options & CaptureOptions.OptimizeDefaultCase) &&
#if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK            
                secCtxNew == null &&
#endif
#if FEATURE_CAS_POLICY
                hostCtxNew == null &&
#endif // FEATURE_CAS_POLICY
                syncCtxNew == null &&
#if FEATURE_REMOTING
                (logCtxNew == null || !logCtxNew.HasInfo) &&
#endif // #if FEATURE_REMOTING
                localValues == null &&
                localChangeNotifications == null
                )
            {
                return s_dummyDefaultEC;
            }
 
            //
            // Allocate the new context, and fill it in.
            //
            ExecutionContext ecNew = new ExecutionContext();
#if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK            
            ecNew.SecurityContext = secCtxNew;
            if (ecNew.SecurityContext != null)
                ecNew.SecurityContext.ExecutionContext = ecNew;
#endif
#if FEATURE_CAS_POLICY
            ecNew._hostExecutionContext = hostCtxNew;
#endif // FEATURE_CAS_POLICY
            ecNew._syncContext = syncCtxNew;
#if FEATURE_REMOTING
            ecNew.LogicalCallContext = logCtxNew;
#endif // #if FEATURE_REMOTING
            ecNew._localValues = localValues;
            ecNew._localChangeNotifications = localChangeNotifications;
            ecNew.isNewCapture = true;
 
            return ecNew;
        }
 
        //
        // Implementation of ISerializable
        //
 
        [System.Security.SecurityCritical]  // auto-generated_required
        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            if (info==null) 
                throw new ArgumentNullException("info");
            Contract.EndContractBlock();
 
#if FEATURE_REMOTING
            if (_logicalCallContext != null)
            {
                info.AddValue("LogicalCallContext", _logicalCallContext, typeof(LogicalCallContext));
            }
#endif // #if FEATURE_REMOTING
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        private ExecutionContext(SerializationInfo info, StreamingContext context) 
        {
            SerializationInfoEnumerator e = info.GetEnumerator();
            while (e.MoveNext())
            {
#if FEATURE_REMOTING
                if (e.Name.Equals("LogicalCallContext"))
                {
                    _logicalCallContext = (LogicalCallContext) e.Value;
                }
#endif // #if FEATURE_REMOTING
            }
        } // ObjRef .ctor
     
 
        [System.Security.SecurityCritical]  // auto-generated
        internal bool IsDefaultFTContext(bool ignoreSyncCtx)
        {
#if FEATURE_CAS_POLICY
            if (_hostExecutionContext != null)
                return false;
#endif // FEATURE_CAS_POLICY            
            if (!ignoreSyncCtx && _syncContext != null)
                return false;
#if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK            
            if (_securityContext != null && !_securityContext.IsDefaultFTSecurityContext())
                return false;
#endif //#if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
#if FEATURE_REMOTING
            if (_logicalCallContext != null && _logicalCallContext.HasInfo)
                return false;
            if (_illogicalCallContext != null && _illogicalCallContext.HasUserData)
                return false;
#endif //#if FEATURE_REMOTING
            return true;
        }
    } // class ExecutionContext
 
#endif //FEATURE_CORECLR
}