2 #define FEATURE_REMOTING
6 // Copyright (c) Microsoft Corporation. All rights reserved.
9 // <OWNER>Microsoft</OWNER>
10 /*============================================================
12 ** Class: ExecutionContext
15 ** Purpose: Capture execution context for a thread
18 ===========================================================*/
19 namespace System
.Threading
22 using System
.Security
;
23 using System
.Runtime
.Remoting
;
24 using System
.Security
.Principal
;
25 using System
.Collections
;
26 using System
.Collections
.Generic
;
27 using System
.Reflection
;
28 using System
.Runtime
.ExceptionServices
;
29 using System
.Runtime
.Serialization
;
30 using System
.Security
.Permissions
;
32 using System
.Runtime
.Remoting
.Messaging
;
33 #endif // FEATURE_REMOTING
34 using System
.Runtime
.InteropServices
;
35 using System
.Runtime
.CompilerServices
;
36 using System
.Runtime
.ConstrainedExecution
;
37 using System
.Diagnostics
.Contracts
;
38 using System
.Diagnostics
.CodeAnalysis
;
41 [System
.Security
.SecurityCritical
] // auto-generated
43 [System
.Runtime
.InteropServices
.ComVisible(true)]
44 public delegate void ContextCallback(Object state
);
49 internal struct ExecutionContextSwitcher
51 internal ExecutionContext m_ec
;
52 internal SynchronizationContext m_sc
;
56 SynchronizationContext
.SetSynchronizationContext(m_sc
);
57 ExecutionContext
.Restore(m_ec
);
61 public sealed class ExecutionContext
: IDisposable
63 public static readonly ExecutionContext Default
= new ExecutionContext();
67 static ExecutionContext t_currentMaybeNull
;
69 private readonly Dictionary
<IAsyncLocal
, object> m_localValues
;
70 private readonly List
<IAsyncLocal
> m_localChangeNotifications
;
72 private ExecutionContext()
74 m_localValues
= new Dictionary
<IAsyncLocal
, object>();
75 m_localChangeNotifications
= new List
<IAsyncLocal
>();
78 private ExecutionContext(ExecutionContext other
)
80 m_localValues
= new Dictionary
<IAsyncLocal
, object>(other
.m_localValues
);
81 m_localChangeNotifications
= new List
<IAsyncLocal
>(other
.m_localChangeNotifications
);
84 [SecuritySafeCritical
]
85 public static ExecutionContext
Capture()
87 return t_currentMaybeNull
?? ExecutionContext
.Default
;
91 [HandleProcessCorruptedStateExceptions
]
92 public static void Run(ExecutionContext executionContext
, ContextCallback callback
, Object state
)
94 ExecutionContextSwitcher ecsw
= default(ExecutionContextSwitcher
);
97 EstablishCopyOnWriteScope(ref ecsw
);
99 ExecutionContext
.Restore(executionContext
);
104 // Note: we have a "catch" rather than a "finally" because we want
105 // to stop the first pass of EH here. That way we can restore the previous
106 // context before any of our callers' EH filters run. That means we need to
107 // end the scope separately in the non-exceptional case below.
115 internal static void Restore(ExecutionContext executionContext
)
117 if (executionContext
== null)
118 throw new InvalidOperationException(Environment
.GetResourceString("InvalidOperation_NullContext"));
120 ExecutionContext previous
= t_currentMaybeNull
?? Default
;
121 t_currentMaybeNull
= executionContext
;
123 if (previous
!= executionContext
)
124 OnContextChanged(previous
, executionContext
);
128 static internal void EstablishCopyOnWriteScope(ref ExecutionContextSwitcher ecsw
)
130 ecsw
.m_ec
= Capture();
131 ecsw
.m_sc
= SynchronizationContext
.CurrentNoFlow
;
135 [HandleProcessCorruptedStateExceptions
]
136 private static void OnContextChanged(ExecutionContext previous
, ExecutionContext current
)
138 previous
= previous
?? Default
;
140 foreach (IAsyncLocal local
in previous
.m_localChangeNotifications
)
142 object previousValue
;
144 previous
.m_localValues
.TryGetValue(local
, out previousValue
);
145 current
.m_localValues
.TryGetValue(local
, out currentValue
);
147 if (previousValue
!= currentValue
)
148 local
.OnValueChanged(previousValue
, currentValue
, true);
151 if (current
.m_localChangeNotifications
!= previous
.m_localChangeNotifications
)
155 foreach (IAsyncLocal local
in current
.m_localChangeNotifications
)
157 // If the local has a value in the previous context, we already fired the event for that local
158 // in the code above.
159 object previousValue
;
160 if (!previous
.m_localValues
.TryGetValue(local
, out previousValue
))
163 current
.m_localValues
.TryGetValue(local
, out currentValue
);
165 if (previousValue
!= currentValue
)
166 local
.OnValueChanged(previousValue
, currentValue
, true);
172 Environment
.FailFast(
173 Environment
.GetResourceString("ExecutionContext_ExceptionInAsyncLocalNotification"),
180 internal static object GetLocalValue(IAsyncLocal local
)
182 ExecutionContext current
= t_currentMaybeNull
;
187 current
.m_localValues
.TryGetValue(local
, out value);
192 internal static void SetLocalValue(IAsyncLocal local
, object newValue
, bool needChangeNotifications
)
194 ExecutionContext current
= t_currentMaybeNull
?? ExecutionContext
.Default
;
196 object previousValue
;
197 bool hadPreviousValue
= current
.m_localValues
.TryGetValue(local
, out previousValue
);
199 if (previousValue
== newValue
)
202 current
= new ExecutionContext(current
);
203 current
.m_localValues
[local
] = newValue
;
205 t_currentMaybeNull
= current
;
207 if (needChangeNotifications
)
209 if (hadPreviousValue
)
210 Contract
.Assert(current
.m_localChangeNotifications
.Contains(local
));
212 current
.m_localChangeNotifications
.Add(local
);
214 local
.OnValueChanged(previousValue
, newValue
, false);
218 #region Wrappers for CLR compat, to avoid ifdefs all over the BCL
221 internal enum CaptureOptions
224 IgnoreSyncCtx
= 0x01,
225 OptimizeDefaultCase
= 0x02,
229 internal static ExecutionContext
Capture(ref StackCrawlMark stackMark
, CaptureOptions captureOptions
)
234 [SecuritySafeCritical
]
235 [FriendAccessAllowed
]
236 internal static ExecutionContext
FastCapture()
242 [FriendAccessAllowed
]
243 internal static void Run(ExecutionContext executionContext
, ContextCallback callback
, Object state
, bool preserveSyncCtx
)
245 Run(executionContext
, callback
, state
);
249 internal bool IsDefaultFTContext(bool ignoreSyncCtx
)
251 ExecutionContext current
= t_currentMaybeNull
;
252 return current
== null || current
== Default
;
255 [SecuritySafeCritical
]
256 public ExecutionContext
CreateCopy()
258 return this; // since CoreCLR's ExecutionContext is immutable, we don't need to create copies.
261 public void Dispose()
263 // For CLR compat only
266 public static bool IsFlowSuppressed()
271 internal static ExecutionContext PreAllocatedDefault
273 [SecuritySafeCritical
]
274 get { return ExecutionContext.Default; }
277 internal bool IsPreAllocatedDefault
279 get { return this == ExecutionContext.Default; }
285 #else // FEATURE_CORECLR
287 // Legacy desktop ExecutionContext implementation
289 internal struct ExecutionContextSwitcher
291 internal ExecutionContext
.Reader outerEC
; // previous EC we need to restore on Undo
292 internal bool outerECBelongsToScope
;
293 #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
294 internal SecurityContextSwitcher scsw
;
295 #endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
296 internal Object hecsw
;
297 #if !FEATURE_PAL && FEATURE_IMPERSONATION
298 internal WindowsIdentity wi
;
299 internal bool cachedAlwaysFlowImpersonationPolicy
;
300 internal bool wiIsValid
;
302 internal Thread thread
;
304 [System
.Security
.SecurityCritical
] // auto-generated
305 [ReliabilityContract(Consistency
.WillNotCorruptState
, Cer
.MayFail
)]
306 #if FEATURE_CORRUPTING_EXCEPTIONS
307 [HandleProcessCorruptedStateExceptions
] //
308 #endif // FEATURE_CORRUPTING_EXCEPTIONS
309 internal bool UndoNoThrow()
322 [System
.Security
.SecurityCritical
] // auto-generated
323 [ReliabilityContract(Consistency
.WillNotCorruptState
, Cer
.MayFail
)]
327 // Don't use an uninitialized switcher, or one that's already been used.
330 return; // Don't do anything
332 Contract
.Assert(Thread
.CurrentThread
== this.thread
);
333 Thread currentThread
= this.thread
;
336 // Restore the HostExecutionContext before restoring the ExecutionContext.
338 #if FEATURE_CAS_POLICY
340 HostExecutionContextSwitcher
.Undo(hecsw
);
341 #endif // FEATURE_CAS_POLICY
344 // restore the saved Execution Context. Note that this will also restore the
345 // SynchronizationContext, Logical/IllogicalCallContext, etc.
347 ExecutionContext
.Reader innerEC
= currentThread
.GetExecutionContextReader();
348 currentThread
.SetExecutionContext(outerEC
, outerECBelongsToScope
);
353 currentThread
.ForbidExecutionContextMutation
= true;
357 // Tell the SecurityContext to do the side-effects of restoration.
359 #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
360 if (scsw
.currSC
!= null)
362 // Any critical failure inside scsw will cause FailFast
365 #endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
367 #if !FEATURE_PAL && FEATURE_IMPERSONATION
369 SecurityContext
.RestoreCurrentWI(outerEC
, innerEC
, wi
, cachedAlwaysFlowImpersonationPolicy
);
372 thread
= null; // this will prevent the switcher object being used again
377 currentThread
.ForbidExecutionContextMutation
= false;
380 ExecutionContext
.OnAsyncLocalContextChanged(innerEC
.DangerousGetRawExecutionContext(), outerEC
.DangerousGetRawExecutionContext());
385 public struct AsyncFlowControl
: IDisposable
388 private ExecutionContext _ec
;
389 #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
390 private SecurityContext _sc
;
391 #endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
392 private Thread _thread
;
393 #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
395 internal void Setup(SecurityContextDisableFlow flags
)
398 Thread currentThread
= Thread
.CurrentThread
;
399 _sc
= currentThread
.GetMutableExecutionContext().SecurityContext
;
400 _sc
._disableFlow
= flags
;
401 _thread
= currentThread
;
403 #endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
405 internal void Setup()
408 Thread currentThread
= Thread
.CurrentThread
;
409 _ec
= currentThread
.GetMutableExecutionContext();
410 _ec
.isFlowSuppressed
= true;
411 _thread
= currentThread
;
414 public void Dispose()
419 [SecuritySafeCritical
]
424 throw new InvalidOperationException(Environment
.GetResourceString("InvalidOperation_CannotUseAFCMultiple"));
426 if (_thread
!= Thread
.CurrentThread
)
428 throw new InvalidOperationException(Environment
.GetResourceString("InvalidOperation_CannotUseAFCOtherThread"));
432 if (Thread
.CurrentThread
.GetMutableExecutionContext() != _ec
)
434 throw new InvalidOperationException(Environment
.GetResourceString("InvalidOperation_AsyncFlowCtrlCtxMismatch"));
436 ExecutionContext
.RestoreFlow();
438 #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
441 if (!Thread
.CurrentThread
.GetExecutionContextReader().SecurityContext
.IsSame(_sc
))
443 throw new InvalidOperationException(Environment
.GetResourceString("InvalidOperation_AsyncFlowCtrlCtxMismatch"));
445 SecurityContext
.RestoreFlow();
447 #endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
451 public override int GetHashCode()
453 // review - Microsoft
454 return _thread
== null ? ToString().GetHashCode() : _thread
.GetHashCode();
457 public override bool Equals(Object obj
)
459 if (obj
is AsyncFlowControl
)
460 return Equals((AsyncFlowControl
)obj
);
465 public bool Equals(AsyncFlowControl obj
)
467 return obj
.useEC
== useEC
&& obj
._ec
== _ec
&&
468 #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
470 #endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
471 obj
._thread
== _thread
;
474 public static bool operator ==(AsyncFlowControl a
, AsyncFlowControl b
)
479 public static bool operator !=(AsyncFlowControl a
, AsyncFlowControl b
)
488 public sealed class ExecutionContext
: IDisposable
, ISerializable
490 /*=========================================================================
491 ** Data accessed from managed code that needs to be defined in
492 ** ExecutionContextObject to maintain alignment between the two classes.
493 ** DON'T CHANGE THESE UNLESS YOU MODIFY ExecutionContextObject in vm\object.h
494 =========================================================================*/
495 #if FEATURE_CAS_POLICY
496 private HostExecutionContext _hostExecutionContext
;
497 #endif // FEATURE_CAS_POLICY
498 private SynchronizationContext _syncContext
;
499 private SynchronizationContext _syncContextNoFlow
;
500 #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
501 private SecurityContext _securityContext
;
502 #endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
504 [System
.Security
.SecurityCritical
] // auto-generated
505 private LogicalCallContext _logicalCallContext
;
506 private IllogicalCallContext _illogicalCallContext
; // this call context follows the physical thread
507 #endif // #if FEATURE_REMOTING
513 IsFlowSuppressed
= 0x2,
514 IsPreAllocatedDefault
= 0x4
516 private Flags _flags
;
518 private Dictionary
<IAsyncLocal
, object> _localValues
;
519 private List
<IAsyncLocal
> _localChangeNotifications
;
521 internal bool isNewCapture
525 return (_flags
& (Flags
.IsNewCapture
| Flags
.IsPreAllocatedDefault
)) != Flags
.None
;
529 Contract
.Assert(!IsPreAllocatedDefault
);
531 _flags
|= Flags
.IsNewCapture
;
533 _flags
&= ~Flags
.IsNewCapture
;
536 internal bool isFlowSuppressed
540 return (_flags
& Flags
.IsFlowSuppressed
) != Flags
.None
;
544 Contract
.Assert(!IsPreAllocatedDefault
);
546 _flags
|= Flags
.IsFlowSuppressed
;
548 _flags
&= ~Flags
.IsFlowSuppressed
;
553 private static readonly ExecutionContext s_dummyDefaultEC
= new ExecutionContext(isPreAllocatedDefault
: true);
555 static internal ExecutionContext PreAllocatedDefault
557 [SecuritySafeCritical
]
558 get { return s_dummyDefaultEC; }
561 internal bool IsPreAllocatedDefault
565 // we use _flags instead of a direct comparison w/ s_dummyDefaultEC to avoid the static access on
567 if ((_flags
& Flags
.IsPreAllocatedDefault
) != Flags
.None
)
569 Contract
.Assert(this == s_dummyDefaultEC
);
580 internal static readonly ExecutionContext Default
= new ExecutionContext();
583 [ReliabilityContract(Consistency
.WillNotCorruptState
, Cer
.Success
)]
584 internal ExecutionContext()
588 [ReliabilityContract(Consistency
.WillNotCorruptState
, Cer
.Success
)]
589 internal ExecutionContext(bool isPreAllocatedDefault
)
591 if (isPreAllocatedDefault
)
592 _flags
= Flags
.IsPreAllocatedDefault
;
595 // Read-only wrapper around ExecutionContext. This enables safe reading of an ExecutionContext without accidentally modifying it.
596 internal struct Reader
598 ExecutionContext m_ec
;
600 public Reader(ExecutionContext ec
) { m_ec = ec; }
602 public ExecutionContext
DangerousGetRawExecutionContext() { return m_ec; }
604 public bool IsNull { get { return m_ec == null; }
}
606 public bool IsDefaultFTContext(bool ignoreSyncCtx
) { return m_ec.IsDefaultFTContext(ignoreSyncCtx); }
607 public bool IsFlowSuppressed
609 [MethodImpl(MethodImplOptions
.AggressiveInlining
)]
610 get { return IsNull ? false : m_ec.isFlowSuppressed; }
612 //public Thread Thread { get { return m_ec._thread; } }
613 public bool IsSame(ExecutionContext
.Reader other
) { return m_ec == other.m_ec; }
615 public SynchronizationContext SynchronizationContext { get { return IsNull ? null : m_ec.SynchronizationContext; }
}
616 public SynchronizationContext SynchronizationContextNoFlow { get { return IsNull ? null : m_ec.SynchronizationContextNoFlow; }
}
618 #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
619 public SecurityContext
.Reader SecurityContext
622 [MethodImpl(MethodImplOptions
.AggressiveInlining
)]
623 get { return new SecurityContext.Reader(IsNull ? null : m_ec.SecurityContext); }
628 public LogicalCallContext
.Reader LogicalCallContext
631 get { return new LogicalCallContext.Reader(IsNull ? null : m_ec.LogicalCallContext); }
634 public IllogicalCallContext
.Reader IllogicalCallContext
637 get { return new IllogicalCallContext.Reader(IsNull ? null : m_ec.IllogicalCallContext); }
642 public object GetLocalValue(IAsyncLocal local
)
647 if (m_ec
._localValues
== null)
651 m_ec
._localValues
.TryGetValue(local
, out value);
656 public bool HasSameLocalValues(ExecutionContext other
)
658 var thisLocalValues
= IsNull
? null : m_ec
._localValues
;
659 var otherLocalValues
= other
== null ? null : other
._localValues
;
660 return thisLocalValues
== otherLocalValues
;
664 public bool HasLocalValues()
666 return !this.IsNull
&& m_ec
._localValues
!= null;
671 internal static object GetLocalValue(IAsyncLocal local
)
673 return Thread
.CurrentThread
.GetExecutionContextReader().GetLocalValue(local
);
677 internal static void SetLocalValue(IAsyncLocal local
, object newValue
, bool needChangeNotifications
)
679 ExecutionContext current
= Thread
.CurrentThread
.GetMutableExecutionContext();
681 object previousValue
= null;
682 bool hadPreviousValue
= current
._localValues
!= null && current
._localValues
.TryGetValue(local
, out previousValue
);
684 if (previousValue
== newValue
)
687 if (current
._localValues
== null)
688 current
._localValues
= new Dictionary
<IAsyncLocal
, object>();
690 current
._localValues
= new Dictionary
<IAsyncLocal
, object>(current
._localValues
);
692 current
._localValues
[local
] = newValue
;
694 if (needChangeNotifications
)
696 if (hadPreviousValue
)
698 Contract
.Assert(current
._localChangeNotifications
!= null);
699 Contract
.Assert(current
._localChangeNotifications
.Contains(local
));
703 if (current
._localChangeNotifications
== null)
704 current
._localChangeNotifications
= new List
<IAsyncLocal
>();
706 current
._localChangeNotifications
= new List
<IAsyncLocal
>(current
._localChangeNotifications
);
708 current
._localChangeNotifications
.Add(local
);
711 local
.OnValueChanged(previousValue
, newValue
, false);
716 [HandleProcessCorruptedStateExceptions
]
717 internal static void OnAsyncLocalContextChanged(ExecutionContext previous
, ExecutionContext current
)
719 List
<IAsyncLocal
> previousLocalChangeNotifications
= (previous
== null) ? null : previous
._localChangeNotifications
;
720 if (previousLocalChangeNotifications
!= null)
722 foreach (IAsyncLocal local
in previousLocalChangeNotifications
)
724 object previousValue
= null;
725 if (previous
!= null && previous
._localValues
!= null)
726 previous
._localValues
.TryGetValue(local
, out previousValue
);
728 object currentValue
= null;
729 if (current
!= null && current
._localValues
!= null)
730 current
._localValues
.TryGetValue(local
, out currentValue
);
732 if (previousValue
!= currentValue
)
733 local
.OnValueChanged(previousValue
, currentValue
, true);
737 List
<IAsyncLocal
> currentLocalChangeNotifications
= (current
== null) ? null : current
._localChangeNotifications
;
738 if (currentLocalChangeNotifications
!= null && currentLocalChangeNotifications
!= previousLocalChangeNotifications
)
742 foreach (IAsyncLocal local
in currentLocalChangeNotifications
)
744 // If the local has a value in the previous context, we already fired the event for that local
745 // in the code above.
746 object previousValue
= null;
747 if (previous
== null ||
748 previous
._localValues
== null ||
749 !previous
._localValues
.TryGetValue(local
, out previousValue
))
751 object currentValue
= null;
752 if (current
!= null && current
._localValues
!= null)
753 current
._localValues
.TryGetValue(local
, out currentValue
);
755 if (previousValue
!= currentValue
)
756 local
.OnValueChanged(previousValue
, currentValue
, true);
762 Environment
.FailFast(
763 Environment
.GetResourceString("ExecutionContext_ExceptionInAsyncLocalNotification"),
771 internal LogicalCallContext LogicalCallContext
773 [System
.Security
.SecurityCritical
] // auto-generated
776 if (_logicalCallContext
== null)
778 _logicalCallContext
= new LogicalCallContext();
780 return _logicalCallContext
;
782 [System
.Security
.SecurityCritical
] // auto-generated
785 Contract
.Assert(this != s_dummyDefaultEC
);
786 _logicalCallContext
= value;
790 internal IllogicalCallContext IllogicalCallContext
794 if (_illogicalCallContext
== null)
796 _illogicalCallContext
= new IllogicalCallContext();
798 return _illogicalCallContext
;
802 Contract
.Assert(this != s_dummyDefaultEC
);
803 _illogicalCallContext
= value;
806 #endif // #if FEATURE_REMOTING
808 internal SynchronizationContext SynchronizationContext
810 [ReliabilityContract(Consistency
.WillNotCorruptState
, Cer
.Success
)]
815 [ReliabilityContract(Consistency
.WillNotCorruptState
, Cer
.Success
)]
818 Contract
.Assert(this != s_dummyDefaultEC
);
819 _syncContext
= value;
823 internal SynchronizationContext SynchronizationContextNoFlow
825 [ReliabilityContract(Consistency
.WillNotCorruptState
, Cer
.Success
)]
828 return _syncContextNoFlow
;
830 [ReliabilityContract(Consistency
.WillNotCorruptState
, Cer
.Success
)]
833 Contract
.Assert(this != s_dummyDefaultEC
);
834 _syncContextNoFlow
= value;
838 #if FEATURE_CAS_POLICY
839 internal HostExecutionContext HostExecutionContext
843 return _hostExecutionContext
;
847 Contract
.Assert(this != s_dummyDefaultEC
);
848 _hostExecutionContext
= value;
851 #endif // FEATURE_CAS_POLICY
852 #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
853 internal SecurityContext SecurityContext
855 [ReliabilityContract(Consistency
.WillNotCorruptState
, Cer
.Success
)]
858 return _securityContext
;
860 [ReliabilityContract(Consistency
.WillNotCorruptState
, Cer
.Success
)]
863 Contract
.Assert(this != s_dummyDefaultEC
);
864 // store the new security context
865 _securityContext
= value;
866 // perform the reverse link too
868 _securityContext
.ExecutionContext
= this;
871 #endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
874 public void Dispose()
876 if(this.IsPreAllocatedDefault
)
877 return; //Do nothing if this is the default context
878 #if FEATURE_CAS_POLICY
879 if (_hostExecutionContext
!= null)
880 _hostExecutionContext
.Dispose();
881 #endif // FEATURE_CAS_POLICY
882 #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
883 if (_securityContext
!= null)
884 _securityContext
.Dispose();
885 #endif //FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
888 [DynamicSecurityMethod
]
889 [System
.Security
.SecurityCritical
] // auto-generated_required
890 public static void Run(ExecutionContext executionContext
, ContextCallback callback
, Object state
)
892 if (executionContext
== null)
893 throw new InvalidOperationException(Environment
.GetResourceString("InvalidOperation_NullContext"));
894 if (!executionContext
.isNewCapture
)
895 throw new InvalidOperationException(Environment
.GetResourceString("InvalidOperation_NotNewCaptureContext"));
897 Run(executionContext
, callback
, state
, false);
900 // This method is special from a security perspective - the VM will not allow a stack walk to
901 // continue past the call to ExecutionContext.Run. If you change the signature to this method, make
902 // sure to update SecurityStackWalk::IsSpecialRunFrame in the VM to search for the new signature.
903 [DynamicSecurityMethod
]
905 [FriendAccessAllowed
]
906 internal static void Run(ExecutionContext executionContext
, ContextCallback callback
, Object state
, bool preserveSyncCtx
)
908 RunInternal(executionContext
, callback
, state
, preserveSyncCtx
);
911 // Actual implementation of Run is here, in a non-DynamicSecurityMethod, because the JIT seems to refuse to inline callees into
912 // a DynamicSecurityMethod.
914 [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification
= "Reviewed for thread safety")]
915 [HandleProcessCorruptedStateExceptions
]
916 internal static void RunInternal(ExecutionContext executionContext
, ContextCallback callback
, Object state
, bool preserveSyncCtx
)
918 Contract
.Assert(executionContext
!= null);
919 if (executionContext
.IsPreAllocatedDefault
)
921 Contract
.Assert(executionContext
.IsDefaultFTContext(preserveSyncCtx
));
925 Contract
.Assert(executionContext
.isNewCapture
);
926 executionContext
.isNewCapture
= false;
929 Thread currentThread
= Thread
.CurrentThread
;
930 ExecutionContextSwitcher ecsw
= default(ExecutionContextSwitcher
);
932 RuntimeHelpers
.PrepareConstrainedRegions();
935 ExecutionContext
.Reader ec
= currentThread
.GetExecutionContextReader();
936 if ( (ec
.IsNull
|| ec
.IsDefaultFTContext(preserveSyncCtx
)) &&
937 #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
938 SecurityContext
.CurrentlyInDefaultFTSecurityContext(ec
) &&
939 #endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
940 executionContext
.IsDefaultFTContext(preserveSyncCtx
) &&
941 ec
.HasSameLocalValues(executionContext
)
944 // Neither context is interesting, so we don't need to set the context.
945 // We do need to reset any changes made by the user's callback,
946 // so here we establish a "copy-on-write scope". Any changes will
947 // result in a copy of the context being made, preserving the original
949 EstablishCopyOnWriteScope(currentThread
, true, ref ecsw
);
953 if (executionContext
.IsPreAllocatedDefault
)
954 executionContext
= new ExecutionContext();
955 ecsw
= SetExecutionContext(executionContext
, preserveSyncCtx
);
959 // Call the user's callback
970 static internal void EstablishCopyOnWriteScope(ref ExecutionContextSwitcher ecsw
)
972 EstablishCopyOnWriteScope(Thread
.CurrentThread
, false, ref ecsw
);
976 static private void EstablishCopyOnWriteScope(Thread currentThread
, bool knownNullWindowsIdentity
, ref ExecutionContextSwitcher ecsw
)
978 Contract
.Assert(currentThread
== Thread
.CurrentThread
);
980 ecsw
.outerEC
= currentThread
.GetExecutionContextReader();
981 ecsw
.outerECBelongsToScope
= currentThread
.ExecutionContextBelongsToCurrentScope
;
983 #if !FEATURE_PAL && FEATURE_IMPERSONATION
984 ecsw
.cachedAlwaysFlowImpersonationPolicy
= SecurityContext
.AlwaysFlowImpersonationPolicy
;
985 if (knownNullWindowsIdentity
)
986 Contract
.Assert(SecurityContext
.GetCurrentWI(ecsw
.outerEC
, ecsw
.cachedAlwaysFlowImpersonationPolicy
) == null);
988 ecsw
.wi
= SecurityContext
.GetCurrentWI(ecsw
.outerEC
, ecsw
.cachedAlwaysFlowImpersonationPolicy
);
989 ecsw
.wiIsValid
= true;
991 currentThread
.ExecutionContextBelongsToCurrentScope
= false;
992 ecsw
.thread
= currentThread
;
996 // Sets the given execution context object on the thread.
997 // Returns the previous one.
998 [System
.Security
.SecurityCritical
] // auto-generated
999 [DynamicSecurityMethodAttribute()]
1000 [MethodImplAttribute(MethodImplOptions
.NoInlining
)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
1001 #if FEATURE_CORRUPTING_EXCEPTIONS
1002 [HandleProcessCorruptedStateExceptions
] //
1003 #endif // FEATURE_CORRUPTING_EXCEPTIONS
1004 internal static ExecutionContextSwitcher
SetExecutionContext(ExecutionContext executionContext
, bool preserveSyncCtx
)
1006 #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
1007 StackCrawlMark stackMark
= StackCrawlMark
.LookForMyCaller
;
1008 #endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
1010 Contract
.Assert(executionContext
!= null);
1011 Contract
.Assert(executionContext
!= s_dummyDefaultEC
);
1013 // Set up the switcher object to return;
1014 ExecutionContextSwitcher ecsw
= new ExecutionContextSwitcher();
1016 Thread currentThread
= Thread
.CurrentThread
;
1017 ExecutionContext
.Reader outerEC
= currentThread
.GetExecutionContextReader();
1019 ecsw
.thread
= currentThread
;
1020 ecsw
.outerEC
= outerEC
;
1021 ecsw
.outerECBelongsToScope
= currentThread
.ExecutionContextBelongsToCurrentScope
;
1023 if (preserveSyncCtx
)
1024 executionContext
.SynchronizationContext
= outerEC
.SynchronizationContext
;
1025 executionContext
.SynchronizationContextNoFlow
= outerEC
.SynchronizationContextNoFlow
;
1027 currentThread
.SetExecutionContext(executionContext
, belongsToCurrentScope
: true);
1029 RuntimeHelpers
.PrepareConstrainedRegions();
1032 OnAsyncLocalContextChanged(outerEC
.DangerousGetRawExecutionContext(), executionContext
);
1034 #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
1035 //set the security context
1036 SecurityContext sc
= executionContext
.SecurityContext
;
1039 // non-null SC: needs to be set
1040 SecurityContext
.Reader prevSeC
= outerEC
.SecurityContext
;
1041 ecsw
.scsw
= SecurityContext
.SetSecurityContext(sc
, prevSeC
, false, ref stackMark
);
1043 else if (!SecurityContext
.CurrentlyInDefaultFTSecurityContext(ecsw
.outerEC
))
1045 // null incoming SC, but we're currently not in FT: use static FTSC to set
1046 SecurityContext
.Reader prevSeC
= outerEC
.SecurityContext
;
1047 ecsw
.scsw
= SecurityContext
.SetSecurityContext(SecurityContext
.FullTrustSecurityContext
, prevSeC
, false, ref stackMark
);
1049 #endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
1050 #if FEATURE_CAS_POLICY
1051 // set the Host Context
1052 HostExecutionContext hostContext
= executionContext
.HostExecutionContext
;
1053 if (hostContext
!= null)
1055 ecsw
.hecsw
= HostExecutionContextManager
.SetHostExecutionContextInternal(hostContext
);
1057 #endif // FEATURE_CAS_POLICY
1068 // Public CreateCopy. Used to copy captured ExecutionContexts so they can be reused multiple times.
1069 // This should only copy the portion of the context that we actually capture.
1071 [SecuritySafeCritical
]
1072 public ExecutionContext
CreateCopy()
1076 throw new InvalidOperationException(Environment
.GetResourceString("InvalidOperation_CannotCopyUsedContext"));
1078 ExecutionContext ec
= new ExecutionContext();
1079 ec
.isNewCapture
= true;
1080 ec
._syncContext
= _syncContext
== null ? null : _syncContext
.CreateCopy();
1081 ec
._localValues
= _localValues
;
1082 ec
._localChangeNotifications
= _localChangeNotifications
;
1083 #if FEATURE_CAS_POLICY
1084 // capture the host execution context
1085 ec
._hostExecutionContext
= _hostExecutionContext
== null ? null : _hostExecutionContext
.CreateCopy();
1086 #endif // FEATURE_CAS_POLICY
1087 #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
1088 if (_securityContext
!= null)
1090 ec
._securityContext
= _securityContext
.CreateCopy();
1091 ec
._securityContext
.ExecutionContext
= ec
;
1093 #endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
1095 #if FEATURE_REMOTING
1096 if (this._logicalCallContext
!= null)
1097 ec
.LogicalCallContext
= (LogicalCallContext
)this.LogicalCallContext
.Clone();
1099 Contract
.Assert(this._illogicalCallContext
== null);
1100 #endif // #if FEATURE_REMOTING
1106 // Creates a complete copy, used for copy-on-write.
1108 [SecuritySafeCritical
]
1109 internal ExecutionContext
CreateMutableCopy()
1111 Contract
.Assert(!this.isNewCapture
);
1113 ExecutionContext ec
= new ExecutionContext();
1115 // We don't deep-copy the SyncCtx, since we're still in the same context after copy-on-write.
1116 ec
._syncContext
= this._syncContext
;
1117 ec
._syncContextNoFlow
= this._syncContextNoFlow
;
1119 #if FEATURE_CAS_POLICY
1120 // capture the host execution context
1121 ec
._hostExecutionContext
= this._hostExecutionContext
== null ? null : _hostExecutionContext
.CreateCopy();
1122 #endif // FEATURE_CAS_POLICY
1124 #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
1125 if (_securityContext
!= null)
1127 ec
._securityContext
= this._securityContext
.CreateMutableCopy();
1128 ec
._securityContext
.ExecutionContext
= ec
;
1130 #endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
1132 #if FEATURE_REMOTING
1133 if (this._logicalCallContext
!= null)
1134 ec
.LogicalCallContext
= (LogicalCallContext
)this.LogicalCallContext
.Clone();
1136 if (this._illogicalCallContext
!= null)
1137 ec
.IllogicalCallContext
= (IllogicalCallContext
)this.IllogicalCallContext
.CreateCopy();
1138 #endif // #if FEATURE_REMOTING
1140 ec
._localValues
= this._localValues
;
1141 ec
._localChangeNotifications
= this._localChangeNotifications
;
1142 ec
.isFlowSuppressed
= this.isFlowSuppressed
;
1147 [System
.Security
.SecurityCritical
] // auto-generated_required
1148 public static AsyncFlowControl
SuppressFlow()
1150 if (IsFlowSuppressed())
1152 throw new InvalidOperationException(Environment
.GetResourceString("InvalidOperation_CannotSupressFlowMultipleTimes"));
1154 Contract
.EndContractBlock();
1155 AsyncFlowControl afc
= new AsyncFlowControl();
1160 [SecuritySafeCritical
]
1161 public static void RestoreFlow()
1163 ExecutionContext ec
= Thread
.CurrentThread
.GetMutableExecutionContext();
1164 if (!ec
.isFlowSuppressed
)
1166 throw new InvalidOperationException(Environment
.GetResourceString("InvalidOperation_CannotRestoreUnsupressedFlow"));
1168 ec
.isFlowSuppressed
= false;
1172 public static bool IsFlowSuppressed()
1174 return Thread
.CurrentThread
.GetExecutionContextReader().IsFlowSuppressed
;
1177 [System
.Security
.SecuritySafeCritical
] // auto-generated
1178 [MethodImplAttribute(MethodImplOptions
.NoInlining
)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
1179 public static ExecutionContext
Capture()
1181 // set up a stack mark for finding the caller
1182 StackCrawlMark stackMark
= StackCrawlMark
.LookForMyCaller
;
1183 return ExecutionContext
.Capture(ref stackMark
, CaptureOptions
.None
);
1187 // Captures an ExecutionContext with optimization for the "default" case, and captures a "null" synchronization context.
1188 // When calling ExecutionContext.Run on the returned context, specify ignoreSyncCtx = true
1190 [System
.Security
.SecuritySafeCritical
] // auto-generated
1191 [MethodImplAttribute(MethodImplOptions
.NoInlining
)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
1192 [FriendAccessAllowed
]
1193 internal static ExecutionContext
FastCapture()
1195 // set up a stack mark for finding the caller
1196 StackCrawlMark stackMark
= StackCrawlMark
.LookForMyCaller
;
1197 return ExecutionContext
.Capture(ref stackMark
, CaptureOptions
.IgnoreSyncCtx
| CaptureOptions
.OptimizeDefaultCase
);
1202 internal enum CaptureOptions
1206 IgnoreSyncCtx
= 0x01, //Don't flow SynchronizationContext
1208 OptimizeDefaultCase
= 0x02, //Faster in the typical case, but can't show the result to users
1209 // because they could modify the shared default EC.
1210 // Use this only if you won't be exposing the captured EC to users.
1213 // internal helper to capture the current execution context using a passed in stack mark
1214 [System
.Security
.SecurityCritical
] // auto-generated
1215 static internal ExecutionContext
Capture(ref StackCrawlMark stackMark
, CaptureOptions options
)
1217 ExecutionContext
.Reader ecCurrent
= Thread
.CurrentThread
.GetExecutionContextReader();
1219 // check to see if Flow is suppressed
1220 if (ecCurrent
.IsFlowSuppressed
)
1224 // Attempt to capture context. There may be nothing to capture...
1227 #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
1228 // capture the security context
1229 SecurityContext secCtxNew
= SecurityContext
.Capture(ecCurrent
, ref stackMark
);
1230 #endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
1231 #if FEATURE_CAS_POLICY
1232 // capture the host execution context
1233 HostExecutionContext hostCtxNew
= HostExecutionContextManager
.CaptureHostExecutionContext();
1234 #endif // FEATURE_CAS_POLICY
1236 SynchronizationContext syncCtxNew
= null;
1238 #if FEATURE_REMOTING
1239 LogicalCallContext logCtxNew
= null;
1242 if (!ecCurrent
.IsNull
)
1244 // capture the sync context
1245 if (0 == (options
& CaptureOptions
.IgnoreSyncCtx
))
1246 syncCtxNew
= (ecCurrent
.SynchronizationContext
== null) ? null : ecCurrent
.SynchronizationContext
.CreateCopy();
1248 #if FEATURE_REMOTING
1249 // copy over the Logical Call Context
1250 if (ecCurrent
.LogicalCallContext
.HasInfo
)
1251 logCtxNew
= ecCurrent
.LogicalCallContext
.Clone();
1252 #endif // #if FEATURE_REMOTING
1255 Dictionary
<IAsyncLocal
, object> localValues
= null;
1256 List
<IAsyncLocal
> localChangeNotifications
= null;
1257 if (!ecCurrent
.IsNull
)
1259 localValues
= ecCurrent
.DangerousGetRawExecutionContext()._localValues
;
1260 localChangeNotifications
= ecCurrent
.DangerousGetRawExecutionContext()._localChangeNotifications
;
1264 // If we didn't get anything but defaults, and we're allowed to return the
1265 // dummy default EC, don't bother allocating a new context.
1267 if (0 != (options
& CaptureOptions
.OptimizeDefaultCase
) &&
1268 #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
1269 secCtxNew
== null &&
1271 #if FEATURE_CAS_POLICY
1272 hostCtxNew
== null &&
1273 #endif // FEATURE_CAS_POLICY
1274 syncCtxNew
== null &&
1275 #if FEATURE_REMOTING
1276 (logCtxNew
== null || !logCtxNew
.HasInfo
) &&
1277 #endif // #if FEATURE_REMOTING
1278 localValues
== null &&
1279 localChangeNotifications
== null
1282 return s_dummyDefaultEC
;
1286 // Allocate the new context, and fill it in.
1288 ExecutionContext ecNew
= new ExecutionContext();
1289 #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
1290 ecNew
.SecurityContext
= secCtxNew
;
1291 if (ecNew
.SecurityContext
!= null)
1292 ecNew
.SecurityContext
.ExecutionContext
= ecNew
;
1294 #if FEATURE_CAS_POLICY
1295 ecNew
._hostExecutionContext
= hostCtxNew
;
1296 #endif // FEATURE_CAS_POLICY
1297 ecNew
._syncContext
= syncCtxNew
;
1298 #if FEATURE_REMOTING
1299 ecNew
.LogicalCallContext
= logCtxNew
;
1300 #endif // #if FEATURE_REMOTING
1301 ecNew
._localValues
= localValues
;
1302 ecNew
._localChangeNotifications
= localChangeNotifications
;
1303 ecNew
.isNewCapture
= true;
1309 // Implementation of ISerializable
1312 [System
.Security
.SecurityCritical
] // auto-generated_required
1313 public void GetObjectData(SerializationInfo info
, StreamingContext context
)
1316 throw new ArgumentNullException("info");
1317 Contract
.EndContractBlock();
1319 #if FEATURE_REMOTING
1320 if (_logicalCallContext
!= null)
1322 info
.AddValue("LogicalCallContext", _logicalCallContext
, typeof(LogicalCallContext
));
1324 #endif // #if FEATURE_REMOTING
1327 [System
.Security
.SecurityCritical
] // auto-generated
1328 private ExecutionContext(SerializationInfo info
, StreamingContext context
)
1330 SerializationInfoEnumerator e
= info
.GetEnumerator();
1331 while (e
.MoveNext())
1333 #if FEATURE_REMOTING
1334 if (e
.Name
.Equals("LogicalCallContext"))
1336 _logicalCallContext
= (LogicalCallContext
) e
.Value
;
1338 #endif // #if FEATURE_REMOTING
1343 [System
.Security
.SecurityCritical
] // auto-generated
1344 internal bool IsDefaultFTContext(bool ignoreSyncCtx
)
1346 #if FEATURE_CAS_POLICY
1347 if (_hostExecutionContext
!= null)
1349 #endif // FEATURE_CAS_POLICY
1350 if (!ignoreSyncCtx
&& _syncContext
!= null)
1352 #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
1353 if (_securityContext
!= null && !_securityContext
.IsDefaultFTSecurityContext())
1355 #endif //#if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
1356 #if FEATURE_REMOTING
1357 if (_logicalCallContext
!= null && _logicalCallContext
.HasInfo
)
1359 if (_illogicalCallContext
!= null && _illogicalCallContext
.HasUserData
)
1361 #endif //#if FEATURE_REMOTING
1364 } // class ExecutionContext
1366 #endif //FEATURE_CORECLR