[corlib] CoreRT System.Threading.Tasks (#6672)
[mono-project.git] / mcs / class / referencesource / mscorlib / system / threading / executioncontext.cs
blob6f5f609c556da207dcff0c65d0eb7565f8290ddf
1 #if MOBILE_LEGACY
2 #define FEATURE_REMOTING
3 #endif
4 // ==++==
5 //
6 // Copyright (c) Microsoft Corporation. All rights reserved.
7 //
8 //
9 // <OWNER>Microsoft</OWNER>
10 /*============================================================
12 ** Class: ExecutionContext
15 ** Purpose: Capture execution context for a thread
17 **
18 ===========================================================*/
19 namespace System.Threading
21 using System;
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;
31 #if FEATURE_REMOTING
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;
40 #if FEATURE_CORECLR
41 [System.Security.SecurityCritical] // auto-generated
42 #endif
43 [System.Runtime.InteropServices.ComVisible(true)]
44 public delegate void ContextCallback(Object state);
46 #if FEATURE_CORECLR
48 [SecurityCritical]
49 internal struct ExecutionContextSwitcher
51 internal ExecutionContext m_ec;
52 internal SynchronizationContext m_sc;
54 internal void Undo()
56 SynchronizationContext.SetSynchronizationContext(m_sc);
57 ExecutionContext.Restore(m_ec);
61 public sealed class ExecutionContext : IDisposable
63 public static readonly ExecutionContext Default = new ExecutionContext();
65 [ThreadStatic]
66 [SecurityCritical]
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;
90 [SecurityCritical]
91 [HandleProcessCorruptedStateExceptions]
92 public static void Run(ExecutionContext executionContext, ContextCallback callback, Object state)
94 ExecutionContextSwitcher ecsw = default(ExecutionContextSwitcher);
95 try
97 EstablishCopyOnWriteScope(ref ecsw);
99 ExecutionContext.Restore(executionContext);
100 callback(state);
102 catch
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.
108 ecsw.Undo();
109 throw;
111 ecsw.Undo();
114 [SecurityCritical]
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);
127 [SecurityCritical]
128 static internal void EstablishCopyOnWriteScope(ref ExecutionContextSwitcher ecsw)
130 ecsw.m_ec = Capture();
131 ecsw.m_sc = SynchronizationContext.CurrentNoFlow;
134 [SecurityCritical]
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;
143 object currentValue;
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))
162 object currentValue;
163 current.m_localValues.TryGetValue(local, out currentValue);
165 if (previousValue != currentValue)
166 local.OnValueChanged(previousValue, currentValue, true);
170 catch (Exception ex)
172 Environment.FailFast(
173 Environment.GetResourceString("ExecutionContext_ExceptionInAsyncLocalNotification"),
174 ex);
179 [SecurityCritical]
180 internal static object GetLocalValue(IAsyncLocal local)
182 ExecutionContext current = t_currentMaybeNull;
183 if (current == null)
184 return null;
186 object value;
187 current.m_localValues.TryGetValue(local, out value);
188 return value;
191 [SecurityCritical]
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)
200 return;
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));
211 else
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
220 [Flags]
221 internal enum CaptureOptions
223 None = 0x00,
224 IgnoreSyncCtx = 0x01,
225 OptimizeDefaultCase = 0x02,
228 [SecurityCritical]
229 internal static ExecutionContext Capture(ref StackCrawlMark stackMark, CaptureOptions captureOptions)
231 return Capture();
234 [SecuritySafeCritical]
235 [FriendAccessAllowed]
236 internal static ExecutionContext FastCapture()
238 return Capture();
241 [SecurityCritical]
242 [FriendAccessAllowed]
243 internal static void Run(ExecutionContext executionContext, ContextCallback callback, Object state, bool preserveSyncCtx)
245 Run(executionContext, callback, state);
248 [SecurityCritical]
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()
268 return false;
271 internal static ExecutionContext PreAllocatedDefault
273 [SecuritySafeCritical]
274 get { return ExecutionContext.Default; }
277 internal bool IsPreAllocatedDefault
279 get { return this == ExecutionContext.Default; }
282 #endregion
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;
301 #endif
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()
313 Undo();
315 catch
317 return false;
319 return true;
322 [System.Security.SecurityCritical] // auto-generated
323 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
324 internal void Undo()
327 // Don't use an uninitialized switcher, or one that's already been used.
329 if (thread == null)
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
339 if (hecsw != null)
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);
350 #if !MONO && DEBUG
353 currentThread.ForbidExecutionContextMutation = true;
354 #endif
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
363 scsw.Undo();
365 #endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
367 #if !FEATURE_PAL && FEATURE_IMPERSONATION
368 if (wiIsValid)
369 SecurityContext.RestoreCurrentWI(outerEC, innerEC, wi, cachedAlwaysFlowImpersonationPolicy);
370 #endif
372 thread = null; // this will prevent the switcher object being used again
373 #if !MONO && DEBUG
375 finally
377 currentThread.ForbidExecutionContextMutation = false;
379 #endif
380 ExecutionContext.OnAsyncLocalContextChanged(innerEC.DangerousGetRawExecutionContext(), outerEC.DangerousGetRawExecutionContext());
385 public struct AsyncFlowControl: IDisposable
387 private bool useEC;
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
394 [SecurityCritical]
395 internal void Setup(SecurityContextDisableFlow flags)
397 useEC = false;
398 Thread currentThread = Thread.CurrentThread;
399 _sc = currentThread.GetMutableExecutionContext().SecurityContext;
400 _sc._disableFlow = flags;
401 _thread = currentThread;
403 #endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
404 [SecurityCritical]
405 internal void Setup()
407 useEC = true;
408 Thread currentThread = Thread.CurrentThread;
409 _ec = currentThread.GetMutableExecutionContext();
410 _ec.isFlowSuppressed = true;
411 _thread = currentThread;
414 public void Dispose()
416 Undo();
419 [SecuritySafeCritical]
420 public void Undo()
422 if (_thread == null)
424 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CannotUseAFCMultiple"));
426 if (_thread != Thread.CurrentThread)
428 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CannotUseAFCOtherThread"));
430 if (useEC)
432 if (Thread.CurrentThread.GetMutableExecutionContext() != _ec)
434 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_AsyncFlowCtrlCtxMismatch"));
436 ExecutionContext.RestoreFlow();
438 #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
439 else
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
448 _thread = null;
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);
461 else
462 return false;
465 public bool Equals(AsyncFlowControl obj)
467 return obj.useEC == useEC && obj._ec == _ec &&
468 #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
469 obj._sc == _sc &&
470 #endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
471 obj._thread == _thread;
474 public static bool operator ==(AsyncFlowControl a, AsyncFlowControl b)
476 return a.Equals(b);
479 public static bool operator !=(AsyncFlowControl a, AsyncFlowControl b)
481 return !(a == b);
487 [Serializable]
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
503 #if FEATURE_REMOTING
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
509 enum Flags
511 None = 0x0,
512 IsNewCapture = 0x1,
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);
530 if (value)
531 _flags |= Flags.IsNewCapture;
532 else
533 _flags &= ~Flags.IsNewCapture;
536 internal bool isFlowSuppressed
538 get
540 return (_flags & Flags.IsFlowSuppressed) != Flags.None;
544 Contract.Assert(!IsPreAllocatedDefault);
545 if (value)
546 _flags |= Flags.IsFlowSuppressed;
547 else
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
566 // hot code paths.
567 if ((_flags & Flags.IsPreAllocatedDefault) != Flags.None)
569 Contract.Assert(this == s_dummyDefaultEC);
570 return true;
572 else
574 return false;
579 #if MONO
580 internal static readonly ExecutionContext Default = new ExecutionContext();
581 #endif
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; } }
605 [SecurityCritical]
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
621 [SecurityCritical]
622 [MethodImpl(MethodImplOptions.AggressiveInlining)]
623 get { return new SecurityContext.Reader(IsNull ? null : m_ec.SecurityContext); }
625 #endif
627 #if FEATURE_REMOTING
628 public LogicalCallContext.Reader LogicalCallContext
630 [SecurityCritical]
631 get { return new LogicalCallContext.Reader(IsNull ? null : m_ec.LogicalCallContext); }
634 public IllogicalCallContext.Reader IllogicalCallContext
636 [SecurityCritical]
637 get { return new IllogicalCallContext.Reader(IsNull ? null : m_ec.IllogicalCallContext); }
639 #endif
641 [SecurityCritical]
642 public object GetLocalValue(IAsyncLocal local)
644 if (IsNull)
645 return null;
647 if (m_ec._localValues == null)
648 return null;
650 object value;
651 m_ec._localValues.TryGetValue(local, out value);
652 return value;
655 [SecurityCritical]
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;
663 [SecurityCritical]
664 public bool HasLocalValues()
666 return !this.IsNull && m_ec._localValues != null;
670 [SecurityCritical]
671 internal static object GetLocalValue(IAsyncLocal local)
673 return Thread.CurrentThread.GetExecutionContextReader().GetLocalValue(local);
676 [SecurityCritical]
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)
685 return;
687 if (current._localValues == null)
688 current._localValues = new Dictionary<IAsyncLocal, object>();
689 else
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));
701 else
703 if (current._localChangeNotifications == null)
704 current._localChangeNotifications = new List<IAsyncLocal>();
705 else
706 current._localChangeNotifications = new List<IAsyncLocal>(current._localChangeNotifications);
708 current._localChangeNotifications.Add(local);
711 local.OnValueChanged(previousValue, newValue, false);
715 [SecurityCritical]
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);
760 catch (Exception ex)
762 Environment.FailFast(
763 Environment.GetResourceString("ExecutionContext_ExceptionInAsyncLocalNotification"),
764 ex);
770 #if FEATURE_REMOTING
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)]
813 return _syncContext;
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
841 get
843 return _hostExecutionContext;
845 set
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
867 if (value != null)
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]
904 [SecurityCritical]
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.
913 [SecurityCritical]
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));
923 else
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
948 // context.
949 EstablishCopyOnWriteScope(currentThread, true, ref ecsw);
951 else
953 if (executionContext.IsPreAllocatedDefault)
954 executionContext = new ExecutionContext();
955 ecsw = SetExecutionContext(executionContext, preserveSyncCtx);
959 // Call the user's callback
961 callback(state);
963 finally
965 ecsw.Undo();
969 [SecurityCritical]
970 static internal void EstablishCopyOnWriteScope(ref ExecutionContextSwitcher ecsw)
972 EstablishCopyOnWriteScope(Thread.CurrentThread, false, ref ecsw);
975 [SecurityCritical]
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);
987 else
988 ecsw.wi = SecurityContext.GetCurrentWI(ecsw.outerEC, ecsw.cachedAlwaysFlowImpersonationPolicy);
989 ecsw.wiIsValid = true;
990 #endif
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;
1037 if (sc != null)
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
1059 catch
1061 ecsw.UndoNoThrow();
1062 throw;
1064 return ecsw;
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()
1074 if (!isNewCapture)
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
1102 return ec;
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;
1144 return ec;
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();
1156 afc.Setup();
1157 return afc;
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;
1171 [Pure]
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);
1201 [Flags]
1202 internal enum CaptureOptions
1204 None = 0x00,
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)
1221 return null;
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;
1240 #endif
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 &&
1270 #endif
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;
1293 #endif
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;
1305 return ecNew;
1309 // Implementation of ISerializable
1312 [System.Security.SecurityCritical] // auto-generated_required
1313 public void GetObjectData(SerializationInfo info, StreamingContext context)
1315 if (info==null)
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
1340 } // ObjRef .ctor
1343 [System.Security.SecurityCritical] // auto-generated
1344 internal bool IsDefaultFTContext(bool ignoreSyncCtx)
1346 #if FEATURE_CAS_POLICY
1347 if (_hostExecutionContext != null)
1348 return false;
1349 #endif // FEATURE_CAS_POLICY
1350 if (!ignoreSyncCtx && _syncContext != null)
1351 return false;
1352 #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
1353 if (_securityContext != null && !_securityContext.IsDefaultFTSecurityContext())
1354 return false;
1355 #endif //#if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
1356 #if FEATURE_REMOTING
1357 if (_logicalCallContext != null && _logicalCallContext.HasInfo)
1358 return false;
1359 if (_illogicalCallContext != null && _illogicalCallContext.HasUserData)
1360 return false;
1361 #endif //#if FEATURE_REMOTING
1362 return true;
1364 } // class ExecutionContext
1366 #endif //FEATURE_CORECLR