Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.

Commit

Permalink
Merge pull request #9342 from stephentoub/tasks_inlining
Browse files Browse the repository at this point in the history
Remove NoInlining/StackCrawlMarks from Tasks
  • Loading branch information
stephentoub committed Feb 5, 2017
2 parents d676fc3 + b72fc3a commit a8c08f3
Show file tree
Hide file tree
Showing 14 changed files with 243 additions and 770 deletions.
8 changes: 2 additions & 6 deletions src/mscorlib/src/System/IO/Stream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -617,7 +617,6 @@ private sealed class ReadWriteTask : Task<int>, ITaskCompletionAction
_buffer = null;
}

[MethodImpl(MethodImplOptions.NoInlining)]
public ReadWriteTask(
bool isRead,
bool apm,
Expand All @@ -630,8 +629,6 @@ public ReadWriteTask(
Contract.Requires(buffer != null);
Contract.EndContractBlock();

StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;

// Store the arguments
_isRead = isRead;
_apm = apm;
Expand All @@ -648,8 +645,7 @@ public ReadWriteTask(
if (callback != null)
{
_callback = callback;
_context = ExecutionContext.Capture(ref stackMark,
ExecutionContext.CaptureOptions.OptimizeDefaultCase | ExecutionContext.CaptureOptions.IgnoreSyncCtx);
_context = ExecutionContext.Capture();
base.AddCompletionAction(this);
}
}
Expand Down Expand Up @@ -683,7 +679,7 @@ void ITaskCompletionAction.Invoke(Task completingTask)
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);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -876,12 +876,12 @@ internal Action GetCompletionAction(Task taskForTracing, ref MoveNextRunner runn
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;
Expand Down Expand Up @@ -1016,12 +1016,8 @@ internal void RunWithCapturedContext()

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
{
Expand All @@ -1046,24 +1042,11 @@ internal MoveNextRunner(IAsyncStateMachine stateMachine)
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>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,21 +198,19 @@ private static void ThrowForNonSuccess(Task task)
/// <exception cref="System.ArgumentNullException">The <paramref name="continuation"/> argument is null (Nothing in Visual Basic).</exception>
/// <exception cref="System.NullReferenceException">The awaiter was not properly initialized.</exception>
/// <remarks>This method is intended for compiler user rather than use directly in code.</remarks>
[MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
internal static void OnCompletedInternal(Task task, Action continuation, bool continueOnCapturedContext, bool flowExecutionContext)
{
if (continuation == null) throw new ArgumentNullException(nameof(continuation));
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;

// If TaskWait* ETW events are enabled, trace a beginning event for this await
// and set up an ending event to be traced when the asynchronous await completes.
if ( TplEtwProvider.Log.IsEnabled() || Task.s_asyncDebuggingEnabled)
if (TplEtwProvider.Log.IsEnabled() || Task.s_asyncDebuggingEnabled)
{
continuation = OutputWaitEtwEvents(task, continuation);
}

// Set the continuation onto the awaited task.
task.SetContinuationForAwait(continuation, continueOnCapturedContext, flowExecutionContext, ref stackMark);
task.SetContinuationForAwait(continuation, continueOnCapturedContext, flowExecutionContext);
}

/// <summary>
Expand Down
6 changes: 1 addition & 5 deletions src/mscorlib/src/System/Threading/CancellationToken.cs
Original file line number Diff line number Diff line change
Expand Up @@ -317,11 +317,8 @@ internal CancellationTokenRegistration InternalRegisterWithoutEC(Action<object>
}

// the real work..
[MethodImpl(MethodImplOptions.NoInlining)]
private CancellationTokenRegistration Register(Action<Object> callback, Object state, bool useSynchronizationContext, bool useExecutionContext)
{
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;

if (callback == null)
throw new ArgumentNullException(nameof(callback));

Expand All @@ -341,8 +338,7 @@ private CancellationTokenRegistration Register(Action<Object> callback, Object s
if (useSynchronizationContext)
capturedSyncContext = SynchronizationContext.Current;
if (useExecutionContext)
capturedExecutionContext = ExecutionContext.Capture(
ref stackMark, ExecutionContext.CaptureOptions.OptimizeDefaultCase); // ideally we'd also use IgnoreSyncCtx, but that could break compat
capturedExecutionContext = ExecutionContext.Capture();
}

// Register the callback with the source.
Expand Down
48 changes: 5 additions & 43 deletions src/mscorlib/src/System/Threading/ExecutionContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ internal void Undo(Thread currentThread)
[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;
Expand Down Expand Up @@ -93,16 +93,10 @@ private ExecutionContext(SerializationInfo info, StreamingContext context)
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)
Expand Down Expand Up @@ -301,21 +295,6 @@ internal static void SetLocalValue(IAsyncLocal local, object newValue, bool need
}
}

#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()
{
Expand All @@ -328,11 +307,6 @@ internal static void Run(ExecutionContext executionContext, ContextCallback call
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.
Expand All @@ -342,18 +316,6 @@ public void Dispose()
{
// 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
Expand Down
45 changes: 19 additions & 26 deletions src/mscorlib/src/System/Threading/Overlapped.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,11 @@ static _IOCompletionCallback()
{
}

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);
Expand All @@ -103,26 +101,23 @@ static unsafe internal void PerformIOCompletionCallback(uint errorCode, // Error
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);

}
Expand Down Expand Up @@ -174,17 +169,15 @@ internal void ReInitialize()
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
Expand Down
Loading

0 comments on commit a8c08f3

Please sign in to comment.