diff options
Diffstat (limited to 'src/mscorlib/src/System/Threading/Tasks/Task.cs')
-rw-r--r-- | src/mscorlib/src/System/Threading/Tasks/Task.cs | 229 |
1 files changed, 78 insertions, 151 deletions
diff --git a/src/mscorlib/src/System/Threading/Tasks/Task.cs b/src/mscorlib/src/System/Threading/Tasks/Task.cs index 36f8401a4d..cf081f75fd 100644 --- a/src/mscorlib/src/System/Threading/Tasks/Task.cs +++ b/src/mscorlib/src/System/Threading/Tasks/Task.cs @@ -137,7 +137,6 @@ namespace System.Threading.Tasks /// InternalWait method serves a potential marker for when a Task is entering a wait operation. /// </para> /// </remarks> - [HostProtection(Synchronization = true, ExternalThreading = true)] [DebuggerTypeProxy(typeof(SystemThreadingTasks_TaskDebugView))] [DebuggerDisplay("Id = {Id}, Status = {Status}, Method = {DebuggerDisplayMethodDescription}")] public class Task : IThreadPoolWorkItem, IAsyncResult, IDisposable @@ -152,7 +151,7 @@ namespace System.Threading.Tasks private volatile int m_taskId; // this task's unique ID. initialized only if it is ever requested - internal object m_action; // The body of the task. Might be Action<object>, Action<TState> or Action. Or possibly a Func. + internal Delegate m_action; // The body of the task. Might be Action<object>, Action<TState> or Action. Or possibly a Func. // If m_action is set to null it will indicate that we operate in the // "externally triggered completion" mode, which is exclusively meant // for the signalling Task<TResult> (aka. promise). In this mode, @@ -339,7 +338,7 @@ namespace System.Threading.Tasks // (action,TCO). It should always be true. internal Task(object state, TaskCreationOptions creationOptions, bool promiseStyle) { - Contract.Assert(promiseStyle, "Promise CTOR: promiseStyle was false"); + Debug.Assert(promiseStyle, "Promise CTOR: promiseStyle was false"); // Check the creationOptions. We allow the AttachedToParent option to be specified for promise tasks. // Also allow RunContinuationsAsynchronously because this is the constructor called by TCS @@ -580,7 +579,7 @@ namespace System.Threading.Tasks /// <param name="cancellationToken">A CancellationToken for the Task.</param> /// <param name="creationOptions">Options to customize behavior of Task.</param> /// <param name="internalOptions">Internal options to customize behavior of Task.</param> - internal void TaskConstructorCore(object action, object state, CancellationToken cancellationToken, + internal void TaskConstructorCore(Delegate action, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler) { m_action = action; @@ -609,7 +608,7 @@ namespace System.Threading.Tasks InternalTaskOptions.ContinuationTask | InternalTaskOptions.LazyCancellation | InternalTaskOptions.QueuedByRuntime)); - Contract.Assert(illegalInternalOptions == 0, "TaskConstructorCore: Illegal internal options"); + Debug.Assert(illegalInternalOptions == 0, "TaskConstructorCore: Illegal internal options"); #endif // Throw exception if the user specifies both LongRunning and SelfReplicating @@ -620,8 +619,8 @@ namespace System.Threading.Tasks } // Assign options to m_stateAndOptionsFlag. - Contract.Assert(m_stateFlags == 0, "TaskConstructorCore: non-zero m_stateFlags"); - Contract.Assert((((int)creationOptions) | OptionsMask) == OptionsMask, "TaskConstructorCore: options take too many bits"); + Debug.Assert(m_stateFlags == 0, "TaskConstructorCore: non-zero m_stateFlags"); + Debug.Assert((((int)creationOptions) | OptionsMask) == OptionsMask, "TaskConstructorCore: options take too many bits"); var tmpFlags = (int)creationOptions | (int)internalOptions; if ((m_action == null) || ((internalOptions & InternalTaskOptions.ContinuationTask) != 0)) { @@ -649,7 +648,7 @@ namespace System.Threading.Tasks // we need to do this as the very last thing in the construction path, because the CT registration could modify m_stateFlags if (cancellationToken.CanBeCanceled) { - Contract.Assert((internalOptions & + Debug.Assert((internalOptions & (InternalTaskOptions.ChildReplica | InternalTaskOptions.SelfReplicating | InternalTaskOptions.ContinuationTask)) == 0, "TaskConstructorCore: Did not expect to see cancelable token for replica/replicating or continuation task."); @@ -743,7 +742,7 @@ namespace System.Threading.Tasks antecedentTask.RemoveContinuation(continuation); } } - Contract.Assert(targetTask != null, + Debug.Assert(targetTask != null, "targetTask should have been non-null, with the supplied argument being a task or a tuple containing one"); targetTask.InternalCancel(false); } @@ -753,7 +752,7 @@ namespace System.Threading.Tasks { get { - Delegate d = (Delegate)m_action; + Delegate d = m_action; return d != null ? d.Method.ToString() : "{null}"; } } @@ -764,10 +763,9 @@ namespace System.Threading.Tasks /// </summary> /// <param name="stackMark">A stack crawl mark pointing to the frame of the caller.</param> - [SecuritySafeCritical] internal void PossiblyCaptureContext(ref StackCrawlMark stackMark) { - Contract.Assert(m_contingentProperties == null || m_contingentProperties.m_capturedContext == null, + Debug.Assert(m_contingentProperties == null || m_contingentProperties.m_capturedContext == null, "Captured an ExecutionContext when one was already captured."); // In the legacy .NET 3.5 build, we don't have the optimized overload of Capture() @@ -791,7 +789,7 @@ namespace System.Threading.Tasks // a read of the volatile m_stateFlags field. internal static TaskCreationOptions OptionsMethod(int flags) { - Contract.Assert((OptionsMask & 1) == 1, "OptionsMask needs a shift in Options.get"); + Debug.Assert((OptionsMask & 1) == 1, "OptionsMask needs a shift in Options.get"); return (TaskCreationOptions)(flags & OptionsMask); } @@ -841,7 +839,7 @@ namespace System.Threading.Tasks /// <param name="enabled">true to set the bit; false to unset the bit.</param> internal void SetNotificationForWaitCompletion(bool enabled) { - Contract.Assert((Options & (TaskCreationOptions)InternalTaskOptions.PromiseTask) != 0, + Debug.Assert((Options & (TaskCreationOptions)InternalTaskOptions.PromiseTask) != 0, "Should only be used for promise-style tasks"); // hasn't been vetted on other kinds as there hasn't been a need if (enabled) @@ -849,7 +847,7 @@ namespace System.Threading.Tasks // Atomically set the END_AWAIT_NOTIFICATION bit bool success = AtomicStateUpdate(TASK_STATE_WAIT_COMPLETION_NOTIFICATION, TASK_STATE_COMPLETED_MASK | TASK_STATE_COMPLETION_RESERVED); - Contract.Assert(success, "Tried to set enabled on completed Task"); + Debug.Assert(success, "Tried to set enabled on completed Task"); } else { @@ -886,7 +884,7 @@ namespace System.Threading.Tasks /// <returns>true if any of the tasks require notification; otherwise, false.</returns> internal static bool AnyTaskRequiresNotifyDebuggerOfWaitCompletion(Task[] tasks) { - Contract.Assert(tasks != null, "Expected non-null array of tasks"); + Debug.Assert(tasks != null, "Expected non-null array of tasks"); foreach (var task in tasks) { if (task != null && @@ -926,7 +924,7 @@ namespace System.Threading.Tasks // bit was unset between the time that it was checked and this method was called. // It's so remote a chance that it's worth having the assert to protect against misuse. bool isWaitNotificationEnabled = IsWaitNotificationEnabled; - Contract.Assert(isWaitNotificationEnabled, "Should only be called if the wait completion bit is set."); + Debug.Assert(isWaitNotificationEnabled, "Should only be called if the wait completion bit is set."); return isWaitNotificationEnabled; } } @@ -946,7 +944,7 @@ namespace System.Threading.Tasks // It's theoretically possible but extremely rare that this assert could fire because the // bit was unset between the time that it was checked and this method was called. // It's so remote a chance that it's worth having the assert to protect against misuse. - Contract.Assert(IsWaitNotificationEnabled, "Should only be called if the wait completion bit is set."); + Debug.Assert(IsWaitNotificationEnabled, "Should only be called if the wait completion bit is set."); // Now that we're notifying the debugger, clear the bit. The debugger should do this anyway, // but this adds a bit of protection in case it fails to, and given that the debugger is involved, @@ -991,7 +989,7 @@ namespace System.Threading.Tasks /// </summary> internal void AddNewChild() { - Contract.Assert(Task.InternalCurrent == this || this.IsSelfReplicatingRoot, "Task.AddNewChild(): Called from an external context"); + Debug.Assert(Task.InternalCurrent == this || this.IsSelfReplicatingRoot, "Task.AddNewChild(): Called from an external context"); var props = EnsureContingentPropertiesInitialized(); @@ -1014,10 +1012,10 @@ namespace System.Threading.Tasks // We need to subtract that child from m_completionCountdown, or the parent will never complete. internal void DisregardChild() { - Contract.Assert(Task.InternalCurrent == this, "Task.DisregardChild(): Called from an external context"); + Debug.Assert(Task.InternalCurrent == this, "Task.DisregardChild(): Called from an external context"); var props = EnsureContingentPropertiesInitialized(); - Contract.Assert(props.m_completionCountdown >= 2, "Task.DisregardChild(): Expected parent count to be >= 2"); + Debug.Assert(props.m_completionCountdown >= 2, "Task.DisregardChild(): Expected parent count to be >= 2"); Interlocked.Decrement(ref props.m_completionCountdown); } @@ -1161,7 +1159,6 @@ namespace System.Threading.Tasks // // Internal version of RunSynchronously that allows not waiting for completion. // - [SecuritySafeCritical] // Needed for QueueTask internal void InternalRunSynchronously(TaskScheduler scheduler, bool waitForCompletion) { Contract.Requires(scheduler != null, "Task.InternalRunSynchronously(): null TaskScheduler"); @@ -1235,7 +1232,7 @@ namespace System.Threading.Tasks // Mark ourselves as "handled" to avoid crashing the finalizer thread if the caller neglects to // call Wait() on this task. // m_contingentProperties.m_exceptionsHolder *should* already exist after AddException() - Contract.Assert( + Debug.Assert( (m_contingentProperties != null) && (m_contingentProperties.m_exceptionsHolder != null) && (m_contingentProperties.m_exceptionsHolder.ContainsFaultList), @@ -1252,7 +1249,7 @@ namespace System.Threading.Tasks } else { - Contract.Assert((m_stateFlags & TASK_STATE_CANCELED) != 0, "Task.RunSynchronously: expected TASK_STATE_CANCELED to be set"); + Debug.Assert((m_stateFlags & TASK_STATE_CANCELED) != 0, "Task.RunSynchronously: expected TASK_STATE_CANCELED to be set"); // Can't call this method on canceled task. ThrowHelper.ThrowInvalidOperationException(ExceptionResource.Task_RunSynchronously_TaskCompleted); } @@ -1403,7 +1400,7 @@ namespace System.Threading.Tasks // Only return an exception in faulted state (skip manufactured exceptions) // A "benevolent" race condition makes it possible to return null when IsFaulted is // true (i.e., if IsFaulted is set just after the check to IsFaulted above). - Contract.Assert((e == null) || IsFaulted, "Task.Exception_get(): returning non-null value when not Faulted"); + Debug.Assert((e == null) || IsFaulted, "Task.Exception_get(): returning non-null value when not Faulted"); return e; } @@ -1884,11 +1881,10 @@ namespace System.Threading.Tasks /// underneath us. If false, TASK_STATE_STARTED bit is OR-ed right in. This /// allows us to streamline things a bit for StartNew(), where competing cancellations /// are not a problem.</param> - [SecuritySafeCritical] // Needed for QueueTask internal void ScheduleAndStart(bool needsProtection) { - Contract.Assert(m_taskScheduler != null, "expected a task scheduler to have been selected"); - Contract.Assert((m_stateFlags & TASK_STATE_STARTED) == 0, "task has already started"); + Debug.Assert(m_taskScheduler != null, "expected a task scheduler to have been selected"); + Debug.Assert((m_stateFlags & TASK_STATE_STARTED) == 0, "task has already started"); // Set the TASK_STATE_STARTED bit if (needsProtection) @@ -1912,7 +1908,7 @@ namespace System.Threading.Tasks if (AsyncCausalityTracer.LoggingOn && (Options & (TaskCreationOptions)InternalTaskOptions.ContinuationTask) == 0) { //For all other task than TaskContinuations we want to log. TaskContinuations log in their constructor - AsyncCausalityTracer.TraceOperationCreation(CausalityTraceLevel.Required, this.Id, "Task: "+((Delegate)m_action).Method.Name, 0); + AsyncCausalityTracer.TraceOperationCreation(CausalityTraceLevel.Required, this.Id, "Task: " + m_action.Method.Name, 0); } @@ -1942,7 +1938,7 @@ namespace System.Threading.Tasks if ((Options & (TaskCreationOptions)InternalTaskOptions.ContinuationTask) == 0) { // m_contingentProperties.m_exceptionsHolder *should* already exist after AddException() - Contract.Assert( + Debug.Assert( (m_contingentProperties != null) && (m_contingentProperties.m_exceptionsHolder != null) && (m_contingentProperties.m_exceptionsHolder.ContainsFaultList), @@ -1981,13 +1977,13 @@ namespace System.Threading.Tasks var eoAsEdi = exceptionObject as ExceptionDispatchInfo; var eoAsEnumerableEdi = exceptionObject as IEnumerable<ExceptionDispatchInfo>; - Contract.Assert( + Debug.Assert( eoAsException != null || eoAsEnumerableException != null || eoAsEdi != null || eoAsEnumerableEdi != null, "Task.AddException: Expected an Exception, ExceptionDispatchInfo, or an IEnumerable<> of one of those"); var eoAsOce = exceptionObject as OperationCanceledException; - Contract.Assert( + Debug.Assert( !representsCancellation || eoAsOce != null || (eoAsEdi != null && eoAsEdi.SourceException is OperationCanceledException), @@ -2078,7 +2074,7 @@ namespace System.Threading.Tasks { // There are exceptions; get the aggregate and optionally add the canceled // exception to the aggregate (if applicable). - Contract.Assert(m_contingentProperties != null); // ExceptionRecorded ==> m_contingentProperties != null + Debug.Assert(m_contingentProperties != null); // ExceptionRecorded ==> m_contingentProperties != null // No need to lock around this, as other logic prevents the consumption of exceptions // before they have been completely processed. @@ -2097,7 +2093,7 @@ namespace System.Threading.Tasks internal ReadOnlyCollection<ExceptionDispatchInfo> GetExceptionDispatchInfos() { bool exceptionsAvailable = IsFaulted && ExceptionRecorded; - Contract.Assert(exceptionsAvailable, "Must only be used when the task has faulted with exceptions."); + Debug.Assert(exceptionsAvailable, "Must only be used when the task has faulted with exceptions."); return exceptionsAvailable ? m_contingentProperties.m_exceptionsHolder.GetExceptionDispatchInfos() : new ReadOnlyCollection<ExceptionDispatchInfo>(new ExceptionDispatchInfo[0]); @@ -2107,7 +2103,7 @@ namespace System.Threading.Tasks /// <returns>The ExceptionDispatchInfo. May be null if no OCE was stored for the task.</returns> internal ExceptionDispatchInfo GetCancellationExceptionDispatchInfo() { - Contract.Assert(IsCanceled, "Must only be used when the task has canceled."); + Debug.Assert(IsCanceled, "Must only be used when the task has canceled."); return Volatile.Read(ref m_contingentProperties)?.m_exceptionsHolder?.GetCancellationExceptionDispatchInfo(); // may be null } @@ -2344,7 +2340,7 @@ namespace System.Threading.Tasks Contract.Requires(childTask != null); Contract.Requires(childTask.IsCompleted, "ProcessChildCompletion was called for an uncompleted task"); - Contract.Assert(childTask.m_contingentProperties?.m_parent == this, "ProcessChildCompletion should only be called for a child of this task"); + Debug.Assert(childTask.m_contingentProperties?.m_parent == this, "ProcessChildCompletion should only be called for a child of this task"); var props = Volatile.Read(ref m_contingentProperties); @@ -2404,11 +2400,11 @@ namespace System.Threading.Tasks { // Ensure any exceptions thrown by children are added to the parent. // In doing this, we are implicitly marking children as being "handled". - Contract.Assert(task.IsCompleted, "Expected all tasks in list to be completed"); + Debug.Assert(task.IsCompleted, "Expected all tasks in list to be completed"); if (task.IsFaulted && !task.IsExceptionObservedByParent) { TaskExceptionHolder exceptionHolder = Volatile.Read(ref task.m_contingentProperties).m_exceptionsHolder; - Contract.Assert(exceptionHolder != null); + Debug.Assert(exceptionHolder != null); // No locking necessary since child task is finished adding exceptions // and concurrent CreateExceptionObject() calls do not constitute @@ -2435,7 +2431,7 @@ namespace System.Threading.Tasks /// <param name="delegateRan">Whether the delegate was executed.</param> internal void FinishThreadAbortedTask(bool bTAEAddedToExceptionHolder, bool delegateRan) { - Contract.Assert(!bTAEAddedToExceptionHolder || m_contingentProperties?.m_exceptionsHolder != null, + Debug.Assert(!bTAEAddedToExceptionHolder || m_contingentProperties?.m_exceptionsHolder != null, "FinishThreadAbortedTask() called on a task whose exception holder wasn't initialized"); // this will only be false for non-root self replicating task copies, because all of their exceptions go to the root task. @@ -2671,7 +2667,6 @@ namespace System.Threading.Tasks /// IThreadPoolWorkItem override, which is the entry function for this task when the TP scheduler decides to run it. /// /// </summary> - [SecurityCritical] void IThreadPoolWorkItem.ExecuteWorkItem() { ExecuteEntry(false); @@ -2681,7 +2676,6 @@ namespace System.Threading.Tasks /// The ThreadPool calls this if a ThreadAbortException is thrown while trying to execute this workitem. This may occur /// before Task would otherwise be able to observe it. /// </summary> - [SecurityCritical] void IThreadPoolWorkItem.MarkAborted(ThreadAbortException tae) { // If the task has marked itself as Completed, then it either a) already observed this exception (so we shouldn't handle it here) @@ -2700,7 +2694,6 @@ namespace System.Threading.Tasks /// </summary> /// <param name="bPreventDoubleExecution"> Performs atomic updates to prevent double execution. Should only be set to true /// in codepaths servicing user provided TaskSchedulers. The ConcRT or ThreadPool schedulers don't need this. </param> - [SecuritySafeCritical] internal bool ExecuteEntry(bool bPreventDoubleExecution) { if (bPreventDoubleExecution || ((Options & (TaskCreationOptions)InternalTaskOptions.SelfReplicating) != 0)) @@ -2742,7 +2735,6 @@ namespace System.Threading.Tasks } // A trick so we can refer to the TLS slot with a byref. - [SecurityCritical] private void ExecuteWithThreadLocal(ref Task currentTaskSlot) { // Remember the current task so we can restore it after running, and then @@ -2819,14 +2811,12 @@ namespace System.Threading.Tasks } // Cached callback delegate that's lazily initialized due to ContextCallback being SecurityCritical - [SecurityCritical] private static ContextCallback s_ecCallback; - [SecurityCritical] private static void ExecutionContextCallback(object obj) { Task task = obj as Task; - Contract.Assert(task != null, "expected a task object"); + Debug.Assert(task != null, "expected a task object"); task.Execute(); } @@ -2837,7 +2827,7 @@ namespace System.Threading.Tasks internal virtual void InnerInvoke() { // Invoke the delegate - Contract.Assert(m_action != null, "Null action in InnerInvoke()"); + Debug.Assert(m_action != null, "Null action in InnerInvoke()"); var action = m_action as Action; if (action != null) { @@ -2850,7 +2840,7 @@ namespace System.Threading.Tasks actionWithState(m_stateObject); return; } - Contract.Assert(false, "Invalid m_action in Task"); + Debug.Assert(false, "Invalid m_action in Task"); } /// <summary> @@ -2929,7 +2919,6 @@ namespace System.Threading.Tasks /// <param name="flowExecutionContext">Whether to flow ExecutionContext across the await.</param> /// <param name="stackMark">A stack crawl mark tied to execution context.</param> /// <exception cref="System.InvalidOperationException">The awaiter was not properly initialized.</exception> - [SecurityCritical] internal void SetContinuationForAwait( Action continuationAction, bool continueOnCapturedContext, bool flowExecutionContext, ref StackCrawlMark stackMark) { @@ -2986,7 +2975,7 @@ namespace System.Threading.Tasks } else { - Contract.Assert(!flowExecutionContext, "We already determined we're not required to flow context."); + Debug.Assert(!flowExecutionContext, "We already determined we're not required to flow context."); if (!AddTaskContinuation(continuationAction, addBeforeOthers: false)) AwaitTaskContinuation.UnsafeScheduleAction(continuationAction, this); } @@ -3019,7 +3008,7 @@ namespace System.Threading.Tasks Wait(Timeout.Infinite, default(CancellationToken)); #if DEBUG - Contract.Assert(waitResult, "expected wait to succeed"); + Debug.Assert(waitResult, "expected wait to succeed"); #endif } @@ -3154,7 +3143,7 @@ namespace System.Threading.Tasks ThrowIfExceptional(true); } - Contract.Assert((m_stateFlags & TASK_STATE_FAULTED) == 0, "Task.Wait() completing when in Faulted state."); + Debug.Assert((m_stateFlags & TASK_STATE_FAULTED) == 0, "Task.Wait() completing when in Faulted state."); return true; } @@ -3230,7 +3219,7 @@ namespace System.Threading.Tasks } } - Contract.Assert(IsCompleted || millisecondsTimeout != Timeout.Infinite); + Debug.Assert(IsCompleted || millisecondsTimeout != Timeout.Infinite); // ETW event for Task Wait End if (etwIsEnabled) @@ -3358,7 +3347,6 @@ namespace System.Threading.Tasks /// For custom schedulers we also attempt an atomic state transition. /// </param> /// <returns>true if the task was successfully canceled; otherwise, false.</returns> - [SecuritySafeCritical] internal bool InternalCancel(bool bCancelNonExecutingOnly) { Contract.Requires((Options & (TaskCreationOptions)InternalTaskOptions.PromiseTask) == 0, "Task.InternalCancel() did not expect promise-style task"); @@ -3426,7 +3414,7 @@ namespace System.Threading.Tasks if (bPopSucceeded) { // hitting this would mean something wrong with the AtomicStateUpdate above - Contract.Assert(!mustCleanup, "Possibly an invalid state transition call was made in InternalCancel()"); + Debug.Assert(!mustCleanup, "Possibly an invalid state transition call was made in InternalCancel()"); // Include TASK_STATE_DELEGATE_INVOKED in "illegal" bits to protect against the situation where // TS.TryDequeue() returns true but the task is still left on the queue. @@ -3466,8 +3454,8 @@ namespace System.Threading.Tasks { RecordInternalCancellationRequest(); - Contract.Assert((Options & (TaskCreationOptions)InternalTaskOptions.PromiseTask) != 0, "Task.RecordInternalCancellationRequest(CancellationToken) only valid for promise-style task"); - Contract.Assert(m_contingentProperties.m_cancellationToken == default(CancellationToken)); + Debug.Assert((Options & (TaskCreationOptions)InternalTaskOptions.PromiseTask) != 0, "Task.RecordInternalCancellationRequest(CancellationToken) only valid for promise-style task"); + Debug.Assert(m_contingentProperties.m_cancellationToken == default(CancellationToken)); // Store the supplied cancellation token as this task's token. // Waiting on this task will then result in an OperationCanceledException containing this token. @@ -3492,11 +3480,11 @@ namespace System.Threading.Tasks if (oce == null) { var edi = cancellationException as ExceptionDispatchInfo; - Contract.Assert(edi != null, "Expected either an OCE or an EDI"); + Debug.Assert(edi != null, "Expected either an OCE or an EDI"); oce = edi.SourceException as OperationCanceledException; - Contract.Assert(oce != null, "Expected EDI to contain an OCE"); + Debug.Assert(oce != null, "Expected EDI to contain an OCE"); } - Contract.Assert(oce.CancellationToken == tokenToRecord, + Debug.Assert(oce.CancellationToken == tokenToRecord, "Expected OCE's token to match the provided token."); #endif AddException(cancellationException, representsCancellation: true); @@ -3507,10 +3495,10 @@ namespace System.Threading.Tasks // And this method should be called at most once per task. internal void CancellationCleanupLogic() { - Contract.Assert((m_stateFlags & (TASK_STATE_CANCELED | TASK_STATE_COMPLETION_RESERVED)) != 0, "Task.CancellationCleanupLogic(): Task not canceled or reserved."); + Debug.Assert((m_stateFlags & (TASK_STATE_CANCELED | TASK_STATE_COMPLETION_RESERVED)) != 0, "Task.CancellationCleanupLogic(): Task not canceled or reserved."); // I'd like to do this, but there is a small window for a race condition. If someone calls Wait() between InternalCancel() and // here, that will set m_completionEvent, leading to a meaningless/harmless assertion. - //Contract.Assert((m_completionEvent == null) || !m_completionEvent.IsSet, "Task.CancellationCleanupLogic(): Completion event already set."); + //Debug.Assert((m_completionEvent == null) || !m_completionEvent.IsSet, "Task.CancellationCleanupLogic(): Completion event already set."); // This may have been set already, but we need to make sure. Interlocked.Exchange(ref m_stateFlags, m_stateFlags | TASK_STATE_CANCELED); @@ -3541,8 +3529,8 @@ namespace System.Threading.Tasks /// </summary> private void SetCancellationAcknowledged() { - Contract.Assert(this == Task.InternalCurrent, "SetCancellationAcknowledged() should only be called while this is still the current task"); - Contract.Assert(IsCancellationRequested, "SetCancellationAcknowledged() should not be called if the task's CT wasn't signaled"); + Debug.Assert(this == Task.InternalCurrent, "SetCancellationAcknowledged() should only be called while this is still the current task"); + Debug.Assert(IsCancellationRequested, "SetCancellationAcknowledged() should not be called if the task's CT wasn't signaled"); m_stateFlags |= TASK_STATE_CANCELLATIONACKNOWLEDGED; } @@ -3558,7 +3546,6 @@ namespace System.Threading.Tasks /// <summary> /// Runs all of the continuations, as appropriate. /// </summary> - [SecuritySafeCritical] // for AwaitTaskContinuation.RunOrScheduleAction internal void FinishContinuations() { // Atomically store the fact that this task is completing. From this point on, the adding of continuations will @@ -3684,7 +3671,7 @@ namespace System.Threading.Tasks // Otherwise, it must be an ITaskCompletionAction, so invoke it. else { - Contract.Assert(currentContinuation is ITaskCompletionAction, "Expected continuation element to be Action, TaskContinuation, or ITaskContinuationAction"); + Debug.Assert(currentContinuation is ITaskCompletionAction, "Expected continuation element to be Action, TaskContinuation, or ITaskContinuationAction"); var action = (ITaskCompletionAction)currentContinuation; if (bCanInlineContinuations || !action.InvokeMayRunArbitraryCode) @@ -4730,7 +4717,7 @@ namespace System.Threading.Tasks // m_continuationObject is guaranteed at this point to be either a List or // s_taskCompletionSentinel. List<object> list = m_continuationObject as List<object>; - Contract.Assert((list != null) || (m_continuationObject == s_taskCompletionSentinel), + Debug.Assert((list != null) || (m_continuationObject == s_taskCompletionSentinel), "Expected m_continuationObject to be list or sentinel"); // If list is null, it can only mean that s_taskCompletionSentinel has been exchanged @@ -4873,7 +4860,7 @@ namespace System.Threading.Tasks WaitAll(tasks, Timeout.Infinite); #if DEBUG - Contract.Assert(waitResult, "expected wait to succeed"); + Debug.Assert(waitResult, "expected wait to succeed"); #endif } @@ -5134,7 +5121,7 @@ namespace System.Threading.Tasks // Now gather up and throw all of the exceptions. foreach (var task in tasks) AddExceptionsForCompletedTask(ref exceptions, task); - Contract.Assert(exceptions != null, "Should have seen at least one exception"); + Debug.Assert(exceptions != null, "Should have seen at least one exception"); ThrowHelper.ThrowAggregateException(exceptions); } @@ -5159,8 +5146,8 @@ namespace System.Threading.Tasks /// <returns>true if all of the tasks completed; otherwise, false.</returns> private static bool WaitAllBlockingCore(List<Task> tasks, int millisecondsTimeout, CancellationToken cancellationToken) { - Contract.Assert(tasks != null, "Expected a non-null list of tasks"); - Contract.Assert(tasks.Count > 0, "Expected at least one task"); + Debug.Assert(tasks != null, "Expected a non-null list of tasks"); + Debug.Assert(tasks.Count > 0, "Expected at least one task"); bool waitCompleted = false; var mres = new SetOnCountdownMres(tasks.Count); @@ -5206,14 +5193,14 @@ namespace System.Threading.Tasks internal SetOnCountdownMres(int count) { - Contract.Assert(count > 0, "Expected count > 0"); + Debug.Assert(count > 0, "Expected count > 0"); _count = count; } public void Invoke(Task completingTask) { if (Interlocked.Decrement(ref _count) == 0) Set(); - Contract.Assert(_count >= 0, "Count should never go below 0"); + Debug.Assert(_count >= 0, "Count should never go below 0"); } public bool InvokeMayRunArbitraryCode { get { return false; } } @@ -5304,7 +5291,7 @@ namespace System.Threading.Tasks public static int WaitAny(params Task[] tasks) { int waitResult = WaitAny(tasks, Timeout.Infinite); - Contract.Assert(tasks.Length == 0 || waitResult != -1, "expected wait to succeed"); + Debug.Assert(tasks.Length == 0 || waitResult != -1, "expected wait to succeed"); return waitResult; } @@ -5475,9 +5462,9 @@ namespace System.Threading.Tasks bool waitCompleted = firstCompleted.Wait(millisecondsTimeout, cancellationToken); if (waitCompleted) { - Contract.Assert(firstCompleted.Status == TaskStatus.RanToCompletion); + Debug.Assert(firstCompleted.Status == TaskStatus.RanToCompletion); signaledTaskIndex = Array.IndexOf(tasks, firstCompleted.Result); - Contract.Assert(signaledTaskIndex >= 0); + Debug.Assert(signaledTaskIndex >= 0); } } @@ -5521,7 +5508,7 @@ namespace System.Threading.Tasks var task = new Task<TResult>(); bool succeeded = task.TrySetException(exception); - Contract.Assert(succeeded, "This should always succeed on a new task."); + Debug.Assert(succeeded, "This should always succeed on a new task."); return task; } @@ -5559,7 +5546,7 @@ namespace System.Threading.Tasks var task = new Task<TResult>(); bool succeeded = task.TrySetCanceled(exception.CancellationToken, exception); - Contract.Assert(succeeded, "This should always succeed on a new task."); + Debug.Assert(succeeded, "This should always succeed on a new task."); return task; } @@ -6124,7 +6111,7 @@ namespace System.Threading.Tasks for (int i = 0; i < m_tasks.Length; i++) { var task = m_tasks[i]; - Contract.Assert(task != null, "Constituent task in WhenAll should never be null"); + Debug.Assert(task != null, "Constituent task in WhenAll should never be null"); if (task.IsFaulted) { @@ -6144,7 +6131,7 @@ namespace System.Threading.Tasks if (observedExceptions != null) { - Contract.Assert(observedExceptions.Count > 0, "Expected at least one exception"); + Debug.Assert(observedExceptions.Count > 0, "Expected at least one exception"); //We don't need to TraceOperationCompleted here because TrySetException will call Finish and we'll log it there @@ -6166,7 +6153,7 @@ namespace System.Threading.Tasks TrySetResult(default(VoidTaskResult)); } } - Contract.Assert(m_count >= 0, "Count should never go below 0"); + Debug.Assert(m_count >= 0, "Count should never go below 0"); } public bool InvokeMayRunArbitraryCode { get { return true; } } @@ -6371,7 +6358,7 @@ namespace System.Threading.Tasks for (int i = 0; i < m_tasks.Length; i++) { Task<T> task = m_tasks[i]; - Contract.Assert(task != null, "Constituent task in WhenAll should never be null"); + Debug.Assert(task != null, "Constituent task in WhenAll should never be null"); if (task.IsFaulted) { @@ -6384,7 +6371,7 @@ namespace System.Threading.Tasks } else { - Contract.Assert(task.Status == TaskStatus.RanToCompletion); + Debug.Assert(task.Status == TaskStatus.RanToCompletion); results[i] = task.GetResultCore(waitCompletionNotification: false); // avoid Result, which would triggering debug notification } @@ -6396,7 +6383,7 @@ namespace System.Threading.Tasks if (observedExceptions != null) { - Contract.Assert(observedExceptions.Count > 0, "Expected at least one exception"); + Debug.Assert(observedExceptions.Count > 0, "Expected at least one exception"); //We don't need to TraceOperationCompleted here because TrySetException will call Finish and we'll log it there @@ -6418,7 +6405,7 @@ namespace System.Threading.Tasks TrySetResult(results); } } - Contract.Assert(m_count >= 0, "Count should never go below 0"); + Debug.Assert(m_count >= 0, "Count should never go below 0"); } public bool InvokeMayRunArbitraryCode { get { return true; } } @@ -6612,7 +6599,7 @@ namespace System.Threading.Tasks Task continuationTask = continuationObject as Task; if (continuationTask != null) { - Contract.Assert(continuationTask.m_action == null); + Debug.Assert(continuationTask.m_action == null); Delegate[] delegates = continuationTask.GetDelegateContinuationsForDebugger(); if (delegates != null) return delegates; @@ -6677,13 +6664,11 @@ namespace System.Threading.Tasks m_completingTask = completingTask; } - [SecurityCritical] void IThreadPoolWorkItem.ExecuteWorkItem() { m_action.Invoke(m_completingTask); } - [SecurityCritical] void IThreadPoolWorkItem.MarkAborted(ThreadAbortException tae) { /* NOP */ @@ -6999,25 +6984,12 @@ namespace System.Threading.Tasks // that can SO in 20 inlines on a typical 1MB stack size probably needs to be revisited anyway. private const int MAX_UNCHECKED_INLINING_DEPTH = 20; -#if !FEATURE_CORECLR - - private UInt64 m_lastKnownWatermark; - private static int s_pageSize; - - // We are conservative here. We assume that the platform needs a whole 64KB to - // respond to stack overflow. This means that for very small stacks (e.g. 128KB) - // we'll fail a lot of stack checks incorrectly. - private const long STACK_RESERVED_SPACE = 4096 * 16; - -#endif // !FEATURE_CORECLR - /// <summary> /// This method needs to be called before attempting inline execution on the current thread. /// If false is returned, it means we are too close to the end of the stack and should give up inlining. /// Each call to TryBeginInliningScope() that returns true must be matched with a /// call to EndInliningScope() regardless of whether inlining actually took place. /// </summary> - [SecuritySafeCritical] internal bool TryBeginInliningScope() { // If we're still under the 'safe' limit we'll just skip the stack probe to save p/invoke calls @@ -7037,59 +7009,15 @@ namespace System.Threading.Tasks internal void EndInliningScope() { m_inliningDepth--; - Contract.Assert(m_inliningDepth >= 0, "Inlining depth count should never go negative."); + Debug.Assert(m_inliningDepth >= 0, "Inlining depth count should never go negative."); // do the right thing just in case... if (m_inliningDepth < 0) m_inliningDepth = 0; } - [SecurityCritical] private unsafe bool CheckForSufficientStack() { -#if FEATURE_CORECLR return RuntimeHelpers.TryEnsureSufficientExecutionStack(); -#else - // see if we already have the system page size info recorded - int pageSize = s_pageSize; - if (pageSize == 0) - { - // If not we need to query it from GetSystemInfo() - // Note that this happens only once for the process lifetime - Win32Native.SYSTEM_INFO sysInfo = new Win32Native.SYSTEM_INFO(); - Win32Native.GetSystemInfo(ref sysInfo); - - s_pageSize = pageSize = sysInfo.dwPageSize; - } - - Win32Native.MEMORY_BASIC_INFORMATION stackInfo = new Win32Native.MEMORY_BASIC_INFORMATION(); - - // We subtract one page for our request. VirtualQuery rounds UP to the next page. - // Unfortunately, the stack grows down. If we're on the first page (last page in the - // VirtualAlloc), we'll be moved to the next page, which is off the stack! - - UIntPtr currentAddr = new UIntPtr(&stackInfo - pageSize); - UInt64 current64 = currentAddr.ToUInt64(); - - // Check whether we previously recorded a deeper stack than where we currently are, - // If so we don't need to do the P/Invoke to VirtualQuery - if (m_lastKnownWatermark != 0 && current64 > m_lastKnownWatermark) - return true; - - // Actual stack probe. P/Invoke to query for the current stack allocation information. - Win32Native.VirtualQuery(currentAddr.ToPointer(), ref stackInfo, (UIntPtr)(sizeof(Win32Native.MEMORY_BASIC_INFORMATION))); - - // If the current address minus the base (remember: the stack grows downward in the - // address space) is greater than the number of bytes requested plus the reserved - // space at the end, the request has succeeded. - - if ((current64 - ((UIntPtr)stackInfo.AllocationBase).ToUInt64()) > STACK_RESERVED_SPACE) - { - m_lastKnownWatermark = current64; - return true; - } - - return false; -#endif } } @@ -7204,16 +7132,15 @@ namespace System.Threading.Tasks case STATE_WAITING_ON_INNER_TASK: bool result = TrySetFromTask(completingTask, lookForOce: false); _state = STATE_DONE; // bump the state - Contract.Assert(result, "Expected TrySetFromTask from inner task to succeed"); + Debug.Assert(result, "Expected TrySetFromTask from inner task to succeed"); break; default: - Contract.Assert(false, "UnwrapPromise in illegal state"); + Debug.Assert(false, "UnwrapPromise in illegal state"); break; } } // Calls InvokeCore asynchronously. - [SecuritySafeCritical] private void InvokeCoreAsync(Task completingTask) { // Queue a call to Invoke. If we're so deep on the stack that we're at risk of overflowing, @@ -7233,7 +7160,7 @@ namespace System.Threading.Tasks private void ProcessCompletedOuterTask(Task task) { Contract.Requires(task != null && task.IsCompleted, "Expected non-null, completed outer task"); - Contract.Assert(_state == STATE_WAITING_ON_OUTER_TASK, "We're in the wrong state!"); + Debug.Assert(_state == STATE_WAITING_ON_OUTER_TASK, "We're in the wrong state!"); // Bump our state before proceeding any further _state = STATE_WAITING_ON_INNER_TASK; @@ -7245,7 +7172,7 @@ namespace System.Threading.Tasks case TaskStatus.Canceled: case TaskStatus.Faulted: bool result = TrySetFromTask(task, _lookForOce); - Contract.Assert(result, "Expected TrySetFromTask from outer task to succeed"); + Debug.Assert(result, "Expected TrySetFromTask from outer task to succeed"); break; // Otherwise, process the inner task it returned. |