コード例 #1
0
ファイル: ExecutionContext.cs プロジェクト: weshaggard/corert
        public void Undo()
        {
            if (_thread == null)
            {
                throw new InvalidOperationException(SR.InvalidOperation_CannotUseAFCMultiple);
            }
            if (Thread.CurrentThread != _thread)
            {
                throw new InvalidOperationException(SR.InvalidOperation_CannotUseAFCOtherThread);
            }

            // An async flow control cannot be undone when a different execution context is applied. The desktop framework
            // mutates the execution context when its state changes, and only changes the instance when an execution context
            // is applied (for instance, through ExecutionContext.Run). The framework prevents a suppressed-flow execution
            // context from being applied by returning null from ExecutionContext.Capture, so the only type of execution
            // context that can be applied is one whose flow is not suppressed. After suppressing flow and changing an async
            // local's value, the desktop framework verifies that a different execution context has not been applied by
            // checking the execution context instance against the one saved from when flow was suppressed. In .NET Core,
            // since the execution context instance will change after changing the async local's value, it verifies that a
            // different execution context has not been applied, by instead ensuring that the current execution context's
            // flow is suppressed.
            if (!ExecutionContext.IsFlowSuppressed())
            {
                throw new InvalidOperationException(SR.InvalidOperation_AsyncFlowCtrlCtxMismatch);
            }
            Contract.EndContractBlock();

            _thread = null;
            ExecutionContext.RestoreFlow();
        }
コード例 #2
0
ファイル: ExecutionContext.cs プロジェクト: weshaggard/corert
        public static void Run(ExecutionContext executionContext, ContextCallback callback, Object state)
        {
            if (executionContext == null)
            {
                throw new InvalidOperationException(SR.InvalidOperation_NullContext);
            }

            Thread currentThread          = Thread.CurrentThread;
            ExecutionContextSwitcher ecsw = default(ExecutionContextSwitcher);

            try
            {
                EstablishCopyOnWriteScope(currentThread, ref ecsw);
                ExecutionContext.Restore(currentThread, 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(currentThread);
                throw;
            }
            ecsw.Undo(currentThread);
        }
コード例 #3
0
ファイル: ExecutionContext.cs プロジェクト: weshaggard/corert
        internal static void EstablishCopyOnWriteScope(Thread currentThread, ref ExecutionContextSwitcher ecsw)
        {
            Debug.Assert(currentThread == Thread.CurrentThread);

            ecsw.m_ec = currentThread.ExecutionContext;
            ecsw.m_sc = currentThread.SynchronizationContext;
        }
コード例 #4
0
ファイル: ExecutionContext.cs プロジェクト: ermshiperete/mono
        internal static void RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, object state)
        {
            Debug.Assert(threadPoolThread == Thread.CurrentThread);
            CheckThreadPoolAndContextsAreDefault();
            // ThreadPool starts on Default Context so we don't need to save the "previous" state as we know it is Default (null)

            if (executionContext != null && executionContext.m_isDefault)
            {
                // Default is a null ExecutionContext internally
                executionContext = null;
            }
            else if (executionContext != null)
            {
                // Non-Default context to restore
                threadPoolThread.ExecutionContext = executionContext;
                if (executionContext.HasChangeNotifications)
                {
                    // There are change notifications; trigger any affected
                    OnValuesChanged(previousExecutionCtx: null, executionContext);
                }
            }

            ExceptionDispatchInfo edi = null;

            try
            {
                callback.Invoke(state);
            }
            catch (Exception ex)
            {
                // 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.
                edi = ExceptionDispatchInfo.Capture(ex);
            }

            // Enregister threadPoolThread as it crossed EH, and use enregistered variable
            Thread currentThread = threadPoolThread;

            ExecutionContext currentExecutionCtx = currentThread.ExecutionContext;

            // Restore changed SynchronizationContext back to Default
            currentThread.SynchronizationContext = null;
            if (currentExecutionCtx != null)
            {
                // The EC always needs to be reset for this overload, as it will flow back to the caller if it performs
                // extra work prior to returning to the Dispatch loop. For example for Task-likes it will flow out of await points

                // Restore to Default before Notifications, as the change can be observed in the handler.
                currentThread.ExecutionContext = null;
                if (currentExecutionCtx.HasChangeNotifications)
                {
                    // There are change notifications; trigger any affected
                    OnValuesChanged(currentExecutionCtx, nextExecutionCtx: null);
                }
            }

            // If exception was thrown by callback, rethrow it now original contexts are restored
            edi?.Throw();
        }
コード例 #5
0
        public static void RestoreFlow()
        {
            Thread           currentThread    = Thread.CurrentThread;
            ExecutionContext executionContext = currentThread.ExecutionContext;

            if (executionContext == null || !executionContext.m_isFlowSuppressed)
            {
                throw new InvalidOperationException(SR.InvalidOperation_CannotRestoreUnsupressedFlow);
            }

            currentThread.ExecutionContext = executionContext.ShallowClone(isFlowSuppressed: false);
        }
コード例 #6
0
ファイル: ExecutionContext.cs プロジェクト: weshaggard/corert
        internal void Undo(Thread currentThread)
        {
            Debug.Assert(currentThread == Thread.CurrentThread);

            // The common case is that these have not changed, so avoid the cost of a write if not needed.
            if (currentThread.SynchronizationContext != m_sc)
            {
                currentThread.SynchronizationContext = m_sc;
            }

            if (currentThread.ExecutionContext != m_ec)
            {
                ExecutionContext.Restore(currentThread, m_ec);
            }
        }
コード例 #7
0
ファイル: ExecutionContext.cs プロジェクト: weshaggard/corert
        internal static void Restore(Thread currentThread, ExecutionContext executionContext)
        {
            Debug.Assert(currentThread == Thread.CurrentThread);

            ExecutionContext previous = currentThread.ExecutionContext ?? Default;

            currentThread.ExecutionContext = executionContext;

            // New EC could be null if that's what ECS.Undo saved off.
            // For the purposes of dealing with context change, treat this as the default EC
            executionContext = executionContext ?? Default;

            if (previous != executionContext)
            {
                OnContextChanged(previous, executionContext);
            }
        }
コード例 #8
0
        public static AsyncFlowControl SuppressFlow()
        {
            Thread           currentThread    = Thread.CurrentThread;
            ExecutionContext executionContext = currentThread.ExecutionContext ?? Default;

            if (executionContext.m_isFlowSuppressed)
            {
                throw new InvalidOperationException(SR.InvalidOperation_CannotSupressFlowMultipleTimes);
            }

            executionContext = executionContext.ShallowClone(isFlowSuppressed: true);
            var asyncFlowControl = new AsyncFlowControl();

            currentThread.ExecutionContext = executionContext;
            asyncFlowControl.Initialize(currentThread);
            return(asyncFlowControl);
        }
コード例 #9
0
ファイル: ExecutionContext.cs プロジェクト: weshaggard/corert
 internal void Initialize(Thread currentThread)
 {
     Debug.Assert(currentThread == Thread.CurrentThread);
     _thread = currentThread;
 }
コード例 #10
0
        // Direct copy of the above RunInternal overload, except that it passes the state into the callback strongly-typed and by ref.
        internal static void RunInternal <TState>(ExecutionContext executionContext, ContextCallback <TState> callback, ref TState 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"
            //       https://github.com/dotnet/coreclr/blob/master/Documentation/design-docs/eh-writethru.md

            // Enregister variables with 0 post-fix so they can be used in registers without EH forcing them to stack
            // Capture references to Thread Contexts
            Thread           currentThread0        = Thread.CurrentThread;
            Thread           currentThread         = currentThread0;
            ExecutionContext previousExecutionCtx0 = currentThread0.ExecutionContext;

            if (previousExecutionCtx0 != null && previousExecutionCtx0.m_isDefault)
            {
                // Default is a null ExecutionContext internally
                previousExecutionCtx0 = null;
            }

            // Store current ExecutionContext and SynchronizationContext as "previousXxx".
            // This allows us to restore them and undo any Context changes made in callback.Invoke
            // so that they won't "leak" back into caller.
            // These variables will cross EH so be forced to stack
            ExecutionContext       previousExecutionCtx = previousExecutionCtx0;
            SynchronizationContext previousSyncCtx      = currentThread0.SynchronizationContext;

            if (executionContext != null && executionContext.m_isDefault)
            {
                // Default is a null ExecutionContext internally
                executionContext = null;
            }

            if (previousExecutionCtx0 != executionContext)
            {
                RestoreChangedContextToThread(currentThread0, executionContext, previousExecutionCtx0);
            }

            ExceptionDispatchInfo edi = null;

            try
            {
                callback.Invoke(ref state);
            }
            catch (Exception ex)
            {
                // 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.
                edi = ExceptionDispatchInfo.Capture(ex);
            }

            // Re-enregistrer variables post EH with 1 post-fix so they can be used in registers rather than from stack
            SynchronizationContext previousSyncCtx1 = previousSyncCtx;
            Thread currentThread1 = currentThread;

            // The common case is that these have not changed, so avoid the cost of a write barrier if not needed.
            if (currentThread1.SynchronizationContext != previousSyncCtx1)
            {
                // Restore changed SynchronizationContext back to previous
                currentThread1.SynchronizationContext = previousSyncCtx1;
            }

            ExecutionContext previousExecutionCtx1 = previousExecutionCtx;
            ExecutionContext currentExecutionCtx1  = currentThread1.ExecutionContext;

            if (currentExecutionCtx1 != previousExecutionCtx1)
            {
                RestoreChangedContextToThread(currentThread1, previousExecutionCtx1, currentExecutionCtx1);
            }

            // If exception was thrown by callback, rethrow it now original contexts are restored
            edi?.Throw();
        }