Task 源代码

    [HostProtection(Synchronization = true, ExternalThreading = true)]
    [DebuggerTypeProxy(typeof(SystemThreadingTasks_TaskDebugView))]
    [DebuggerDisplay("Id = {Id}, Status = {Status}, Method = {DebuggerDisplayMethodDescription}")]
    public class Task : IThreadPoolWorkItem, IAsyncResult, IDisposable
    {
        [ThreadStatic]
        internal static Task t_currentTask;
[ThreadStatic]
private static StackGuard t_stackGuard; internal static int s_taskIdCounter; private readonly static TaskFactory s_factory = new TaskFactory(); private volatile int m_taskId; internal object m_action; internal object m_stateObject; internal TaskScheduler m_taskScheduler; internal readonly Task m_parent; internal volatile int m_stateFlags; private const int OptionsMask = 0xFFFF; internal const int TASK_STATE_STARTED = 0x10000; internal const int TASK_STATE_DELEGATE_INVOKED = 0x20000; internal const int TASK_STATE_DISPOSED = 0x40000; internal const int TASK_STATE_EXCEPTIONOBSERVEDBYPARENT = 0x80000; internal const int TASK_STATE_CANCELLATIONACKNOWLEDGED = 0x100000; internal const int TASK_STATE_FAULTED = 0x200000; internal const int TASK_STATE_CANCELED = 0x400000; internal const int TASK_STATE_WAITING_ON_CHILDREN = 0x800000; internal const int TASK_STATE_RAN_TO_COMPLETION = 0x1000000; internal const int TASK_STATE_WAITINGFORACTIVATION = 0x2000000; internal const int TASK_STATE_COMPLETION_RESERVED = 0x4000000; internal const int TASK_STATE_THREAD_WAS_ABORTED = 0x8000000; internal const int TASK_STATE_WAIT_COMPLETION_NOTIFICATION = 0x10000000; internal const int TASK_STATE_EXECUTIONCONTEXT_IS_NULL = 0x20000000; internal const int TASK_STATE_TASKSCHEDULED_WAS_FIRED = 0x40000000; private const int TASK_STATE_COMPLETED_MASK = TASK_STATE_CANCELED | TASK_STATE_FAULTED | TASK_STATE_RAN_TO_COMPLETION; private const int CANCELLATION_REQUESTED = 0x1; private volatile object m_continuationObject = null; private static readonly object s_taskCompletionSentinel = new object(); [FriendAccessAllowed] internal static bool s_asyncDebuggingEnabled; private static readonly Dictionary<int, Task> s_currentActiveTasks = new Dictionary<int, Task>(); private static readonly Object s_activeTasksLock = new Object(); [FriendAccessAllowed] internal static bool AddToActiveTasks(Task task) { Contract.Requires(task != null, "Null Task objects can't be added to the ActiveTasks collection"); lock (s_activeTasksLock) { s_currentActiveTasks[task.Id] = task; } return true; } [FriendAccessAllowed] internal static void RemoveFromActiveTasks(int taskId) { lock (s_activeTasksLock) { s_currentActiveTasks.Remove(taskId); } } internal class ContingentProperties { internal ExecutionContext m_capturedContext; internal volatile ManualResetEventSlim m_completionEvent; internal volatile TaskExceptionHolder m_exceptionsHolder; internal CancellationToken m_cancellationToken; internal Shared<CancellationTokenRegistration> m_cancellationRegistration; internal volatile int m_internalCancellationRequested; internal volatile int m_completionCountdown = 1; internal volatile List<Task> m_exceptionalChildren; internal void SetCompleted() { var mres = m_completionEvent; if (mres != null) mres.Set(); } internal void DeregisterCancellationCallback() { if (m_cancellationRegistration != null) { try { m_cancellationRegistration.Value.Dispose(); } catch (ObjectDisposedException) { } m_cancellationRegistration = null; } } } internal volatile ContingentProperties m_contingentProperties; internal Task(bool canceled, TaskCreationOptions creationOptions, CancellationToken ct) { int optionFlags = (int)creationOptions; if (canceled) { m_stateFlags = TASK_STATE_CANCELED | TASK_STATE_CANCELLATIONACKNOWLEDGED | optionFlags; ContingentProperties props; m_contingentProperties = props = new ContingentProperties(); props.m_cancellationToken = ct; props.m_internalCancellationRequested = CANCELLATION_REQUESTED; } else m_stateFlags = TASK_STATE_RAN_TO_COMPLETION | optionFlags; } internal Task() { m_stateFlags = TASK_STATE_WAITINGFORACTIVATION | (int)InternalTaskOptions.PromiseTask; } internal Task(object state, TaskCreationOptions creationOptions, bool promiseStyle) { Contract.Assert(promiseStyle, "Promise CTOR: promiseStyle was false"); if ((creationOptions & ~(TaskCreationOptions.AttachedToParent | TaskCreationOptions.RunContinuationsAsynchronously)) != 0) { throw new ArgumentOutOfRangeException("creationOptions"); } if ((creationOptions & TaskCreationOptions.AttachedToParent) != 0) m_parent = Task.InternalCurrent; TaskConstructorCore(null, state, default(CancellationToken), creationOptions, InternalTaskOptions.PromiseTask, null); } [MethodImplAttribute(MethodImplOptions.NoInlining)] public Task(Action action) : this(action, null, null, default(CancellationToken), TaskCreationOptions.None, InternalTaskOptions.None, null) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; PossiblyCaptureContext(ref stackMark); } [MethodImplAttribute(MethodImplOptions.NoInlining)] public Task(Action action, CancellationToken cancellationToken) : this(action, null, null, cancellationToken, TaskCreationOptions.None, InternalTaskOptions.None, null) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; PossiblyCaptureContext(ref stackMark); } [MethodImplAttribute(MethodImplOptions.NoInlining)] public Task(Action action, TaskCreationOptions creationOptions) : this(action, null, Task.InternalCurrentIfAttached(creationOptions), default(CancellationToken), creationOptions, InternalTaskOptions.None, null) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; PossiblyCaptureContext(ref stackMark); } [MethodImplAttribute(MethodImplOptions.NoInlining)] public Task(Action action, CancellationToken cancellationToken, TaskCreationOptions creationOptions) : this(action, null, Task.InternalCurrentIfAttached(creationOptions), cancellationToken, creationOptions, InternalTaskOptions.None, null) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; PossiblyCaptureContext(ref stackMark); } [MethodImplAttribute(MethodImplOptions.NoInlining)] public Task(Action<object> action, object state) : this(action, state, null, default(CancellationToken), TaskCreationOptions.None, InternalTaskOptions.None, null) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; PossiblyCaptureContext(ref stackMark); } [MethodImplAttribute(MethodImplOptions.NoInlining)] public Task(Action<object> action, object state, CancellationToken cancellationToken) : this(action, state, null, cancellationToken, TaskCreationOptions.None, InternalTaskOptions.None, null) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; PossiblyCaptureContext(ref stackMark); } [MethodImplAttribute(MethodImplOptions.NoInlining)] public Task(Action<object> action, object state, TaskCreationOptions creationOptions) : this(action, state, Task.InternalCurrentIfAttached(creationOptions), default(CancellationToken), creationOptions, InternalTaskOptions.None, null) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; PossiblyCaptureContext(ref stackMark); } [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task(Action<object> action, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions) : this(action, state, Task.InternalCurrentIfAttached(creationOptions), cancellationToken, creationOptions, InternalTaskOptions.None, null) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; PossiblyCaptureContext(ref stackMark); } internal Task(Action<object> action, object state, Task parent, CancellationToken cancellationToken, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler, ref StackCrawlMark stackMark) : this(action, state, parent, cancellationToken, creationOptions, internalOptions, scheduler) { PossiblyCaptureContext(ref stackMark); } internal Task(Delegate action, object state, Task parent, CancellationToken cancellationToken, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler) { if (action == null) { throw new ArgumentNullException("action"); } Contract.EndContractBlock(); if (((creationOptions & TaskCreationOptions.AttachedToParent) != 0) || ((internalOptions & InternalTaskOptions.SelfReplicating) != 0) ) { m_parent = parent; } TaskConstructorCore(action, state, cancellationToken, creationOptions, internalOptions, scheduler); } internal void TaskConstructorCore(object action, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler) { m_action = action; m_stateObject = state; m_taskScheduler = scheduler; if ((creationOptions & ~(TaskCreationOptions.AttachedToParent | TaskCreationOptions.LongRunning | TaskCreationOptions.DenyChildAttach | TaskCreationOptions.HideScheduler | TaskCreationOptions.PreferFairness | TaskCreationOptions.RunContinuationsAsynchronously)) != 0) { throw new ArgumentOutOfRangeException("creationOptions"); } #if DEBUG int illegalInternalOptions = (int) (internalOptions & ~(InternalTaskOptions.SelfReplicating | InternalTaskOptions.ChildReplica | InternalTaskOptions.PromiseTask | InternalTaskOptions.ContinuationTask | InternalTaskOptions.LazyCancellation | InternalTaskOptions.QueuedByRuntime)); Contract.Assert(illegalInternalOptions == 0, "TaskConstructorCore: Illegal internal options"); #endif if (((creationOptions & TaskCreationOptions.LongRunning) != 0) && ((internalOptions & InternalTaskOptions.SelfReplicating) != 0)) { throw new InvalidOperationException(Environment.GetResourceString("Task_ctor_LRandSR")); } Contract.Assert(m_stateFlags == 0, "TaskConstructorCore: non-zero m_stateFlags"); Contract.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)) { tmpFlags |= TASK_STATE_WAITINGFORACTIVATION; } m_stateFlags = tmpFlags; if (m_parent != null && ((creationOptions & TaskCreationOptions.AttachedToParent) != 0) && ((m_parent.CreationOptions & TaskCreationOptions.DenyChildAttach) == 0) ) { m_parent.AddNewChild(); } if (cancellationToken.CanBeCanceled) { Contract.Assert((internalOptions & (InternalTaskOptions.ChildReplica | InternalTaskOptions.SelfReplicating | InternalTaskOptions.ContinuationTask)) == 0,"TaskConstructorCore: Did not expect to see cancelable token for replica/replicating or continuation task."); AssignCancellationToken(cancellationToken, null, null); } } private void AssignCancellationToken(CancellationToken cancellationToken, Task antecedent, TaskContinuation continuation) { ContingentProperties props = EnsureContingentPropertiesInitialized(needsProtection: false); props.m_cancellationToken = cancellationToken; try { if (AppContextSwitches.ThrowExceptionIfDisposedCancellationTokenSource) { cancellationToken.ThrowIfSourceDisposed(); } if ((((InternalTaskOptions)Options & (InternalTaskOptions.QueuedByRuntime | InternalTaskOptions.PromiseTask | InternalTaskOptions.LazyCancellation)) == 0)) { if (cancellationToken.IsCancellationRequested) { this.InternalCancel(false); } else { CancellationTokenRegistration ctr; if (antecedent == null) { ctr = cancellationToken.InternalRegisterWithoutEC(s_taskCancelCallback, this); } else { ctr = cancellationToken.InternalRegisterWithoutEC(s_taskCancelCallback, new Tuple<Task, Task, TaskContinuation>(this, antecedent, continuation)); } props.m_cancellationRegistration = new Shared<CancellationTokenRegistration>(ctr); } } } catch { if ((m_parent != null) && ((Options & TaskCreationOptions.AttachedToParent) != 0) && ((m_parent.Options & TaskCreationOptions.DenyChildAttach) == 0)) { m_parent.DisregardChild(); } throw; } } private readonly static Action<Object> s_taskCancelCallback = new Action<Object>(TaskCancelCallback); private static void TaskCancelCallback(Object o) { var targetTask = o as Task; if (targetTask == null) { var tuple = o as Tuple<Task, Task, TaskContinuation>; if (tuple != null) { targetTask = tuple.Item1; Task antecedentTask = tuple.Item2; TaskContinuation continuation = tuple.Item3; antecedentTask.RemoveContinuation(continuation); } } Contract.Assert(targetTask != null, "targetTask should have been non-null, with the supplied argument being a task or a tuple containing one"); targetTask.InternalCancel(false); } private string DebuggerDisplayMethodDescription { get { Delegate d = (Delegate)m_action; return d != null ? d.Method.ToString() : "{null}"; } } [SecuritySafeCritical] internal void PossiblyCaptureContext(ref StackCrawlMark stackMark) { Contract.Assert(m_contingentProperties == null || m_contingentProperties.m_capturedContext == null, "Captured an ExecutionContext when one was already captured."); #if PFX_LEGACY_3_5 CapturedContext = ExecutionContext.Capture(); #else CapturedContext = ExecutionContext.Capture( ref stackMark, ExecutionContext.CaptureOptions.IgnoreSyncCtx | ExecutionContext.CaptureOptions.OptimizeDefaultCase); #endif } internal TaskCreationOptions Options { get { int stateFlags = m_stateFlags; return OptionsMethod(stateFlags); } } internal static TaskCreationOptions OptionsMethod(int flags) { Contract.Assert((OptionsMask & 1) == 1, "OptionsMask needs a shift in Options.get"); return (TaskCreationOptions)(flags & OptionsMask); } internal bool AtomicStateUpdate(int newBits, int illegalBits) { SpinWait sw = new SpinWait(); do { int oldFlags = m_stateFlags; if ((oldFlags & illegalBits) != 0) return false; if (Interlocked.CompareExchange(ref m_stateFlags, oldFlags | newBits, oldFlags) == oldFlags) { return true; } sw.SpinOnce(); } while (true); } internal bool AtomicStateUpdate(int newBits, int illegalBits, ref int oldFlags) { SpinWait sw = new SpinWait(); do { oldFlags = m_stateFlags; if ((oldFlags & illegalBits) != 0) return false; if (Interlocked.CompareExchange(ref m_stateFlags, oldFlags | newBits, oldFlags) == oldFlags) { return true; } sw.SpinOnce(); } while (true); } internal void SetNotificationForWaitCompletion(bool enabled) { Contract.Assert((Options & (TaskCreationOptions)InternalTaskOptions.PromiseTask) != 0, "Should only be used for promise-style tasks"); if (enabled) { 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"); } else { SpinWait sw = new SpinWait(); while (true) { int oldFlags = m_stateFlags; int newFlags = oldFlags & (~TASK_STATE_WAIT_COMPLETION_NOTIFICATION); if (Interlocked.CompareExchange(ref m_stateFlags, newFlags, oldFlags) == oldFlags) break; sw.SpinOnce(); } } } internal bool NotifyDebuggerOfWaitCompletionIfNecessary() { if (IsWaitNotificationEnabled && ShouldNotifyDebuggerOfWaitCompletion) { NotifyDebuggerOfWaitCompletion(); return true; } return false; } internal static bool AnyTaskRequiresNotifyDebuggerOfWaitCompletion(Task[] tasks) { Contract.Assert(tasks != null, "Expected non-null array of tasks"); foreach (var task in tasks) { if (task != null && task.IsWaitNotificationEnabled && task.ShouldNotifyDebuggerOfWaitCompletion) { return true; } } return false; } internal bool IsWaitNotificationEnabledOrNotRanToCompletion { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return (m_stateFlags & (Task.TASK_STATE_WAIT_COMPLETION_NOTIFICATION | Task.TASK_STATE_RAN_TO_COMPLETION)) != Task.TASK_STATE_RAN_TO_COMPLETION; } }
internal virtual bool ShouldNotifyDebuggerOfWaitCompletion // ideally would be familyAndAssembly, but that can't be done in C# { get { bool isWaitNotificationEnabled = IsWaitNotificationEnabled; Contract.Assert(isWaitNotificationEnabled, "Should only be called if the wait completion bit is set."); return isWaitNotificationEnabled; } } internal bool IsWaitNotificationEnabled { get { return (m_stateFlags & TASK_STATE_WAIT_COMPLETION_NOTIFICATION) != 0; } }
[MethodImpl(MethodImplOptions.NoOptimization
| MethodImplOptions.NoInlining)] private void NotifyDebuggerOfWaitCompletion() { Contract.Assert(IsWaitNotificationEnabled, "Should only be called if the wait completion bit is set."); SetNotificationForWaitCompletion(enabled: false); } internal bool MarkStarted() { return AtomicStateUpdate(TASK_STATE_STARTED, TASK_STATE_CANCELED | TASK_STATE_STARTED); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal bool FireTaskScheduledIfNeeded(TaskScheduler ts) { var etwLog = TplEtwProvider.Log; if (etwLog.IsEnabled() && (m_stateFlags & Task.TASK_STATE_TASKSCHEDULED_WAS_FIRED) == 0) { m_stateFlags |= Task.TASK_STATE_TASKSCHEDULED_WAS_FIRED; Task currentTask = Task.InternalCurrent; Task parentTask = this.m_parent; etwLog.TaskScheduled(ts.Id, currentTask == null ? 0 : currentTask.Id, this.Id, parentTask == null ? 0 : parentTask.Id, (int)this.Options, System.Threading.Thread.GetDomainID()); return true; } else return false; } internal void AddNewChild() { Contract.Assert(Task.InternalCurrent == this || this.IsSelfReplicatingRoot, "Task.AddNewChild(): Called from an external context"); var props = EnsureContingentPropertiesInitialized(needsProtection: true); if (props.m_completionCountdown == 1 && !IsSelfReplicatingRoot) { props.m_completionCountdown++; } else { Interlocked.Increment(ref props.m_completionCountdown); } } internal void DisregardChild() { Contract.Assert(Task.InternalCurrent == this, "Task.DisregardChild(): Called from an external context"); var props = EnsureContingentPropertiesInitialized(needsProtection: true); Contract.Assert(props.m_completionCountdown >= 2, "Task.DisregardChild(): Expected parent count to be >= 2"); Interlocked.Decrement(ref props.m_completionCountdown); } public void Start() { Start(TaskScheduler.Current); } public void Start(TaskScheduler scheduler) { int flags = m_stateFlags; if (IsCompletedMethod(flags)) { throw new InvalidOperationException(Environment.GetResourceString("Task_Start_TaskCompleted")); } if (scheduler == null) { throw new ArgumentNullException("scheduler"); } var options = OptionsMethod(flags); if ((options & (TaskCreationOptions)InternalTaskOptions.PromiseTask) != 0) { throw new InvalidOperationException(Environment.GetResourceString("Task_Start_Promise")); } if ((options & (TaskCreationOptions)InternalTaskOptions.ContinuationTask) != 0) { throw new InvalidOperationException(Environment.GetResourceString("Task_Start_ContinuationTask")); } if (Interlocked.CompareExchange(ref m_taskScheduler, scheduler, null) != null) { throw new InvalidOperationException(Environment.GetResourceString("Task_Start_AlreadyStarted")); } ScheduleAndStart(true); } public void RunSynchronously() { InternalRunSynchronously(TaskScheduler.Current, waitForCompletion: true); }
public void RunSynchronously(TaskScheduler scheduler) { if (scheduler == null) { throw new ArgumentNullException("scheduler"); } Contract.EndContractBlock(); InternalRunSynchronously(scheduler, waitForCompletion: true); } [SecuritySafeCritical] internal void InternalRunSynchronously(TaskScheduler scheduler, bool waitForCompletion) { Contract.Requires(scheduler != null, "Task.InternalRunSynchronously(): null TaskScheduler"); int flags = m_stateFlags; var options = OptionsMethod(flags); if ((options & (TaskCreationOptions)InternalTaskOptions.ContinuationTask) != 0) { throw new InvalidOperationException(Environment.GetResourceString("Task_RunSynchronously_Continuation")); } if ((options & (TaskCreationOptions)InternalTaskOptions.PromiseTask) != 0) { throw new InvalidOperationException(Environment.GetResourceString("Task_RunSynchronously_Promise")); } if (IsCompletedMethod(flags)) { throw new InvalidOperationException(Environment.GetResourceString("Task_RunSynchronously_TaskCompleted")); } if (Interlocked.CompareExchange(ref m_taskScheduler, scheduler, null) != null) { throw new InvalidOperationException(Environment.GetResourceString("Task_RunSynchronously_AlreadyStarted")); } if (MarkStarted()) { bool taskQueued = false; try { if (!scheduler.TryRunInline(this, false)) { scheduler.InternalQueueTask(this); taskQueued = true; // only mark this after successfully queuing the task. } if (waitForCompletion && !IsCompleted) { SpinThenBlockingWait(Timeout.Infinite, default(CancellationToken)); } } catch (Exception e) { if (!taskQueued && !(e is ThreadAbortException)) { TaskSchedulerException tse = new TaskSchedulerException(e); AddException(tse); Finish(false); Contract.Assert( (m_contingentProperties != null) && (m_contingentProperties.m_exceptionsHolder != null) && (m_contingentProperties.m_exceptionsHolder.ContainsFaultList), "Task.InternalRunSynchronously(): Expected m_contingentProperties.m_exceptionsHolder to exist " + "and to have faults recorded."); m_contingentProperties.m_exceptionsHolder.MarkAsHandled(false); throw tse; } else throw; } } else { Contract.Assert((m_stateFlags & TASK_STATE_CANCELED) != 0, "Task.RunSynchronously: expected TASK_STATE_CANCELED to be set"); throw new InvalidOperationException(Environment.GetResourceString("Task_RunSynchronously_TaskCompleted")); } } internal static Task InternalStartNew( Task creatingTask, Delegate action, object state, CancellationToken cancellationToken, TaskScheduler scheduler, TaskCreationOptions options, InternalTaskOptions internalOptions, ref StackCrawlMark stackMark) { if (scheduler == null) { throw new ArgumentNullException("scheduler"); } Contract.EndContractBlock(); Task t = new Task(action, state, creatingTask, cancellationToken, options, internalOptions | InternalTaskOptions.QueuedByRuntime, scheduler); t.PossiblyCaptureContext(ref stackMark); t.ScheduleAndStart(false); return t; } internal static int NewId() { int newId = 0; do { newId = Interlocked.Increment(ref s_taskIdCounter); } while (newId == 0); TplEtwProvider.Log.NewID(newId); return newId; } public int Id { get { if (m_taskId == 0) { int newId = NewId(); Interlocked.CompareExchange(ref m_taskId, newId, 0); } return m_taskId; } } public static int? CurrentId { get { Task currentTask = InternalCurrent; if (currentTask != null) return currentTask.Id; else return null; } } internal static Task InternalCurrent { get { return t_currentTask; } } internal static Task InternalCurrentIfAttached(TaskCreationOptions creationOptions) { return (creationOptions & TaskCreationOptions.AttachedToParent) != 0 ? InternalCurrent : null; } internal static StackGuard CurrentStackGuard { get { StackGuard sg = t_stackGuard; if (sg == null) { t_stackGuard = sg = new StackGuard(); } return sg; } } public AggregateException Exception { get { AggregateException e = null; if (IsFaulted) e = GetExceptions(false); Contract.Assert((e == null) || IsFaulted, "Task.Exception_get(): returning non-null value when not Faulted"); return e; } } public TaskStatus Status { get { TaskStatus rval; int sf = m_stateFlags; if ((sf & TASK_STATE_FAULTED) != 0) rval = TaskStatus.Faulted; else if ((sf & TASK_STATE_CANCELED) != 0) rval = TaskStatus.Canceled; else if ((sf & TASK_STATE_RAN_TO_COMPLETION) != 0) rval = TaskStatus.RanToCompletion; else if ((sf & TASK_STATE_WAITING_ON_CHILDREN) != 0) rval = TaskStatus.WaitingForChildrenToComplete; else if ((sf & TASK_STATE_DELEGATE_INVOKED) != 0) rval = TaskStatus.Running; else if ((sf & TASK_STATE_STARTED) != 0) rval = TaskStatus.WaitingToRun; else if ((sf & TASK_STATE_WAITINGFORACTIVATION) != 0) rval = TaskStatus.WaitingForActivation; else rval = TaskStatus.Created; return rval; } } public bool IsCanceled { get { return (m_stateFlags & (TASK_STATE_CANCELED | TASK_STATE_FAULTED)) == TASK_STATE_CANCELED; } } internal bool IsCancellationRequested { get { var props = m_contingentProperties; return props != null && (props.m_internalCancellationRequested == CANCELLATION_REQUESTED || props.m_cancellationToken.IsCancellationRequested); } } internal ContingentProperties EnsureContingentPropertiesInitialized(bool needsProtection) { var props = m_contingentProperties; return props != null ? props : EnsureContingentPropertiesInitializedCore(needsProtection); } private ContingentProperties EnsureContingentPropertiesInitializedCore(bool needsProtection) { if (needsProtection) { return LazyInitializer.EnsureInitialized<ContingentProperties>(ref m_contingentProperties, s_createContingentProperties); } else { Contract.Assert(m_contingentProperties == null, "Expected props to be null after checking and with needsProtection == false"); return m_contingentProperties = new ContingentProperties(); } } private static readonly Func<ContingentProperties> s_createContingentProperties = () => new ContingentProperties(); internal CancellationToken CancellationToken { get { var props = m_contingentProperties; return (props == null) ? default(CancellationToken) : props.m_cancellationToken; } } internal bool IsCancellationAcknowledged { get { return (m_stateFlags & TASK_STATE_CANCELLATIONACKNOWLEDGED) != 0; } } public bool IsCompleted { get { int stateFlags = m_stateFlags; return IsCompletedMethod(stateFlags); } } private static bool IsCompletedMethod(int flags) { return (flags & TASK_STATE_COMPLETED_MASK) != 0; } internal bool IsRanToCompletion { get { return (m_stateFlags & TASK_STATE_COMPLETED_MASK) == TASK_STATE_RAN_TO_COMPLETION; } } public TaskCreationOptions CreationOptions { get { return Options & (TaskCreationOptions)(~InternalTaskOptions.InternalOptionsMask); } } WaitHandle IAsyncResult.AsyncWaitHandle { get { bool isDisposed = (m_stateFlags & TASK_STATE_DISPOSED) != 0; if (isDisposed) { throw new ObjectDisposedException(null, Environment.GetResourceString("Task_ThrowIfDisposed")); } return CompletedEvent.WaitHandle; } } public object AsyncState { get { return m_stateObject; } } bool IAsyncResult.CompletedSynchronously { get { return false; } } internal TaskScheduler ExecutingTaskScheduler { get { return m_taskScheduler; } } public static TaskFactory Factory { get { return s_factory; } } private static Task s_completedTask; public static Task CompletedTask { get { var completedTask = s_completedTask; if (completedTask == null) s_completedTask = completedTask = new Task(false, (TaskCreationOptions)InternalTaskOptions.DoNotDispose, default(CancellationToken)); return completedTask; } } internal ManualResetEventSlim CompletedEvent { get { var contingentProps = EnsureContingentPropertiesInitialized(needsProtection: true); if (contingentProps.m_completionEvent == null) { bool wasCompleted = IsCompleted; ManualResetEventSlim newMre = new ManualResetEventSlim(wasCompleted); if (Interlocked.CompareExchange(ref contingentProps.m_completionEvent, newMre, null) != null) { newMre.Dispose(); } else if (!wasCompleted && IsCompleted) { newMre.Set(); } } return contingentProps.m_completionEvent; } } internal bool IsSelfReplicatingRoot { get { return (Options & (TaskCreationOptions)(InternalTaskOptions.SelfReplicating | InternalTaskOptions.ChildReplica)) == (TaskCreationOptions)InternalTaskOptions.SelfReplicating; } } internal bool IsChildReplica { get { return (Options & (TaskCreationOptions)InternalTaskOptions.ChildReplica) != 0; } } internal int ActiveChildCount { get { var props = m_contingentProperties; return props != null ? props.m_completionCountdown - 1 : 0; } } internal bool ExceptionRecorded { get { var props = m_contingentProperties; return (props != null) && (props.m_exceptionsHolder != null) && (props.m_exceptionsHolder.ContainsFaultList); } } public bool IsFaulted { get { return ((m_stateFlags & TASK_STATE_FAULTED) != 0); } } internal ExecutionContext CapturedContext { get { if ((m_stateFlags & TASK_STATE_EXECUTIONCONTEXT_IS_NULL) == TASK_STATE_EXECUTIONCONTEXT_IS_NULL) { return null; } else { var props = m_contingentProperties; if (props != null && props.m_capturedContext != null) return props.m_capturedContext; else return ExecutionContext.PreAllocatedDefault; } } set { if (value == null) { m_stateFlags |= TASK_STATE_EXECUTIONCONTEXT_IS_NULL; } else if (!value.IsPreAllocatedDefault) { EnsureContingentPropertiesInitialized(needsProtection: false).m_capturedContext = value; } } } private static ExecutionContext CopyExecutionContext(ExecutionContext capturedContext) { if (capturedContext == null) return null; if (capturedContext.IsPreAllocatedDefault) return ExecutionContext.PreAllocatedDefault; return capturedContext.CreateCopy(); } #if DEBUG /// <summary> /// Retrieves an identifier for the task. /// </summary> internal int InternalId { get { return GetHashCode(); } } #endif public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (disposing) { if ((Options & (TaskCreationOptions)InternalTaskOptions.DoNotDispose) != 0) { return; } if (!IsCompleted) { throw new InvalidOperationException(Environment.GetResourceString("Task_Dispose_NotCompleted")); } var cp = m_contingentProperties; if (cp != null) { var ev = cp.m_completionEvent; if (ev != null) { cp.m_completionEvent = null; if (!ev.IsSet) ev.Set(); ev.Dispose(); } } } m_stateFlags |= TASK_STATE_DISPOSED; } [SecuritySafeCritical] 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"); if (needsProtection) { if (!MarkStarted()) { return; } } else { m_stateFlags |= TASK_STATE_STARTED; } if (s_asyncDebuggingEnabled) { AddToActiveTasks(this); } if (AsyncCausalityTracer.LoggingOn && (Options & (TaskCreationOptions)InternalTaskOptions.ContinuationTask) == 0) { AsyncCausalityTracer.TraceOperationCreation(CausalityTraceLevel.Required, this.Id, "Task: "+((Delegate)m_action).Method.Name, 0); } try { m_taskScheduler.InternalQueueTask(this); } catch (ThreadAbortException tae) { AddException(tae); FinishThreadAbortedTask(true, false); } catch (Exception e) { TaskSchedulerException tse = new TaskSchedulerException(e); AddException(tse); Finish(false); if ((Options & (TaskCreationOptions)InternalTaskOptions.ContinuationTask) == 0) { Contract.Assert( (m_contingentProperties != null) && (m_contingentProperties.m_exceptionsHolder != null) && (m_contingentProperties.m_exceptionsHolder.ContainsFaultList), "Task.ScheduleAndStart(): Expected m_contingentProperties.m_exceptionsHolder to exist " + "and to have faults recorded."); m_contingentProperties.m_exceptionsHolder.MarkAsHandled(false); } throw tse; } } internal void AddException(object exceptionObject) { Contract.Requires(exceptionObject != null, "Task.AddException: Expected a non-null exception object"); AddException(exceptionObject, representsCancellation: false); } internal void AddException(object exceptionObject, bool representsCancellation) { Contract.Requires(exceptionObject != null, "Task.AddException: Expected a non-null exception object"); #if DEBUG var eoAsException = exceptionObject as Exception; var eoAsEnumerableException = exceptionObject as IEnumerable<Exception>; var eoAsEdi = exceptionObject as ExceptionDispatchInfo; var eoAsEnumerableEdi = exceptionObject as IEnumerable<ExceptionDispatchInfo>; Contract.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( !representsCancellation || eoAsOce != null || (eoAsEdi != null && eoAsEdi.SourceException is OperationCanceledException), "representsCancellation should be true only if an OCE was provided."); #endif var props = EnsureContingentPropertiesInitialized(needsProtection: true); if (props.m_exceptionsHolder == null) { TaskExceptionHolder holder = new TaskExceptionHolder(this); if (Interlocked.CompareExchange(ref props.m_exceptionsHolder, holder, null) != null) { holder.MarkAsHandled(false); } } lock (props) { props.m_exceptionsHolder.Add(exceptionObject, representsCancellation); } } private AggregateException GetExceptions(bool includeTaskCanceledExceptions) { Exception canceledException = null; if (includeTaskCanceledExceptions && IsCanceled) { canceledException = new TaskCanceledException(this); } if (ExceptionRecorded) { Contract.Assert(m_contingentProperties != null); return m_contingentProperties.m_exceptionsHolder.CreateExceptionObject(false, canceledException); } else if (canceledException != null) { return new AggregateException(canceledException); } return null; } internal ReadOnlyCollection<ExceptionDispatchInfo> GetExceptionDispatchInfos() { bool exceptionsAvailable = IsFaulted && ExceptionRecorded; Contract.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]); } internal ExceptionDispatchInfo GetCancellationExceptionDispatchInfo() { Contract.Assert(IsCanceled, "Must only be used when the task has canceled."); var props = m_contingentProperties; if (props == null) return null; var holder = props.m_exceptionsHolder; if (holder == null) return null; return holder.GetCancellationExceptionDispatchInfo(); } internal void ThrowIfExceptional(bool includeTaskCanceledExceptions) { Contract.Requires(IsCompleted, "ThrowIfExceptional(): Expected IsCompleted == true"); Exception exception = GetExceptions(includeTaskCanceledExceptions); if (exception != null) { UpdateExceptionObservedStatus(); throw exception; } } internal void UpdateExceptionObservedStatus() { if ((m_parent != null) && ((Options & TaskCreationOptions.AttachedToParent) != 0) && ((m_parent.CreationOptions & TaskCreationOptions.DenyChildAttach) == 0) && Task.InternalCurrent == m_parent) { m_stateFlags |= TASK_STATE_EXCEPTIONOBSERVEDBYPARENT; } } internal bool IsExceptionObservedByParent { get { return (m_stateFlags & TASK_STATE_EXCEPTIONOBSERVEDBYPARENT) != 0; } } internal bool IsDelegateInvoked { get { return (m_stateFlags & TASK_STATE_DELEGATE_INVOKED) != 0; } } internal void Finish(bool bUserDelegateExecuted) { if (!bUserDelegateExecuted) { FinishStageTwo(); } else { var props = m_contingentProperties; if (props == null || (props.m_completionCountdown == 1 && !IsSelfReplicatingRoot) || Interlocked.Decrement(ref props.m_completionCountdown) == 0) { FinishStageTwo(); } else { AtomicStateUpdate(TASK_STATE_WAITING_ON_CHILDREN, TASK_STATE_FAULTED | TASK_STATE_CANCELED | TASK_STATE_RAN_TO_COMPLETION); } List<Task> exceptionalChildren = props != null ? props.m_exceptionalChildren : null; if (exceptionalChildren != null) { lock (exceptionalChildren) { exceptionalChildren.RemoveAll(s_IsExceptionObservedByParentPredicate); } } } } private readonly static Predicate<Task> s_IsExceptionObservedByParentPredicate = new Predicate<Task>((t) => { return t.IsExceptionObservedByParent; }); internal void FinishStageTwo() { AddExceptionsFromChildren(); int completionState; if (ExceptionRecorded) { completionState = TASK_STATE_FAULTED; if (AsyncCausalityTracer.LoggingOn) AsyncCausalityTracer.TraceOperationCompletion(CausalityTraceLevel.Required, this.Id, AsyncCausalityStatus.Error); if (Task.s_asyncDebuggingEnabled) { RemoveFromActiveTasks(this.Id); } } else if (IsCancellationRequested && IsCancellationAcknowledged) { completionState = TASK_STATE_CANCELED; if (AsyncCausalityTracer.LoggingOn) AsyncCausalityTracer.TraceOperationCompletion(CausalityTraceLevel.Required, this.Id, AsyncCausalityStatus.Canceled); if (Task.s_asyncDebuggingEnabled) { RemoveFromActiveTasks(this.Id); } } else { completionState = TASK_STATE_RAN_TO_COMPLETION; if (AsyncCausalityTracer.LoggingOn) AsyncCausalityTracer.TraceOperationCompletion(CausalityTraceLevel.Required, this.Id, AsyncCausalityStatus.Completed); if (Task.s_asyncDebuggingEnabled) { RemoveFromActiveTasks(this.Id); } } Interlocked.Exchange(ref m_stateFlags, m_stateFlags | completionState); var cp = m_contingentProperties; if (cp != null) { cp.SetCompleted(); cp.DeregisterCancellationCallback(); } FinishStageThree(); } internal void FinishStageThree() { m_action = null; if (m_parent != null && ((m_parent.CreationOptions & TaskCreationOptions.DenyChildAttach) == 0) && (((TaskCreationOptions)(m_stateFlags & OptionsMask)) & TaskCreationOptions.AttachedToParent) != 0) { m_parent.ProcessChildCompletion(this); } FinishContinuations(); }
internal void ProcessChildCompletion(Task childTask) { Contract.Requires(childTask != null); Contract.Requires(childTask.IsCompleted, "ProcessChildCompletion was called for an uncompleted task"); Contract.Assert(childTask.m_parent == this, "ProcessChildCompletion should only be called for a child of this task"); var props = m_contingentProperties; if (childTask.IsFaulted && !childTask.IsExceptionObservedByParent) { if (props.m_exceptionalChildren == null) { Interlocked.CompareExchange(ref props.m_exceptionalChildren, new List<Task>(), null); } List<Task> tmp = props.m_exceptionalChildren; if (tmp != null) { lock (tmp) { tmp.Add(childTask); } } } if (Interlocked.Decrement(ref props.m_completionCountdown) == 0) { FinishStageTwo(); } }
internal void AddExceptionsFromChildren() { var props = m_contingentProperties; List<Task> tmp = (props != null) ? props.m_exceptionalChildren : null; if (tmp != null) { lock (tmp) { foreach (Task task in tmp) { Contract.Assert(task.IsCompleted, "Expected all tasks in list to be completed"); if (task.IsFaulted && !task.IsExceptionObservedByParent) { TaskExceptionHolder exceptionHolder = task.m_contingentProperties.m_exceptionsHolder; Contract.Assert(exceptionHolder != null); AddException(exceptionHolder.CreateExceptionObject(false, null)); } } } props.m_exceptionalChildren = null; } } internal void FinishThreadAbortedTask(bool bTAEAddedToExceptionHolder, bool delegateRan) { Contract.Assert(!bTAEAddedToExceptionHolder || (m_contingentProperties != null && m_contingentProperties.m_exceptionsHolder != null), "FinishThreadAbortedTask() called on a task whose exception holder wasn't initialized"); if (bTAEAddedToExceptionHolder) m_contingentProperties.m_exceptionsHolder.MarkAsHandled(false); if (!AtomicStateUpdate(TASK_STATE_THREAD_WAS_ABORTED, TASK_STATE_THREAD_WAS_ABORTED | TASK_STATE_RAN_TO_COMPLETION | TASK_STATE_FAULTED | TASK_STATE_CANCELED)) { return; } Finish(delegateRan); } private void Execute() { if (IsSelfReplicatingRoot) { ExecuteSelfReplicating(this); } else { try { InnerInvoke(); } catch (ThreadAbortException tae) { if (!IsChildReplica) { HandleException(tae); FinishThreadAbortedTask(true, true); } } catch (Exception exn) { HandleException(exn); } } } internal virtual bool ShouldReplicate() { return true; } internal virtual Task CreateReplicaTask(Action<object> taskReplicaDelegate, Object stateObject, Task parentTask, TaskScheduler taskScheduler, TaskCreationOptions creationOptionsForReplica, InternalTaskOptions internalOptionsForReplica) { return new Task(taskReplicaDelegate, stateObject, parentTask, default(CancellationToken), creationOptionsForReplica, internalOptionsForReplica, parentTask.ExecutingTaskScheduler); } internal virtual Object SavedStateForNextReplica { get { return null; } set { /*do nothing*/ } } internal virtual Object SavedStateFromPreviousReplica { get { return null; } set { /*do nothing*/ } }
internal virtual Task HandedOverChildReplica { get { return null; } set { /* do nothing*/ } } private static void ExecuteSelfReplicating(Task root) { TaskCreationOptions creationOptionsForReplicas = root.CreationOptions | TaskCreationOptions.AttachedToParent; InternalTaskOptions internalOptionsForReplicas = InternalTaskOptions.ChildReplica | InternalTaskOptions.SelfReplicating | InternalTaskOptions.QueuedByRuntime; bool replicasAreQuitting = false; Action<object> taskReplicaDelegate = null; taskReplicaDelegate = delegate { Task currentTask = Task.InternalCurrent; Task childTask = currentTask.HandedOverChildReplica; if (childTask == null) { if (!root.ShouldReplicate()) return; if (Volatile.Read(ref replicasAreQuitting)) { return; } ExecutionContext creatorContext = root.CapturedContext; childTask = root.CreateReplicaTask(taskReplicaDelegate, root.m_stateObject, root, root.ExecutingTaskScheduler, creationOptionsForReplicas, internalOptionsForReplicas); childTask.CapturedContext = CopyExecutionContext(creatorContext); childTask.ScheduleAndStart(false); } try { root.InnerInvokeWithArg(currentTask); } catch (Exception exn) { root.HandleException(exn); if (exn is ThreadAbortException) { currentTask.FinishThreadAbortedTask(false, true); } } Object savedState = currentTask.SavedStateForNextReplica; if (savedState != null) { Task replacementReplica = root.CreateReplicaTask(taskReplicaDelegate, root.m_stateObject, root, root.ExecutingTaskScheduler, creationOptionsForReplicas, internalOptionsForReplicas); ExecutionContext creatorContext = root.CapturedContext; replacementReplica.CapturedContext = CopyExecutionContext(creatorContext); replacementReplica.HandedOverChildReplica = childTask; replacementReplica.SavedStateFromPreviousReplica = savedState; replacementReplica.ScheduleAndStart(false); } else { replicasAreQuitting = true; try { childTask.InternalCancel(true); } catch (Exception e) { root.HandleException(e); } } }; taskReplicaDelegate(null); } [SecurityCritical] void IThreadPoolWorkItem.ExecuteWorkItem() { ExecuteEntry(false); } [SecurityCritical] void IThreadPoolWorkItem.MarkAborted(ThreadAbortException tae) { if (!IsCompleted) { HandleException(tae); FinishThreadAbortedTask(true, false); } } [SecuritySafeCritical] internal bool ExecuteEntry(bool bPreventDoubleExecution) { if (bPreventDoubleExecution || ((Options & (TaskCreationOptions)InternalTaskOptions.SelfReplicating) != 0)) { int previousState = 0; if (!AtomicStateUpdate(TASK_STATE_DELEGATE_INVOKED, TASK_STATE_DELEGATE_INVOKED | TASK_STATE_COMPLETED_MASK, ref previousState) && (previousState & TASK_STATE_CANCELED) == 0) { return false; } } else { m_stateFlags |= TASK_STATE_DELEGATE_INVOKED; } if (!IsCancellationRequested && !IsCanceled) { ExecuteWithThreadLocal(ref t_currentTask); } else if (!IsCanceled) { int prevState = Interlocked.Exchange(ref m_stateFlags, m_stateFlags | TASK_STATE_CANCELED); if ((prevState & TASK_STATE_CANCELED) == 0) { CancellationCleanupLogic(); } } return true; } [SecurityCritical] private void ExecuteWithThreadLocal(ref Task currentTaskSlot) { Task previousTask = currentTaskSlot; var etwLog = TplEtwProvider.Log; Guid savedActivityID = new Guid(); bool etwIsEnabled = etwLog.IsEnabled(); if (etwIsEnabled) { if (etwLog.TasksSetActivityIds) EventSource.SetCurrentThreadActivityId(TplEtwProvider.CreateGuidForTaskID(this.Id), out savedActivityID); if (previousTask != null) etwLog.TaskStarted(previousTask.m_taskScheduler.Id, previousTask.Id, this.Id); else etwLog.TaskStarted(TaskScheduler.Current.Id, 0, this.Id); } if (AsyncCausalityTracer.LoggingOn) AsyncCausalityTracer.TraceSynchronousWorkStart(CausalityTraceLevel.Required, this.Id, CausalitySynchronousWork.Execution); try { currentTaskSlot = this; ExecutionContext ec = CapturedContext; if (ec == null) { Execute(); } else { if (IsSelfReplicatingRoot || IsChildReplica) { CapturedContext = CopyExecutionContext(ec); } var callback = s_ecCallback; if (callback == null) s_ecCallback = callback = new ContextCallback(ExecutionContextCallback); #if PFX_LEGACY_3_5 ExecutionContext.Run(ec, callback, this); #else ExecutionContext.Run(ec, callback, this, true); #endif } if (AsyncCausalityTracer.LoggingOn) AsyncCausalityTracer.TraceSynchronousWorkCompletion(CausalityTraceLevel.Required, CausalitySynchronousWork.Execution); Finish(true); } finally { currentTaskSlot = previousTask; if (etwIsEnabled) { if (previousTask != null) etwLog.TaskCompleted(previousTask.m_taskScheduler.Id, previousTask.Id, this.Id, IsFaulted); else etwLog.TaskCompleted(TaskScheduler.Current.Id, 0, this.Id, IsFaulted); if (etwLog.TasksSetActivityIds) EventSource.SetCurrentThreadActivityId(savedActivityID); } } } [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"); task.Execute(); } internal virtual void InnerInvoke() { Contract.Assert(m_action != null, "Null action in InnerInvoke()"); var action = m_action as Action; if (action != null) { action(); return; } var actionWithState = m_action as Action<object>; if (actionWithState != null) { actionWithState(m_stateObject); return; } Contract.Assert(false, "Invalid m_action in Task"); } [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] internal void InnerInvokeWithArg(Task childTask) { InnerInvoke(); } private void HandleException(Exception unhandledException) { Contract.Requires(unhandledException != null); OperationCanceledException exceptionAsOce = unhandledException as OperationCanceledException; if (exceptionAsOce != null && IsCancellationRequested && m_contingentProperties.m_cancellationToken == exceptionAsOce.CancellationToken) { SetCancellationAcknowledged(); AddException(exceptionAsOce, representsCancellation: true); } else { AddException(unhandledException); } } #region Await Support public TaskAwaiter GetAwaiter() { return new TaskAwaiter(this); } public ConfiguredTaskAwaitable ConfigureAwait(bool continueOnCapturedContext) { return new ConfiguredTaskAwaitable(this, continueOnCapturedContext); } [SecurityCritical] internal void SetContinuationForAwait( Action continuationAction, bool continueOnCapturedContext, bool flowExecutionContext, ref StackCrawlMark stackMark) { Contract.Requires(continuationAction != null); TaskContinuation tc = null; if (continueOnCapturedContext) { var syncCtx = SynchronizationContext.CurrentNoFlow; if (syncCtx != null && syncCtx.GetType() != typeof(SynchronizationContext)) { tc = new SynchronizationContextAwaitTaskContinuation(syncCtx, continuationAction, flowExecutionContext, ref stackMark); } else { var scheduler = TaskScheduler.InternalCurrent; if (scheduler != null && scheduler != TaskScheduler.Default) { tc = new TaskSchedulerAwaitTaskContinuation(scheduler, continuationAction, flowExecutionContext, ref stackMark); } } } if (tc == null && flowExecutionContext) { tc = new AwaitTaskContinuation(continuationAction, flowExecutionContext: true, stackMark: ref stackMark); } if (tc != null) { if (!AddTaskContinuation(tc, addBeforeOthers: false)) tc.Run(this, bCanInlineContinuationTask: false); } else { Contract.Assert(!flowExecutionContext, "We already determined we're not required to flow context."); if (!AddTaskContinuation(continuationAction, addBeforeOthers: false)) AwaitTaskContinuation.UnsafeScheduleAction(continuationAction, this); } } public static YieldAwaitable Yield() { return new YieldAwaitable(); } #endregion public void Wait() { #if DEBUG bool waitResult = #endif Wait(Timeout.Infinite, default(CancellationToken)); #if DEBUG Contract.Assert(waitResult, "expected wait to succeed"); #endif } public bool Wait(TimeSpan timeout) { long totalMilliseconds = (long)timeout.TotalMilliseconds; if (totalMilliseconds < -1 || totalMilliseconds > Int32.MaxValue) { throw new ArgumentOutOfRangeException("timeout"); } return Wait((int)totalMilliseconds, default(CancellationToken)); } public void Wait(CancellationToken cancellationToken) { Wait(Timeout.Infinite, cancellationToken); } public bool Wait(int millisecondsTimeout) { return Wait(millisecondsTimeout, default(CancellationToken)); } public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken) { if (millisecondsTimeout < -1) { throw new ArgumentOutOfRangeException("millisecondsTimeout"); } Contract.EndContractBlock(); if (!IsWaitNotificationEnabledOrNotRanToCompletion) return true; if (!InternalWait(millisecondsTimeout, cancellationToken)) return false; if (IsWaitNotificationEnabledOrNotRanToCompletion) { NotifyDebuggerOfWaitCompletionIfNecessary(); if (IsCanceled) cancellationToken.ThrowIfCancellationRequested(); ThrowIfExceptional(true); } Contract.Assert((m_stateFlags & TASK_STATE_FAULTED) == 0, "Task.Wait() completing when in Faulted state."); return true; } private bool WrappedTryRunInline() { if (m_taskScheduler == null) return false; try { return m_taskScheduler.TryRunInline(this, true); } catch (Exception e) { if (!(e is ThreadAbortException)) { TaskSchedulerException tse = new TaskSchedulerException(e); throw tse; } else { throw; } } } [MethodImpl(MethodImplOptions.NoOptimization)] internal bool InternalWait(int millisecondsTimeout, CancellationToken cancellationToken) { var etwLog = TplEtwProvider.Log; bool etwIsEnabled = etwLog.IsEnabled(); if (etwIsEnabled) { Task currentTask = Task.InternalCurrent; etwLog.TaskWaitBegin( (currentTask != null ? currentTask.m_taskScheduler.Id : TaskScheduler.Default.Id), (currentTask != null ? currentTask.Id : 0), this.Id, TplEtwProvider.TaskWaitBehavior.Synchronous, 0, System.Threading.Thread.GetDomainID()); } bool returnValue = IsCompleted; if (!returnValue) { Debugger.NotifyOfCrossThreadDependency(); if (millisecondsTimeout == Timeout.Infinite && !cancellationToken.CanBeCanceled && WrappedTryRunInline() && IsCompleted) { returnValue = true; } else { returnValue = SpinThenBlockingWait(millisecondsTimeout, cancellationToken); } } Contract.Assert(IsCompleted || millisecondsTimeout != Timeout.Infinite); if (etwIsEnabled) { Task currentTask = Task.InternalCurrent; if (currentTask != null) { etwLog.TaskWaitEnd(currentTask.m_taskScheduler.Id, currentTask.Id, this.Id); } else { etwLog.TaskWaitEnd(TaskScheduler.Default.Id, 0, this.Id); } etwLog.TaskWaitContinuationComplete(this.Id); } return returnValue; } private sealed class SetOnInvokeMres : ManualResetEventSlim, ITaskCompletionAction { internal SetOnInvokeMres() : base(false, 0) { } public void Invoke(Task completingTask) { Set(); } } private bool SpinThenBlockingWait(int millisecondsTimeout, CancellationToken cancellationToken) { bool infiniteWait = millisecondsTimeout == Timeout.Infinite; uint startTimeTicks = infiniteWait ? 0 : (uint)Environment.TickCount; bool returnValue = SpinWait(millisecondsTimeout); if (!returnValue) { var mres = new SetOnInvokeMres(); try { AddCompletionAction(mres, addBeforeOthers: true); if (infiniteWait) { returnValue = mres.Wait(Timeout.Infinite, cancellationToken); } else { uint elapsedTimeTicks = ((uint)Environment.TickCount) - startTimeTicks; if (elapsedTimeTicks < millisecondsTimeout) { returnValue = mres.Wait((int)(millisecondsTimeout - elapsedTimeTicks), cancellationToken); } } } finally { if (!IsCompleted) RemoveContinuation(mres); } } return returnValue; } private bool SpinWait(int millisecondsTimeout) { if (IsCompleted) return true; if (millisecondsTimeout == 0) { return false; } int spinCount = PlatformHelper.IsSingleProcessor ? 1 : System.Threading.SpinWait.YIELD_THRESHOLD; for (int i = 0; i < spinCount; i++) { if (IsCompleted) { return true; } if (i == spinCount / 2) { Thread.Yield(); } else { Thread.SpinWait(PlatformHelper.ProcessorCount * (4 << i)); } } return IsCompleted; } [SecuritySafeCritical] internal bool InternalCancel(bool bCancelNonExecutingOnly) { Contract.Requires((Options & (TaskCreationOptions)InternalTaskOptions.PromiseTask) == 0, "Task.InternalCancel() did not expect promise-style task"); bool bPopSucceeded = false; bool mustCleanup = false; TaskSchedulerException tse = null; if ((m_stateFlags & TASK_STATE_STARTED) != 0) { TaskScheduler ts = m_taskScheduler; try { bPopSucceeded = (ts != null) && ts.TryDequeue(this); } catch (Exception e) { if (!(e is ThreadAbortException)) { tse = new TaskSchedulerException(e); } } bool bRequiresAtomicStartTransition = (ts != null && ts.RequiresAtomicStartTransition) || ((Options & (TaskCreationOptions)InternalTaskOptions.SelfReplicating) != 0); if (!bPopSucceeded && bCancelNonExecutingOnly && bRequiresAtomicStartTransition) { mustCleanup = AtomicStateUpdate(TASK_STATE_CANCELED, TASK_STATE_DELEGATE_INVOKED | TASK_STATE_CANCELED); } } if (!bCancelNonExecutingOnly || bPopSucceeded || mustCleanup) { RecordInternalCancellationRequest(); if (bPopSucceeded) { Contract.Assert(!mustCleanup, "Possibly an invalid state transition call was made in InternalCancel()"); mustCleanup = AtomicStateUpdate(TASK_STATE_CANCELED, TASK_STATE_CANCELED | TASK_STATE_DELEGATE_INVOKED); } else if (!mustCleanup && (m_stateFlags & TASK_STATE_STARTED) == 0) { mustCleanup = AtomicStateUpdate(TASK_STATE_CANCELED, TASK_STATE_CANCELED | TASK_STATE_STARTED | TASK_STATE_RAN_TO_COMPLETION | TASK_STATE_FAULTED | TASK_STATE_DELEGATE_INVOKED); } if (mustCleanup) { CancellationCleanupLogic(); } } if (tse != null) throw tse; else return (mustCleanup); } internal void RecordInternalCancellationRequest() { var props = EnsureContingentPropertiesInitialized(needsProtection: true); props.m_internalCancellationRequested = CANCELLATION_REQUESTED; } internal void RecordInternalCancellationRequest(CancellationToken tokenToRecord) { 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)); if (tokenToRecord != default(CancellationToken)) { m_contingentProperties.m_cancellationToken = tokenToRecord; } } internal void RecordInternalCancellationRequest(CancellationToken tokenToRecord, object cancellationException) { RecordInternalCancellationRequest(tokenToRecord); if (cancellationException != null) { #if DEBUG var oce = cancellationException as OperationCanceledException; if (oce == null) { var edi = cancellationException as ExceptionDispatchInfo; Contract.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"); } Contract.Assert(oce.CancellationToken == tokenToRecord, "Expected OCE's token to match the provided token."); #endif AddException(cancellationException, representsCancellation: true); } } internal void CancellationCleanupLogic() { Contract.Assert((m_stateFlags & (TASK_STATE_CANCELED | TASK_STATE_COMPLETION_RESERVED)) != 0, "Task.CancellationCleanupLogic(): Task not canceled or reserved."); Interlocked.Exchange(ref m_stateFlags, m_stateFlags | TASK_STATE_CANCELED); var cp = m_contingentProperties; if (cp != null) { cp.SetCompleted(); cp.DeregisterCancellationCallback(); } if (AsyncCausalityTracer.LoggingOn) AsyncCausalityTracer.TraceOperationCompletion(CausalityTraceLevel.Required, this.Id, AsyncCausalityStatus.Canceled); if (Task.s_asyncDebuggingEnabled) { RemoveFromActiveTasks(this.Id); } FinishStageThree(); } 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"); m_stateFlags |= TASK_STATE_CANCELLATIONACKNOWLEDGED; } [SecuritySafeCritical] internal void FinishContinuations() { object continuationObject = Interlocked.Exchange(ref m_continuationObject, s_taskCompletionSentinel); TplEtwProvider.Log.RunningContinuation(Id, continuationObject); if (continuationObject != null) { if (AsyncCausalityTracer.LoggingOn) AsyncCausalityTracer.TraceSynchronousWorkStart(CausalityTraceLevel.Required, this.Id, CausalitySynchronousWork.CompletionNotification); bool bCanInlineContinuations = !(((m_stateFlags & TASK_STATE_THREAD_WAS_ABORTED) != 0) || (Thread.CurrentThread.ThreadState == ThreadState.AbortRequested) || ((m_stateFlags & (int)TaskCreationOptions.RunContinuationsAsynchronously) != 0)); Action singleAction = continuationObject as Action; if (singleAction != null) { AwaitTaskContinuation.RunOrScheduleAction(singleAction, bCanInlineContinuations, ref t_currentTask); LogFinishCompletionNotification(); return; } ITaskCompletionAction singleTaskCompletionAction = continuationObject as ITaskCompletionAction; if (singleTaskCompletionAction != null) { if (bCanInlineContinuations) { singleTaskCompletionAction.Invoke(this); } else { ThreadPool.UnsafeQueueCustomWorkItem(new CompletionActionInvoker(singleTaskCompletionAction, this), forceGlobal: false); } LogFinishCompletionNotification(); return; } TaskContinuation singleTaskContinuation = continuationObject as TaskContinuation; if (singleTaskContinuation != null) { singleTaskContinuation.Run(this, bCanInlineContinuations); LogFinishCompletionNotification(); return; } List<object> continuations = continuationObject as List<object>; if (continuations == null) { LogFinishCompletionNotification(); return; } lock (continuations) { } int continuationCount = continuations.Count; for (int i = 0; i < continuationCount; i++) { var tc = continuations[i] as StandardTaskContinuation; if (tc != null && (tc.m_options & TaskContinuationOptions.ExecuteSynchronously) == 0) { TplEtwProvider.Log.RunningContinuationList(Id, i, tc); continuations[i] = null; tc.Run(this, bCanInlineContinuations); } } for (int i = 0; i < continuationCount; i++) { object currentContinuation = continuations[i]; if (currentContinuation == null) continue; continuations[i] = null; TplEtwProvider.Log.RunningContinuationList(Id, i, currentContinuation); Action ad = currentContinuation as Action; if (ad != null) { AwaitTaskContinuation.RunOrScheduleAction(ad, bCanInlineContinuations, ref t_currentTask); } else { TaskContinuation tc = currentContinuation as TaskContinuation; if (tc != null) { tc.Run(this, bCanInlineContinuations); } else { Contract.Assert(currentContinuation is ITaskCompletionAction, "Expected continuation element to be Action, TaskContinuation, or ITaskContinuationAction"); var action = (ITaskCompletionAction)currentContinuation; if (bCanInlineContinuations) { action.Invoke(this); } else { ThreadPool.UnsafeQueueCustomWorkItem(new CompletionActionInvoker(action, this), forceGlobal: false); } } } } LogFinishCompletionNotification(); } } private void LogFinishCompletionNotification() { if (AsyncCausalityTracer.LoggingOn) AsyncCausalityTracer.TraceSynchronousWorkCompletion(CausalityTraceLevel.Required, CausalitySynchronousWork.CompletionNotification); } #region Continuation methods #region Action<Task> continuation [MethodImplAttribute(MethodImplOptions.NoInlining)] public Task ContinueWith(Action<Task> continuationAction) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith(continuationAction, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None, ref stackMark); } [MethodImplAttribute(MethodImplOptions.NoInlining)] public Task ContinueWith(Action<Task> continuationAction, CancellationToken cancellationToken) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith(continuationAction, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None, ref stackMark); } [MethodImplAttribute(MethodImplOptions.NoInlining)] public Task ContinueWith(Action<Task> continuationAction, TaskScheduler scheduler) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith(continuationAction, scheduler, default(CancellationToken), TaskContinuationOptions.None, ref stackMark); } [MethodImplAttribute(MethodImplOptions.NoInlining)] public Task ContinueWith(Action<Task> continuationAction, TaskContinuationOptions continuationOptions) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith(continuationAction, TaskScheduler.Current, default(CancellationToken), continuationOptions, ref stackMark); } [MethodImplAttribute(MethodImplOptions.NoInlining)] public Task ContinueWith(Action<Task> continuationAction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith(continuationAction, scheduler, cancellationToken, continuationOptions, ref stackMark); } private Task ContinueWith(Action<Task> continuationAction, TaskScheduler scheduler, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, ref StackCrawlMark stackMark) { if (continuationAction == null) { throw new ArgumentNullException("continuationAction"); } if (scheduler == null) { throw new ArgumentNullException("scheduler"); } Contract.EndContractBlock(); TaskCreationOptions creationOptions; InternalTaskOptions internalOptions; CreationOptionsFromContinuationOptions(continuationOptions, out creationOptions, out internalOptions); Task continuationTask = new ContinuationTaskFromTask( this, continuationAction, null, creationOptions, internalOptions, ref stackMark ); ContinueWithCore(continuationTask, scheduler, cancellationToken, continuationOptions); return continuationTask; } #endregion #region Action<Task, Object> continuation [MethodImplAttribute(MethodImplOptions.NoInlining)] public Task ContinueWith(Action<Task, Object> continuationAction, Object state) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith(continuationAction, state, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None, ref stackMark); } [MethodImplAttribute(MethodImplOptions.NoInlining)] public Task ContinueWith(Action<Task, Object> continuationAction, Object state, CancellationToken cancellationToken) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith(continuationAction, state, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None, ref stackMark); } [MethodImplAttribute(MethodImplOptions.NoInlining)] public Task ContinueWith(Action<Task, Object> continuationAction, Object state, TaskScheduler scheduler) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith(continuationAction, state, scheduler, default(CancellationToken), TaskContinuationOptions.None, ref stackMark); } [MethodImplAttribute(MethodImplOptions.NoInlining)] public Task ContinueWith(Action<Task, Object> continuationAction, Object state, TaskContinuationOptions continuationOptions) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith(continuationAction, state, TaskScheduler.Current, default(CancellationToken), continuationOptions, ref stackMark); } [MethodImplAttribute(MethodImplOptions.NoInlining)] public Task ContinueWith(Action<Task, Object> continuationAction, Object state, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith(continuationAction, state, scheduler, cancellationToken, continuationOptions, ref stackMark); } private Task ContinueWith(Action<Task, Object> continuationAction, Object state, TaskScheduler scheduler, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, ref StackCrawlMark stackMark) { if (continuationAction == null) { throw new ArgumentNullException("continuationAction"); } if (scheduler == null) { throw new ArgumentNullException("scheduler"); } Contract.EndContractBlock(); TaskCreationOptions creationOptions; InternalTaskOptions internalOptions; CreationOptionsFromContinuationOptions(continuationOptions, out creationOptions, out internalOptions); Task continuationTask = new ContinuationTaskFromTask( this, continuationAction, state, creationOptions, internalOptions, ref stackMark ); ContinueWithCore(continuationTask, scheduler, cancellationToken, continuationOptions); return continuationTask; } #endregion #region Func<Task, TResult> continuation [MethodImplAttribute(MethodImplOptions.NoInlining)] public Task<TResult> ContinueWith<TResult>(Func<Task, TResult> continuationFunction) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith<TResult>(continuationFunction, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None, ref stackMark); } [MethodImplAttribute(MethodImplOptions.NoInlining)] public Task<TResult> ContinueWith<TResult>(Func<Task, TResult> continuationFunction, CancellationToken cancellationToken) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith<TResult>(continuationFunction, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None, ref stackMark); } [MethodImplAttribute(MethodImplOptions.NoInlining)] public Task<TResult> ContinueWith<TResult>(Func<Task, TResult> continuationFunction, TaskScheduler scheduler) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith<TResult>(continuationFunction, scheduler, default(CancellationToken), TaskContinuationOptions.None, ref stackMark); } [MethodImplAttribute(MethodImplOptions.NoInlining)] public Task<TResult> ContinueWith<TResult>(Func<Task, TResult> continuationFunction, TaskContinuationOptions continuationOptions) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith<TResult>(continuationFunction, TaskScheduler.Current, default(CancellationToken), continuationOptions, ref stackMark); } [MethodImplAttribute(MethodImplOptions.NoInlining)] public Task<TResult> ContinueWith<TResult>(Func<Task, TResult> continuationFunction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith<TResult>(continuationFunction, scheduler, cancellationToken, continuationOptions, ref stackMark); } private Task<TResult> ContinueWith<TResult>(Func<Task, TResult> continuationFunction, TaskScheduler scheduler, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, ref StackCrawlMark stackMark) { if (continuationFunction == null) { throw new ArgumentNullException("continuationFunction"); } if (scheduler == null) { throw new ArgumentNullException("scheduler"); } Contract.EndContractBlock(); TaskCreationOptions creationOptions; InternalTaskOptions internalOptions; CreationOptionsFromContinuationOptions(continuationOptions, out creationOptions, out internalOptions); Task<TResult> continuationTask = new ContinuationResultTaskFromTask<TResult>( this, continuationFunction, null, creationOptions, internalOptions, ref stackMark ); ContinueWithCore(continuationTask, scheduler, cancellationToken, continuationOptions); return continuationTask; } #endregion #region Func<Task, Object, TResult> continuation [MethodImplAttribute(MethodImplOptions.NoInlining)] public Task<TResult> ContinueWith<TResult>(Func<Task, Object, TResult> continuationFunction, Object state) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith<TResult>(continuationFunction, state, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None, ref stackMark); } [MethodImplAttribute(MethodImplOptions.NoInlining)] public Task<TResult> ContinueWith<TResult>(Func<Task, Object, TResult> continuationFunction, Object state, CancellationToken cancellationToken) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith<TResult>(continuationFunction, state, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None, ref stackMark); } [MethodImplAttribute(MethodImplOptions.NoInlining)] public Task<TResult> ContinueWith<TResult>(Func<Task, Object, TResult> continuationFunction, Object state, TaskScheduler scheduler) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith<TResult>(continuationFunction, state, scheduler, default(CancellationToken), TaskContinuationOptions.None, ref stackMark); } [MethodImplAttribute(MethodImplOptions.NoInlining)] public Task<TResult> ContinueWith<TResult>(Func<Task, Object, TResult> continuationFunction, Object state, TaskContinuationOptions continuationOptions) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith<TResult>(continuationFunction, state, TaskScheduler.Current, default(CancellationToken), continuationOptions, ref stackMark); } [MethodImplAttribute(MethodImplOptions.NoInlining)] public Task<TResult> ContinueWith<TResult>(Func<Task, Object, TResult> continuationFunction, Object state, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith<TResult>(continuationFunction, state, scheduler, cancellationToken, continuationOptions, ref stackMark); } private Task<TResult> ContinueWith<TResult>(Func<Task, Object, TResult> continuationFunction, Object state, TaskScheduler scheduler, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, ref StackCrawlMark stackMark) { if (continuationFunction == null) { throw new ArgumentNullException("continuationFunction"); } if (scheduler == null) { throw new ArgumentNullException("scheduler"); } Contract.EndContractBlock(); TaskCreationOptions creationOptions; InternalTaskOptions internalOptions; CreationOptionsFromContinuationOptions(continuationOptions, out creationOptions, out internalOptions); Task<TResult> continuationTask = new ContinuationResultTaskFromTask<TResult>( this, continuationFunction, state, creationOptions, internalOptions, ref stackMark ); ContinueWithCore(continuationTask, scheduler, cancellationToken, continuationOptions); return continuationTask; } #endregion internal static void CreationOptionsFromContinuationOptions( TaskContinuationOptions continuationOptions, out TaskCreationOptions creationOptions, out InternalTaskOptions internalOptions) { TaskContinuationOptions NotOnAnything = TaskContinuationOptions.NotOnCanceled | TaskContinuationOptions.NotOnFaulted | TaskContinuationOptions.NotOnRanToCompletion; TaskContinuationOptions creationOptionsMask = TaskContinuationOptions.PreferFairness | TaskContinuationOptions.LongRunning | TaskContinuationOptions.DenyChildAttach | TaskContinuationOptions.HideScheduler | TaskContinuationOptions.AttachedToParent| TaskContinuationOptions.RunContinuationsAsynchronously; TaskContinuationOptions illegalMask = TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.LongRunning; if ((continuationOptions & illegalMask) == illegalMask) { throw new ArgumentOutOfRangeException("continuationOptions", Environment.GetResourceString("Task_ContinueWith_ESandLR")); } if ((continuationOptions & ~(creationOptionsMask | NotOnAnything | TaskContinuationOptions.LazyCancellation | TaskContinuationOptions.ExecuteSynchronously)) != 0) { throw new ArgumentOutOfRangeException("continuationOptions"); } if ((continuationOptions & NotOnAnything) == NotOnAnything) { throw new ArgumentOutOfRangeException("continuationOptions", Environment.GetResourceString("Task_ContinueWith_NotOnAnything")); } creationOptions = (TaskCreationOptions)(continuationOptions & creationOptionsMask); internalOptions = InternalTaskOptions.ContinuationTask; if ((continuationOptions & TaskContinuationOptions.LazyCancellation) != 0) internalOptions |= InternalTaskOptions.LazyCancellation; } internal void ContinueWithCore(Task continuationTask, TaskScheduler scheduler, CancellationToken cancellationToken, TaskContinuationOptions options) { Contract.Requires(continuationTask != null, "Task.ContinueWithCore(): null continuationTask"); Contract.Requires(scheduler != null, "Task.ContinueWithCore(): null scheduler"); Contract.Requires(!continuationTask.IsCompleted, "Did not expect continuationTask to be completed"); TaskContinuation continuation = new StandardTaskContinuation(continuationTask, options, scheduler); if (cancellationToken.CanBeCanceled) { if (IsCompleted || cancellationToken.IsCancellationRequested) { continuationTask.AssignCancellationToken(cancellationToken, null, null); } else { continuationTask.AssignCancellationToken(cancellationToken, this, continuation); } } if (!continuationTask.IsCompleted) { if ((this.Options & (TaskCreationOptions)InternalTaskOptions.PromiseTask) != 0 && !(this is ITaskCompletionAction)) { var etwLog = TplEtwProvider.Log; if (etwLog.IsEnabled()) { etwLog.AwaitTaskContinuationScheduled(TaskScheduler.Current.Id, Task.CurrentId ?? 0, continuationTask.Id); } } bool continuationQueued = AddTaskContinuation(continuation, addBeforeOthers: false); if (!continuationQueued) continuation.Run(this, bCanInlineContinuationTask: true); } } #endregion internal void AddCompletionAction(ITaskCompletionAction action) { AddCompletionAction(action, addBeforeOthers: false); } private void AddCompletionAction(ITaskCompletionAction action, bool addBeforeOthers) { if (!AddTaskContinuation(action, addBeforeOthers)) action.Invoke(this); } private bool AddTaskContinuationComplex(object tc, bool addBeforeOthers) { Contract.Requires(tc != null, "Expected non-null tc object in AddTaskContinuationComplex"); object oldValue = m_continuationObject; if ((oldValue != s_taskCompletionSentinel) && (!(oldValue is List<object>))) { List<object> newList = new List<object>(); newList.Add(oldValue); Interlocked.CompareExchange(ref m_continuationObject, newList, oldValue); } List<object> list = m_continuationObject as List<object>; Contract.Assert((list != null) || (m_continuationObject == s_taskCompletionSentinel), "Expected m_continuationObject to be list or sentinel"); if (list != null) { lock (list) { if (m_continuationObject != s_taskCompletionSentinel) { if (list.Count == list.Capacity) { list.RemoveAll(s_IsTaskContinuationNullPredicate); } if (addBeforeOthers) list.Insert(0, tc); else list.Add(tc); return true; } } } return false; } private bool AddTaskContinuation(object tc, bool addBeforeOthers) { Contract.Requires(tc != null); if (IsCompleted) return false; if ((m_continuationObject != null) || (Interlocked.CompareExchange(ref m_continuationObject, tc, null) != null)) { return AddTaskContinuationComplex(tc, addBeforeOthers); } else return true; } internal void RemoveContinuation(object continuationObject) { object continuationsLocalRef = m_continuationObject; if (continuationsLocalRef == s_taskCompletionSentinel) return; List<object> continuationsLocalListRef = continuationsLocalRef as List<object>; if (continuationsLocalListRef == null) { if (Interlocked.CompareExchange(ref m_continuationObject, new List<object>(), continuationObject) != continuationObject) { continuationsLocalListRef = m_continuationObject as List<object>; } else { return; } } if (continuationsLocalListRef != null) { lock (continuationsLocalListRef) { if (m_continuationObject == s_taskCompletionSentinel) return; int index = continuationsLocalListRef.IndexOf(continuationObject); if (index != -1) { continuationsLocalListRef[index] = null; } } } } private readonly static Predicate<object> s_IsTaskContinuationNullPredicate = new Predicate<object>((tc) => { return (tc == null); }); [MethodImpl(MethodImplOptions.NoOptimization)] public static void WaitAll(params Task[] tasks) { #if DEBUG bool waitResult = #endif WaitAll(tasks, Timeout.Infinite); #if DEBUG Contract.Assert(waitResult, "expected wait to succeed"); #endif } [MethodImpl(MethodImplOptions.NoOptimization)] public static bool WaitAll(Task[] tasks, TimeSpan timeout) { long totalMilliseconds = (long)timeout.TotalMilliseconds; if (totalMilliseconds < -1 || totalMilliseconds > Int32.MaxValue) { throw new ArgumentOutOfRangeException("timeout"); } return WaitAll(tasks, (int)totalMilliseconds); } [MethodImpl(MethodImplOptions.NoOptimization)] public static bool WaitAll(Task[] tasks, int millisecondsTimeout) { return WaitAll(tasks, millisecondsTimeout, default(CancellationToken)); } [MethodImpl(MethodImplOptions.NoOptimization)] public static void WaitAll(Task[] tasks, CancellationToken cancellationToken) { WaitAll(tasks, Timeout.Infinite, cancellationToken); } [MethodImpl(MethodImplOptions.NoOptimization)] public static bool WaitAll(Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken) { if (tasks == null) { throw new ArgumentNullException("tasks"); } if (millisecondsTimeout < -1) { throw new ArgumentOutOfRangeException("millisecondsTimeout"); } Contract.EndContractBlock(); cancellationToken.ThrowIfCancellationRequested(); List<Exception> exceptions = null; List<Task> waitedOnTaskList = null; List<Task> notificationTasks = null; bool exceptionSeen = false, cancellationSeen = false; bool returnValue = true; for (int i = tasks.Length - 1; i >= 0; i--) { Task task = tasks[i]; if (task == null) { throw new ArgumentException(Environment.GetResourceString("Task_WaitMulti_NullTask"), "tasks"); } bool taskIsCompleted = task.IsCompleted; if (!taskIsCompleted) { if (millisecondsTimeout != Timeout.Infinite || cancellationToken.CanBeCanceled) { AddToList(task, ref waitedOnTaskList, initSize: tasks.Length); } else { taskIsCompleted = task.WrappedTryRunInline() && task.IsCompleted; if (!taskIsCompleted) AddToList(task, ref waitedOnTaskList, initSize: tasks.Length); } } if (taskIsCompleted) { if (task.IsFaulted) exceptionSeen = true; else if (task.IsCanceled) cancellationSeen = true; if (task.IsWaitNotificationEnabled) AddToList(task, ref notificationTasks, initSize: 1); } } if (waitedOnTaskList != null) { returnValue = WaitAllBlockingCore(waitedOnTaskList, millisecondsTimeout, cancellationToken); if (returnValue) { foreach (var task in waitedOnTaskList) { if (task.IsFaulted) exceptionSeen = true; else if (task.IsCanceled) cancellationSeen = true; if (task.IsWaitNotificationEnabled) AddToList(task, ref notificationTasks, initSize: 1); } } GC.KeepAlive(tasks); } if (returnValue && notificationTasks != null) { foreach (var task in notificationTasks) { if (task.NotifyDebuggerOfWaitCompletionIfNecessary()) break; } } if (returnValue && (exceptionSeen || cancellationSeen)) { if (!exceptionSeen) cancellationToken.ThrowIfCancellationRequested(); foreach (var task in tasks) AddExceptionsForCompletedTask(ref exceptions, task); Contract.Assert(exceptions != null, "Should have seen at least one exception"); throw new AggregateException(exceptions); } return returnValue; } private static void AddToList<T>(T item, ref List<T> list, int initSize) { if (list == null) list = new List<T>(initSize); list.Add(item); } 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"); bool waitCompleted = false; var mres = new SetOnCountdownMres(tasks.Count); try { foreach (var task in tasks) { task.AddCompletionAction(mres, addBeforeOthers: true); } waitCompleted = mres.Wait(millisecondsTimeout, cancellationToken); } finally { if (!waitCompleted) { foreach (var task in tasks) { if (!task.IsCompleted) task.RemoveContinuation(mres); } } } return waitCompleted; }
private sealed class SetOnCountdownMres : ManualResetEventSlim, ITaskCompletionAction { private int _count; internal SetOnCountdownMres(int count) { Contract.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"); } } internal static void FastWaitAll(Task[] tasks) { Contract.Requires(tasks != null); List<Exception> exceptions = null; for (int i = tasks.Length - 1; i >= 0; i--) { if (!tasks[i].IsCompleted) { tasks[i].WrappedTryRunInline(); } } for (int i = tasks.Length - 1; i >= 0; i--) { var task = tasks[i]; task.SpinThenBlockingWait(Timeout.Infinite, default(CancellationToken)); AddExceptionsForCompletedTask(ref exceptions, task); } if (exceptions != null) { throw new AggregateException(exceptions); } } internal static void AddExceptionsForCompletedTask(ref List<Exception> exceptions, Task t) { AggregateException ex = t.GetExceptions(true); if (ex != null) { t.UpdateExceptionObservedStatus(); if (exceptions == null) { exceptions = new List<Exception>(ex.InnerExceptions.Count); } exceptions.AddRange(ex.InnerExceptions); } } [MethodImpl(MethodImplOptions.NoOptimization)] public static int WaitAny(params Task[] tasks) { int waitResult = WaitAny(tasks, Timeout.Infinite); Contract.Assert(tasks.Length == 0 || waitResult != -1, "expected wait to succeed"); return waitResult; } [MethodImpl(MethodImplOptions.NoOptimization)] public static int WaitAny(Task[] tasks, TimeSpan timeout) { long totalMilliseconds = (long)timeout.TotalMilliseconds; if (totalMilliseconds < -1 || totalMilliseconds > Int32.MaxValue) { throw new ArgumentOutOfRangeException("timeout"); } return WaitAny(tasks, (int)totalMilliseconds); } [MethodImpl(MethodImplOptions.NoOptimization)] public static int WaitAny(Task[] tasks, CancellationToken cancellationToken) { return WaitAny(tasks, Timeout.Infinite, cancellationToken); } [MethodImpl(MethodImplOptions.NoOptimization)] public static int WaitAny(Task[] tasks, int millisecondsTimeout) { return WaitAny(tasks, millisecondsTimeout, default(CancellationToken)); } [MethodImpl(MethodImplOptions.NoOptimization)] public static int WaitAny(Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken) { if (tasks == null) { throw new ArgumentNullException("tasks"); } if (millisecondsTimeout < -1) { throw new ArgumentOutOfRangeException("millisecondsTimeout"); } Contract.EndContractBlock(); cancellationToken.ThrowIfCancellationRequested(); int signaledTaskIndex = -1; for (int taskIndex = 0; taskIndex < tasks.Length; taskIndex++) { Task task = tasks[taskIndex]; if (task == null) { throw new ArgumentException(Environment.GetResourceString("Task_WaitMulti_NullTask"), "tasks"); } if (signaledTaskIndex == -1 && task.IsCompleted) { signaledTaskIndex = taskIndex; } } if (signaledTaskIndex == -1 && tasks.Length != 0) { Task<Task> firstCompleted = TaskFactory.CommonCWAnyLogic(tasks); bool waitCompleted = firstCompleted.Wait(millisecondsTimeout, cancellationToken); if (waitCompleted) { Contract.Assert(firstCompleted.Status == TaskStatus.RanToCompletion); signaledTaskIndex = Array.IndexOf(tasks, firstCompleted.Result); Contract.Assert(signaledTaskIndex >= 0); } } GC.KeepAlive(tasks); return signaledTaskIndex; } #region FromResult / FromException / FromCancellation public static Task<TResult> FromResult<TResult>(TResult result) { return new Task<TResult>(result); } public static Task FromException(Exception exception) { return FromException<VoidTaskResult>(exception); } public static Task<TResult> FromException<TResult>(Exception exception) { if (exception == null) throw new ArgumentNullException("exception"); Contract.EndContractBlock(); var task = new Task<TResult>(); bool succeeded = task.TrySetException(exception); Contract.Assert(succeeded, "This should always succeed on a new task."); return task; } [FriendAccessAllowed] internal static Task FromCancellation(CancellationToken cancellationToken) { if (!cancellationToken.IsCancellationRequested) throw new ArgumentOutOfRangeException("cancellationToken"); Contract.EndContractBlock(); return new Task(true, TaskCreationOptions.None, cancellationToken); } public static Task FromCanceled(CancellationToken cancellationToken) { return FromCancellation(cancellationToken); } [FriendAccessAllowed] internal static Task<TResult> FromCancellation<TResult>(CancellationToken cancellationToken) { if (!cancellationToken.IsCancellationRequested) throw new ArgumentOutOfRangeException("cancellationToken"); Contract.EndContractBlock(); return new Task<TResult>(true, default(TResult), TaskCreationOptions.None, cancellationToken); } public static Task<TResult> FromCanceled<TResult>(CancellationToken cancellationToken) { return FromCancellation<TResult>(cancellationToken); } internal static Task<TResult> FromCancellation<TResult>(OperationCanceledException exception) { if (exception == null) throw new ArgumentNullException("exception"); Contract.EndContractBlock(); var task = new Task<TResult>(); bool succeeded = task.TrySetCanceled(exception.CancellationToken, exception); Contract.Assert(succeeded, "This should always succeed on a new task."); return task; } #endregion

#region Run methods [MethodImplAttribute(MethodImplOptions.NoInlining)] public static Task Run(Action action) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return Task.InternalStartNew(null, action, null, default(CancellationToken), TaskScheduler.Default, TaskCreationOptions.DenyChildAttach, InternalTaskOptions.None, ref stackMark); } [MethodImplAttribute(MethodImplOptions.NoInlining)] public static Task Run(Action action, CancellationToken cancellationToken) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return Task.InternalStartNew(null, action, null, cancellationToken, TaskScheduler.Default, TaskCreationOptions.DenyChildAttach, InternalTaskOptions.None, ref stackMark); } [MethodImplAttribute(MethodImplOptions.NoInlining)] public static Task<TResult> Run<TResult>(Func<TResult> function) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return Task<TResult>.StartNew(null, function, default(CancellationToken), TaskCreationOptions.DenyChildAttach, InternalTaskOptions.None, TaskScheduler.Default, ref stackMark); } [MethodImplAttribute(MethodImplOptions.NoInlining)] public static Task<TResult> Run<TResult>(Func<TResult> function, CancellationToken cancellationToken) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return Task<TResult>.StartNew(null, function, cancellationToken, TaskCreationOptions.DenyChildAttach, InternalTaskOptions.None, TaskScheduler.Default, ref stackMark); } public static Task Run(Func<Task> function) { return Run(function, default(CancellationToken)); } public static Task Run(Func<Task> function, CancellationToken cancellationToken) { if (function == null) throw new ArgumentNullException("function"); Contract.EndContractBlock(); if (AppContextSwitches.ThrowExceptionIfDisposedCancellationTokenSource) { cancellationToken.ThrowIfSourceDisposed(); } if (cancellationToken.IsCancellationRequested) return Task.FromCancellation(cancellationToken); Task<Task> task1 = Task<Task>.Factory.StartNew(function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); UnwrapPromise<VoidTaskResult> promise = new UnwrapPromise<VoidTaskResult>(task1, lookForOce: true); return promise; } public static Task<TResult> Run<TResult>(Func<Task<TResult>> function) { return Run(function, default(CancellationToken)); } public static Task<TResult> Run<TResult>(Func<Task<TResult>> function, CancellationToken cancellationToken) { if (function == null) throw new ArgumentNullException("function"); Contract.EndContractBlock(); if (AppContextSwitches.ThrowExceptionIfDisposedCancellationTokenSource) { cancellationToken.ThrowIfSourceDisposed(); } if (cancellationToken.IsCancellationRequested) return Task.FromCancellation<TResult>(cancellationToken); Task<Task<TResult>> task1 = Task<Task<TResult>>.Factory.StartNew(function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); UnwrapPromise<TResult> promise = new UnwrapPromise<TResult>(task1, lookForOce: true); return promise; } #endregion #region Delay methods public static Task Delay(TimeSpan delay) { return Delay(delay, default(CancellationToken)); } public static Task Delay(TimeSpan delay, CancellationToken cancellationToken) { long totalMilliseconds = (long)delay.TotalMilliseconds; if (totalMilliseconds < -1 || totalMilliseconds > Int32.MaxValue) { throw new ArgumentOutOfRangeException("delay", Environment.GetResourceString("Task_Delay_InvalidDelay")); } return Delay((int)totalMilliseconds, cancellationToken); } public static Task Delay(int millisecondsDelay) { return Delay(millisecondsDelay, default(CancellationToken)); } public static Task Delay(int millisecondsDelay, CancellationToken cancellationToken) { if (millisecondsDelay < -1) { throw new ArgumentOutOfRangeException("millisecondsDelay", Environment.GetResourceString("Task_Delay_InvalidMillisecondsDelay")); } Contract.EndContractBlock(); if (cancellationToken.IsCancellationRequested) { return Task.FromCancellation(cancellationToken); } else if (millisecondsDelay == 0) { return Task.CompletedTask; } var promise = new DelayPromise(cancellationToken); if (cancellationToken.CanBeCanceled) { promise.Registration = cancellationToken.InternalRegisterWithoutEC(state => ((DelayPromise)state).Complete(), promise); } if (millisecondsDelay != Timeout.Infinite) { promise.Timer = new Timer(state => ((DelayPromise)state).Complete(), promise, millisecondsDelay, Timeout.Infinite); promise.Timer.KeepRootedWhileScheduled(); } return promise; } private sealed class DelayPromise : Task<VoidTaskResult> { internal DelayPromise(CancellationToken token) : base() { this.Token = token; if (AsyncCausalityTracer.LoggingOn) AsyncCausalityTracer.TraceOperationCreation(CausalityTraceLevel.Required, this.Id, "Task.Delay", 0); if (Task.s_asyncDebuggingEnabled) { AddToActiveTasks(this); } } internal readonly CancellationToken Token; internal CancellationTokenRegistration Registration; internal Timer Timer; internal void Complete() { bool setSucceeded; if (Token.IsCancellationRequested) { setSucceeded = TrySetCanceled(Token); } else { if (AsyncCausalityTracer.LoggingOn) AsyncCausalityTracer.TraceOperationCompletion(CausalityTraceLevel.Required, this.Id, AsyncCausalityStatus.Completed); if (Task.s_asyncDebuggingEnabled) { RemoveFromActiveTasks(this.Id); } setSucceeded = TrySetResult(default(VoidTaskResult)); } if (setSucceeded) { if (Timer != null) Timer.Dispose(); Registration.Dispose(); } } } #endregion #region WhenAll public static Task WhenAll(IEnumerable<Task> tasks) { Task[] taskArray = tasks as Task[]; if (taskArray != null) { return WhenAll(taskArray); } ICollection<Task> taskCollection = tasks as ICollection<Task>; if (taskCollection != null) { int index = 0; taskArray = new Task[taskCollection.Count]; foreach (var task in tasks) { if (task == null) throw new ArgumentException(Environment.GetResourceString("Task_MultiTaskContinuation_NullTask"), "tasks"); taskArray[index++] = task; } return InternalWhenAll(taskArray); } if (tasks == null) throw new ArgumentNullException("tasks"); List<Task> taskList = new List<Task>(); foreach (Task task in tasks) { if (task == null) throw new ArgumentException(Environment.GetResourceString("Task_MultiTaskContinuation_NullTask"), "tasks"); taskList.Add(task); } return InternalWhenAll(taskList.ToArray()); } public static Task WhenAll(params Task[] tasks) { if (tasks == null) throw new ArgumentNullException("tasks"); Contract.EndContractBlock(); int taskCount = tasks.Length; if (taskCount == 0) return InternalWhenAll(tasks); Task[] tasksCopy = new Task[taskCount]; for (int i = 0; i < taskCount; i++) { Task task = tasks[i]; if (task == null) throw new ArgumentException(Environment.GetResourceString("Task_MultiTaskContinuation_NullTask"), "tasks"); tasksCopy[i] = task; } return InternalWhenAll(tasksCopy); } private static Task InternalWhenAll(Task[] tasks) { Contract.Requires(tasks != null, "Expected a non-null tasks array"); return (tasks.Length == 0) ? Task.CompletedTask : new WhenAllPromise(tasks); } private sealed class WhenAllPromise : Task<VoidTaskResult>, ITaskCompletionAction { private readonly Task[] m_tasks; private int m_count; internal WhenAllPromise(Task[] tasks) : base() { Contract.Requires(tasks != null, "Expected a non-null task array"); Contract.Requires(tasks.Length > 0, "Expected a non-zero length task array"); if (AsyncCausalityTracer.LoggingOn) AsyncCausalityTracer.TraceOperationCreation(CausalityTraceLevel.Required, this.Id, "Task.WhenAll", 0); if (s_asyncDebuggingEnabled) { AddToActiveTasks(this); } m_tasks = tasks; m_count = tasks.Length; foreach (var task in tasks) { if (task.IsCompleted) this.Invoke(task); else task.AddCompletionAction(this); } } public void Invoke(Task completedTask) { if (AsyncCausalityTracer.LoggingOn) AsyncCausalityTracer.TraceOperationRelation(CausalityTraceLevel.Important, this.Id, CausalityRelation.Join); if (Interlocked.Decrement(ref m_count) == 0) { List<ExceptionDispatchInfo> observedExceptions = null; Task canceledTask = null; 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"); if (task.IsFaulted) { if (observedExceptions == null) observedExceptions = new List<ExceptionDispatchInfo>(); observedExceptions.AddRange(task.GetExceptionDispatchInfos()); } else if (task.IsCanceled) { if (canceledTask == null) canceledTask = task; // use the first task that's canceled } if (task.IsWaitNotificationEnabled) this.SetNotificationForWaitCompletion(enabled: true); else m_tasks[i] = null; } if (observedExceptions != null) { Contract.Assert(observedExceptions.Count > 0, "Expected at least one exception"); TrySetException(observedExceptions); } else if (canceledTask != null) { TrySetCanceled(canceledTask.CancellationToken, canceledTask.GetCancellationExceptionDispatchInfo()); } else { if (AsyncCausalityTracer.LoggingOn) AsyncCausalityTracer.TraceOperationCompletion(CausalityTraceLevel.Required, this.Id, AsyncCausalityStatus.Completed); if (Task.s_asyncDebuggingEnabled) { RemoveFromActiveTasks(this.Id); } TrySetResult(default(VoidTaskResult)); } } Contract.Assert(m_count >= 0, "Count should never go below 0"); } internal override bool ShouldNotifyDebuggerOfWaitCompletion { get { return base.ShouldNotifyDebuggerOfWaitCompletion && Task.AnyTaskRequiresNotifyDebuggerOfWaitCompletion(m_tasks); } } } public static Task<TResult[]> WhenAll<TResult>(IEnumerable<Task<TResult>> tasks) { Task<TResult>[] taskArray = tasks as Task<TResult>[]; if (taskArray != null) { return WhenAll<TResult>(taskArray); } ICollection<Task<TResult>> taskCollection = tasks as ICollection<Task<TResult>>; if (taskCollection != null) { int index = 0; taskArray = new Task<TResult>[taskCollection.Count]; foreach (var task in tasks) { if (task == null) throw new ArgumentException(Environment.GetResourceString("Task_MultiTaskContinuation_NullTask"), "tasks"); taskArray[index++] = task; } return InternalWhenAll<TResult>(taskArray); } if (tasks == null) throw new ArgumentNullException("tasks"); List<Task<TResult>> taskList = new List<Task<TResult>>(); foreach (Task<TResult> task in tasks) { if (task == null) throw new ArgumentException(Environment.GetResourceString("Task_MultiTaskContinuation_NullTask"), "tasks"); taskList.Add(task); } return InternalWhenAll<TResult>(taskList.ToArray()); } public static Task<TResult[]> WhenAll<TResult>(params Task<TResult>[] tasks) { if (tasks == null) throw new ArgumentNullException("tasks"); Contract.EndContractBlock(); int taskCount = tasks.Length; if (taskCount == 0) return InternalWhenAll<TResult>(tasks); // small optimization in the case of an empty task array Task<TResult>[] tasksCopy = new Task<TResult>[taskCount]; for (int i = 0; i < taskCount; i++) { Task<TResult> task = tasks[i]; if (task == null) throw new ArgumentException(Environment.GetResourceString("Task_MultiTaskContinuation_NullTask"), "tasks"); tasksCopy[i] = task; } return InternalWhenAll<TResult>(tasksCopy); } private static Task<TResult[]> InternalWhenAll<TResult>(Task<TResult>[] tasks) { Contract.Requires(tasks != null, "Expected a non-null tasks array"); return (tasks.Length == 0) ? // take shortcut if there are no tasks upon which to wait new Task<TResult[]>(false, new TResult[0], TaskCreationOptions.None, default(CancellationToken)) : new WhenAllPromise<TResult>(tasks); } private sealed class WhenAllPromise<T> : Task<T[]>, ITaskCompletionAction { private readonly Task<T>[] m_tasks; private int m_count; internal WhenAllPromise(Task<T>[] tasks) : base() { Contract.Requires(tasks != null, "Expected a non-null task array"); Contract.Requires(tasks.Length > 0, "Expected a non-zero length task array"); m_tasks = tasks; m_count = tasks.Length; if (AsyncCausalityTracer.LoggingOn) AsyncCausalityTracer.TraceOperationCreation(CausalityTraceLevel.Required, this.Id, "Task.WhenAll", 0); if (s_asyncDebuggingEnabled) { AddToActiveTasks(this); } foreach (var task in tasks) { if (task.IsCompleted) this.Invoke(task); else task.AddCompletionAction(this); } } public void Invoke(Task ignored) { if (AsyncCausalityTracer.LoggingOn) AsyncCausalityTracer.TraceOperationRelation(CausalityTraceLevel.Important, this.Id, CausalityRelation.Join); if (Interlocked.Decrement(ref m_count) == 0) { T[] results = new T[m_tasks.Length]; List<ExceptionDispatchInfo> observedExceptions = null; Task canceledTask = null; 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"); if (task.IsFaulted) { if (observedExceptions == null) observedExceptions = new List<ExceptionDispatchInfo>(); observedExceptions.AddRange(task.GetExceptionDispatchInfos()); } else if (task.IsCanceled) { if (canceledTask == null) canceledTask = task; } else { Contract.Assert(task.Status == TaskStatus.RanToCompletion); results[i] = task.GetResultCore(waitCompletionNotification: false); } if (task.IsWaitNotificationEnabled) this.SetNotificationForWaitCompletion(enabled: true); else m_tasks[i] = null; } if (observedExceptions != null) { Contract.Assert(observedExceptions.Count > 0, "Expected at least one exception"); TrySetException(observedExceptions); } else if (canceledTask != null) { TrySetCanceled(canceledTask.CancellationToken, canceledTask.GetCancellationExceptionDispatchInfo()); } else { if (AsyncCausalityTracer.LoggingOn) AsyncCausalityTracer.TraceOperationCompletion(CausalityTraceLevel.Required, this.Id, AsyncCausalityStatus.Completed); if (Task.s_asyncDebuggingEnabled) { RemoveFromActiveTasks(this.Id); } TrySetResult(results); } } Contract.Assert(m_count >= 0, "Count should never go below 0"); } internal override bool ShouldNotifyDebuggerOfWaitCompletion { get { return base.ShouldNotifyDebuggerOfWaitCompletion && Task.AnyTaskRequiresNotifyDebuggerOfWaitCompletion(m_tasks); } } } #endregion #region WhenAny public static Task<Task> WhenAny(params Task[] tasks) { if (tasks == null) throw new ArgumentNullException("tasks"); if (tasks.Length == 0) { throw new ArgumentException(Environment.GetResourceString("Task_MultiTaskContinuation_EmptyTaskList"), "tasks"); } Contract.EndContractBlock(); int taskCount = tasks.Length; Task[] tasksCopy = new Task[taskCount]; for (int i = 0; i < taskCount; i++) { Task task = tasks[i]; if (task == null) throw new ArgumentException(Environment.GetResourceString("Task_MultiTaskContinuation_NullTask"), "tasks"); tasksCopy[i] = task; } return TaskFactory.CommonCWAnyLogic(tasksCopy); } public static Task<Task> WhenAny(IEnumerable<Task> tasks) { if (tasks == null) throw new ArgumentNullException("tasks"); Contract.EndContractBlock(); List<Task> taskList = new List<Task>(); foreach (Task task in tasks) { if (task == null) throw new ArgumentException(Environment.GetResourceString("Task_MultiTaskContinuation_NullTask"), "tasks"); taskList.Add(task); } if (taskList.Count == 0) { throw new ArgumentException(Environment.GetResourceString("Task_MultiTaskContinuation_EmptyTaskList"), "tasks"); } return TaskFactory.CommonCWAnyLogic(taskList); } public static Task<Task<TResult>> WhenAny<TResult>(params Task<TResult>[] tasks) { Task<Task> intermediate = WhenAny((Task[])tasks); return intermediate.ContinueWith(Task<TResult>.TaskWhenAnyCast, default(CancellationToken), TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.DenyChildAttach, TaskScheduler.Default); } public static Task<Task<TResult>> WhenAny<TResult>(IEnumerable<Task<TResult>> tasks) { Task<Task> intermediate = WhenAny((IEnumerable<Task>)tasks); return intermediate.ContinueWith(Task<TResult>.TaskWhenAnyCast, default(CancellationToken), TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.DenyChildAttach, TaskScheduler.Default); } #endregion [FriendAccessAllowed] internal static Task<TResult> CreateUnwrapPromise<TResult>(Task outerTask, bool lookForOce) { Contract.Requires(outerTask != null); return new UnwrapPromise<TResult>(outerTask, lookForOce); } internal virtual Delegate[] GetDelegateContinuationsForDebugger() { if (this.m_continuationObject != this) return GetDelegatesFromContinuationObject(this.m_continuationObject); else return null; } internal static Delegate[] GetDelegatesFromContinuationObject(object continuationObject) { if (continuationObject != null) { Action singleAction = continuationObject as Action; if (singleAction != null) { return new Delegate[] { AsyncMethodBuilderCore.TryGetStateMachineForDebugger(singleAction) }; } TaskContinuation taskContinuation = continuationObject as TaskContinuation; if (taskContinuation != null) { return taskContinuation.GetDelegateContinuationsForDebugger(); } Task continuationTask = continuationObject as Task; if (continuationTask != null) { Contract.Assert(continuationTask.m_action == null); Delegate[] delegates = continuationTask.GetDelegateContinuationsForDebugger(); if (delegates != null) return delegates; } ITaskCompletionAction singleCompletionAction = continuationObject as ITaskCompletionAction; if (singleCompletionAction != null) { return new Delegate[] { new Action<Task>(singleCompletionAction.Invoke) }; } List<object> continuationList = continuationObject as List<object>; if (continuationList != null) { List<Delegate> result = new List<Delegate>(); foreach (object obj in continuationList) { var innerDelegates = GetDelegatesFromContinuationObject(obj); if (innerDelegates != null) { foreach (var del in innerDelegates) { if (del != null) result.Add(del); } } } return result.ToArray(); } } return null; } private static Task GetActiveTaskFromId(int taskId) { Task task = null; s_currentActiveTasks.TryGetValue(taskId, out task); return task; } private static Task[] GetActiveTasks() { return new List<Task>(s_currentActiveTasks.Values).ToArray(); } }

 

posted @ 2016-09-07 11:20  茗::流  阅读(713)  评论(0)    收藏  举报
如有雷同,纯属参考。如有侵犯你的版权,请联系我。