diff options
Diffstat (limited to 'src/System.Private.CoreLib/shared/System/Threading/ExecutionContext.cs')
-rw-r--r-- | src/System.Private.CoreLib/shared/System/Threading/ExecutionContext.cs | 33 |
1 files changed, 20 insertions, 13 deletions
diff --git a/src/System.Private.CoreLib/shared/System/Threading/ExecutionContext.cs b/src/System.Private.CoreLib/shared/System/Threading/ExecutionContext.cs index 9f27c6dcb..694514ef0 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/ExecutionContext.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/ExecutionContext.cs @@ -19,11 +19,12 @@ using Thread = Internal.Runtime.Augments.RuntimeThread; namespace System.Threading { - public delegate void ContextCallback(Object state); + public delegate void ContextCallback(object state); public sealed class ExecutionContext : IDisposable, ISerializable { internal static readonly ExecutionContext Default = new ExecutionContext(isDefault: true); + internal static readonly ExecutionContext DefaultFlowSuppressed = new ExecutionContext(AsyncLocalValueMap.Empty, Array.Empty<IAsyncLocal>(), isFlowSuppressed: true); private readonly IAsyncLocalValueMap m_localValues; private readonly IAsyncLocal[] m_localChangeNotifications; @@ -63,15 +64,14 @@ namespace System.Threading { Debug.Assert(isFlowSuppressed != m_isFlowSuppressed); - if (!isFlowSuppressed && - (m_localValues == null || - m_localValues.GetType() == typeof(AsyncLocalValueMap.EmptyAsyncLocalValueMap)) - ) + if (m_localValues == null || AsyncLocalValueMap.IsEmpty(m_localValues)) { - return null; // implies the default context + return isFlowSuppressed ? + DefaultFlowSuppressed : + null; // implies the default context } - // Flow suppressing a Default context will have null values, set them to Empty - return new ExecutionContext(m_localValues ?? AsyncLocalValueMap.Empty, m_localChangeNotifications ?? Array.Empty<IAsyncLocal>(), isFlowSuppressed); + + return new ExecutionContext(m_localValues, m_localChangeNotifications, isFlowSuppressed); } public static AsyncFlowControl SuppressFlow() @@ -112,7 +112,7 @@ namespace System.Threading internal bool IsDefault => m_isDefault; - public static void Run(ExecutionContext executionContext, ContextCallback callback, Object state) + public static void Run(ExecutionContext executionContext, ContextCallback callback, object state) { // Note: ExecutionContext.Run is an extremely hot function and used by every await, ThreadPool execution, etc. if (executionContext == null) @@ -123,7 +123,7 @@ namespace System.Threading RunInternal(executionContext, callback, state); } - internal static void RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) + internal static void RunInternal(ExecutionContext executionContext, ContextCallback callback, object state) { // Note: ExecutionContext.RunInternal is an extremely hot function and used by every await, ThreadPool execution, etc. // Note: Manual enregistering may be addressed by "Exception Handling Write Through Optimization" @@ -321,19 +321,26 @@ namespace System.Threading 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. IAsyncLocal[] newChangeNotifications = null; IAsyncLocalValueMap newValues; bool isFlowSuppressed = false; if (current != null) { isFlowSuppressed = current.m_isFlowSuppressed; - newValues = current.m_localValues.Set(local, newValue); + newValues = current.m_localValues.Set(local, newValue, treatNullValueAsNonexistent: !needChangeNotifications); newChangeNotifications = current.m_localChangeNotifications; } else { // First AsyncLocal - newValues = new AsyncLocalValueMap.OneElementAsyncLocalValueMap(local, newValue); + newValues = AsyncLocalValueMap.Create(local, newValue, treatNullValueAsNonexistent: !needChangeNotifications); } // @@ -359,7 +366,7 @@ namespace System.Threading } Thread.CurrentThread.ExecutionContext = - (!isFlowSuppressed && newValues.GetType() == typeof(AsyncLocalValueMap.EmptyAsyncLocalValueMap)) ? + (!isFlowSuppressed && AsyncLocalValueMap.IsEmpty(newValues)) ? null : // No values, return to Default context new ExecutionContext(newValues, newChangeNotifications, isFlowSuppressed); |