var invokeAsyncCallback = s_invokeAsyncCallback;
if (invokeAsyncCallback == null) s_invokeAsyncCallback = invokeAsyncCallback = InvokeAsyncCallback; // benign race condition
- using(context) ExecutionContext.Run(context, invokeAsyncCallback, this, true);
+ ExecutionContext.Run(context, invokeAsyncCallback, this);
}
}
Debugger.NotifyOfCrossThreadDependency();
// The builder needs to flow ExecutionContext, so capture it.
- var capturedContext = ExecutionContext.FastCapture(); // ok to use FastCapture as we haven't made any permission demands/asserts
+ var capturedContext = ExecutionContext.Capture();
// If the ExecutionContext is the default context, try to use a cached delegate, creating one if necessary.
Action action;
MoveNextRunner runner;
- if (capturedContext != null && capturedContext.IsPreAllocatedDefault)
+ if (capturedContext == ExecutionContext.Default)
{
// Get the cached delegate, and if it's non-null, return it.
action = m_defaultContextAction;
if (m_context != null)
{
- try
- {
- // Use the context and callback to invoke m_stateMachine.MoveNext.
- ExecutionContext.Run(m_context, InvokeMoveNextCallback, m_stateMachine, preserveSyncCtx: true);
- }
- finally { m_context.Dispose(); }
+ // Use the context and callback to invoke m_stateMachine.MoveNext.
+ ExecutionContext.Run(m_context, InvokeMoveNextCallback, m_stateMachine);
}
else
{
internal void RunWithDefaultContext()
{
Debug.Assert(m_stateMachine != null, "The state machine must have been set before calling Run.");
- ExecutionContext.Run(ExecutionContext.PreAllocatedDefault, InvokeMoveNextCallback, m_stateMachine, preserveSyncCtx: true);
+ ExecutionContext.Run(ExecutionContext.Default, InvokeMoveNextCallback, m_stateMachine);
}
/// <summary>Gets a delegate to the InvokeMoveNext method.</summary>
- protected static ContextCallback InvokeMoveNextCallback
- {
- get { return s_invokeMoveNext ?? (s_invokeMoveNext = InvokeMoveNext); }
- }
-
- /// <summary>Cached delegate used with ExecutionContext.Run.</summary>
- private static ContextCallback s_invokeMoveNext; // lazily-initialized due to SecurityCritical attribution
-
- /// <summary>Invokes the MoveNext method on the supplied IAsyncStateMachine.</summary>
- /// <param name="stateMachine">The IAsyncStateMachine machine instance.</param>
- private static void InvokeMoveNext(object stateMachine)
- {
- ((IAsyncStateMachine)stateMachine).MoveNext();
- }
+ protected static readonly ContextCallback InvokeMoveNextCallback = sm => ((IAsyncStateMachine)sm).MoveNext();
}
/// <summary>
[Serializable]
public sealed class ExecutionContext : IDisposable, ISerializable
{
- private static readonly ExecutionContext Default = new ExecutionContext();
+ internal static readonly ExecutionContext Default = new ExecutionContext();
private readonly IAsyncLocalValueMap m_localValues;
private readonly IAsyncLocal[] m_localChangeNotifications;
public static ExecutionContext Capture()
{
ExecutionContext executionContext = Thread.CurrentThread.ExecutionContext;
- if (executionContext == null)
- {
- return Default;
- }
- if (executionContext.m_isFlowSuppressed)
- {
- // Prevent ExecutionContext.Run on a suppressed-flow context for desktop framework compatibility
- return null;
- }
- return executionContext;
+ return
+ executionContext == null ? Default :
+ executionContext.m_isFlowSuppressed ? null :
+ executionContext;
}
private ExecutionContext ShallowClone(bool isFlowSuppressed)
}
}
- #region Wrappers for CLR compat, to avoid ifdefs all over the BCL
-
- [Flags]
- internal enum CaptureOptions
- {
- None = 0x00,
- IgnoreSyncCtx = 0x01,
- OptimizeDefaultCase = 0x02,
- }
-
- internal static ExecutionContext Capture(ref StackCrawlMark stackMark, CaptureOptions captureOptions)
- {
- return Capture();
- }
-
[FriendAccessAllowed]
internal static ExecutionContext FastCapture()
{
Run(executionContext, callback, state);
}
- internal bool IsDefaultFTContext(bool ignoreSyncCtx)
- {
- return this == Default;
- }
-
public ExecutionContext CreateCopy()
{
return this; // since CoreCLR's ExecutionContext is immutable, we don't need to create copies.
{
// For CLR compat only
}
-
- internal static ExecutionContext PreAllocatedDefault
- {
- get { return ExecutionContext.Default; }
- }
-
- internal bool IsPreAllocatedDefault
- {
- get { return this == ExecutionContext.Default; }
- }
-
- #endregion
}
public struct AsyncFlowControl : IDisposable
{
}
- internal _IOCompletionCallback(IOCompletionCallback ioCompletionCallback, ref StackCrawlMark stackMark)
+ internal _IOCompletionCallback(IOCompletionCallback ioCompletionCallback)
{
_ioCompletionCallback = ioCompletionCallback;
// clone the exection context
- _executionContext = ExecutionContext.Capture(
- ref stackMark,
- ExecutionContext.CaptureOptions.IgnoreSyncCtx | ExecutionContext.CaptureOptions.OptimizeDefaultCase);
+ _executionContext = ExecutionContext.Capture();
}
// Context callback: same sig for SendOrPostCallback and ContextCallback
static internal ContextCallback _ccb = new ContextCallback(IOCompletionCallback_Context);
overlapped = OverlappedData.GetOverlappedFromNative(pOVERLAP).m_overlapped;
helper = overlapped.iocbHelper;
- if (helper == null || helper._executionContext == null || helper._executionContext.IsDefaultFTContext(true))
- {
- // We got here because of UnsafePack (or) Pack with EC flow supressed
- IOCompletionCallback callback = overlapped.UserCallback;
- callback( errorCode, numBytes, pOVERLAP);
- }
- else
- {
- // We got here because of Pack
- helper._errorCode = errorCode;
- helper._numBytes = numBytes;
- helper._pOVERLAP = pOVERLAP;
- using (ExecutionContext executionContext = helper._executionContext.CreateCopy())
- ExecutionContext.Run(executionContext, _ccb, helper, true);
- }
-
- //Quickly check the VM again, to see if a packet has arrived.
-
+ if (helper == null || helper._executionContext == null || helper._executionContext == ExecutionContext.Default)
+ {
+ // We got here because of UnsafePack (or) Pack with EC flow supressed
+ IOCompletionCallback callback = overlapped.UserCallback;
+ callback( errorCode, numBytes, pOVERLAP);
+ }
+ else
+ {
+ // We got here because of Pack
+ helper._errorCode = errorCode;
+ helper._numBytes = numBytes;
+ helper._pOVERLAP = pOVERLAP;
+ ExecutionContext.Run(helper._executionContext, _ccb, helper);
+ }
+
+ //Quickly check the VM again, to see if a packet has arrived.
OverlappedData.CheckVMForIOPacket(out pOVERLAP, out errorCode, out numBytes);
-
} while (pOVERLAP != null);
}
m_nativeOverlapped.InternalHigh = (IntPtr)0;
}
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
unsafe internal NativeOverlapped* Pack(IOCompletionCallback iocb, Object userData)
{
if (!m_pinSelf.IsNull()) {
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_Overlapped_Pack"));
}
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
if (iocb != null)
{
- m_iocbHelper = new _IOCompletionCallback(iocb, ref stackMark);
+ m_iocbHelper = new _IOCompletionCallback(iocb);
m_iocb = iocb;
}
else
}
else
{
- return m_contingentProperties?.m_capturedContext ?? ExecutionContext.PreAllocatedDefault;
+ return m_contingentProperties?.m_capturedContext ?? ExecutionContext.Default;
}
}
set
{
m_stateFlags |= TASK_STATE_EXECUTIONCONTEXT_IS_NULL;
}
- else if (!value.IsPreAllocatedDefault) // not the default context, then inflate the contingent properties and set it
+ else if (value != ExecutionContext.Default) // not the default context, then inflate the contingent properties and set it
{
EnsureContingentPropertiesInitializedUnsafe().m_capturedContext = value;
}
}
}
- /// <summary>
- /// Static helper function to copy specific ExecutionContext
- /// </summary>
- /// <param name="capturedContext">The captured context</param>
- /// <returns>The copied context, null if the capturedContext is null</returns>
- private static ExecutionContext CopyExecutionContext(ExecutionContext capturedContext)
- {
- if (capturedContext == null)
- return null;
- if (capturedContext.IsPreAllocatedDefault)
- return ExecutionContext.PreAllocatedDefault;
-
- return capturedContext.CreateCopy();
- }
-
/////////////
// methods
// Run the task. We need a simple shim that converts the
// object back into a Task object, so that we can Execute it.
- // Lazily initialize the callback delegate; benign race condition
- var callback = s_ecCallback;
- if (callback == null) s_ecCallback = callback = new ContextCallback(ExecutionContextCallback);
- ExecutionContext.Run(ec, callback, this, true);
+ ExecutionContext.Run(ec, s_ecCallback, this);
}
if (AsyncCausalityTracer.LoggingOn)
}
}
- // Cached callback delegate that's lazily initialized due to ContextCallback being SecurityCritical
- private static ContextCallback s_ecCallback;
-
- private static void ExecutionContextCallback(object obj)
- {
- Task task = obj as Task;
- Debug.Assert(task != null, "expected a task object");
- task.Execute();
- }
-
+ private static readonly ContextCallback s_ecCallback = obj => ((Task)obj).Execute();
/// <summary>
/// The actual code which invokes the body of the task. This can be overriden in derived types.
m_action = action;
if (flowExecutionContext)
{
- m_capturedContext = ExecutionContext.FastCapture();
+ m_capturedContext = ExecutionContext.Capture();
}
}
// If there is an execution context, get the cached delegate and run the action under the context.
else
{
- try
- {
- ExecutionContext.Run(m_capturedContext, GetInvokeActionCallback(), m_action, true);
- }
- finally { m_capturedContext.Dispose(); }
+ ExecutionContext.Run(m_capturedContext, GetInvokeActionCallback(), m_action);
}
}
finally
void IThreadPoolWorkItem.ExecuteWorkItem()
{
// inline the fast path
- if (m_capturedContext == null && !TplEtwProvider.Log.IsEnabled()
- )
+ if (m_capturedContext == null && !TplEtwProvider.Log.IsEnabled())
{
m_action();
}
// If there's no captured context, just run the callback directly.
if (m_capturedContext == null) callback(state);
// Otherwise, use the captured context to do so.
- else ExecutionContext.Run(m_capturedContext, callback, state, true);
+ else ExecutionContext.Run(m_capturedContext, callback, state);
}
catch (Exception exc) // we explicitly do not request handling of dangerous exceptions like AVs
{
{
// Restore the current task information
if (prevCurrentTask != null) currentTask = prevCurrentTask;
-
- // Clean up after the execution context, which is only usable once.
- if (m_capturedContext != null) m_capturedContext.Dispose();
}
}
// If we reach here with a null delegate, something is broken. But we'll let the StartInternal method take care of
// reporting an error. Just make sure we dont try to dereference a null delegate.
ThreadHelper t = (ThreadHelper)(m_Delegate.Target);
- ExecutionContext ec = ExecutionContext.Capture(
- ref stackMark,
- ExecutionContext.CaptureOptions.IgnoreSyncCtx);
+ ExecutionContext ec = ExecutionContext.Capture();
t.SetExecutionContextHelper(ec);
}
}
else
{
- ExecutionContext.Run(context, ccb, this, preserveSyncCtx:true);
+ ExecutionContext.Run(context, ccb, this);
}
}
#if DEBUG
MarkExecuted(aborted:false);
#endif
- ExecutionContext.Run(ExecutionContext.PreAllocatedDefault, ccb, this, preserveSyncCtx:true);
+ ExecutionContext.Run(ExecutionContext.Default, ccb, this);
}
void IThreadPoolWorkItem.MarkAborted(ThreadAbortException tae)
private static readonly ContextCallback _ccbt = new ContextCallback(WaitOrTimerCallback_Context_t);
private static readonly ContextCallback _ccbf = new ContextCallback(WaitOrTimerCallback_Context_f);
- internal _ThreadPoolWaitOrTimerCallback(WaitOrTimerCallback waitOrTimerCallback, Object state, bool compressStack, ref StackCrawlMark stackMark)
+ internal _ThreadPoolWaitOrTimerCallback(WaitOrTimerCallback waitOrTimerCallback, Object state, bool compressStack)
{
_waitOrTimerCallback = waitOrTimerCallback;
_state = state;
- if (compressStack && !ExecutionContext.IsFlowSuppressed())
+ if (compressStack)
{
// capture the exection context
- _executionContext = ExecutionContext.Capture(
- ref stackMark,
- ExecutionContext.CaptureOptions.IgnoreSyncCtx | ExecutionContext.CaptureOptions.OptimizeDefaultCase);
+ _executionContext = ExecutionContext.Capture();
}
}
}
else
{
- using (ExecutionContext executionContext = helper._executionContext.CreateCopy())
- {
- ExecutionContext.Run(executionContext, timedOut ? _ccbt : _ccbf, helper, preserveSyncCtx:true);
- }
+ ExecutionContext.Run(helper._executionContext, timedOut ? _ccbt : _ccbf, helper);
}
}
if (callBack != null)
{
- _ThreadPoolWaitOrTimerCallback callBackHelper = new _ThreadPoolWaitOrTimerCallback(callBack, state, compressStack, ref stackMark);
+ _ThreadPoolWaitOrTimerCallback callBackHelper = new _ThreadPoolWaitOrTimerCallback(callBack, state, compressStack);
state = (Object)callBackHelper;
// call SetWaitObject before native call so that waitObject won't be closed before threadpoolmgr registration
// this could occur if callback were to fire before SetWaitObject does its addref
ExecutionContext context = ExecutionContext.Capture();
- IThreadPoolWorkItem tpcallBack = context == ExecutionContext.PreAllocatedDefault ?
+ IThreadPoolWorkItem tpcallBack = context == ExecutionContext.Default ?
new QueueUserWorkItemCallbackDefaultContext(callBack, state) :
(IThreadPoolWorkItem)new QueueUserWorkItemCallback(callBack, state, context);
volatile WaitHandle m_notifyWhenNoCallbacksRunning;
- internal TimerQueueTimer(TimerCallback timerCallback, object state, uint dueTime, uint period, ref StackCrawlMark stackMark)
+ internal TimerQueueTimer(TimerCallback timerCallback, object state, uint dueTime, uint period)
{
m_timerCallback = timerCallback;
m_state = state;
m_dueTime = Timeout.UnsignedInfinite;
m_period = Timeout.UnsignedInfinite;
-
- if (!ExecutionContext.IsFlowSuppressed())
- {
- m_executionContext = ExecutionContext.Capture(
- ref stackMark,
- ExecutionContext.CaptureOptions.IgnoreSyncCtx | ExecutionContext.CaptureOptions.OptimizeDefaultCase);
- }
+ m_executionContext = ExecutionContext.Capture();
//
// After the following statement, the timer may fire. No more manipulation of timer state outside of
}
else
{
- using (ExecutionContext executionContext =
- m_executionContext.IsPreAllocatedDefault ? m_executionContext : m_executionContext.CreateCopy())
- {
- ContextCallback callback = s_callCallbackInContext;
- if (callback == null)
- s_callCallbackInContext = callback = new ContextCallback(CallCallbackInContext);
-
- ExecutionContext.Run(
- executionContext,
- callback,
- this, // state
- true); // ignoreSyncCtx
- }
+ ExecutionContext.Run(m_executionContext, s_callCallbackInContext, this);
}
}
- private static ContextCallback s_callCallbackInContext;
-
- private static void CallCallbackInContext(object state)
+ private static readonly ContextCallback s_callCallbackInContext = state =>
{
TimerQueueTimer t = (TimerQueueTimer)state;
t.m_timerCallback(t.m_state);
- }
+ };
}
//
private TimerHolder m_timer;
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
public Timer(TimerCallback callback,
Object state,
int dueTime,
if (period < -1 )
throw new ArgumentOutOfRangeException(nameof(period), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- TimerSetup(callback,state,(UInt32)dueTime,(UInt32)period,ref stackMark);
+ TimerSetup(callback,state,(UInt32)dueTime,(UInt32)period);
}
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
public Timer(TimerCallback callback,
Object state,
TimeSpan dueTime,
if (periodTm > MAX_SUPPORTED_TIMEOUT)
throw new ArgumentOutOfRangeException(nameof(periodTm),Environment.GetResourceString("ArgumentOutOfRange_PeriodTooLarge"));
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- TimerSetup(callback,state,(UInt32)dueTm,(UInt32)periodTm,ref stackMark);
+ TimerSetup(callback,state,(UInt32)dueTm,(UInt32)periodTm);
}
[CLSCompliant(false)]
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
public Timer(TimerCallback callback,
Object state,
UInt32 dueTime,
UInt32 period)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- TimerSetup(callback,state,dueTime,period,ref stackMark);
+ TimerSetup(callback,state,dueTime,period);
}
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
public Timer(TimerCallback callback,
Object state,
long dueTime,
if (period > MAX_SUPPORTED_TIMEOUT)
throw new ArgumentOutOfRangeException(nameof(period),Environment.GetResourceString("ArgumentOutOfRange_PeriodTooLarge"));
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- TimerSetup(callback,state,(UInt32) dueTime, (UInt32) period,ref stackMark);
+ TimerSetup(callback,state,(UInt32) dueTime, (UInt32) period);
}
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
public Timer(TimerCallback callback)
{
int dueTime = -1; // we want timer to be registered, but not activated. Requires caller to call
// for a timer to be fired before the returned value is assigned to the variable,
// potentially causing the callback to reference a bogus value (if passing the timer to the callback).
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- TimerSetup(callback, this, (UInt32)dueTime, (UInt32)period, ref stackMark);
+ TimerSetup(callback, this, (UInt32)dueTime, (UInt32)period);
}
private void TimerSetup(TimerCallback callback,
Object state,
UInt32 dueTime,
- UInt32 period,
- ref StackCrawlMark stackMark)
+ UInt32 period)
{
if (callback == null)
throw new ArgumentNullException(nameof(TimerCallback));
Contract.EndContractBlock();
- m_timer = new TimerHolder(new TimerQueueTimer(callback, state, dueTime, period, ref stackMark));
+ m_timer = new TimerHolder(new TimerQueueTimer(callback, state, dueTime, period));
}
public bool Change(int dueTime, int period)