From f9cfb538195da0bcc8506b69b4a87f53e444b46e Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Sun, 5 Feb 2017 09:27:53 -0500 Subject: [PATCH] Address PR feedback and other cleanup Addressed PR comment about removing ExecutionContext.Capture(ref StackCrawlMark, ...), which led me to remove NoInlining/StackCrawlMarks from some other places in Timer, Thread, ThreadPool, and Overlapped. In doing so, I found several other unnecessary members on ExecutionContext that could be removed with minor tweaks elsewhere in the source, e.g. - Dispose is a nop, so we can remove explicit try/finally's to clean it up - ExecutionContext.Run(..., bool) just ignores the bool arg, so it can be removed and all call sites redirected (but I've left it in EC, as it appears it's used via internals visible from a library in corefx) - FastCapture() just calls Capture, so the call sites can be changed (but I've left it in EC for a similar reason) - PreAllocatedDefault can be removed in favor of Default; etc. - ExecutionContext.Capture itself checks whether flow is suppressed; doing a check before it adds a TLS lookup and in doing so optimizes for an uncommon case in exchange for making the common case more expensive. I've removed those checks. And in the process, I also noticed that several lazily initialized delegates that no longer need to be, and cleaned those up. These were lazy due to needing to be for security checks that aren't relevant in coreclr. Commit migrated from https://github.com/dotnet/coreclr/commit/b72fc3aa651ffdeb9136f785fc7631663a92685f --- src/coreclr/src/mscorlib/src/System/IO/Stream.cs | 2 +- .../Runtime/CompilerServices/AsyncMethodBuilder.cs | 29 +++--------- .../src/System/Threading/ExecutionContext.cs | 48 ++----------------- .../mscorlib/src/System/Threading/Overlapped.cs | 45 ++++++++---------- .../mscorlib/src/System/Threading/Tasks/Task.cs | 35 ++------------ .../src/System/Threading/Tasks/TaskContinuation.cs | 16 ++----- .../src/mscorlib/src/System/Threading/Thread.cs | 4 +- .../mscorlib/src/System/Threading/ThreadPool.cs | 21 ++++----- .../src/mscorlib/src/System/Threading/Timer.cs | 55 +++++----------------- 9 files changed, 60 insertions(+), 195 deletions(-) diff --git a/src/coreclr/src/mscorlib/src/System/IO/Stream.cs b/src/coreclr/src/mscorlib/src/System/IO/Stream.cs index a7dbe48..371c650 100644 --- a/src/coreclr/src/mscorlib/src/System/IO/Stream.cs +++ b/src/coreclr/src/mscorlib/src/System/IO/Stream.cs @@ -679,7 +679,7 @@ namespace System.IO { 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); } } diff --git a/src/coreclr/src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs b/src/coreclr/src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs index 5952740..35ccdac 100644 --- a/src/coreclr/src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs +++ b/src/coreclr/src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs @@ -876,12 +876,12 @@ namespace System.Runtime.CompilerServices 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; @@ -1016,12 +1016,8 @@ namespace System.Runtime.CompilerServices 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 { @@ -1046,24 +1042,11 @@ namespace System.Runtime.CompilerServices 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); } /// Gets a delegate to the InvokeMoveNext method. - protected static ContextCallback InvokeMoveNextCallback - { - get { return s_invokeMoveNext ?? (s_invokeMoveNext = InvokeMoveNext); } - } - - /// Cached delegate used with ExecutionContext.Run. - private static ContextCallback s_invokeMoveNext; // lazily-initialized due to SecurityCritical attribution - - /// Invokes the MoveNext method on the supplied IAsyncStateMachine. - /// The IAsyncStateMachine machine instance. - private static void InvokeMoveNext(object stateMachine) - { - ((IAsyncStateMachine)stateMachine).MoveNext(); - } + protected static readonly ContextCallback InvokeMoveNextCallback = sm => ((IAsyncStateMachine)sm).MoveNext(); } /// diff --git a/src/coreclr/src/mscorlib/src/System/Threading/ExecutionContext.cs b/src/coreclr/src/mscorlib/src/System/Threading/ExecutionContext.cs index 5ea9942..7baddff 100644 --- a/src/coreclr/src/mscorlib/src/System/Threading/ExecutionContext.cs +++ b/src/coreclr/src/mscorlib/src/System/Threading/ExecutionContext.cs @@ -55,7 +55,7 @@ namespace System.Threading [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; @@ -93,16 +93,10 @@ namespace System.Threading 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) @@ -301,21 +295,6 @@ namespace System.Threading } } - #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() { @@ -328,11 +307,6 @@ namespace System.Threading 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. @@ -342,18 +316,6 @@ namespace System.Threading { // 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 diff --git a/src/coreclr/src/mscorlib/src/System/Threading/Overlapped.cs b/src/coreclr/src/mscorlib/src/System/Threading/Overlapped.cs index 2b192c7..129bea6 100644 --- a/src/coreclr/src/mscorlib/src/System/Threading/Overlapped.cs +++ b/src/coreclr/src/mscorlib/src/System/Threading/Overlapped.cs @@ -71,13 +71,11 @@ namespace System.Threading { } - 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); @@ -103,26 +101,23 @@ namespace System.Threading 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); } @@ -174,17 +169,15 @@ namespace System.Threading 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 diff --git a/src/coreclr/src/mscorlib/src/System/Threading/Tasks/Task.cs b/src/coreclr/src/mscorlib/src/System/Threading/Tasks/Task.cs index 1426f71..82864aa 100644 --- a/src/coreclr/src/mscorlib/src/System/Threading/Tasks/Task.cs +++ b/src/coreclr/src/mscorlib/src/System/Threading/Tasks/Task.cs @@ -1633,7 +1633,7 @@ namespace System.Threading.Tasks } else { - return m_contingentProperties?.m_capturedContext ?? ExecutionContext.PreAllocatedDefault; + return m_contingentProperties?.m_capturedContext ?? ExecutionContext.Default; } } set @@ -1643,7 +1643,7 @@ namespace System.Threading.Tasks { 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; } @@ -1651,21 +1651,6 @@ namespace System.Threading.Tasks } } - /// - /// Static helper function to copy specific ExecutionContext - /// - /// The captured context - /// The copied context, null if the capturedContext is null - private static ExecutionContext CopyExecutionContext(ExecutionContext capturedContext) - { - if (capturedContext == null) - return null; - if (capturedContext.IsPreAllocatedDefault) - return ExecutionContext.PreAllocatedDefault; - - return capturedContext.CreateCopy(); - } - ///////////// // methods @@ -2465,10 +2450,7 @@ namespace System.Threading.Tasks // 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) @@ -2495,16 +2477,7 @@ namespace System.Threading.Tasks } } - // 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(); /// /// The actual code which invokes the body of the task. This can be overriden in derived types. diff --git a/src/coreclr/src/mscorlib/src/System/Threading/Tasks/TaskContinuation.cs b/src/coreclr/src/mscorlib/src/System/Threading/Tasks/TaskContinuation.cs index 9cf0142..3c6ccd8 100644 --- a/src/coreclr/src/mscorlib/src/System/Threading/Tasks/TaskContinuation.cs +++ b/src/coreclr/src/mscorlib/src/System/Threading/Tasks/TaskContinuation.cs @@ -543,7 +543,7 @@ namespace System.Threading.Tasks m_action = action; if (flowExecutionContext) { - m_capturedContext = ExecutionContext.FastCapture(); + m_capturedContext = ExecutionContext.Capture(); } } @@ -648,11 +648,7 @@ namespace System.Threading.Tasks // 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 @@ -667,8 +663,7 @@ namespace System.Threading.Tasks void IThreadPoolWorkItem.ExecuteWorkItem() { // inline the fast path - if (m_capturedContext == null && !TplEtwProvider.Log.IsEnabled() - ) + if (m_capturedContext == null && !TplEtwProvider.Log.IsEnabled()) { m_action(); } @@ -717,7 +712,7 @@ namespace System.Threading.Tasks // 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 { @@ -727,9 +722,6 @@ namespace System.Threading.Tasks { // 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(); } } diff --git a/src/coreclr/src/mscorlib/src/System/Threading/Thread.cs b/src/coreclr/src/mscorlib/src/System/Threading/Thread.cs index bfa47f7..f05e104 100644 --- a/src/coreclr/src/mscorlib/src/System/Threading/Thread.cs +++ b/src/coreclr/src/mscorlib/src/System/Threading/Thread.cs @@ -280,9 +280,7 @@ namespace System.Threading { // 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); } diff --git a/src/coreclr/src/mscorlib/src/System/Threading/ThreadPool.cs b/src/coreclr/src/mscorlib/src/System/Threading/ThreadPool.cs index 67701ec..8076a76 100644 --- a/src/coreclr/src/mscorlib/src/System/Threading/ThreadPool.cs +++ b/src/coreclr/src/mscorlib/src/System/Threading/ThreadPool.cs @@ -951,7 +951,7 @@ namespace System.Threading } else { - ExecutionContext.Run(context, ccb, this, preserveSyncCtx:true); + ExecutionContext.Run(context, ccb, this); } } @@ -1010,7 +1010,7 @@ namespace System.Threading #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) @@ -1042,17 +1042,15 @@ namespace System.Threading 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(); } } @@ -1081,10 +1079,7 @@ namespace System.Threading } else { - using (ExecutionContext executionContext = helper._executionContext.CreateCopy()) - { - ExecutionContext.Run(executionContext, timedOut ? _ccbt : _ccbf, helper, preserveSyncCtx:true); - } + ExecutionContext.Run(helper._executionContext, timedOut ? _ccbt : _ccbf, helper); } } @@ -1167,7 +1162,7 @@ namespace System.Threading 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 @@ -1303,7 +1298,7 @@ namespace System.Threading ExecutionContext context = ExecutionContext.Capture(); - IThreadPoolWorkItem tpcallBack = context == ExecutionContext.PreAllocatedDefault ? + IThreadPoolWorkItem tpcallBack = context == ExecutionContext.Default ? new QueueUserWorkItemCallbackDefaultContext(callBack, state) : (IThreadPoolWorkItem)new QueueUserWorkItemCallback(callBack, state, context); diff --git a/src/coreclr/src/mscorlib/src/System/Threading/Timer.cs b/src/coreclr/src/mscorlib/src/System/Threading/Timer.cs index a2b4378..263e47a 100644 --- a/src/coreclr/src/mscorlib/src/System/Threading/Timer.cs +++ b/src/coreclr/src/mscorlib/src/System/Threading/Timer.cs @@ -435,19 +435,13 @@ namespace System.Threading 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 @@ -601,29 +595,15 @@ namespace System.Threading } 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); - } + }; } // @@ -686,7 +666,6 @@ namespace System.Threading 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, @@ -697,12 +676,10 @@ namespace System.Threading 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, @@ -720,22 +697,18 @@ namespace System.Threading 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, @@ -750,11 +723,9 @@ namespace System.Threading 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 @@ -762,21 +733,19 @@ namespace System.Threading // 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) -- 2.7.4