5c9754f44f64ab7914c45c59754b69bedbc19976
[platform/upstream/coreclr.git] / src / mscorlib / src / System / Threading / Tasks / Task.cs
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 // =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
6 //
7 //
8 //
9 // A schedulable unit of work.
10 //
11 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
12
13 using System.Collections.Generic;
14 using System.Collections.ObjectModel;
15 using System.Diagnostics;
16 using System.Diagnostics.Tracing;
17 using System.Runtime.CompilerServices;
18 using System.Runtime.ExceptionServices;
19 using Internal.Runtime.Augments;
20
21 // Disable the "reference to volatile field not treated as volatile" error.
22 #pragma warning disable 0420
23
24 namespace System.Threading.Tasks
25 {
26     /// <summary>
27     /// Utility class for allocating structs as heap variables
28     /// </summary>
29     internal class Shared<T>
30     {
31         internal T Value;
32
33         internal Shared(T value)
34         {
35             this.Value = value;
36         }
37     }
38
39     /// <summary>
40     /// Represents the current stage in the lifecycle of a <see cref="Task"/>.
41     /// </summary>
42     public enum TaskStatus
43     {
44         /// <summary> 
45         /// The task has been initialized but has not yet been scheduled.
46         /// </summary>
47         Created,
48         /// <summary> 
49         /// The task is waiting to be activated and scheduled internally by the .NET Framework infrastructure.
50         /// </summary>
51         WaitingForActivation,
52         /// <summary>
53         /// The task has been scheduled for execution but has not yet begun executing.
54         /// </summary>
55         WaitingToRun,
56         /// <summary>
57         /// The task is running but has not yet completed.
58         /// </summary>
59         Running,
60         // /// <summary>
61         // /// The task is currently blocked in a wait state.
62         // /// </summary>
63         // Blocked,
64         /// <summary>
65         /// The task has finished executing and is implicitly waiting for
66         /// attached child tasks to complete.
67         /// </summary>
68         WaitingForChildrenToComplete,
69         /// <summary>
70         /// The task completed execution successfully.
71         /// </summary>
72         RanToCompletion,
73         /// <summary>
74         /// The task acknowledged cancellation by throwing an OperationCanceledException with its own CancellationToken
75         /// while the token was in signaled state, or the task's CancellationToken was already signaled before the
76         /// task started executing.
77         /// </summary>
78         Canceled,
79         /// <summary>
80         /// The task completed due to an unhandled exception.
81         /// </summary>
82         Faulted
83     }
84
85     /// <summary>
86     /// Represents an asynchronous operation.
87     /// </summary>
88     /// <remarks>
89     /// <para>
90     /// <see cref="Task"/> instances may be created in a variety of ways. The most common approach is by
91     /// using the Task type's <see cref="Factory"/> property to retrieve a <see
92     /// cref="System.Threading.Tasks.TaskFactory"/> instance that can be used to create tasks for several
93     /// purposes. For example, to create a <see cref="Task"/> that runs an action, the factory's StartNew
94     /// method may be used:
95     /// <code>
96     /// // C# 
97     /// var t = Task.Factory.StartNew(() => DoAction());
98     /// 
99     /// ' Visual Basic 
100     /// Dim t = Task.Factory.StartNew(Function() DoAction())
101     /// </code>
102     /// </para>
103     /// <para>
104     /// The <see cref="Task"/> class also provides constructors that initialize the Task but that do not
105     /// schedule it for execution. For performance reasons, TaskFactory's StartNew method should be the
106     /// preferred mechanism for creating and scheduling computational tasks, but for scenarios where creation
107     /// and scheduling must be separated, the constructors may be used, and the task's <see cref="Start()"/>
108     /// method may then be used to schedule the task for execution at a later time.
109     /// </para>
110     /// <para>
111     /// All members of <see cref="Task"/>, except for <see cref="Dispose()"/>, are thread-safe
112     /// and may be used from multiple threads concurrently.
113     /// </para>
114     /// <para>
115     /// For operations that return values, the <see cref="System.Threading.Tasks.Task{TResult}"/> class
116     /// should be used.
117     /// </para>
118     /// <para>
119     /// For developers implementing custom debuggers, several internal and private members of Task may be
120     /// useful (these may change from release to release). The Int32 m_taskId field serves as the backing
121     /// store for the <see cref="Id"/> property, however accessing this field directly from a debugger may be
122     /// more efficient than accessing the same value through the property's getter method (the
123     /// s_taskIdCounter Int32 counter is used to retrieve the next available ID for a Task). Similarly, the
124     /// Int32 m_stateFlags field stores information about the current lifecycle stage of the Task,
125     /// information also accessible through the <see cref="Status"/> property. The m_action System.Object
126     /// field stores a reference to the Task's delegate, and the m_stateObject System.Object field stores the
127     /// async state passed to the Task by the developer. Finally, for debuggers that parse stack frames, the
128     /// InternalWait method serves a potential marker for when a Task is entering a wait operation.
129     /// </para>
130     /// </remarks>
131     [DebuggerTypeProxy(typeof(SystemThreadingTasks_TaskDebugView))]
132     [DebuggerDisplay("Id = {Id}, Status = {Status}, Method = {DebuggerDisplayMethodDescription}")]
133     public class Task : IThreadPoolWorkItem, IAsyncResult, IDisposable
134     {
135         [ThreadStatic]
136         internal static Task t_currentTask;  // The currently executing task.
137         [ThreadStatic]
138         private static StackGuard t_stackGuard;  // The stack guard object for this thread
139
140         internal static int s_taskIdCounter; //static counter used to generate unique task IDs
141
142         private volatile int m_taskId; // this task's unique ID. initialized only if it is ever requested
143
144         internal Delegate m_action;    // The body of the task.  Might be Action<object>, Action<TState> or Action.  Or possibly a Func.
145         // If m_action is set to null it will indicate that we operate in the
146         // "externally triggered completion" mode, which is exclusively meant 
147         // for the signalling Task<TResult> (aka. promise). In this mode,
148         // we don't call InnerInvoke() in response to a Wait(), but simply wait on
149         // the completion event which will be set when the Future class calls Finish().
150         // But the event would now be signalled if Cancel() is called
151
152
153         internal object m_stateObject; // A state object that can be optionally supplied, passed to action.
154         internal TaskScheduler m_taskScheduler; // The task scheduler this task runs under. 
155
156         internal volatile int m_stateFlags;
157
158         private Task ParentForDebugger => m_contingentProperties?.m_parent; // Private property used by a debugger to access this Task's parent
159         private int StateFlagsForDebugger => m_stateFlags; // Private property used by a debugger to access this Task's state flags
160
161         // State constants for m_stateFlags;
162         // The bits of m_stateFlags are allocated as follows:
163         //   0x40000000 - TaskBase state flag
164         //   0x3FFF0000 - Task state flags
165         //   0x0000FF00 - internal TaskCreationOptions flags
166         //   0x000000FF - publicly exposed TaskCreationOptions flags
167         //
168         // See TaskCreationOptions for bit values associated with TaskCreationOptions
169         //
170         private const int OptionsMask = 0xFFFF; // signifies the Options portion of m_stateFlags bin: 0000 0000 0000 0000 1111 1111 1111 1111
171         internal const int TASK_STATE_STARTED = 0x10000;                                       //bin: 0000 0000 0000 0001 0000 0000 0000 0000
172         internal const int TASK_STATE_DELEGATE_INVOKED = 0x20000;                              //bin: 0000 0000 0000 0010 0000 0000 0000 0000
173         internal const int TASK_STATE_DISPOSED = 0x40000;                                      //bin: 0000 0000 0000 0100 0000 0000 0000 0000
174         internal const int TASK_STATE_EXCEPTIONOBSERVEDBYPARENT = 0x80000;                     //bin: 0000 0000 0000 1000 0000 0000 0000 0000
175         internal const int TASK_STATE_CANCELLATIONACKNOWLEDGED = 0x100000;                     //bin: 0000 0000 0001 0000 0000 0000 0000 0000
176         internal const int TASK_STATE_FAULTED = 0x200000;                                      //bin: 0000 0000 0010 0000 0000 0000 0000 0000
177         internal const int TASK_STATE_CANCELED = 0x400000;                                     //bin: 0000 0000 0100 0000 0000 0000 0000 0000
178         internal const int TASK_STATE_WAITING_ON_CHILDREN = 0x800000;                          //bin: 0000 0000 1000 0000 0000 0000 0000 0000
179         internal const int TASK_STATE_RAN_TO_COMPLETION = 0x1000000;                           //bin: 0000 0001 0000 0000 0000 0000 0000 0000
180         internal const int TASK_STATE_WAITINGFORACTIVATION = 0x2000000;                        //bin: 0000 0010 0000 0000 0000 0000 0000 0000
181         internal const int TASK_STATE_COMPLETION_RESERVED = 0x4000000;                         //bin: 0000 0100 0000 0000 0000 0000 0000 0000
182         internal const int TASK_STATE_THREAD_WAS_ABORTED = 0x8000000;                          //bin: 0000 1000 0000 0000 0000 0000 0000 0000
183         internal const int TASK_STATE_WAIT_COMPLETION_NOTIFICATION = 0x10000000;               //bin: 0001 0000 0000 0000 0000 0000 0000 0000
184         //This could be moved to InternalTaskOptions enum
185         internal const int TASK_STATE_EXECUTIONCONTEXT_IS_NULL = 0x20000000;                   //bin: 0010 0000 0000 0000 0000 0000 0000 0000
186         internal const int TASK_STATE_TASKSCHEDULED_WAS_FIRED = 0x40000000;                    //bin: 0100 0000 0000 0000 0000 0000 0000 0000
187
188         // A mask for all of the final states a task may be in
189         private const int TASK_STATE_COMPLETED_MASK = TASK_STATE_CANCELED | TASK_STATE_FAULTED | TASK_STATE_RAN_TO_COMPLETION;
190
191         // Values for ContingentProperties.m_internalCancellationRequested.
192         private const int CANCELLATION_REQUESTED = 0x1;
193
194         // Can be null, a single continuation, a list of continuations, or s_taskCompletionSentinel,
195         // in that order. The logic arround this object assumes it will never regress to a previous state.
196         private volatile object m_continuationObject = null;
197
198         // m_continuationObject is set to this when the task completes.
199         private static readonly object s_taskCompletionSentinel = new object();
200
201         // A private flag that would be set (only) by the debugger
202         // When true the Async Causality logging trace is enabled as well as a dictionary to relate operation ids with Tasks
203         // [FriendAccessAllowed]
204         internal static bool s_asyncDebuggingEnabled; //false by default
205
206         // This dictonary relates the task id, from an operation id located in the Async Causality log to the actual
207         // task. This is to be used by the debugger ONLY. Task in this dictionary represent current active tasks.
208         private static readonly Dictionary<int, Task> s_currentActiveTasks = new Dictionary<int, Task>();
209         private static readonly Object s_activeTasksLock = new Object();
210
211         // These methods are a way to access the dictionary both from this class and for other classes that also
212         // activate dummy tasks. Specifically the AsyncTaskMethodBuilder and AsyncTaskMethodBuilder<>
213         // [FriendAccessAllowed]
214         internal static bool AddToActiveTasks(Task task)
215         {
216             Debug.Assert(task != null, "Null Task objects can't be added to the ActiveTasks collection");
217             lock (s_activeTasksLock)
218             {
219                 s_currentActiveTasks[task.Id] = task;
220             }
221             //always return true to keep signature as bool for backwards compatibility
222             return true;
223         }
224
225         // [FriendAccessAllowed]
226         internal static void RemoveFromActiveTasks(int taskId)
227         {
228             lock (s_activeTasksLock)
229             {
230                 s_currentActiveTasks.Remove(taskId);
231             }
232         }
233
234         // We moved a number of Task properties into this class.  The idea is that in most cases, these properties never
235         // need to be accessed during the life cycle of a Task, so we don't want to instantiate them every time.  Once
236         // one of these properties needs to be written, we will instantiate a ContingentProperties object and set
237         // the appropriate property.
238         internal class ContingentProperties
239         {
240             // Additional context
241
242             internal ExecutionContext m_capturedContext; // The execution context to run the task within, if any. Only set from non-concurrent contexts.
243
244             // Completion fields (exceptions and event)
245
246             internal volatile ManualResetEventSlim m_completionEvent; // Lazily created if waiting is required.
247             internal volatile TaskExceptionHolder m_exceptionsHolder; // Tracks exceptions, if any have occurred
248
249             // Cancellation fields (token, registration, and internally requested)
250
251             internal CancellationToken m_cancellationToken; // Task's cancellation token, if it has one
252             internal Shared<CancellationTokenRegistration> m_cancellationRegistration; // Task's registration with the cancellation token
253             internal volatile int m_internalCancellationRequested; // Its own field because multiple threads legally try to set it.
254
255             // Parenting fields
256
257             // # of active children + 1 (for this task itself).
258             // Used for ensuring all children are done before this task can complete
259             // The extra count helps prevent the race condition for executing the final state transition
260             // (i.e. whether the last child or this task itself should call FinishStageTwo())
261             internal volatile int m_completionCountdown = 1;
262             // A list of child tasks that threw an exception (TCEs don't count),
263             // but haven't yet been waited on by the parent, lazily initialized.
264             internal volatile List<Task> m_exceptionalChildren;
265             // A task's parent, or null if parent-less. Only set during Task construction.
266             internal Task m_parent;
267
268             /// <summary>
269             /// Sets the internal completion event.
270             /// </summary>
271             internal void SetCompleted()
272             {
273                 var mres = m_completionEvent;
274                 if (mres != null) mres.Set();
275             }
276
277             /// <summary>
278             /// Checks if we registered a CT callback during construction, and deregisters it. 
279             /// This should be called when we know the registration isn't useful anymore. Specifically from Finish() if the task has completed
280             /// successfully or with an exception.
281             /// </summary>
282             internal void DeregisterCancellationCallback()
283             {
284                 if (m_cancellationRegistration != null)
285                 {
286                     // Harden against ODEs thrown from disposing of the CTR.
287                     // Since the task has already been put into a final state by the time this
288                     // is called, all we can do here is suppress the exception.
289                     try { m_cancellationRegistration.Value.Dispose(); }
290                     catch (ObjectDisposedException) { }
291                     m_cancellationRegistration = null;
292                 }
293             }
294         }
295
296
297         // This field will only be instantiated to some non-null value if any ContingentProperties need to be set.
298         // This will be a ContingentProperties instance or a type derived from it
299         internal ContingentProperties m_contingentProperties;
300
301         // Special internal constructor to create an already-completed task.
302         // if canceled==true, create a Canceled task, or else create a RanToCompletion task.
303         // Constructs the task as already completed
304         internal Task(bool canceled, TaskCreationOptions creationOptions, CancellationToken ct)
305         {
306             int optionFlags = (int)creationOptions;
307             if (canceled)
308             {
309                 m_stateFlags = TASK_STATE_CANCELED | TASK_STATE_CANCELLATIONACKNOWLEDGED | optionFlags;
310                 m_contingentProperties = new ContingentProperties() // can't have children, so just instantiate directly
311                 {
312                     m_cancellationToken = ct,
313                     m_internalCancellationRequested = CANCELLATION_REQUESTED,
314                 };
315             }
316             else
317                 m_stateFlags = TASK_STATE_RAN_TO_COMPLETION | optionFlags;
318         }
319
320         /// <summary>Constructor for use with promise-style tasks that aren't configurable.</summary>
321         internal Task()
322         {
323             m_stateFlags = TASK_STATE_WAITINGFORACTIVATION | (int)InternalTaskOptions.PromiseTask;
324         }
325
326         // Special constructor for use with promise-style tasks.
327         // Added promiseStyle parameter as an aid to the compiler to distinguish between (state,TCO) and
328         // (action,TCO).  It should always be true.
329         internal Task(object state, TaskCreationOptions creationOptions, bool promiseStyle)
330         {
331             Debug.Assert(promiseStyle, "Promise CTOR: promiseStyle was false");
332
333             // Check the creationOptions. We allow the AttachedToParent option to be specified for promise tasks.
334             // Also allow RunContinuationsAsynchronously because this is the constructor called by TCS
335             if ((creationOptions & ~(TaskCreationOptions.AttachedToParent | TaskCreationOptions.RunContinuationsAsynchronously)) != 0)
336             {
337                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.creationOptions);
338             }
339
340             // Only set a parent if AttachedToParent is specified.
341             if ((creationOptions & TaskCreationOptions.AttachedToParent) != 0)
342             {
343                 Task parent = Task.InternalCurrent;
344                 if (parent != null)
345                 {
346                     EnsureContingentPropertiesInitializedUnsafe().m_parent = parent;
347                 }
348             }
349
350             TaskConstructorCore(null, state, default(CancellationToken), creationOptions, InternalTaskOptions.PromiseTask, null);
351         }
352
353         /// <summary>
354         /// Initializes a new <see cref="Task"/> with the specified action.
355         /// </summary>
356         /// <param name="action">The delegate that represents the code to execute in the Task.</param>
357         /// <exception cref="T:System.ArgumentNullException">The <paramref name="action"/> argument is null.</exception>
358         public Task(Action action)
359             : this(action, null, null, default(CancellationToken), TaskCreationOptions.None, InternalTaskOptions.None, null)
360         {
361         }
362
363         /// <summary>
364         /// Initializes a new <see cref="Task"/> with the specified action and <see cref="System.Threading.CancellationToken">CancellationToken</see>.
365         /// </summary>
366         /// <param name="action">The delegate that represents the code to execute in the Task.</param>
367         /// <param name="cancellationToken">The <see cref="System.Threading.CancellationToken">CancellationToken</see>
368         /// that will be assigned to the new Task.</param>
369         /// <exception cref="T:System.ArgumentNullException">The <paramref name="action"/> argument is null.</exception>
370         /// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
371         /// has already been disposed.
372         /// </exception>
373         public Task(Action action, CancellationToken cancellationToken)
374             : this(action, null, null, cancellationToken, TaskCreationOptions.None, InternalTaskOptions.None, null)
375         {
376         }
377
378         /// <summary>
379         /// Initializes a new <see cref="Task"/> with the specified action and creation options.
380         /// </summary>
381         /// <param name="action">The delegate that represents the code to execute in the task.</param>
382         /// <param name="creationOptions">
383         /// The <see cref="System.Threading.Tasks.TaskCreationOptions">TaskCreationOptions</see> used to
384         /// customize the Task's behavior.
385         /// </param>
386         /// <exception cref="T:System.ArgumentNullException">
387         /// The <paramref name="action"/> argument is null.
388         /// </exception>
389         /// <exception cref="T:System.ArgumentOutOfRangeException">
390         /// The <paramref name="creationOptions"/> argument specifies an invalid value for <see
391         /// cref="T:System.Threading.Tasks.TaskCreationOptions"/>.
392         /// </exception>
393         public Task(Action action, TaskCreationOptions creationOptions)
394             : this(action, null, Task.InternalCurrentIfAttached(creationOptions), default(CancellationToken), creationOptions, InternalTaskOptions.None, null)
395         {
396         }
397
398         /// <summary>
399         /// Initializes a new <see cref="Task"/> with the specified action and creation options.
400         /// </summary>
401         /// <param name="action">The delegate that represents the code to execute in the task.</param>
402         /// <param name="cancellationToken">The <see cref="CancellationToken"/> that will be assigned to the new task.</param>
403         /// <param name="creationOptions">
404         /// The <see cref="System.Threading.Tasks.TaskCreationOptions">TaskCreationOptions</see> used to
405         /// customize the Task's behavior.
406         /// </param>
407         /// <exception cref="T:System.ArgumentNullException">
408         /// The <paramref name="action"/> argument is null.
409         /// </exception>
410         /// <exception cref="T:System.ArgumentOutOfRangeException">
411         /// The <paramref name="creationOptions"/> argument specifies an invalid value for <see
412         /// cref="T:System.Threading.Tasks.TaskCreationOptions"/>.
413         /// </exception>
414         /// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
415         /// has already been disposed.
416         /// </exception>
417         public Task(Action action, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
418             : this(action, null, Task.InternalCurrentIfAttached(creationOptions), cancellationToken, creationOptions, InternalTaskOptions.None, null)
419         {
420         }
421
422
423         /// <summary>
424         /// Initializes a new <see cref="Task"/> with the specified action and state.
425         /// </summary>
426         /// <param name="action">The delegate that represents the code to execute in the task.</param>
427         /// <param name="state">An object representing data to be used by the action.</param>
428         /// <exception cref="T:System.ArgumentNullException">
429         /// The <paramref name="action"/> argument is null.
430         /// </exception>
431         public Task(Action<object> action, object state)
432             : this(action, state, null, default(CancellationToken), TaskCreationOptions.None, InternalTaskOptions.None, null)
433         {
434         }
435
436         /// <summary>
437         /// Initializes a new <see cref="Task"/> with the specified action, state, and options.
438         /// </summary>
439         /// <param name="action">The delegate that represents the code to execute in the task.</param>
440         /// <param name="state">An object representing data to be used by the action.</param>
441         /// <param name="cancellationToken">The <see cref="CancellationToken"/> that will be assigned to the new task.</param>
442         /// <exception cref="T:System.ArgumentNullException">
443         /// The <paramref name="action"/> argument is null.
444         /// </exception>
445         /// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
446         /// has already been disposed.
447         /// </exception>
448         public Task(Action<object> action, object state, CancellationToken cancellationToken)
449             : this(action, state, null, cancellationToken, TaskCreationOptions.None, InternalTaskOptions.None, null)
450         {
451         }
452
453         /// <summary>
454         /// Initializes a new <see cref="Task"/> with the specified action, state, and options.
455         /// </summary>
456         /// <param name="action">The delegate that represents the code to execute in the task.</param>
457         /// <param name="state">An object representing data to be used by the action.</param>
458         /// <param name="creationOptions">
459         /// The <see cref="System.Threading.Tasks.TaskCreationOptions">TaskCreationOptions</see> used to
460         /// customize the Task's behavior.
461         /// </param>
462         /// <exception cref="T:System.ArgumentNullException">
463         /// The <paramref name="action"/> argument is null.
464         /// </exception>
465         /// <exception cref="T:System.ArgumentOutOfRangeException">
466         /// The <paramref name="creationOptions"/> argument specifies an invalid value for <see
467         /// cref="T:System.Threading.Tasks.TaskCreationOptions"/>.
468         /// </exception>
469         public Task(Action<object> action, object state, TaskCreationOptions creationOptions)
470             : this(action, state, Task.InternalCurrentIfAttached(creationOptions), default(CancellationToken), creationOptions, InternalTaskOptions.None, null)
471         {
472         }
473
474         /// <summary>
475         /// Initializes a new <see cref="Task"/> with the specified action, state, and options.
476         /// </summary>
477         /// <param name="action">The delegate that represents the code to execute in the task.</param>
478         /// <param name="state">An object representing data to be used by the action.</param>
479         /// <param name="cancellationToken">The <see cref="CancellationToken"/> that will be assigned to the new task.</param>
480         /// <param name="creationOptions">
481         /// The <see cref="System.Threading.Tasks.TaskCreationOptions">TaskCreationOptions</see> used to
482         /// customize the Task's behavior.
483         /// </param>
484         /// <exception cref="T:System.ArgumentNullException">
485         /// The <paramref name="action"/> argument is null.
486         /// </exception>
487         /// <exception cref="T:System.ArgumentOutOfRangeException">
488         /// The <paramref name="creationOptions"/> argument specifies an invalid value for <see
489         /// cref="T:System.Threading.Tasks.TaskCreationOptions"/>.
490         /// </exception>
491         /// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
492         /// has already been disposed.
493         /// </exception>
494         public Task(Action<object> action, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
495             : this(action, state, Task.InternalCurrentIfAttached(creationOptions), cancellationToken, creationOptions, InternalTaskOptions.None, null)
496         {
497         }
498
499         /// <summary>
500         /// An internal constructor used by the factory methods on task and its descendent(s).
501         /// This variant does not capture the ExecutionContext; it is up to the caller to do that.
502         /// </summary>
503         /// <param name="action">An action to execute.</param>
504         /// <param name="state">Optional state to pass to the action.</param>
505         /// <param name="parent">Parent of Task.</param>
506         /// <param name="cancellationToken">A CancellationToken for the task.</param>
507         /// <param name="scheduler">A task scheduler under which the task will run.</param>
508         /// <param name="creationOptions">Options to control its execution.</param>
509         /// <param name="internalOptions">Internal options to control its execution</param>
510         internal Task(Delegate action, object state, Task parent, CancellationToken cancellationToken,
511             TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler)
512         {
513             if (action == null)
514             {
515                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.action);
516             }
517
518             // Keep a link to the parent if attached
519             if (parent != null && (creationOptions & TaskCreationOptions.AttachedToParent) != 0)
520             {
521                 EnsureContingentPropertiesInitializedUnsafe().m_parent = parent;
522             }
523
524             TaskConstructorCore(action, state, cancellationToken, creationOptions, internalOptions, scheduler);
525         }
526
527         /// <summary>
528         /// Common logic used by the following internal ctors:
529         ///     Task()
530         ///     Task(object action, object state, Task parent, TaskCreationOptions options, TaskScheduler taskScheduler)
531         /// </summary>
532         /// <param name="action">Action for task to execute.</param>
533         /// <param name="state">Object to which to pass to action (may be null)</param>
534         /// <param name="scheduler">Task scheduler on which to run thread (only used by continuation tasks).</param>
535         /// <param name="cancellationToken">A CancellationToken for the Task.</param>
536         /// <param name="creationOptions">Options to customize behavior of Task.</param>
537         /// <param name="internalOptions">Internal options to customize behavior of Task.</param>
538         internal void TaskConstructorCore(Delegate action, object state, CancellationToken cancellationToken,
539             TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler)
540         {
541             m_action = action;
542             m_stateObject = state;
543             m_taskScheduler = scheduler;
544
545             Debug.Assert(m_contingentProperties == null || m_contingentProperties.m_capturedContext == null,
546                 "Captured an ExecutionContext when one was already captured.");
547             CapturedContext = ExecutionContext.Capture();
548
549             // Check for validity of options
550             if ((creationOptions &
551                     ~(TaskCreationOptions.AttachedToParent |
552                       TaskCreationOptions.LongRunning |
553                       TaskCreationOptions.DenyChildAttach |
554                       TaskCreationOptions.HideScheduler |
555                       TaskCreationOptions.PreferFairness |
556                       TaskCreationOptions.RunContinuationsAsynchronously)) != 0)
557             {
558                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.creationOptions);
559             }
560
561 #if DEBUG
562             // Check the validity of internalOptions
563             int illegalInternalOptions =
564                     (int)(internalOptions &
565                             ~(InternalTaskOptions.PromiseTask |
566                               InternalTaskOptions.ContinuationTask |
567                               InternalTaskOptions.LazyCancellation |
568                               InternalTaskOptions.QueuedByRuntime));
569             Debug.Assert(illegalInternalOptions == 0, "TaskConstructorCore: Illegal internal options");
570 #endif
571
572             // Assign options to m_stateAndOptionsFlag.
573             Debug.Assert(m_stateFlags == 0, "TaskConstructorCore: non-zero m_stateFlags");
574             Debug.Assert((((int)creationOptions) | OptionsMask) == OptionsMask, "TaskConstructorCore: options take too many bits");
575             int tmpFlags = (int)creationOptions | (int)internalOptions; // one write to the volatile m_stateFlags instead of two when setting the above options
576             m_stateFlags = m_action == null || (internalOptions & InternalTaskOptions.ContinuationTask) != 0 ?
577                 tmpFlags | TASK_STATE_WAITINGFORACTIVATION :
578                 tmpFlags;
579
580             // Now is the time to add the new task to the children list 
581             // of the creating task if the options call for it.
582             // We can safely call the creator task's AddNewChild() method to register it, 
583             // because at this point we are already on its thread of execution.
584
585             ContingentProperties props = m_contingentProperties;
586             if (props != null)
587             {
588                 Task parent = props.m_parent;
589                 if (parent != null
590                     && ((creationOptions & TaskCreationOptions.AttachedToParent) != 0)
591                     && ((parent.CreationOptions & TaskCreationOptions.DenyChildAttach) == 0))
592                 {
593                     parent.AddNewChild();
594                 }
595             }
596
597             // if we have a non-null cancellationToken, allocate the contingent properties to save it
598             // we need to do this as the very last thing in the construction path, because the CT registration could modify m_stateFlags
599             if (cancellationToken.CanBeCanceled)
600             {
601                 Debug.Assert((internalOptions & InternalTaskOptions.ContinuationTask) == 0, "TaskConstructorCore: Did not expect to see cancelable token for continuation task.");
602
603                 AssignCancellationToken(cancellationToken, null, null);
604             }
605         }
606
607         /// <summary>
608         /// Handles everything needed for associating a CancellationToken with a task which is being constructed.
609         /// This method is meant to be called either from the TaskConstructorCore or from ContinueWithCore.
610         /// </summary>
611         private void AssignCancellationToken(CancellationToken cancellationToken, Task antecedent, TaskContinuation continuation)
612         {
613             // There is no need to worry about concurrency issues here because we are in the constructor path of the task --
614             // there should not be any race conditions to set m_contingentProperties at this point.
615             ContingentProperties props = EnsureContingentPropertiesInitializedUnsafe();
616             props.m_cancellationToken = cancellationToken;
617
618             try
619             {
620                 // If an unstarted task has a valid CancellationToken that gets signalled while the task is still not queued
621                 // we need to proactively cancel it, because it may never execute to transition itself. 
622                 // The only way to accomplish this is to register a callback on the CT.
623                 // We exclude Promise tasks from this, because TaskCompletionSource needs to fully control the inner tasks's lifetime (i.e. not allow external cancellations)                
624                 if ((((InternalTaskOptions)Options &
625                     (InternalTaskOptions.QueuedByRuntime | InternalTaskOptions.PromiseTask | InternalTaskOptions.LazyCancellation)) == 0))
626                 {
627                     if (cancellationToken.IsCancellationRequested)
628                     {
629                         // Fast path for an already-canceled cancellationToken
630                         this.InternalCancel(false);
631                     }
632                     else
633                     {
634                         // Regular path for an uncanceled cancellationToken
635                         CancellationTokenRegistration ctr;
636                         if (antecedent == null)
637                         {
638                             // if no antecedent was specified, use this task's reference as the cancellation state object
639                             ctr = cancellationToken.InternalRegisterWithoutEC(s_taskCancelCallback, this);
640                         }
641                         else
642                         {
643                             // If an antecedent was specified, pack this task, its antecedent and the TaskContinuation together as a tuple 
644                             // and use it as the cancellation state object. This will be unpacked in the cancellation callback so that 
645                             // antecedent.RemoveCancellation(continuation) can be invoked.
646                             ctr = cancellationToken.InternalRegisterWithoutEC(s_taskCancelCallback,
647                                                                               new Tuple<Task, Task, TaskContinuation>(this, antecedent, continuation));
648                         }
649
650                         props.m_cancellationRegistration = new Shared<CancellationTokenRegistration>(ctr);
651                     }
652                 }
653             }
654             catch
655             {
656                 // If we have an exception related to our CancellationToken, then we need to subtract ourselves
657                 // from our parent before throwing it.
658                 Task parent = m_contingentProperties?.m_parent;
659                 if ((parent != null) &&
660                     ((Options & TaskCreationOptions.AttachedToParent) != 0)
661                      && ((parent.Options & TaskCreationOptions.DenyChildAttach) == 0))
662                 {
663                     parent.DisregardChild();
664                 }
665                 throw;
666             }
667         }
668
669
670         // Static delegate to be used as a cancellation callback on unstarted tasks that have a valid cancellation token.
671         // This is necessary to transition them into canceled state if their cancellation token is signalled while they are still not queued
672         private readonly static Action<Object> s_taskCancelCallback = new Action<Object>(TaskCancelCallback);
673         private static void TaskCancelCallback(Object o)
674         {
675             var targetTask = o as Task;
676             if (targetTask == null)
677             {
678                 var tuple = o as Tuple<Task, Task, TaskContinuation>;
679                 if (tuple != null)
680                 {
681                     targetTask = tuple.Item1;
682
683                     Task antecedentTask = tuple.Item2;
684                     TaskContinuation continuation = tuple.Item3;
685                     antecedentTask.RemoveContinuation(continuation);
686                 }
687             }
688             Debug.Assert(targetTask != null,
689                 "targetTask should have been non-null, with the supplied argument being a task or a tuple containing one");
690             targetTask.InternalCancel(false);
691         }
692
693         // Debugger support
694         private string DebuggerDisplayMethodDescription
695         {
696             get
697             {
698                 Delegate d = m_action;
699                 return d != null ? d.Method.ToString() : "{null}";
700             }
701         }
702
703         // Internal property to process TaskCreationOptions access and mutation.
704         internal TaskCreationOptions Options => OptionsMethod(m_stateFlags);
705
706         // Similar to Options property, but allows for the use of a cached flags value rather than
707         // a read of the volatile m_stateFlags field.
708         internal static TaskCreationOptions OptionsMethod(int flags)
709         {
710             Debug.Assert((OptionsMask & 1) == 1, "OptionsMask needs a shift in Options.get");
711             return (TaskCreationOptions)(flags & OptionsMask);
712         }
713
714         // Atomically OR-in newBits to m_stateFlags, while making sure that
715         // no illegalBits are set.  Returns true on success, false on failure.
716         internal bool AtomicStateUpdate(int newBits, int illegalBits)
717         {
718             int oldFlags = m_stateFlags;
719             return
720                 (oldFlags & illegalBits) == 0 &&
721                 (Interlocked.CompareExchange(ref m_stateFlags, oldFlags | newBits, oldFlags) == oldFlags ||
722                  AtomicStateUpdateSlow(newBits, illegalBits));
723         }
724
725         private bool AtomicStateUpdateSlow(int newBits, int illegalBits)
726         {
727             var sw = new SpinWait();
728             do
729             {
730                 int oldFlags = m_stateFlags;
731                 if ((oldFlags & illegalBits) != 0) return false;
732                 if (Interlocked.CompareExchange(ref m_stateFlags, oldFlags | newBits, oldFlags) == oldFlags)
733                 {
734                     return true;
735                 }
736                 sw.SpinOnce();
737             } while (true);
738         }
739
740         internal bool AtomicStateUpdate(int newBits, int illegalBits, ref int oldFlags)
741         {
742             SpinWait sw = new SpinWait();
743             do
744             {
745                 oldFlags = m_stateFlags;
746                 if ((oldFlags & illegalBits) != 0) return false;
747                 if (Interlocked.CompareExchange(ref m_stateFlags, oldFlags | newBits, oldFlags) == oldFlags)
748                 {
749                     return true;
750                 }
751                 sw.SpinOnce();
752             } while (true);
753         }
754
755         /// <summary>
756         /// Sets or clears the TASK_STATE_WAIT_COMPLETION_NOTIFICATION state bit.
757         /// The debugger sets this bit to aid it in "stepping out" of an async method body.
758         /// If enabled is true, this must only be called on a task that has not yet been completed.
759         /// If enabled is false, this may be called on completed tasks.
760         /// Either way, it should only be used for promise-style tasks.
761         /// </summary>
762         /// <param name="enabled">true to set the bit; false to unset the bit.</param>
763         internal void SetNotificationForWaitCompletion(bool enabled)
764         {
765             Debug.Assert((Options & (TaskCreationOptions)InternalTaskOptions.PromiseTask) != 0,
766                 "Should only be used for promise-style tasks"); // hasn't been vetted on other kinds as there hasn't been a need
767
768             if (enabled)
769             {
770                 // Atomically set the END_AWAIT_NOTIFICATION bit
771                 bool success = AtomicStateUpdate(TASK_STATE_WAIT_COMPLETION_NOTIFICATION,
772                                   TASK_STATE_COMPLETED_MASK | TASK_STATE_COMPLETION_RESERVED);
773                 Debug.Assert(success, "Tried to set enabled on completed Task");
774             }
775             else
776             {
777                 // Atomically clear the END_AWAIT_NOTIFICATION bit
778                 SpinWait sw = new SpinWait();
779                 while (true)
780                 {
781                     int oldFlags = m_stateFlags;
782                     int newFlags = oldFlags & (~TASK_STATE_WAIT_COMPLETION_NOTIFICATION);
783                     if (Interlocked.CompareExchange(ref m_stateFlags, newFlags, oldFlags) == oldFlags) break;
784                     sw.SpinOnce();
785                 }
786             }
787         }
788
789         /// <summary>
790         /// Calls the debugger notification method if the right bit is set and if
791         /// the task itself allows for the notification to proceed.
792         /// </summary>
793         /// <returns>true if the debugger was notified; otherwise, false.</returns>
794         internal bool NotifyDebuggerOfWaitCompletionIfNecessary()
795         {
796             // Notify the debugger if of any of the tasks we've waited on requires notification
797             if (IsWaitNotificationEnabled && ShouldNotifyDebuggerOfWaitCompletion)
798             {
799                 NotifyDebuggerOfWaitCompletion();
800                 return true;
801             }
802             return false;
803         }
804
805         /// <summary>Returns true if any of the supplied tasks require wait notification.</summary>
806         /// <param name="tasks">The tasks to check.</param>
807         /// <returns>true if any of the tasks require notification; otherwise, false.</returns>
808         internal static bool AnyTaskRequiresNotifyDebuggerOfWaitCompletion(Task[] tasks)
809         {
810             Debug.Assert(tasks != null, "Expected non-null array of tasks");
811             foreach (var task in tasks)
812             {
813                 if (task != null &&
814                     task.IsWaitNotificationEnabled &&
815                     task.ShouldNotifyDebuggerOfWaitCompletion) // potential recursion
816                 {
817                     return true;
818                 }
819             }
820             return false;
821         }
822
823         /// <summary>Gets whether either the end await bit is set or (not xor) the task has not completed successfully.</summary>
824         /// <returns>(DebuggerBitSet || !RanToCompletion)</returns>
825         internal bool IsWaitNotificationEnabledOrNotRanToCompletion
826         {
827             [MethodImpl(MethodImplOptions.AggressiveInlining)]
828             get
829             {
830                 return (m_stateFlags & (Task.TASK_STATE_WAIT_COMPLETION_NOTIFICATION | Task.TASK_STATE_RAN_TO_COMPLETION))
831                         != Task.TASK_STATE_RAN_TO_COMPLETION;
832             }
833         }
834
835         /// <summary>
836         /// Determines whether we should inform the debugger that we're ending a join with a task.  
837         /// This should only be called if the debugger notification bit is set, as it is has some cost,
838         /// namely it is a virtual call (however calling it if the bit is not set is not functionally 
839         /// harmful).  Derived implementations may choose to only conditionally call down to this base 
840         /// implementation.
841         /// </summary>
842         internal virtual bool ShouldNotifyDebuggerOfWaitCompletion // ideally would be familyAndAssembly, but that can't be done in C#
843         {
844             get
845             {
846                 // It's theoretically possible but extremely rare that this assert could fire because the 
847                 // bit was unset between the time that it was checked and this method was called.
848                 // It's so remote a chance that it's worth having the assert to protect against misuse.
849                 bool isWaitNotificationEnabled = IsWaitNotificationEnabled;
850                 Debug.Assert(isWaitNotificationEnabled, "Should only be called if the wait completion bit is set.");
851                 return isWaitNotificationEnabled;
852             }
853         }
854
855         /// <summary>Gets whether the task's debugger notification for wait completion bit is set.</summary>
856         /// <returns>true if the bit is set; false if it's not set.</returns>
857         internal bool IsWaitNotificationEnabled // internal only to enable unit tests; would otherwise be private
858         {
859             get { return (m_stateFlags & TASK_STATE_WAIT_COMPLETION_NOTIFICATION) != 0; }
860         }
861
862         /// <summary>Placeholder method used as a breakpoint target by the debugger.  Must not be inlined or optimized.</summary>
863         /// <remarks>All joins with a task should end up calling this if their debugger notification bit is set.</remarks>
864         [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
865         private void NotifyDebuggerOfWaitCompletion()
866         {
867             // It's theoretically possible but extremely rare that this assert could fire because the 
868             // bit was unset between the time that it was checked and this method was called.
869             // It's so remote a chance that it's worth having the assert to protect against misuse.
870             Debug.Assert(IsWaitNotificationEnabled, "Should only be called if the wait completion bit is set.");
871
872             // Now that we're notifying the debugger, clear the bit.  The debugger should do this anyway,
873             // but this adds a bit of protection in case it fails to, and given that the debugger is involved, 
874             // the overhead here for the interlocked is negligable.  We do still rely on the debugger
875             // to clear bits, as this doesn't recursively clear bits in the case of, for example, WhenAny.
876             SetNotificationForWaitCompletion(enabled: false);
877         }
878
879
880         // Atomically mark a Task as started while making sure that it is not canceled.
881         internal bool MarkStarted()
882         {
883             return AtomicStateUpdate(TASK_STATE_STARTED, TASK_STATE_CANCELED | TASK_STATE_STARTED);
884         }
885
886         internal bool FireTaskScheduledIfNeeded(TaskScheduler ts)
887         {
888             var etwLog = TplEtwProvider.Log;
889             if (etwLog.IsEnabled() && (m_stateFlags & Task.TASK_STATE_TASKSCHEDULED_WAS_FIRED) == 0)
890             {
891                 m_stateFlags |= Task.TASK_STATE_TASKSCHEDULED_WAS_FIRED;
892
893                 Task currentTask = Task.InternalCurrent;
894                 Task parentTask = m_contingentProperties?.m_parent;
895                 etwLog.TaskScheduled(ts.Id, currentTask == null ? 0 : currentTask.Id,
896                                      this.Id, parentTask == null ? 0 : parentTask.Id, (int)this.Options,
897                                      System.Threading.Thread.GetDomainID());
898                 return true;
899             }
900             else
901                 return false;
902         }
903
904         /// <summary>
905         /// Internal function that will be called by a new child task to add itself to 
906         /// the children list of the parent (this).
907         /// 
908         /// Since a child task can only be created from the thread executing the action delegate
909         /// of this task, reentrancy is neither required nor supported. This should not be called from
910         /// anywhere other than the task construction/initialization codepaths.
911         /// </summary>
912         internal void AddNewChild()
913         {
914             Debug.Assert(Task.InternalCurrent == this, "Task.AddNewChild(): Called from an external context");
915
916             var props = EnsureContingentPropertiesInitialized();
917
918             if (props.m_completionCountdown == 1)
919             {
920                 // A count of 1 indicates so far there was only the parent, and this is the first child task
921                 // Single kid => no fuss about who else is accessing the count. Let's save ourselves 100 cycles
922                 props.m_completionCountdown++;
923             }
924             else
925             {
926                 // otherwise do it safely
927                 Interlocked.Increment(ref props.m_completionCountdown);
928             }
929         }
930
931         // This is called in the case where a new child is added, but then encounters a CancellationToken-related exception.
932         // We need to subtract that child from m_completionCountdown, or the parent will never complete.
933         internal void DisregardChild()
934         {
935             Debug.Assert(Task.InternalCurrent == this, "Task.DisregardChild(): Called from an external context");
936
937             var props = EnsureContingentPropertiesInitialized();
938             Debug.Assert(props.m_completionCountdown >= 2, "Task.DisregardChild(): Expected parent count to be >= 2");
939             Interlocked.Decrement(ref props.m_completionCountdown);
940         }
941
942         /// <summary>
943         /// Starts the <see cref="Task"/>, scheduling it for execution to the current <see
944         /// cref="System.Threading.Tasks.TaskScheduler">TaskScheduler</see>.
945         /// </summary>
946         /// <remarks>
947         /// A task may only be started and run only once.  Any attempts to schedule a task a second time
948         /// will result in an exception.
949         /// </remarks>
950         /// <exception cref="InvalidOperationException">
951         /// The <see cref="Task"/> is not in a valid state to be started. It may have already been started,
952         /// executed, or canceled, or it may have been created in a manner that doesn't support direct
953         /// scheduling.
954         /// </exception>
955         public void Start()
956         {
957             Start(TaskScheduler.Current);
958         }
959
960         /// <summary>
961         /// Starts the <see cref="Task"/>, scheduling it for execution to the specified <see
962         /// cref="System.Threading.Tasks.TaskScheduler">TaskScheduler</see>.
963         /// </summary>
964         /// <remarks>
965         /// A task may only be started and run only once. Any attempts to schedule a task a second time will
966         /// result in an exception.
967         /// </remarks>
968         /// <param name="scheduler">
969         /// The <see cref="System.Threading.Tasks.TaskScheduler">TaskScheduler</see> with which to associate
970         /// and execute this task.
971         /// </param>
972         /// <exception cref="ArgumentNullException">
973         /// The <paramref name="scheduler"/> argument is null.
974         /// </exception>
975         /// <exception cref="InvalidOperationException">
976         /// The <see cref="Task"/> is not in a valid state to be started. It may have already been started,
977         /// executed, or canceled, or it may have been created in a manner that doesn't support direct
978         /// scheduling.
979         /// </exception>
980         public void Start(TaskScheduler scheduler)
981         {
982             // Read the volatile m_stateFlags field once and cache it for subsequent operations
983             int flags = m_stateFlags;
984
985             // Need to check this before (m_action == null) because completed tasks will
986             // set m_action to null.  We would want to know if this is the reason that m_action == null.
987             if (IsCompletedMethod(flags))
988             {
989                 ThrowHelper.ThrowInvalidOperationException(ExceptionResource.Task_Start_TaskCompleted);
990             }
991
992             if (scheduler == null)
993             {
994                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.scheduler);
995             }
996
997             var options = OptionsMethod(flags);
998             if ((options & (TaskCreationOptions)InternalTaskOptions.PromiseTask) != 0)
999             {
1000                 ThrowHelper.ThrowInvalidOperationException(ExceptionResource.Task_Start_Promise);
1001             }
1002             if ((options & (TaskCreationOptions)InternalTaskOptions.ContinuationTask) != 0)
1003             {
1004                 ThrowHelper.ThrowInvalidOperationException(ExceptionResource.Task_Start_ContinuationTask);
1005             }
1006
1007             // Make sure that Task only gets started once.  Or else throw an exception.
1008             if (Interlocked.CompareExchange(ref m_taskScheduler, scheduler, null) != null)
1009             {
1010                 ThrowHelper.ThrowInvalidOperationException(ExceptionResource.Task_Start_AlreadyStarted);
1011             }
1012
1013             ScheduleAndStart(true);
1014         }
1015
1016         /// <summary>
1017         /// Runs the <see cref="Task"/> synchronously on the current <see
1018         /// cref="System.Threading.Tasks.TaskScheduler">TaskScheduler</see>.
1019         /// </summary>
1020         /// <remarks>
1021         /// <para>
1022         /// A task may only be started and run only once. Any attempts to schedule a task a second time will
1023         /// result in an exception.
1024         /// </para>
1025         /// <para>
1026         /// Tasks executed with <see cref="RunSynchronously()"/> will be associated with the current <see
1027         /// cref="System.Threading.Tasks.TaskScheduler">TaskScheduler</see>.
1028         /// </para>
1029         /// <para>
1030         /// If the target scheduler does not support running this Task on the current thread, the Task will
1031         /// be scheduled for execution on the scheduler, and the current thread will block until the
1032         /// Task has completed execution.
1033         /// </para>
1034         /// </remarks>
1035         /// <exception cref="InvalidOperationException">
1036         /// The <see cref="Task"/> is not in a valid state to be started. It may have already been started,
1037         /// executed, or canceled, or it may have been created in a manner that doesn't support direct
1038         /// scheduling.
1039         /// </exception>
1040         public void RunSynchronously()
1041         {
1042             InternalRunSynchronously(TaskScheduler.Current, waitForCompletion: true);
1043         }
1044
1045         /// <summary>
1046         /// Runs the <see cref="Task"/> synchronously on the <see
1047         /// cref="System.Threading.Tasks.TaskScheduler">scheduler</see> provided.
1048         /// </summary>
1049         /// <remarks>
1050         /// <para>
1051         /// A task may only be started and run only once. Any attempts to schedule a task a second time will
1052         /// result in an exception.
1053         /// </para>
1054         /// <para>
1055         /// If the target scheduler does not support running this Task on the current thread, the Task will
1056         /// be scheduled for execution on the scheduler, and the current thread will block until the
1057         /// Task has completed execution.
1058         /// </para>
1059         /// </remarks>
1060         /// <exception cref="InvalidOperationException">
1061         /// The <see cref="Task"/> is not in a valid state to be started. It may have already been started,
1062         /// executed, or canceled, or it may have been created in a manner that doesn't support direct
1063         /// scheduling.
1064         /// </exception>
1065         /// <exception cref="ArgumentNullException">The <paramref name="scheduler"/> parameter
1066         /// is null.</exception>
1067         /// <param name="scheduler">The scheduler on which to attempt to run this task inline.</param>
1068         public void RunSynchronously(TaskScheduler scheduler)
1069         {
1070             if (scheduler == null)
1071             {
1072                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.scheduler);
1073             }
1074
1075             InternalRunSynchronously(scheduler, waitForCompletion: true);
1076         }
1077
1078         //
1079         // Internal version of RunSynchronously that allows not waiting for completion.
1080         // 
1081         internal void InternalRunSynchronously(TaskScheduler scheduler, bool waitForCompletion)
1082         {
1083             Debug.Assert(scheduler != null, "Task.InternalRunSynchronously(): null TaskScheduler");
1084
1085             // Read the volatile m_stateFlags field once and cache it for subsequent operations
1086             int flags = m_stateFlags;
1087
1088             // Can't call this method on a continuation task
1089             var options = OptionsMethod(flags);
1090             if ((options & (TaskCreationOptions)InternalTaskOptions.ContinuationTask) != 0)
1091             {
1092                 ThrowHelper.ThrowInvalidOperationException(ExceptionResource.Task_RunSynchronously_Continuation);
1093             }
1094
1095             // Can't call this method on a promise-style task
1096             if ((options & (TaskCreationOptions)InternalTaskOptions.PromiseTask) != 0)
1097             {
1098                 ThrowHelper.ThrowInvalidOperationException(ExceptionResource.Task_RunSynchronously_Promise);
1099             }
1100
1101             // Can't call this method on a task that has already completed
1102             if (IsCompletedMethod(flags))
1103             {
1104                 ThrowHelper.ThrowInvalidOperationException(ExceptionResource.Task_RunSynchronously_TaskCompleted);
1105             }
1106
1107             // Make sure that Task only gets started once.  Or else throw an exception.
1108             if (Interlocked.CompareExchange(ref m_taskScheduler, scheduler, null) != null)
1109             {
1110                 ThrowHelper.ThrowInvalidOperationException(ExceptionResource.Task_RunSynchronously_AlreadyStarted);
1111             }
1112
1113             // execute only if we successfully cancel when concurrent cancel attempts are made.
1114             // otherwise throw an exception, because we've been canceled.
1115             if (MarkStarted())
1116             {
1117                 bool taskQueued = false;
1118                 try
1119                 {
1120                     // We wrap TryRunInline() in a try/catch block and move an excepted task to Faulted here,
1121                     // but not in Wait()/WaitAll()/FastWaitAll().  Here, we know for sure that the
1122                     // task will not be subsequently scheduled (assuming that the scheduler adheres
1123                     // to the guideline that an exception implies that no state change took place),
1124                     // so it is safe to catch the exception and move the task to a final state.  The
1125                     // same cannot be said for Wait()/WaitAll()/FastWaitAll().
1126                     if (!scheduler.TryRunInline(this, false))
1127                     {
1128                         scheduler.InternalQueueTask(this);
1129                         taskQueued = true; // only mark this after successfully queuing the task.
1130                     }
1131
1132                     // A successful TryRunInline doesn't guarantee completion, as there may be unfinished children.
1133                     // Also if we queued the task above, the task may not be done yet.
1134                     if (waitForCompletion && !IsCompleted)
1135                     {
1136                         SpinThenBlockingWait(Timeout.Infinite, default(CancellationToken));
1137                     }
1138                 }
1139                 catch (Exception e)
1140                 {
1141                     // we 1) either received an unexpected exception originating from a custom scheduler, which needs to be wrapped in a TSE and thrown
1142                     //    2) or a a ThreadAbortException, which we need to skip here, because it would already have been handled in Task.Execute
1143                     if (!taskQueued && !(e is ThreadAbortException))
1144                     {
1145                         // We had a problem with TryRunInline() or QueueTask().  
1146                         // Record the exception, marking ourselves as Completed/Faulted.
1147                         TaskSchedulerException tse = new TaskSchedulerException(e);
1148                         AddException(tse);
1149                         Finish(false);
1150
1151                         // Mark ourselves as "handled" to avoid crashing the finalizer thread if the caller neglects to
1152                         // call Wait() on this task.
1153                         // m_contingentProperties.m_exceptionsHolder *should* already exist after AddException()
1154                         Debug.Assert(
1155                             (m_contingentProperties != null) &&
1156                             (m_contingentProperties.m_exceptionsHolder != null) &&
1157                             (m_contingentProperties.m_exceptionsHolder.ContainsFaultList),
1158                             "Task.InternalRunSynchronously(): Expected m_contingentProperties.m_exceptionsHolder to exist " +
1159                             "and to have faults recorded.");
1160                         m_contingentProperties.m_exceptionsHolder.MarkAsHandled(false);
1161
1162                         // And re-throw.
1163                         throw tse;
1164                     }
1165                     // We had a problem with waiting or this is a thread abort.  Just re-throw.
1166                     else throw;
1167                 }
1168             }
1169             else
1170             {
1171                 Debug.Assert((m_stateFlags & TASK_STATE_CANCELED) != 0, "Task.RunSynchronously: expected TASK_STATE_CANCELED to be set");
1172                 // Can't call this method on canceled task.
1173                 ThrowHelper.ThrowInvalidOperationException(ExceptionResource.Task_RunSynchronously_TaskCompleted);
1174             }
1175         }
1176
1177
1178         ////
1179         //// Helper methods for Factory StartNew methods.
1180         ////
1181
1182
1183         // Implicitly converts action to object and handles the meat of the StartNew() logic.
1184         internal static Task InternalStartNew(
1185             Task creatingTask, Delegate action, object state, CancellationToken cancellationToken, TaskScheduler scheduler,
1186             TaskCreationOptions options, InternalTaskOptions internalOptions)
1187         {
1188             // Validate arguments.
1189             if (scheduler == null)
1190             {
1191                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.scheduler);
1192             }
1193
1194             // Create and schedule the task. This throws an InvalidOperationException if already shut down.
1195             // Here we add the InternalTaskOptions.QueuedByRuntime to the internalOptions, so that TaskConstructorCore can skip the cancellation token registration
1196             Task t = new Task(action, state, creatingTask, cancellationToken, options, internalOptions | InternalTaskOptions.QueuedByRuntime, scheduler);
1197
1198             t.ScheduleAndStart(false);
1199             return t;
1200         }
1201
1202         /// <summary>
1203         /// Gets a unique ID for a <see cref="Task">Task</see> or task continuation instance.
1204         /// </summary>
1205         internal static int NewId()
1206         {
1207             int newId = 0;
1208             // We need to repeat if Interlocked.Increment wraps around and returns 0.
1209             // Otherwise next time this task's Id is queried it will get a new value
1210             do
1211             {
1212                 newId = Interlocked.Increment(ref s_taskIdCounter);
1213             }
1214             while (newId == 0);
1215             TplEtwProvider.Log.NewID(newId);
1216             return newId;
1217         }
1218
1219
1220         /////////////
1221         // properties
1222
1223         /// <summary>
1224         /// Gets a unique ID for this <see cref="Task">Task</see> instance.
1225         /// </summary>
1226         /// <remarks>
1227         /// Task IDs are assigned on-demand and do not necessarily represent the order in the which Task
1228         /// instances were created.
1229         /// </remarks>
1230         public int Id
1231         {
1232             get
1233             {
1234                 if (m_taskId == 0)
1235                 {
1236                     int newId = NewId();
1237                     Interlocked.CompareExchange(ref m_taskId, newId, 0);
1238                 }
1239
1240                 return m_taskId;
1241             }
1242         }
1243
1244         /// <summary>
1245         /// Returns the unique ID of the currently executing <see cref="Task">Task</see>.
1246         /// </summary>
1247         public static int? CurrentId
1248         {
1249             get
1250             {
1251                 Task currentTask = InternalCurrent;
1252                 if (currentTask != null)
1253                     return currentTask.Id;
1254                 else
1255                     return null;
1256             }
1257         }
1258
1259         /// <summary>
1260         /// Gets the <see cref="Task">Task</see> instance currently executing, or
1261         /// null if none exists.
1262         /// </summary>
1263         internal static Task InternalCurrent
1264         {
1265             get { return t_currentTask; }
1266         }
1267
1268         /// <summary>
1269         /// Gets the Task instance currently executing if the specified creation options
1270         /// contain AttachedToParent.
1271         /// </summary>
1272         /// <param name="options">The options to check.</param>
1273         /// <returns>The current task if there is one and if AttachToParent is in the options; otherwise, null.</returns>
1274         internal static Task InternalCurrentIfAttached(TaskCreationOptions creationOptions)
1275         {
1276             return (creationOptions & TaskCreationOptions.AttachedToParent) != 0 ? InternalCurrent : null;
1277         }
1278
1279         /// <summary>
1280         /// Gets the StackGuard object assigned to the current thread.
1281         /// </summary>
1282         internal static StackGuard CurrentStackGuard
1283         {
1284             get
1285             {
1286                 StackGuard sg = t_stackGuard;
1287                 if (sg == null)
1288                 {
1289                     t_stackGuard = sg = new StackGuard();
1290                 }
1291                 return sg;
1292             }
1293         }
1294
1295
1296         /// <summary>
1297         /// Gets the <see cref="T:System.AggregateException">Exception</see> that caused the <see
1298         /// cref="Task">Task</see> to end prematurely. If the <see
1299         /// cref="Task">Task</see> completed successfully or has not yet thrown any
1300         /// exceptions, this will return null.
1301         /// </summary>
1302         /// <remarks>
1303         /// Tasks that throw unhandled exceptions store the resulting exception and propagate it wrapped in a
1304         /// <see cref="System.AggregateException"/> in calls to <see cref="Wait()">Wait</see>
1305         /// or in accesses to the <see cref="Exception"/> property.  Any exceptions not observed by the time
1306         /// the Task instance is garbage collected will be propagated on the finalizer thread.
1307         /// </remarks>
1308         public AggregateException Exception
1309         {
1310             get
1311             {
1312                 AggregateException e = null;
1313
1314                 // If you're faulted, retrieve the exception(s)
1315                 if (IsFaulted) e = GetExceptions(false);
1316
1317                 // Only return an exception in faulted state (skip manufactured exceptions)
1318                 // A "benevolent" race condition makes it possible to return null when IsFaulted is
1319                 // true (i.e., if IsFaulted is set just after the check to IsFaulted above).
1320                 Debug.Assert((e == null) || IsFaulted, "Task.Exception_get(): returning non-null value when not Faulted");
1321
1322                 return e;
1323             }
1324         }
1325
1326         /// <summary>
1327         /// Gets the <see cref="T:System.Threading.Tasks.TaskStatus">TaskStatus</see> of this Task. 
1328         /// </summary>
1329         public TaskStatus Status
1330         {
1331             get
1332             {
1333                 TaskStatus rval;
1334
1335                 // get a cached copy of the state flags.  This should help us
1336                 // to get a consistent view of the flags if they are changing during the
1337                 // execution of this method.
1338                 int sf = m_stateFlags;
1339
1340                 if ((sf & TASK_STATE_FAULTED) != 0) rval = TaskStatus.Faulted;
1341                 else if ((sf & TASK_STATE_CANCELED) != 0) rval = TaskStatus.Canceled;
1342                 else if ((sf & TASK_STATE_RAN_TO_COMPLETION) != 0) rval = TaskStatus.RanToCompletion;
1343                 else if ((sf & TASK_STATE_WAITING_ON_CHILDREN) != 0) rval = TaskStatus.WaitingForChildrenToComplete;
1344                 else if ((sf & TASK_STATE_DELEGATE_INVOKED) != 0) rval = TaskStatus.Running;
1345                 else if ((sf & TASK_STATE_STARTED) != 0) rval = TaskStatus.WaitingToRun;
1346                 else if ((sf & TASK_STATE_WAITINGFORACTIVATION) != 0) rval = TaskStatus.WaitingForActivation;
1347                 else rval = TaskStatus.Created;
1348
1349                 return rval;
1350             }
1351         }
1352
1353         /// <summary>
1354         /// Gets whether this <see cref="Task">Task</see> instance has completed
1355         /// execution due to being canceled.
1356         /// </summary>
1357         /// <remarks>
1358         /// A <see cref="Task">Task</see> will complete in Canceled state either if its <see cref="CancellationToken">CancellationToken</see> 
1359         /// was marked for cancellation before the task started executing, or if the task acknowledged the cancellation request on 
1360         /// its already signaled CancellationToken by throwing an 
1361         /// <see cref="System.OperationCanceledException">OperationCanceledException</see> that bears the same 
1362         /// <see cref="System.Threading.CancellationToken">CancellationToken</see>.
1363         /// </remarks>
1364         public bool IsCanceled
1365         {
1366             get
1367             {
1368                 // Return true if canceled bit is set and faulted bit is not set
1369                 return (m_stateFlags & (TASK_STATE_CANCELED | TASK_STATE_FAULTED)) == TASK_STATE_CANCELED;
1370             }
1371         }
1372
1373         /// <summary>
1374         /// Returns true if this task has a cancellation token and it was signaled.
1375         /// To be used internally in execute entry codepaths.
1376         /// </summary>
1377         internal bool IsCancellationRequested
1378         {
1379             get
1380             {
1381                 // check both the internal cancellation request flag and the CancellationToken attached to this task
1382                 var props = Volatile.Read(ref m_contingentProperties);
1383                 return props != null &&
1384                     (props.m_internalCancellationRequested == CANCELLATION_REQUESTED ||
1385                      props.m_cancellationToken.IsCancellationRequested);
1386             }
1387         }
1388
1389         /// <summary>
1390         /// Ensures that the contingent properties field has been initialized.
1391         /// ASSUMES THAT m_stateFlags IS ALREADY SET!
1392         /// </summary>
1393         /// <returns>The initialized contingent properties object.</returns>
1394         internal ContingentProperties EnsureContingentPropertiesInitialized()
1395         {
1396             return LazyInitializer.EnsureInitialized(ref m_contingentProperties, () => new ContingentProperties());
1397         }
1398
1399         /// <summary>
1400         /// Without synchronization, ensures that the contingent properties field has been initialized.
1401         /// ASSUMES THAT m_stateFlags IS ALREADY SET!
1402         /// </summary>
1403         /// <returns>The initialized contingent properties object.</returns>
1404         internal ContingentProperties EnsureContingentPropertiesInitializedUnsafe()
1405         {
1406             return m_contingentProperties ?? (m_contingentProperties = new ContingentProperties());
1407         }
1408
1409         /// <summary>
1410         /// This internal property provides access to the CancellationToken that was set on the task 
1411         /// when it was constructed.
1412         /// </summary>
1413         internal CancellationToken CancellationToken
1414         {
1415             get
1416             {
1417                 var props = Volatile.Read(ref m_contingentProperties);
1418                 return (props == null) ? default(CancellationToken) : props.m_cancellationToken;
1419             }
1420         }
1421
1422         /// <summary>
1423         /// Gets whether this <see cref="Task"/> threw an OperationCanceledException while its CancellationToken was signaled.
1424         /// </summary>
1425         internal bool IsCancellationAcknowledged
1426         {
1427             get { return (m_stateFlags & TASK_STATE_CANCELLATIONACKNOWLEDGED) != 0; }
1428         }
1429
1430
1431         /// <summary>
1432         /// Gets whether this <see cref="Task">Task</see> has completed.
1433         /// </summary>
1434         /// <remarks>
1435         /// <see cref="IsCompleted"/> will return true when the Task is in one of the three
1436         /// final states: <see cref="System.Threading.Tasks.TaskStatus.RanToCompletion">RanToCompletion</see>,
1437         /// <see cref="System.Threading.Tasks.TaskStatus.Faulted">Faulted</see>, or
1438         /// <see cref="System.Threading.Tasks.TaskStatus.Canceled">Canceled</see>.
1439         /// </remarks>
1440         public bool IsCompleted
1441         {
1442             get
1443             {
1444                 int stateFlags = m_stateFlags; // enable inlining of IsCompletedMethod by "cast"ing away the volatility
1445                 return IsCompletedMethod(stateFlags);
1446             }
1447         }
1448
1449         // Similar to IsCompleted property, but allows for the use of a cached flags value
1450         // rather than reading the volatile m_stateFlags field.
1451         private static bool IsCompletedMethod(int flags)
1452         {
1453             return (flags & TASK_STATE_COMPLETED_MASK) != 0;
1454         }
1455
1456         public bool IsCompletedSuccessfully
1457         {
1458             get { return (m_stateFlags & TASK_STATE_COMPLETED_MASK) == TASK_STATE_RAN_TO_COMPLETION; }
1459         }
1460
1461         /// <summary>
1462         /// Gets the <see cref="T:System.Threading.Tasks.TaskCreationOptions">TaskCreationOptions</see> used
1463         /// to create this task.
1464         /// </summary>
1465         public TaskCreationOptions CreationOptions
1466         {
1467             get { return Options & (TaskCreationOptions)(~InternalTaskOptions.InternalOptionsMask); }
1468         }
1469
1470         /// <summary>
1471         /// Gets a <see cref="T:System.Threading.WaitHandle"/> that can be used to wait for the task to
1472         /// complete.
1473         /// </summary>
1474         /// <remarks>
1475         /// Using the wait functionality provided by <see cref="Wait()"/>
1476         /// should be preferred over using <see cref="IAsyncResult.AsyncWaitHandle"/> for similar
1477         /// functionality.
1478         /// </remarks>
1479         /// <exception cref="T:System.ObjectDisposedException">
1480         /// The <see cref="Task"/> has been disposed.
1481         /// </exception>
1482         WaitHandle IAsyncResult.AsyncWaitHandle
1483         {
1484             // Although a slim event is used internally to avoid kernel resource allocation, this function
1485             // forces allocation of a true WaitHandle when called.
1486             get
1487             {
1488                 bool isDisposed = (m_stateFlags & TASK_STATE_DISPOSED) != 0;
1489                 if (isDisposed)
1490                 {
1491                     ThrowHelper.ThrowObjectDisposedException(ExceptionResource.Task_ThrowIfDisposed);
1492                 }
1493                 return CompletedEvent.WaitHandle;
1494             }
1495         }
1496
1497         /// <summary>
1498         /// Gets the state object supplied when the <see cref="Task">Task</see> was created,
1499         /// or null if none was supplied.
1500         /// </summary>
1501         public object AsyncState
1502         {
1503             get { return m_stateObject; }
1504         }
1505
1506         /// <summary>
1507         /// Gets an indication of whether the asynchronous operation completed synchronously.
1508         /// </summary>
1509         /// <value>true if the asynchronous operation completed synchronously; otherwise, false.</value>
1510         bool IAsyncResult.CompletedSynchronously
1511         {
1512             get
1513             {
1514                 return false;
1515             }
1516         }
1517
1518         /// <summary>
1519         /// Provides access to the TaskScheduler responsible for executing this Task.
1520         /// </summary>
1521         internal TaskScheduler ExecutingTaskScheduler
1522         {
1523             get { return m_taskScheduler; }
1524         }
1525
1526         /// <summary>
1527         /// Provides access to factory methods for creating <see cref="Task"/> and <see cref="Task{TResult}"/> instances.
1528         /// </summary>
1529         /// <remarks>
1530         /// The factory returned from <see cref="Factory"/> is a default instance
1531         /// of <see cref="System.Threading.Tasks.TaskFactory"/>, as would result from using
1532         /// the default constructor on TaskFactory.
1533         /// </remarks>
1534         public static TaskFactory Factory { get; } = new TaskFactory();
1535
1536         /// <summary>Gets a task that's already been completed successfully.</summary>
1537         public static Task CompletedTask { get; } = new Task(false, (TaskCreationOptions)InternalTaskOptions.DoNotDispose, default(CancellationToken));
1538
1539         /// <summary>
1540         /// Provides an event that can be used to wait for completion.
1541         /// Only called by IAsyncResult.AsyncWaitHandle, which means that we really do need to instantiate a completion event.
1542         /// </summary>
1543         internal ManualResetEventSlim CompletedEvent
1544         {
1545             get
1546             {
1547                 var contingentProps = EnsureContingentPropertiesInitialized();
1548                 if (contingentProps.m_completionEvent == null)
1549                 {
1550                     bool wasCompleted = IsCompleted;
1551                     ManualResetEventSlim newMre = new ManualResetEventSlim(wasCompleted);
1552                     if (Interlocked.CompareExchange(ref contingentProps.m_completionEvent, newMre, null) != null)
1553                     {
1554                         // Someone else already set the value, so we will just close the event right away.
1555                         newMre.Dispose();
1556                     }
1557                     else if (!wasCompleted && IsCompleted)
1558                     {
1559                         // We published the event as unset, but the task has subsequently completed.
1560                         // Set the event's state properly so that callers don't deadlock.
1561                         newMre.Set();
1562                     }
1563                 }
1564
1565                 return contingentProps.m_completionEvent;
1566             }
1567         }
1568
1569
1570         /// <summary>
1571         /// The property formerly known as IsFaulted.
1572         /// </summary>
1573         internal bool ExceptionRecorded
1574         {
1575             get
1576             {
1577                 var props = Volatile.Read(ref m_contingentProperties);
1578                 return (props != null) && (props.m_exceptionsHolder != null) && (props.m_exceptionsHolder.ContainsFaultList);
1579             }
1580         }
1581
1582         /// <summary>
1583         /// Gets whether the <see cref="Task"/> completed due to an unhandled exception.
1584         /// </summary>
1585         /// <remarks>
1586         /// If <see cref="IsFaulted"/> is true, the Task's <see cref="Status"/> will be equal to
1587         /// <see cref="System.Threading.Tasks.TaskStatus.Faulted">TaskStatus.Faulted</see>, and its
1588         /// <see cref="Exception"/> property will be non-null.
1589         /// </remarks>
1590         public bool IsFaulted
1591         {
1592             get
1593             {
1594                 // Faulted is "king" -- if that bit is present (regardless of other bits), we are faulted.
1595                 return ((m_stateFlags & TASK_STATE_FAULTED) != 0);
1596             }
1597         }
1598
1599         /// <summary>
1600         /// The captured execution context for the current task to run inside
1601         /// If the TASK_STATE_EXECUTIONCONTEXT_IS_NULL flag is set, this means ExecutionContext.Capture returned null, otherwise
1602         /// If the captured context is the default, nothing is saved, otherwise the m_contingentProperties inflates to save the context
1603         /// </summary>
1604         internal ExecutionContext CapturedContext
1605         {
1606             get
1607             {
1608                 if ((m_stateFlags & TASK_STATE_EXECUTIONCONTEXT_IS_NULL) == TASK_STATE_EXECUTIONCONTEXT_IS_NULL)
1609                 {
1610                     return null;
1611                 }
1612                 else
1613                 {
1614                     return m_contingentProperties?.m_capturedContext ?? ExecutionContext.Default;
1615                 }
1616             }
1617             set
1618             {
1619                 // There is no need to atomically set this bit because this set() method is only called during construction, and therefore there should be no contending accesses to m_stateFlags
1620                 if (value == null)
1621                 {
1622                     m_stateFlags |= TASK_STATE_EXECUTIONCONTEXT_IS_NULL;
1623                 }
1624                 else if (value != ExecutionContext.Default) // not the default context, then inflate the contingent properties and set it
1625                 {
1626                     EnsureContingentPropertiesInitializedUnsafe().m_capturedContext = value;
1627                 }
1628                 //else do nothing, this is the default context
1629             }
1630         }
1631
1632         /////////////
1633         // methods
1634
1635
1636         /// <summary>
1637         /// Disposes the <see cref="Task"/>, releasing all of its unmanaged resources.  
1638         /// </summary>
1639         /// <remarks>
1640         /// Unlike most of the members of <see cref="Task"/>, this method is not thread-safe.
1641         /// Also, <see cref="Dispose()"/> may only be called on a <see cref="Task"/> that is in one of
1642         /// the final states: <see cref="System.Threading.Tasks.TaskStatus.RanToCompletion">RanToCompletion</see>,
1643         /// <see cref="System.Threading.Tasks.TaskStatus.Faulted">Faulted</see>, or
1644         /// <see cref="System.Threading.Tasks.TaskStatus.Canceled">Canceled</see>.
1645         /// </remarks>
1646         /// <exception cref="T:System.InvalidOperationException">
1647         /// The exception that is thrown if the <see cref="Task"/> is not in 
1648         /// one of the final states: <see cref="System.Threading.Tasks.TaskStatus.RanToCompletion">RanToCompletion</see>,
1649         /// <see cref="System.Threading.Tasks.TaskStatus.Faulted">Faulted</see>, or
1650         /// <see cref="System.Threading.Tasks.TaskStatus.Canceled">Canceled</see>.
1651         /// </exception>        
1652         public void Dispose()
1653         {
1654             Dispose(true);
1655             GC.SuppressFinalize(this);
1656         }
1657
1658         /// <summary>
1659         /// Disposes the <see cref="Task"/>, releasing all of its unmanaged resources.  
1660         /// </summary>
1661         /// <param name="disposing">
1662         /// A Boolean value that indicates whether this method is being called due to a call to <see
1663         /// cref="Dispose()"/>.
1664         /// </param>
1665         /// <remarks>
1666         /// Unlike most of the members of <see cref="Task"/>, this method is not thread-safe.
1667         /// </remarks>
1668         protected virtual void Dispose(bool disposing)
1669         {
1670             if (disposing)
1671             {
1672                 // Dispose is a nop if this task was created with the DoNotDispose internal option.
1673                 // This is done before the completed check, because if we're not touching any 
1674                 // state on the task, it's ok for it to happen before completion.
1675                 if ((Options & (TaskCreationOptions)InternalTaskOptions.DoNotDispose) != 0)
1676                 {
1677                     return;
1678                 }
1679
1680                 // Task must be completed to dispose
1681                 if (!IsCompleted)
1682                 {
1683                     ThrowHelper.ThrowInvalidOperationException(ExceptionResource.Task_Dispose_NotCompleted);
1684                 }
1685
1686                 // Dispose of the underlying completion event if it exists
1687                 var cp = Volatile.Read(ref m_contingentProperties);
1688                 if (cp != null)
1689                 {
1690                     // Make a copy to protect against racing Disposes.
1691                     // If we wanted to make this a bit safer, we could use an interlocked here,
1692                     // but we state that Dispose is not thread safe.
1693                     var ev = cp.m_completionEvent;
1694                     if (ev != null)
1695                     {
1696                         // Null out the completion event in contingent props; we'll use our copy from here on out
1697                         cp.m_completionEvent = null;
1698
1699                         // In the unlikely event that our completion event is inflated but not yet signaled,
1700                         // go ahead and signal the event.  If you dispose of an unsignaled MRES, then any waiters
1701                         // will deadlock; an ensuing Set() will not wake them up.  In the event of an AppDomainUnload,
1702                         // there is no guarantee that anyone else is going to signal the event, and it does no harm to 
1703                         // call Set() twice on m_completionEvent.
1704                         if (!ev.IsSet) ev.Set();
1705
1706                         // Finally, dispose of the event
1707                         ev.Dispose();
1708                     }
1709                 }
1710             }
1711
1712             // We OR the flags to indicate the object has been disposed. The task
1713             // has already completed at this point, and the only conceivable race condition would
1714             // be with the unsetting of the TASK_STATE_WAIT_COMPLETION_NOTIFICATION flag, which
1715             // is extremely unlikely and also benign.  (Worst case: we hit a breakpoint
1716             // twice instead of once in the debugger.  Weird, but not lethal.)
1717             m_stateFlags |= TASK_STATE_DISPOSED;
1718         }
1719
1720         /////////////
1721         // internal helpers
1722
1723
1724         /// <summary>
1725         /// Schedules the task for execution.
1726         /// </summary>
1727         /// <param name="needsProtection">If true, TASK_STATE_STARTED bit is turned on in
1728         /// an atomic fashion, making sure that TASK_STATE_CANCELED does not get set
1729         /// underneath us.  If false, TASK_STATE_STARTED bit is OR-ed right in.  This
1730         /// allows us to streamline things a bit for StartNew(), where competing cancellations
1731         /// are not a problem.</param>
1732         internal void ScheduleAndStart(bool needsProtection)
1733         {
1734             Debug.Assert(m_taskScheduler != null, "expected a task scheduler to have been selected");
1735             Debug.Assert((m_stateFlags & TASK_STATE_STARTED) == 0, "task has already started");
1736
1737             // Set the TASK_STATE_STARTED bit
1738             if (needsProtection)
1739             {
1740                 if (!MarkStarted())
1741                 {
1742                     // A cancel has snuck in before we could get started.  Quietly exit.
1743                     return;
1744                 }
1745             }
1746             else
1747             {
1748                 m_stateFlags |= TASK_STATE_STARTED;
1749             }
1750
1751             if (s_asyncDebuggingEnabled)
1752             {
1753                 AddToActiveTasks(this);
1754             }
1755
1756             if (AsyncCausalityTracer.LoggingOn && (Options & (TaskCreationOptions)InternalTaskOptions.ContinuationTask) == 0)
1757             {
1758                 //For all other task than TaskContinuations we want to log. TaskContinuations log in their constructor
1759                 AsyncCausalityTracer.TraceOperationCreation(CausalityTraceLevel.Required, this.Id, "Task: " + m_action.Method.Name, 0);
1760             }
1761
1762
1763             try
1764             {
1765                 // Queue to the indicated scheduler.
1766                 m_taskScheduler.InternalQueueTask(this);
1767             }
1768             catch (ThreadAbortException tae)
1769             {
1770                 AddException(tae);
1771                 FinishThreadAbortedTask(delegateRan: false);
1772             }
1773             catch (Exception e)
1774             {
1775                 // The scheduler had a problem queueing this task.  Record the exception, leaving this task in
1776                 // a Faulted state.
1777                 TaskSchedulerException tse = new TaskSchedulerException(e);
1778                 AddException(tse);
1779                 Finish(false);
1780
1781                 // Now we need to mark ourselves as "handled" to avoid crashing the finalizer thread if we are called from StartNew(),
1782                 // because the exception is either propagated outside directly, or added to an enclosing parent. However we won't do this for
1783                 // continuation tasks, because in that case we internally eat the exception and therefore we need to make sure the user does
1784                 // later observe it explicitly or see it on the finalizer.
1785
1786                 if ((Options & (TaskCreationOptions)InternalTaskOptions.ContinuationTask) == 0)
1787                 {
1788                     // m_contingentProperties.m_exceptionsHolder *should* already exist after AddException()
1789                     Debug.Assert(
1790                         (m_contingentProperties != null) &&
1791                         (m_contingentProperties.m_exceptionsHolder != null) &&
1792                         (m_contingentProperties.m_exceptionsHolder.ContainsFaultList),
1793                             "Task.ScheduleAndStart(): Expected m_contingentProperties.m_exceptionsHolder to exist " +
1794                             "and to have faults recorded.");
1795
1796                     m_contingentProperties.m_exceptionsHolder.MarkAsHandled(false);
1797                 }
1798                 // re-throw the exception wrapped as a TaskSchedulerException.
1799                 throw tse;
1800             }
1801         }
1802
1803         /// <summary>
1804         /// Adds an exception to the list of exceptions this task has thrown.
1805         /// </summary>
1806         /// <param name="exceptionObject">An object representing either an Exception or a collection of Exceptions.</param>
1807         internal void AddException(object exceptionObject)
1808         {
1809             Debug.Assert(exceptionObject != null, "Task.AddException: Expected a non-null exception object");
1810             AddException(exceptionObject, representsCancellation: false);
1811         }
1812
1813         /// <summary>
1814         /// Adds an exception to the list of exceptions this task has thrown.
1815         /// </summary>
1816         /// <param name="exceptionObject">An object representing either an Exception or a collection of Exceptions.</param>
1817         /// <param name="representsCancellation">Whether the exceptionObject is an OperationCanceledException representing cancellation.</param>
1818         internal void AddException(object exceptionObject, bool representsCancellation)
1819         {
1820             Debug.Assert(exceptionObject != null, "Task.AddException: Expected a non-null exception object");
1821
1822 #if DEBUG
1823             var eoAsException = exceptionObject as Exception;
1824             var eoAsEnumerableException = exceptionObject as IEnumerable<Exception>;
1825             var eoAsEdi = exceptionObject as ExceptionDispatchInfo;
1826             var eoAsEnumerableEdi = exceptionObject as IEnumerable<ExceptionDispatchInfo>;
1827
1828             Debug.Assert(
1829                 eoAsException != null || eoAsEnumerableException != null || eoAsEdi != null || eoAsEnumerableEdi != null,
1830                 "Task.AddException: Expected an Exception, ExceptionDispatchInfo, or an IEnumerable<> of one of those");
1831
1832             var eoAsOce = exceptionObject as OperationCanceledException;
1833
1834             Debug.Assert(
1835                 !representsCancellation ||
1836                 eoAsOce != null ||
1837                 (eoAsEdi != null && eoAsEdi.SourceException is OperationCanceledException),
1838                 "representsCancellation should be true only if an OCE was provided.");
1839 #endif
1840
1841             //
1842             // WARNING: A great deal of care went into ensuring that
1843             // AddException() and GetExceptions() are never called
1844             // simultaneously.  See comment at start of GetExceptions().
1845             //
1846
1847             // Lazily initialize the holder, ensuring only one thread wins.
1848             var props = EnsureContingentPropertiesInitialized();
1849             if (props.m_exceptionsHolder == null)
1850             {
1851                 TaskExceptionHolder holder = new TaskExceptionHolder(this);
1852                 if (Interlocked.CompareExchange(ref props.m_exceptionsHolder, holder, null) != null)
1853                 {
1854                     // If someone else already set the value, suppress finalization.
1855                     holder.MarkAsHandled(false);
1856                 }
1857             }
1858
1859             lock (props)
1860             {
1861                 props.m_exceptionsHolder.Add(exceptionObject, representsCancellation);
1862             }
1863         }
1864
1865         /// <summary>
1866         /// Returns a list of exceptions by aggregating the holder's contents. Or null if
1867         /// no exceptions have been thrown.
1868         /// </summary>
1869         /// <param name="includeTaskCanceledExceptions">Whether to include a TCE if cancelled.</param>
1870         /// <returns>An aggregate exception, or null if no exceptions have been caught.</returns>
1871         private AggregateException GetExceptions(bool includeTaskCanceledExceptions)
1872         {
1873             //
1874             // WARNING: The Task/Task<TResult>/TaskCompletionSource classes
1875             // have all been carefully crafted to insure that GetExceptions()
1876             // is never called while AddException() is being called.  There
1877             // are locks taken on m_contingentProperties in several places:
1878             //
1879             // -- Task<TResult>.TrySetException(): The lock allows the
1880             //    task to be set to Faulted state, and all exceptions to
1881             //    be recorded, in one atomic action.  
1882             //
1883             // -- Task.Exception_get(): The lock ensures that Task<TResult>.TrySetException()
1884             //    is allowed to complete its operation before Task.Exception_get()
1885             //    can access GetExceptions().
1886             //
1887             // -- Task.ThrowIfExceptional(): The lock insures that Wait() will
1888             //    not attempt to call GetExceptions() while Task<TResult>.TrySetException()
1889             //    is in the process of calling AddException().
1890             //
1891             // For "regular" tasks, we effectively keep AddException() and GetException()
1892             // from being called concurrently by the way that the state flows.  Until
1893             // a Task is marked Faulted, Task.Exception_get() returns null.  And
1894             // a Task is not marked Faulted until it and all of its children have
1895             // completed, which means that all exceptions have been recorded.
1896             //
1897             // It might be a lot easier to follow all of this if we just required
1898             // that all calls to GetExceptions() and AddExceptions() were made
1899             // under a lock on m_contingentProperties.  But that would also
1900             // increase our lock occupancy time and the frequency with which we
1901             // would need to take the lock.
1902             //
1903             // If you add a call to GetExceptions() anywhere in the code,
1904             // please continue to maintain the invariant that it can't be
1905             // called when AddException() is being called.
1906             //
1907
1908             // We'll lazily create a TCE if the task has been canceled.
1909             Exception canceledException = null;
1910             if (includeTaskCanceledExceptions && IsCanceled)
1911             {
1912                 // Backcompat: 
1913                 // Ideally we'd just use the cached OCE from this.GetCancellationExceptionDispatchInfo()
1914                 // here.  However, that would result in a potentially breaking change from .NET 4, which
1915                 // has the code here that throws a new exception instead of the original, and the EDI
1916                 // may not contain a TCE, but an OCE or any OCE-derived type, which would mean we'd be
1917                 // propagating an exception of a different type.
1918                 canceledException = new TaskCanceledException(this);
1919             }
1920
1921             if (ExceptionRecorded)
1922             {
1923                 // There are exceptions; get the aggregate and optionally add the canceled
1924                 // exception to the aggregate (if applicable).
1925                 Debug.Assert(m_contingentProperties != null); // ExceptionRecorded ==> m_contingentProperties != null
1926
1927                 // No need to lock around this, as other logic prevents the consumption of exceptions
1928                 // before they have been completely processed.
1929                 return m_contingentProperties.m_exceptionsHolder.CreateExceptionObject(false, canceledException);
1930             }
1931             else if (canceledException != null)
1932             {
1933                 // No exceptions, but there was a cancelation. Aggregate and return it.
1934                 return new AggregateException(canceledException);
1935             }
1936
1937             return null;
1938         }
1939
1940         /// <summary>Gets the exception dispatch infos once the task has faulted.</summary>
1941         internal ReadOnlyCollection<ExceptionDispatchInfo> GetExceptionDispatchInfos()
1942         {
1943             bool exceptionsAvailable = IsFaulted && ExceptionRecorded;
1944             Debug.Assert(exceptionsAvailable, "Must only be used when the task has faulted with exceptions.");
1945             return exceptionsAvailable ?
1946                 m_contingentProperties.m_exceptionsHolder.GetExceptionDispatchInfos() :
1947                 new ReadOnlyCollection<ExceptionDispatchInfo>(new ExceptionDispatchInfo[0]);
1948         }
1949
1950         /// <summary>Gets the ExceptionDispatchInfo containing the OperationCanceledException for this task.</summary>
1951         /// <returns>The ExceptionDispatchInfo.  May be null if no OCE was stored for the task.</returns>
1952         internal ExceptionDispatchInfo GetCancellationExceptionDispatchInfo()
1953         {
1954             Debug.Assert(IsCanceled, "Must only be used when the task has canceled.");
1955             return Volatile.Read(ref m_contingentProperties)?.m_exceptionsHolder?.GetCancellationExceptionDispatchInfo(); // may be null
1956         }
1957
1958         /// <summary>
1959         /// Throws an aggregate exception if the task contains exceptions. 
1960         /// </summary>
1961         internal void ThrowIfExceptional(bool includeTaskCanceledExceptions)
1962         {
1963             Debug.Assert(IsCompleted, "ThrowIfExceptional(): Expected IsCompleted == true");
1964
1965             Exception exception = GetExceptions(includeTaskCanceledExceptions);
1966             if (exception != null)
1967             {
1968                 UpdateExceptionObservedStatus();
1969                 throw exception;
1970             }
1971         }
1972
1973         /// <summary>
1974         /// Checks whether this is an attached task, and whether we are being called by the parent task.
1975         /// And sets the TASK_STATE_EXCEPTIONOBSERVEDBYPARENT status flag based on that.
1976         /// 
1977         /// This is meant to be used internally when throwing an exception, and when WaitAll is gathering 
1978         /// exceptions for tasks it waited on. If this flag gets set, the implicit wait on children 
1979         /// will skip exceptions to prevent duplication.
1980         /// 
1981         /// This should only be called when this task has completed with an exception
1982         /// 
1983         /// </summary>
1984         internal void UpdateExceptionObservedStatus()
1985         {
1986             Task parent = m_contingentProperties?.m_parent;
1987             if ((parent != null)
1988                 && ((Options & TaskCreationOptions.AttachedToParent) != 0)
1989                 && ((parent.CreationOptions & TaskCreationOptions.DenyChildAttach) == 0)
1990                 && Task.InternalCurrent == parent)
1991             {
1992                 m_stateFlags |= TASK_STATE_EXCEPTIONOBSERVEDBYPARENT;
1993             }
1994         }
1995
1996         /// <summary>
1997         /// Checks whether the TASK_STATE_EXCEPTIONOBSERVEDBYPARENT status flag is set,
1998         /// This will only be used by the implicit wait to prevent double throws
1999         /// 
2000         /// </summary>
2001         internal bool IsExceptionObservedByParent
2002         {
2003             get
2004             {
2005                 return (m_stateFlags & TASK_STATE_EXCEPTIONOBSERVEDBYPARENT) != 0;
2006             }
2007         }
2008
2009         /// <summary>
2010         /// Checks whether the body was ever invoked. Used by task scheduler code to verify custom schedulers actually ran the task.
2011         /// </summary>
2012         internal bool IsDelegateInvoked
2013         {
2014             get
2015             {
2016                 return (m_stateFlags & TASK_STATE_DELEGATE_INVOKED) != 0;
2017             }
2018         }
2019
2020         /// <summary>
2021         /// Signals completion of this particular task.
2022         ///
2023         /// The userDelegateExecute parameter indicates whether this Finish() call comes following the
2024         /// full execution of the user delegate. 
2025         /// 
2026         /// If userDelegateExecute is false, it mean user delegate wasn't invoked at all (either due to
2027         /// a cancellation request, or because this task is a promise style Task). In this case, the steps
2028         /// involving child tasks (i.e. WaitForChildren) will be skipped.
2029         /// 
2030         /// </summary>
2031         internal void Finish(bool userDelegateExecute)
2032         {
2033             if (m_contingentProperties == null)
2034             {
2035                 FinishStageTwo();
2036             }
2037             else
2038             {
2039                 FinishSlow(userDelegateExecute);
2040             }
2041         }
2042
2043         private void FinishSlow(bool userDelegateExecute)
2044         {
2045             Debug.Assert(userDelegateExecute || m_contingentProperties != null);
2046
2047             if (!userDelegateExecute)
2048             {
2049                 // delegate didn't execute => no children. We can safely call the remaining finish stages
2050                 FinishStageTwo();
2051             }
2052             else
2053             {
2054                 ContingentProperties props = m_contingentProperties;
2055
2056                 // Count of 1 => either all children finished, or there were none. Safe to complete ourselves 
2057                 // without paying the price of an Interlocked.Decrement.
2058                 if ((props.m_completionCountdown == 1) ||
2059                     Interlocked.Decrement(ref props.m_completionCountdown) == 0) // Reaching this sub clause means there may be remaining active children,
2060                                                                                  // and we could be racing with one of them to call FinishStageTwo().
2061                                                                                  // So whoever does the final Interlocked.Dec is responsible to finish.
2062                 {
2063                     FinishStageTwo();
2064                 }
2065                 else
2066                 {
2067                     // Apparently some children still remain. It will be up to the last one to process the completion of this task on their own thread.
2068                     // We will now yield the thread back to ThreadPool. Mark our state appropriately before getting out.
2069
2070                     // We have to use an atomic update for this and make sure not to overwrite a final state, 
2071                     // because at this very moment the last child's thread may be concurrently completing us.
2072                     // Otherwise we risk overwriting the TASK_STATE_RAN_TO_COMPLETION, _CANCELED or _FAULTED bit which may have been set by that child task.
2073                     // Note that the concurrent update by the last child happening in FinishStageTwo could still wipe out the TASK_STATE_WAITING_ON_CHILDREN flag, 
2074                     // but it is not critical to maintain, therefore we dont' need to intruduce a full atomic update into FinishStageTwo
2075
2076                     AtomicStateUpdate(TASK_STATE_WAITING_ON_CHILDREN, TASK_STATE_FAULTED | TASK_STATE_CANCELED | TASK_STATE_RAN_TO_COMPLETION);
2077                 }
2078
2079                 // Now is the time to prune exceptional children. We'll walk the list and removes the ones whose exceptions we might have observed after they threw.
2080                 // we use a local variable for exceptional children here because some other thread may be nulling out m_contingentProperties.m_exceptionalChildren 
2081                 List<Task> exceptionalChildren = props.m_exceptionalChildren;
2082                 if (exceptionalChildren != null)
2083                 {
2084                     lock (exceptionalChildren)
2085                     {
2086                         exceptionalChildren.RemoveAll(s_IsExceptionObservedByParentPredicate); // RemoveAll has better performance than doing it ourselves
2087                     }
2088                 }
2089             }
2090         }
2091
2092         // statically allocated delegate for the removeall expression in Finish()
2093         private readonly static Predicate<Task> s_IsExceptionObservedByParentPredicate = new Predicate<Task>((t) => { return t.IsExceptionObservedByParent; });
2094
2095         /// <summary>
2096         /// FinishStageTwo is to be executed as soon as we known there are no more children to complete. 
2097         /// It can happen i) either on the thread that originally executed this task (if no children were spawned, or they all completed by the time this task's delegate quit)
2098         ///              ii) or on the thread that executed the last child.
2099         /// </summary>
2100         private void FinishStageTwo()
2101         {
2102             // At this point, the task is done executing and waiting for its children,
2103             // we can transition our task to a completion state.  
2104
2105             ContingentProperties cp = Volatile.Read(ref m_contingentProperties);
2106             if (cp != null)
2107             {
2108                 AddExceptionsFromChildren(cp);
2109             }
2110
2111             int completionState;
2112             if (ExceptionRecorded)
2113             {
2114                 completionState = TASK_STATE_FAULTED;
2115                 if (AsyncCausalityTracer.LoggingOn)
2116                     AsyncCausalityTracer.TraceOperationCompletion(CausalityTraceLevel.Required, this.Id, AsyncCausalityStatus.Error);
2117
2118                 if (Task.s_asyncDebuggingEnabled)
2119                 {
2120                     RemoveFromActiveTasks(this.Id);
2121                 }
2122             }
2123             else if (IsCancellationRequested && IsCancellationAcknowledged)
2124             {
2125                 // We transition into the TASK_STATE_CANCELED final state if the task's CT was signalled for cancellation, 
2126                 // and the user delegate acknowledged the cancellation request by throwing an OCE, 
2127                 // and the task hasn't otherwise transitioned into faulted state. (TASK_STATE_FAULTED trumps TASK_STATE_CANCELED)
2128                 //
2129                 // If the task threw an OCE without cancellation being requestsed (while the CT not being in signaled state),
2130                 // then we regard it as a regular exception
2131
2132                 completionState = TASK_STATE_CANCELED;
2133                 if (AsyncCausalityTracer.LoggingOn)
2134                     AsyncCausalityTracer.TraceOperationCompletion(CausalityTraceLevel.Required, this.Id, AsyncCausalityStatus.Canceled);
2135
2136                 if (Task.s_asyncDebuggingEnabled)
2137                 {
2138                     RemoveFromActiveTasks(this.Id);
2139                 }
2140             }
2141             else
2142             {
2143                 completionState = TASK_STATE_RAN_TO_COMPLETION;
2144                 if (AsyncCausalityTracer.LoggingOn)
2145                     AsyncCausalityTracer.TraceOperationCompletion(CausalityTraceLevel.Required, this.Id, AsyncCausalityStatus.Completed);
2146
2147                 if (Task.s_asyncDebuggingEnabled)
2148                 {
2149                     RemoveFromActiveTasks(this.Id);
2150                 }
2151             }
2152
2153             // Use Interlocked.Exchange() to effect a memory fence, preventing
2154             // any SetCompleted() (or later) instructions from sneak back before it.
2155             Interlocked.Exchange(ref m_stateFlags, m_stateFlags | completionState);
2156
2157             // Set the completion event if it's been lazy allocated.
2158             // And if we made a cancellation registration, it's now unnecessary.
2159             cp = Volatile.Read(ref m_contingentProperties); // need to re-read after updating state
2160             if (cp != null)
2161             {
2162                 cp.SetCompleted();
2163                 cp.DeregisterCancellationCallback();
2164             }
2165
2166             // ready to run continuations and notify parent.
2167             FinishStageThree();
2168         }
2169
2170
2171         /// <summary>
2172         /// Final stage of the task completion code path. Notifies the parent (if any) that another of its children are done, and runs continuations.
2173         /// This function is only separated out from FinishStageTwo because these two operations are also needed to be called from CancellationCleanupLogic()
2174         /// </summary>
2175         internal void FinishStageThree()
2176         {
2177             // Release the action so that holding this task object alive doesn't also
2178             // hold alive the body of the task.  We do this before notifying a parent,
2179             // so that if notifying the parent completes the parent and causes
2180             // its synchronous continuations to run, the GC can collect the state
2181             // in the interim.  And we do it before finishing continuations, because
2182             // continuations hold onto the task, and therefore are keeping it alive.
2183             m_action = null;
2184
2185             // Notify parent if this was an attached task
2186             if (m_contingentProperties != null)
2187             {
2188                 NotifyParentIfPotentiallyAttachedTask();
2189             }
2190
2191             // Activate continuations (if any).
2192             FinishContinuations();
2193         }
2194
2195         internal void NotifyParentIfPotentiallyAttachedTask()
2196         {
2197             Task parent = m_contingentProperties?.m_parent;
2198             if (parent != null
2199                  && ((parent.CreationOptions & TaskCreationOptions.DenyChildAttach) == 0)
2200                  && (((TaskCreationOptions)(m_stateFlags & OptionsMask)) & TaskCreationOptions.AttachedToParent) != 0)
2201             {
2202                 parent.ProcessChildCompletion(this);
2203             }
2204         }
2205
2206         /// <summary>
2207         /// This is called by children of this task when they are completed.
2208         /// </summary>
2209         internal void ProcessChildCompletion(Task childTask)
2210         {
2211             Debug.Assert(childTask != null);
2212             Debug.Assert(childTask.IsCompleted, "ProcessChildCompletion was called for an uncompleted task");
2213
2214             Debug.Assert(childTask.m_contingentProperties?.m_parent == this, "ProcessChildCompletion should only be called for a child of this task");
2215
2216             var props = Volatile.Read(ref m_contingentProperties);
2217
2218             // if the child threw and we haven't observed it we need to save it for future reference
2219             if (childTask.IsFaulted && !childTask.IsExceptionObservedByParent)
2220             {
2221                 // Lazily initialize the child exception list
2222                 if (props.m_exceptionalChildren == null)
2223                 {
2224                     Interlocked.CompareExchange(ref props.m_exceptionalChildren, new List<Task>(), null);
2225                 }
2226
2227                 // In rare situations involving AppDomainUnload, it's possible (though unlikely) for FinishStageTwo() to be called
2228                 // multiple times for the same task.  In that case, AddExceptionsFromChildren() could be nulling m_exceptionalChildren
2229                 // out at the same time that we're processing it, resulting in a NullReferenceException here.  We'll protect
2230                 // ourselves by caching m_exceptionChildren in a local variable.
2231                 List<Task> tmp = props.m_exceptionalChildren;
2232                 if (tmp != null)
2233                 {
2234                     lock (tmp)
2235                     {
2236                         tmp.Add(childTask);
2237                     }
2238                 }
2239             }
2240
2241             if (Interlocked.Decrement(ref props.m_completionCountdown) == 0)
2242             {
2243                 // This call came from the final child to complete, and apparently we have previously given up this task's right to complete itself.
2244                 // So we need to invoke the final finish stage.
2245
2246                 FinishStageTwo();
2247             }
2248         }
2249
2250         /// <summary>
2251         /// This is to be called just before the task does its final state transition. 
2252         /// It traverses the list of exceptional children, and appends their aggregate exceptions into this one's exception list
2253         /// </summary>
2254         internal void AddExceptionsFromChildren(ContingentProperties props)
2255         {
2256             Debug.Assert(props != null);
2257
2258             // In rare occurences during AppDomainUnload() processing, it is possible for this method to be called
2259             // simultaneously on the same task from two different contexts.  This can result in m_exceptionalChildren
2260             // being nulled out while it is being processed, which could lead to a NullReferenceException.  To
2261             // protect ourselves, we'll cache m_exceptionalChildren in a local variable.
2262             List<Task> exceptionalChildren = props.m_exceptionalChildren;
2263
2264             if (exceptionalChildren != null)
2265             {
2266                 // This lock is necessary because even though AddExceptionsFromChildren is last to execute, it may still 
2267                 // be racing with the code segment at the bottom of Finish() that prunes the exceptional child array. 
2268                 lock (exceptionalChildren)
2269                 {
2270                     foreach (Task task in exceptionalChildren)
2271                     {
2272                         // Ensure any exceptions thrown by children are added to the parent.
2273                         // In doing this, we are implicitly marking children as being "handled".
2274                         Debug.Assert(task.IsCompleted, "Expected all tasks in list to be completed");
2275                         if (task.IsFaulted && !task.IsExceptionObservedByParent)
2276                         {
2277                             TaskExceptionHolder exceptionHolder = Volatile.Read(ref task.m_contingentProperties).m_exceptionsHolder;
2278                             Debug.Assert(exceptionHolder != null);
2279
2280                             // No locking necessary since child task is finished adding exceptions
2281                             // and concurrent CreateExceptionObject() calls do not constitute
2282                             // a concurrency hazard.
2283                             AddException(exceptionHolder.CreateExceptionObject(false, null));
2284                         }
2285                     }
2286                 }
2287
2288                 // Reduce memory pressure by getting rid of the array
2289                 props.m_exceptionalChildren = null;
2290             }
2291         }
2292
2293         /// <summary>
2294         /// Special purpose Finish() entry point to be used when the task delegate throws a ThreadAbortedException
2295         /// This makes a note in the state flags so that we avoid any costly synchronous operations in the finish codepath
2296         /// such as inlined continuations
2297         /// </summary>
2298         /// <param name="delegateRan">Whether the delegate was executed.</param>
2299         internal void FinishThreadAbortedTask(bool delegateRan)
2300         {
2301             Debug.Assert(m_contingentProperties?.m_exceptionsHolder != null,
2302                 "FinishThreadAbortedTask() called on a task whose exception holder wasn't initialized");
2303
2304             m_contingentProperties.m_exceptionsHolder.MarkAsHandled(false);
2305
2306             // If this method has already been called for this task, or if this task has already completed, then
2307             // return before actually calling Finish().
2308             if (!AtomicStateUpdate(TASK_STATE_THREAD_WAS_ABORTED,
2309                             TASK_STATE_THREAD_WAS_ABORTED | TASK_STATE_RAN_TO_COMPLETION | TASK_STATE_FAULTED | TASK_STATE_CANCELED))
2310             {
2311                 return;
2312             }
2313
2314             Finish(delegateRan);
2315         }
2316
2317         /// <summary>
2318         /// IThreadPoolWorkItem override, which is the entry function for this task when the TP scheduler decides to run it.
2319         /// 
2320         /// </summary>
2321         void IThreadPoolWorkItem.ExecuteWorkItem()
2322         {
2323             ExecuteEntryUnsafe();
2324         }
2325
2326         /// <summary>
2327         /// The ThreadPool calls this if a ThreadAbortException is thrown while trying to execute this workitem.  This may occur
2328         /// before Task would otherwise be able to observe it.  
2329         /// </summary>
2330         void IThreadPoolWorkItem.MarkAborted(ThreadAbortException tae)
2331         {
2332             // If the task has marked itself as Completed, then it either a) already observed this exception (so we shouldn't handle it here)
2333             // or b) completed before the exception ocurred (in which case it shouldn't count against this Task).
2334             if (!IsCompleted)
2335             {
2336                 HandleException(tae);
2337                 FinishThreadAbortedTask(delegateRan: false);
2338             }
2339         }
2340
2341         /// <summary>
2342         /// Outermost entry function to execute this task. Handles all aspects of executing a task on the caller thread.
2343         /// </summary>
2344         internal bool ExecuteEntry()
2345         {
2346             // Do atomic state transition from queued to invoked. If we observe a task that's already invoked,
2347             // we will return false so that TaskScheduler.ExecuteTask can throw an exception back to the custom scheduler.
2348             // However we don't want this exception to be throw if the task was already canceled, because it's a
2349             // legitimate scenario for custom schedulers to dequeue a task and mark it as canceled (example: throttling scheduler)
2350             int previousState = 0;
2351             if (!AtomicStateUpdate(TASK_STATE_DELEGATE_INVOKED,
2352                                     TASK_STATE_DELEGATE_INVOKED | TASK_STATE_COMPLETED_MASK,
2353                                     ref previousState) && (previousState & TASK_STATE_CANCELED) == 0)
2354             {
2355                 // This task has already been invoked.  Don't invoke it again.
2356                 return false;
2357             }
2358
2359             if (!IsCancellationRequested & !IsCanceled)
2360             {
2361                 ExecuteWithThreadLocal(ref t_currentTask);
2362             }
2363             else
2364             {
2365                 ExecuteEntryCancellationRequestedOrCanceled();
2366             }
2367
2368             return true;
2369         }
2370
2371         internal void ExecuteEntryUnsafe() // used instead of ExecuteEntry() when we don't have to worry about double-execution prevent
2372         {
2373             // Remember that we started running the task delegate.
2374             m_stateFlags |= TASK_STATE_DELEGATE_INVOKED;
2375
2376             if (!IsCancellationRequested & !IsCanceled)
2377             {
2378                 ExecuteWithThreadLocal(ref t_currentTask);
2379             }
2380             else
2381             {
2382                 ExecuteEntryCancellationRequestedOrCanceled();
2383             }
2384         }
2385
2386         internal void ExecuteEntryCancellationRequestedOrCanceled()
2387         {
2388             if (!IsCanceled)
2389             {
2390                 int prevState = Interlocked.Exchange(ref m_stateFlags, m_stateFlags | TASK_STATE_CANCELED);
2391                 if ((prevState & TASK_STATE_CANCELED) == 0)
2392                 {
2393                     CancellationCleanupLogic();
2394                 }
2395             }
2396         }
2397
2398         // A trick so we can refer to the TLS slot with a byref.
2399         private void ExecuteWithThreadLocal(ref Task currentTaskSlot)
2400         {
2401             // Remember the current task so we can restore it after running, and then
2402             Task previousTask = currentTaskSlot;
2403
2404             // ETW event for Task Started
2405             var etwLog = TplEtwProvider.Log;
2406             Guid savedActivityID = new Guid();
2407             bool etwIsEnabled = etwLog.IsEnabled();
2408             if (etwIsEnabled)
2409             {
2410                 if (etwLog.TasksSetActivityIds)
2411                     EventSource.SetCurrentThreadActivityId(TplEtwProvider.CreateGuidForTaskID(this.Id), out savedActivityID);
2412                 // previousTask holds the actual "current task" we want to report in the event
2413                 if (previousTask != null)
2414                     etwLog.TaskStarted(previousTask.m_taskScheduler.Id, previousTask.Id, this.Id);
2415                 else
2416                     etwLog.TaskStarted(TaskScheduler.Current.Id, 0, this.Id);
2417             }
2418
2419             bool loggingOn = AsyncCausalityTracer.LoggingOn;
2420             if (loggingOn)
2421                 AsyncCausalityTracer.TraceSynchronousWorkStart(CausalityTraceLevel.Required, this.Id, CausalitySynchronousWork.Execution);
2422
2423             try
2424             {
2425                 // place the current task into TLS.
2426                 currentTaskSlot = this;
2427
2428                 // Execute the task body
2429                 try
2430                 {
2431                     ExecutionContext ec = CapturedContext;
2432                     if (ec == null)
2433                     {
2434                         // No context, just run the task directly.
2435                         InnerInvoke();
2436                     }
2437                     else
2438                     {
2439                         // Invoke it under the captured ExecutionContext
2440                         ExecutionContext.Run(ec, s_ecCallback, this);
2441                     }
2442                 }
2443                 catch (Exception exn)
2444                 {
2445                     // Record this exception in the task's exception list
2446                     HandleException(exn);
2447                     if (exn is ThreadAbortException)
2448                     {
2449                         // This is a ThreadAbortException and it will be rethrown from this catch clause, causing us to 
2450                         // skip the regular Finish codepath. In order not to leave the task unfinished, we now call 
2451                         // FinishThreadAbortedTask here.
2452                         FinishThreadAbortedTask(delegateRan: true);
2453                     }
2454                 }
2455
2456                 if (loggingOn)
2457                     AsyncCausalityTracer.TraceSynchronousWorkCompletion(CausalityTraceLevel.Required, CausalitySynchronousWork.Execution);
2458
2459                 Finish(true);
2460             }
2461             finally
2462             {
2463                 currentTaskSlot = previousTask;
2464
2465                 // ETW event for Task Completed
2466                 if (etwIsEnabled)
2467                 {
2468                     // previousTask holds the actual "current task" we want to report in the event
2469                     if (previousTask != null)
2470                         etwLog.TaskCompleted(previousTask.m_taskScheduler.Id, previousTask.Id, this.Id, IsFaulted);
2471                     else
2472                         etwLog.TaskCompleted(TaskScheduler.Current.Id, 0, this.Id, IsFaulted);
2473
2474                     if (etwLog.TasksSetActivityIds)
2475                         EventSource.SetCurrentThreadActivityId(savedActivityID);
2476                 }
2477             }
2478         }
2479
2480         private static readonly ContextCallback s_ecCallback = obj => ((Task)obj).InnerInvoke();
2481
2482         /// <summary>
2483         /// The actual code which invokes the body of the task. This can be overridden in derived types.
2484         /// </summary>
2485         internal virtual void InnerInvoke()
2486         {
2487             // Invoke the delegate
2488             Debug.Assert(m_action != null, "Null action in InnerInvoke()");
2489             var action = m_action as Action;
2490             if (action != null)
2491             {
2492                 action();
2493                 return;
2494             }
2495             var actionWithState = m_action as Action<object>;
2496             if (actionWithState != null)
2497             {
2498                 actionWithState(m_stateObject);
2499                 return;
2500             }
2501             Debug.Fail("Invalid m_action in Task");
2502         }
2503
2504         /// <summary>
2505         /// Performs whatever handling is necessary for an unhandled exception. Normally
2506         /// this just entails adding the exception to the holder object. 
2507         /// </summary>
2508         /// <param name="unhandledException">The exception that went unhandled.</param>
2509         private void HandleException(Exception unhandledException)
2510         {
2511             Debug.Assert(unhandledException != null);
2512
2513             OperationCanceledException exceptionAsOce = unhandledException as OperationCanceledException;
2514             if (exceptionAsOce != null && IsCancellationRequested &&
2515                 m_contingentProperties.m_cancellationToken == exceptionAsOce.CancellationToken)
2516             {
2517                 // All conditions are satisfied for us to go into canceled state in Finish().
2518                 // Mark the acknowledgement.  The exception is also stored to enable it to be
2519                 // the exception propagated from an await.
2520
2521                 SetCancellationAcknowledged();
2522                 AddException(exceptionAsOce, representsCancellation: true);
2523             }
2524             else
2525             {
2526                 // Other exceptions, including any OCE from the task that doesn't match the tasks' own CT, 
2527                 // or that gets thrown without the CT being set will be treated as an ordinary exception 
2528                 // and added to the aggregate.
2529
2530                 AddException(unhandledException);
2531             }
2532         }
2533
2534         #region Await Support
2535         /// <summary>Gets an awaiter used to await this <see cref="System.Threading.Tasks.Task"/>.</summary>
2536         /// <returns>An awaiter instance.</returns>
2537         /// <remarks>This method is intended for compiler user rather than use directly in code.</remarks>
2538         public TaskAwaiter GetAwaiter()
2539         {
2540             return new TaskAwaiter(this);
2541         }
2542
2543         /// <summary>Configures an awaiter used to await this <see cref="System.Threading.Tasks.Task"/>.</summary>
2544         /// <param name="continueOnCapturedContext">
2545         /// true to attempt to marshal the continuation back to the original context captured; otherwise, false.
2546         /// </param>
2547         /// <returns>An object used to await this task.</returns>
2548         public ConfiguredTaskAwaitable ConfigureAwait(bool continueOnCapturedContext)
2549         {
2550             return new ConfiguredTaskAwaitable(this, continueOnCapturedContext);
2551         }
2552
2553         /// <summary>
2554         /// Sets a continuation onto the <see cref="System.Threading.Tasks.Task"/>.
2555         /// The continuation is scheduled to run in the current synchronization context is one exists, 
2556         /// otherwise in the current task scheduler.
2557         /// </summary>
2558         /// <param name="continuationAction">The action to invoke when the <see cref="System.Threading.Tasks.Task"/> has completed.</param>
2559         /// <param name="continueOnCapturedContext">
2560         /// true to attempt to marshal the continuation back to the original context captured; otherwise, false.
2561         /// </param>
2562         /// <param name="flowExecutionContext">Whether to flow ExecutionContext across the await.</param>
2563         /// <exception cref="System.InvalidOperationException">The awaiter was not properly initialized.</exception>
2564         internal void SetContinuationForAwait(
2565             Action continuationAction, bool continueOnCapturedContext, bool flowExecutionContext)
2566         {
2567             Debug.Assert(continuationAction != null);
2568
2569             // Create the best AwaitTaskContinuation object given the request.
2570             // If this remains null by the end of the function, we can use the 
2571             // continuationAction directly without wrapping it.
2572             TaskContinuation tc = null;
2573
2574             // If the user wants the continuation to run on the current "context" if there is one...
2575             if (continueOnCapturedContext)
2576             {
2577                 // First try getting the current synchronization context.
2578                 // If the current context is really just the base SynchronizationContext type, 
2579                 // which is intended to be equivalent to not having a current SynchronizationContext at all, 
2580                 // then ignore it.  This helps with performance by avoiding unnecessary posts and queueing
2581                 // of work items, but more so it ensures that if code happens to publish the default context 
2582                 // as current, it won't prevent usage of a current task scheduler if there is one.
2583                 var syncCtx = SynchronizationContext.Current;
2584                 if (syncCtx != null && syncCtx.GetType() != typeof(SynchronizationContext))
2585                 {
2586                     tc = new SynchronizationContextAwaitTaskContinuation(syncCtx, continuationAction, flowExecutionContext);
2587                 }
2588                 else
2589                 {
2590                     // If there was no SynchronizationContext, then try for the current scheduler.
2591                     // We only care about it if it's not the default.
2592                     var scheduler = TaskScheduler.InternalCurrent;
2593                     if (scheduler != null && scheduler != TaskScheduler.Default)
2594                     {
2595                         tc = new TaskSchedulerAwaitTaskContinuation(scheduler, continuationAction, flowExecutionContext);
2596                     }
2597                 }
2598             }
2599
2600             if (tc == null && flowExecutionContext)
2601             {
2602                 // We're targeting the default scheduler, so we can use the faster path
2603                 // that assumes the default, and thus we don't need to store it.  If we're flowing
2604                 // ExecutionContext, we need to capture it and wrap it in an AwaitTaskContinuation.
2605                 // Otherwise, we're targeting the default scheduler and we don't need to flow ExecutionContext, so
2606                 // we don't actually need a continuation object.  We can just store/queue the action itself.
2607                 tc = new AwaitTaskContinuation(continuationAction, flowExecutionContext: true);
2608             }
2609
2610             // Now register the continuation, and if we couldn't register it because the task is already completing,
2611             // process the continuation directly (in which case make sure we schedule the continuation
2612             // rather than inlining it, the latter of which could result in a rare but possible stack overflow).
2613             if (tc != null)
2614             {
2615                 if (!AddTaskContinuation(tc, addBeforeOthers: false))
2616                     tc.Run(this, bCanInlineContinuationTask: false);
2617             }
2618             else
2619             {
2620                 Debug.Assert(!flowExecutionContext, "We already determined we're not required to flow context.");
2621                 if (!AddTaskContinuation(continuationAction, addBeforeOthers: false))
2622                     AwaitTaskContinuation.UnsafeScheduleAction(continuationAction, this);
2623             }
2624         }
2625
2626         /// <summary>
2627         /// Sets a continuation onto the <see cref="System.Threading.Tasks.Task"/>.
2628         /// The continuation is scheduled to run in the current synchronization context is one exists, 
2629         /// otherwise in the current task scheduler.
2630         /// </summary>
2631         /// <param name="stateMachineBox">The action to invoke when the <see cref="System.Threading.Tasks.Task"/> has completed.</param>
2632         /// <param name="continueOnCapturedContext">
2633         /// true to attempt to marshal the continuation back to the original context captured; otherwise, false.
2634         /// </param>
2635         /// <exception cref="System.InvalidOperationException">The awaiter was not properly initialized.</exception>
2636         internal void UnsafeSetContinuationForAwait(IAsyncStateMachineBox stateMachineBox, bool continueOnCapturedContext)
2637         {
2638             Debug.Assert(stateMachineBox != null);
2639
2640             // If the caller wants to continue on the current context/scheduler and there is one,
2641             // fall back to using the state machine's delegate.
2642             if (continueOnCapturedContext)
2643             {
2644                 SynchronizationContext syncCtx = SynchronizationContext.Current;
2645                 if (syncCtx != null && syncCtx.GetType() != typeof(SynchronizationContext))
2646                 {
2647                     var tc = new SynchronizationContextAwaitTaskContinuation(syncCtx, stateMachineBox.MoveNextAction, flowExecutionContext: false);
2648                     if (!AddTaskContinuation(tc, addBeforeOthers: false))
2649                     {
2650                         tc.Run(this, canInlineContinuationTask: false);
2651                     }
2652                     return;
2653                 }
2654                 else
2655                 {
2656                     TaskScheduler scheduler = TaskScheduler.InternalCurrent;
2657                     if (scheduler != null && scheduler != TaskScheduler.Default)
2658                     {
2659                         var tc = new TaskSchedulerAwaitTaskContinuation(scheduler, stateMachineBox.MoveNextAction, flowExecutionContext: false);
2660                         if (!AddTaskContinuation(tc, addBeforeOthers: false))
2661                         {
2662                             tc.Run(this, canInlineContinuationTask: false);
2663                         }
2664                         return;
2665                     }
2666                 }
2667             }
2668
2669             // Otherwise, add the state machine box directly as the ITaskCompletionAction continuation.
2670             // If we're unable to because the task has already completed, queue the delegate.
2671             if (!AddTaskContinuation(stateMachineBox, addBeforeOthers: false))
2672             {
2673                 AwaitTaskContinuation.UnsafeScheduleAction(stateMachineBox.MoveNextAction, this);
2674             }
2675         }
2676
2677         /// <summary>Creates an awaitable that asynchronously yields back to the current context when awaited.</summary>
2678         /// <returns>
2679         /// A context that, when awaited, will asynchronously transition back into the current context at the 
2680         /// time of the await. If the current SynchronizationContext is non-null, that is treated as the current context.
2681         /// Otherwise, TaskScheduler.Current is treated as the current context.
2682         /// </returns>
2683         public static YieldAwaitable Yield()
2684         {
2685             return new YieldAwaitable();
2686         }
2687         #endregion
2688
2689         /// <summary>
2690         /// Waits for the <see cref="Task"/> to complete execution.
2691         /// </summary>
2692         /// <exception cref="T:System.AggregateException">
2693         /// The <see cref="Task"/> was canceled -or- an exception was thrown during
2694         /// the execution of the <see cref="Task"/>.
2695         /// </exception>
2696         public void Wait()
2697         {
2698 #if DEBUG
2699             bool waitResult =
2700 #endif
2701             Wait(Timeout.Infinite, default(CancellationToken));
2702
2703 #if DEBUG
2704             Debug.Assert(waitResult, "expected wait to succeed");
2705 #endif
2706         }
2707
2708         /// <summary>
2709         /// Waits for the <see cref="Task"/> to complete execution.
2710         /// </summary>
2711         /// <param name="timeout">
2712         /// A <see cref="System.TimeSpan"/> that represents the number of milliseconds to wait, or a <see
2713         /// cref="System.TimeSpan"/> that represents -1 milliseconds to wait indefinitely.
2714         /// </param>
2715         /// <returns>
2716         /// true if the <see cref="Task"/> completed execution within the allotted time; otherwise, false.
2717         /// </returns>
2718         /// <exception cref="T:System.AggregateException">
2719         /// The <see cref="Task"/> was canceled -or- an exception was thrown during the execution of the <see
2720         /// cref="Task"/>.
2721         /// </exception>
2722         /// <exception cref="T:System.ArgumentOutOfRangeException">
2723         /// <paramref name="timeout"/> is a negative number other than -1 milliseconds, which represents an
2724         /// infinite time-out -or- timeout is greater than
2725         /// <see cref="System.Int32.MaxValue"/>.
2726         /// </exception>
2727         public bool Wait(TimeSpan timeout)
2728         {
2729             long totalMilliseconds = (long)timeout.TotalMilliseconds;
2730             if (totalMilliseconds < -1 || totalMilliseconds > Int32.MaxValue)
2731             {
2732                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.timeout);
2733             }
2734
2735             return Wait((int)totalMilliseconds, default(CancellationToken));
2736         }
2737
2738
2739         /// <summary>
2740         /// Waits for the <see cref="Task"/> to complete execution.
2741         /// </summary>
2742         /// <param name="cancellationToken">
2743         /// A <see cref="CancellationToken"/> to observe while waiting for the task to complete.
2744         /// </param>
2745         /// <exception cref="T:System.OperationCanceledException">
2746         /// The <paramref name="cancellationToken"/> was canceled.
2747         /// </exception>
2748         /// <exception cref="T:System.AggregateException">
2749         /// The <see cref="Task"/> was canceled -or- an exception was thrown during the execution of the <see
2750         /// cref="Task"/>.
2751         /// </exception>
2752         public void Wait(CancellationToken cancellationToken)
2753         {
2754             Wait(Timeout.Infinite, cancellationToken);
2755         }
2756
2757
2758         /// <summary>
2759         /// Waits for the <see cref="Task"/> to complete execution.
2760         /// </summary>
2761         /// <param name="millisecondsTimeout">
2762         /// The number of milliseconds to wait, or <see cref="System.Threading.Timeout.Infinite"/> (-1) to
2763         /// wait indefinitely.</param>
2764         /// <returns>true if the <see cref="Task"/> completed execution within the allotted time; otherwise,
2765         /// false.
2766         /// </returns>
2767         /// <exception cref="T:System.ArgumentOutOfRangeException">
2768         /// <paramref name="millisecondsTimeout"/> is a negative number other than -1, which represents an
2769         /// infinite time-out.
2770         /// </exception>
2771         /// <exception cref="T:System.AggregateException">
2772         /// The <see cref="Task"/> was canceled -or- an exception was thrown during the execution of the <see
2773         /// cref="Task"/>.
2774         /// </exception>
2775         public bool Wait(int millisecondsTimeout)
2776         {
2777             return Wait(millisecondsTimeout, default(CancellationToken));
2778         }
2779
2780
2781         /// <summary>
2782         /// Waits for the <see cref="Task"/> to complete execution.
2783         /// </summary>
2784         /// <param name="millisecondsTimeout">
2785         /// The number of milliseconds to wait, or <see cref="System.Threading.Timeout.Infinite"/> (-1) to
2786         /// wait indefinitely.
2787         /// </param>
2788         /// <param name="cancellationToken">
2789         /// A <see cref="CancellationToken"/> to observe while waiting for the task to complete.
2790         /// </param>
2791         /// <returns>
2792         /// true if the <see cref="Task"/> completed execution within the allotted time; otherwise, false.
2793         /// </returns>
2794         /// <exception cref="T:System.AggregateException">
2795         /// The <see cref="Task"/> was canceled -or- an exception was thrown during the execution of the <see
2796         /// cref="Task"/>.
2797         /// </exception>
2798         /// <exception cref="T:System.ArgumentOutOfRangeException">
2799         /// <paramref name="millisecondsTimeout"/> is a negative number other than -1, which represents an
2800         /// infinite time-out.
2801         /// </exception>
2802         /// <exception cref="T:System.OperationCanceledException">
2803         /// The <paramref name="cancellationToken"/> was canceled.
2804         /// </exception>
2805         public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken)
2806         {
2807             if (millisecondsTimeout < -1)
2808             {
2809                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.millisecondsTimeout);
2810             }
2811
2812             // Return immediately if we know that we've completed "clean" -- no exceptions, no cancellations
2813             // and if no notification to the debugger is required
2814             if (!IsWaitNotificationEnabledOrNotRanToCompletion) // (!DebuggerBitSet && RanToCompletion)
2815                 return true;
2816
2817             // Wait, and then return if we're still not done.
2818             if (!InternalWait(millisecondsTimeout, cancellationToken))
2819                 return false;
2820
2821             if (IsWaitNotificationEnabledOrNotRanToCompletion) // avoid a few unnecessary volatile reads if we completed successfully
2822             {
2823                 // Notify the debugger of the wait completion if it's requested such a notification
2824                 NotifyDebuggerOfWaitCompletionIfNecessary();
2825
2826                 // If cancellation was requested and the task was canceled, throw an 
2827                 // OperationCanceledException.  This is prioritized ahead of the ThrowIfExceptional
2828                 // call to bring more determinism to cases where the same token is used to 
2829                 // cancel the Wait and to cancel the Task.  Otherwise, there's a race condition between
2830                 // whether the Wait or the Task observes the cancellation request first,
2831                 // and different exceptions result from the different cases.
2832                 if (IsCanceled) cancellationToken.ThrowIfCancellationRequested();
2833
2834                 // If an exception occurred, or the task was cancelled, throw an exception.
2835                 ThrowIfExceptional(true);
2836             }
2837
2838             Debug.Assert((m_stateFlags & TASK_STATE_FAULTED) == 0, "Task.Wait() completing when in Faulted state.");
2839
2840             return true;
2841         }
2842
2843         // Convenience method that wraps any scheduler exception in a TaskSchedulerException
2844         // and rethrows it.
2845         private bool WrappedTryRunInline()
2846         {
2847             if (m_taskScheduler == null)
2848                 return false;
2849
2850             try
2851             {
2852                 return m_taskScheduler.TryRunInline(this, true);
2853             }
2854             catch (Exception e)
2855             {
2856                 // we 1) either received an unexpected exception originating from a custom scheduler, which needs to be wrapped in a TSE and thrown
2857                 //    2) or a a ThreadAbortException, which we need to skip here, because it would already have been handled in Task.Execute
2858                 if (!(e is ThreadAbortException))
2859                 {
2860                     TaskSchedulerException tse = new TaskSchedulerException(e);
2861                     throw tse;
2862                 }
2863                 else
2864                 {
2865                     throw;
2866                 }
2867             }
2868         }
2869
2870         /// <summary>
2871         /// The core wait function, which is only accessible internally. It's meant to be used in places in TPL code where 
2872         /// the current context is known or cached.
2873         /// </summary>
2874         [MethodImpl(MethodImplOptions.NoOptimization)]  // this is needed for the parallel debugger
2875         internal bool InternalWait(int millisecondsTimeout, CancellationToken cancellationToken) =>
2876             InternalWaitCore(millisecondsTimeout, cancellationToken);
2877
2878         // Separated out to allow it to be optimized (caller is marked NoOptimization for VS parallel debugger
2879         // to be able to see the method on the stack and inspect arguments).
2880         private bool InternalWaitCore(int millisecondsTimeout, CancellationToken cancellationToken)
2881         {
2882             // If the task has already completed, there's nothing to wait for.
2883             bool returnValue = IsCompleted;
2884             if (returnValue)
2885             {
2886                 return true;
2887             }
2888
2889             // ETW event for Task Wait Begin
2890             var etwLog = TplEtwProvider.Log;
2891             bool etwIsEnabled = etwLog.IsEnabled();
2892             if (etwIsEnabled)
2893             {
2894                 Task currentTask = Task.InternalCurrent;
2895                 etwLog.TaskWaitBegin(
2896                     (currentTask != null ? currentTask.m_taskScheduler.Id : TaskScheduler.Default.Id), (currentTask != null ? currentTask.Id : 0),
2897                     this.Id, TplEtwProvider.TaskWaitBehavior.Synchronous, 0);
2898             }
2899
2900             // Alert a listening debugger that we can't make forward progress unless it slips threads.
2901             // We call NOCTD for two reasons:
2902             //    1. If the task runs on another thread, then we'll be blocked here indefinitely.
2903             //    2. If the task runs inline but takes some time to complete, it will suffer ThreadAbort with possible state corruption,
2904             //       and it is best to prevent this unless the user explicitly asks to view the value with thread-slipping enabled.
2905             Debugger.NotifyOfCrossThreadDependency();
2906
2907             // We will attempt inline execution only if an infinite wait was requested
2908             // Inline execution doesn't make sense for finite timeouts and if a cancellation token was specified
2909             // because we don't know how long the task delegate will take.
2910             if (millisecondsTimeout == Timeout.Infinite && !cancellationToken.CanBeCanceled &&
2911                 WrappedTryRunInline() && IsCompleted) // TryRunInline doesn't guarantee completion, as there may be unfinished children.
2912             {
2913                 returnValue = true;
2914             }
2915             else
2916             {
2917                 returnValue = SpinThenBlockingWait(millisecondsTimeout, cancellationToken);
2918             }
2919
2920             Debug.Assert(IsCompleted || millisecondsTimeout != Timeout.Infinite);
2921
2922             // ETW event for Task Wait End
2923             if (etwIsEnabled)
2924             {
2925                 Task currentTask = Task.InternalCurrent;
2926                 if (currentTask != null)
2927                 {
2928                     etwLog.TaskWaitEnd(currentTask.m_taskScheduler.Id, currentTask.Id, this.Id);
2929                 }
2930                 else
2931                 {
2932                     etwLog.TaskWaitEnd(TaskScheduler.Default.Id, 0, this.Id);
2933                 }
2934                 // logically the continuation is empty so we immediately fire
2935                 etwLog.TaskWaitContinuationComplete(this.Id);
2936             }
2937
2938             return returnValue;
2939         }
2940
2941         // An MRES that gets set when Invoke is called.  This replaces old logic that looked like this:
2942         //      ManualResetEventSlim mres = new ManualResetEventSlim(false, 0);
2943         //      Action<Task> completionAction = delegate {mres.Set();}
2944         //      AddCompletionAction(completionAction);
2945         // with this:
2946         //      SetOnInvokeMres mres = new SetOnInvokeMres();
2947         //      AddCompletionAction(mres, addBeforeOthers: true);
2948         // which saves a couple of allocations.
2949         //
2950         // Used in SpinThenBlockingWait (below), but could be seen as a general purpose mechanism.
2951         private sealed class SetOnInvokeMres : ManualResetEventSlim, ITaskCompletionAction
2952         {
2953             internal SetOnInvokeMres() : base(false, 0) { }
2954             public void Invoke(Task completingTask) { Set(); }
2955             public bool InvokeMayRunArbitraryCode { get { return false; } }
2956         }
2957
2958         /// <summary>
2959         /// Waits for the task to complete, for a timeout to occur, or for cancellation to be requested.
2960         /// The method first spins and then falls back to blocking on a new event.
2961         /// </summary>
2962         /// <param name="millisecondsTimeout">The timeout.</param>
2963         /// <param name="cancellationToken">The token.</param>
2964         /// <returns>true if the task is completed; otherwise, false.</returns>
2965         private bool SpinThenBlockingWait(int millisecondsTimeout, CancellationToken cancellationToken)
2966         {
2967             bool infiniteWait = millisecondsTimeout == Timeout.Infinite;
2968             uint startTimeTicks = infiniteWait ? 0 : (uint)Environment.TickCount;
2969             bool returnValue = SpinWait(millisecondsTimeout);
2970             if (!returnValue)
2971             {
2972                 var mres = new SetOnInvokeMres();
2973                 try
2974                 {
2975                     AddCompletionAction(mres, addBeforeOthers: true);
2976                     if (infiniteWait)
2977                     {
2978                         returnValue = mres.Wait(Timeout.Infinite, cancellationToken);
2979                     }
2980                     else
2981                     {
2982                         uint elapsedTimeTicks = ((uint)Environment.TickCount) - startTimeTicks;
2983                         if (elapsedTimeTicks < millisecondsTimeout)
2984                         {
2985                             returnValue = mres.Wait((int)(millisecondsTimeout - elapsedTimeTicks), cancellationToken);
2986                         }
2987                     }
2988                 }
2989                 finally
2990                 {
2991                     if (!IsCompleted) RemoveContinuation(mres);
2992                     // Don't Dispose of the MRES, because the continuation off of this task may
2993                     // still be running.  This is ok, however, as we never access the MRES' WaitHandle,
2994                     // and thus no finalizable resources are actually allocated.
2995                 }
2996             }
2997             return returnValue;
2998         }
2999
3000         /// <summary>
3001         /// Spins briefly while checking IsCompleted
3002         /// </summary>
3003         /// <param name="millisecondsTimeout">The timeout.</param>
3004         /// <returns>true if the task is completed; otherwise, false.</returns>
3005         /// <exception cref="System.OperationCanceledException">The wait was canceled.</exception>
3006         private bool SpinWait(int millisecondsTimeout)
3007         {
3008             if (IsCompleted) return true;
3009
3010             if (millisecondsTimeout == 0)
3011             {
3012                 // For 0-timeouts, we just return immediately.
3013                 return false;
3014             }
3015
3016             int spinCount = Threading.SpinWait.SpinCountforSpinBeforeWait;
3017             var spinner = new SpinWait();
3018             while (spinner.Count < spinCount)
3019             {
3020                 spinner.SpinOnce(Threading.SpinWait.Sleep1ThresholdForSpinBeforeWait);
3021
3022                 if (IsCompleted)
3023                 {
3024                     return true;
3025                 }
3026             }
3027
3028             return false;
3029         }
3030
3031         /// <summary>
3032         /// Cancels the <see cref="Task"/>.
3033         /// </summary>
3034         /// <param name="bCancelNonExecutingOnly"> 
3035         /// Indicates whether we should only cancel non-invoked tasks.
3036         /// For the default scheduler this option will only be serviced through TryDequeue.
3037         /// For custom schedulers we also attempt an atomic state transition.
3038         /// </param>
3039         /// <returns>true if the task was successfully canceled; otherwise, false.</returns>
3040         internal bool InternalCancel(bool bCancelNonExecutingOnly)
3041         {
3042             Debug.Assert((Options & (TaskCreationOptions)InternalTaskOptions.PromiseTask) == 0, "Task.InternalCancel() did not expect promise-style task");
3043
3044             bool bPopSucceeded = false;
3045             bool mustCleanup = false;
3046
3047             TaskSchedulerException tse = null;
3048
3049             // If started, and running in a task context, we can try to pop the chore.
3050             if ((m_stateFlags & TASK_STATE_STARTED) != 0)
3051             {
3052                 TaskScheduler ts = m_taskScheduler;
3053
3054                 try
3055                 {
3056                     bPopSucceeded = (ts != null) && ts.TryDequeue(this);
3057                 }
3058                 catch (Exception e)
3059                 {
3060                     // TryDequeue threw. We don't know whether the task was properly dequeued or not. So we must let the rest of 
3061                     // the cancellation logic run its course (record the request, attempt atomic state transition and do cleanup where appropriate)
3062                     // Here we will only record a TaskSchedulerException, which will later be thrown at function exit.
3063
3064                     if (!(e is ThreadAbortException))
3065                     {
3066                         tse = new TaskSchedulerException(e);
3067                     }
3068                 }
3069
3070                 bool bRequiresAtomicStartTransition = ts != null && ts.RequiresAtomicStartTransition;
3071
3072                 if (!bPopSucceeded && bCancelNonExecutingOnly && bRequiresAtomicStartTransition)
3073                 {
3074                     // The caller requested cancellation of non-invoked tasks only, and TryDequeue was one way of doing it...
3075                     // Since that seems to have failed, we should now try an atomic state transition (from non-invoked state to canceled)
3076                     // An atomic transition here is only safe if we know we're on a custom task scheduler, which also forces a CAS on ExecuteEntry
3077
3078                     // Even though this task can't have any children, we should be ready for handling any continuations that 
3079                     // may be attached to it (although currently 
3080                     // So we need to remeber whether we actually did the flip, so we can do clean up (finish continuations etc)
3081                     mustCleanup = AtomicStateUpdate(TASK_STATE_CANCELED, TASK_STATE_DELEGATE_INVOKED | TASK_STATE_CANCELED);
3082
3083                     // PS: This is slightly different from the regular cancellation codepath 
3084                     // since we record the cancellation request *after* doing the state transition. 
3085                     // However that shouldn't matter too much because the task was never invoked, thus can't have children
3086                 }
3087             }
3088
3089             if (!bCancelNonExecutingOnly || bPopSucceeded || mustCleanup)
3090             {
3091                 // Record the cancellation request.
3092                 RecordInternalCancellationRequest();
3093
3094                 // Determine whether we need to clean up
3095                 // This will be the case 
3096                 //     1) if we were able to pop, and we are able to update task state to TASK_STATE_CANCELED
3097                 //     2) if the task seems to be yet unstarted, and we can transition to
3098                 //        TASK_STATE_CANCELED before anyone else can transition into _STARTED or _CANCELED or 
3099                 //        _RAN_TO_COMPLETION or _FAULTED
3100                 // Note that we do not check for TASK_STATE_COMPLETION_RESERVED.  That only applies to promise-style
3101                 // tasks, and a promise-style task should not enter into this codepath.
3102                 if (bPopSucceeded)
3103                 {
3104                     // hitting this would mean something wrong with the AtomicStateUpdate above
3105                     Debug.Assert(!mustCleanup, "Possibly an invalid state transition call was made in InternalCancel()");
3106
3107                     // Include TASK_STATE_DELEGATE_INVOKED in "illegal" bits to protect against the situation where
3108                     // TS.TryDequeue() returns true but the task is still left on the queue.
3109                     mustCleanup = AtomicStateUpdate(TASK_STATE_CANCELED, TASK_STATE_CANCELED | TASK_STATE_DELEGATE_INVOKED);
3110                 }
3111                 else if (!mustCleanup && (m_stateFlags & TASK_STATE_STARTED) == 0)
3112                 {
3113                     mustCleanup = AtomicStateUpdate(TASK_STATE_CANCELED,
3114                         TASK_STATE_CANCELED | TASK_STATE_STARTED | TASK_STATE_RAN_TO_COMPLETION |
3115                         TASK_STATE_FAULTED | TASK_STATE_DELEGATE_INVOKED);
3116                 }
3117
3118                 // do the cleanup (i.e. set completion event and finish continuations)
3119                 if (mustCleanup)
3120                 {
3121                     CancellationCleanupLogic();
3122                 }
3123             }
3124
3125             if (tse != null)
3126                 throw tse;
3127             else
3128                 return (mustCleanup);
3129         }
3130
3131         // Breaks out logic for recording a cancellation request
3132         internal void RecordInternalCancellationRequest()
3133         {
3134             // Record the cancellation request.
3135             EnsureContingentPropertiesInitialized().m_internalCancellationRequested = CANCELLATION_REQUESTED;
3136         }
3137
3138         // Breaks out logic for recording a cancellation request
3139         // This overload should only be used for promise tasks where no cancellation token
3140         // was supplied when the task was created.
3141         internal void RecordInternalCancellationRequest(CancellationToken tokenToRecord)
3142         {
3143             RecordInternalCancellationRequest();
3144
3145             Debug.Assert((Options & (TaskCreationOptions)InternalTaskOptions.PromiseTask) != 0, "Task.RecordInternalCancellationRequest(CancellationToken) only valid for promise-style task");
3146             Debug.Assert(m_contingentProperties.m_cancellationToken == default(CancellationToken));
3147
3148             // Store the supplied cancellation token as this task's token.
3149             // Waiting on this task will then result in an OperationCanceledException containing this token.
3150             if (tokenToRecord != default(CancellationToken))
3151             {
3152                 m_contingentProperties.m_cancellationToken = tokenToRecord;
3153             }
3154         }
3155
3156         // Breaks out logic for recording a cancellation request
3157         // This overload should only be used for promise tasks where no cancellation token
3158         // was supplied when the task was created.
3159         internal void RecordInternalCancellationRequest(CancellationToken tokenToRecord, object cancellationException)
3160         {
3161             RecordInternalCancellationRequest(tokenToRecord);
3162
3163             // Store the supplied cancellation exception
3164             if (cancellationException != null)
3165             {
3166 #if DEBUG
3167                 var oce = cancellationException as OperationCanceledException;
3168                 if (oce == null)
3169                 {
3170                     var edi = cancellationException as ExceptionDispatchInfo;
3171                     Debug.Assert(edi != null, "Expected either an OCE or an EDI");
3172                     oce = edi.SourceException as OperationCanceledException;
3173                     Debug.Assert(oce != null, "Expected EDI to contain an OCE");
3174                 }
3175                 Debug.Assert(oce.CancellationToken == tokenToRecord,
3176                                 "Expected OCE's token to match the provided token.");
3177 #endif
3178                 AddException(cancellationException, representsCancellation: true);
3179             }
3180         }
3181
3182         // ASSUMES THAT A SUCCESSFUL CANCELLATION HAS JUST OCCURRED ON THIS TASK!!!
3183         // And this method should be called at most once per task.
3184         internal void CancellationCleanupLogic()
3185         {
3186             Debug.Assert((m_stateFlags & (TASK_STATE_CANCELED | TASK_STATE_COMPLETION_RESERVED)) != 0, "Task.CancellationCleanupLogic(): Task not canceled or reserved.");
3187             // I'd like to do this, but there is a small window for a race condition.  If someone calls Wait() between InternalCancel() and
3188             // here, that will set m_completionEvent, leading to a meaningless/harmless assertion.
3189             //Debug.Assert((m_completionEvent == null) || !m_completionEvent.IsSet, "Task.CancellationCleanupLogic(): Completion event already set.");
3190
3191             // This may have been set already, but we need to make sure.
3192             Interlocked.Exchange(ref m_stateFlags, m_stateFlags | TASK_STATE_CANCELED);
3193
3194             // Fire completion event if it has been lazily initialized
3195             var cp = Volatile.Read(ref m_contingentProperties);
3196             if (cp != null)
3197             {
3198                 cp.SetCompleted();
3199                 cp.DeregisterCancellationCallback();
3200             }
3201
3202             if (AsyncCausalityTracer.LoggingOn)
3203                 AsyncCausalityTracer.TraceOperationCompletion(CausalityTraceLevel.Required, this.Id, AsyncCausalityStatus.Canceled);
3204
3205             if (Task.s_asyncDebuggingEnabled)
3206             {
3207                 RemoveFromActiveTasks(this.Id);
3208             }
3209
3210             // Notify parents, fire continuations, other cleanup.
3211             FinishStageThree();
3212         }
3213
3214
3215         /// <summary>
3216         /// Sets the task's cancellation acknowledged flag.
3217         /// </summary>    
3218         private void SetCancellationAcknowledged()
3219         {
3220             Debug.Assert(this == Task.InternalCurrent, "SetCancellationAcknowledged() should only be called while this is still the current task");
3221             Debug.Assert(IsCancellationRequested, "SetCancellationAcknowledged() should not be called if the task's CT wasn't signaled");
3222
3223             m_stateFlags |= TASK_STATE_CANCELLATIONACKNOWLEDGED;
3224         }
3225
3226
3227         //
3228         // Continuation passing functionality (aka ContinueWith)
3229         //
3230
3231
3232
3233
3234         /// <summary>
3235         /// Runs all of the continuations, as appropriate.
3236         /// </summary>
3237         internal void FinishContinuations()
3238         {
3239             // Atomically store the fact that this task is completing.  From this point on, the adding of continuations will
3240             // result in the continuations being run/launched directly rather than being added to the continuation list.
3241             // Then if we grabbed any continuations, run them.
3242             object continuationObject = Interlocked.Exchange(ref m_continuationObject, s_taskCompletionSentinel);
3243             if (continuationObject != null)
3244             {
3245                 RunContinuations(continuationObject);
3246             }
3247         }
3248
3249         private void RunContinuations(object continuationObject) // separated out of FinishContinuations to enable it to be inlined
3250         {
3251             Debug.Assert(continuationObject != null);
3252
3253             TplEtwProvider etw = TplEtwProvider.Log;
3254             bool tplEtwProviderLoggingEnabled = etw.IsEnabled();
3255             if (tplEtwProviderLoggingEnabled)
3256             {
3257                 etw.RunningContinuation(Id, continuationObject);
3258             }
3259
3260             if (AsyncCausalityTracer.LoggingOn)
3261                 AsyncCausalityTracer.TraceSynchronousWorkStart(CausalityTraceLevel.Required, this.Id, CausalitySynchronousWork.CompletionNotification);
3262
3263             // Skip synchronous execution of continuations if this task's thread was aborted
3264             bool bCanInlineContinuations = !(((m_stateFlags & TASK_STATE_THREAD_WAS_ABORTED) != 0) ||
3265                                               (RuntimeThread.CurrentThread.ThreadState == ThreadState.AbortRequested) ||
3266                                               ((m_stateFlags & (int)TaskCreationOptions.RunContinuationsAsynchronously) != 0));
3267
3268             // Handle the single-Action case
3269             Action singleAction = continuationObject as Action;
3270             if (singleAction != null)
3271             {
3272                 AwaitTaskContinuation.RunOrScheduleAction(singleAction, bCanInlineContinuations, ref t_currentTask);
3273                 LogFinishCompletionNotification();
3274                 return;
3275             }
3276
3277             // Handle the single-ITaskCompletionAction case
3278             ITaskCompletionAction singleTaskCompletionAction = continuationObject as ITaskCompletionAction;
3279             if (singleTaskCompletionAction != null)
3280             {
3281                 if (bCanInlineContinuations || !singleTaskCompletionAction.InvokeMayRunArbitraryCode)
3282                 {
3283                     singleTaskCompletionAction.Invoke(this);
3284                 }
3285                 else
3286                 {
3287                     ThreadPool.UnsafeQueueCustomWorkItem(new CompletionActionInvoker(singleTaskCompletionAction, this), forceGlobal: false);
3288                 }
3289                 LogFinishCompletionNotification();
3290                 return;
3291             }
3292
3293             // Handle the single-TaskContinuation case
3294             TaskContinuation singleTaskContinuation = continuationObject as TaskContinuation;
3295             if (singleTaskContinuation != null)
3296             {
3297                 singleTaskContinuation.Run(this, bCanInlineContinuations);
3298                 LogFinishCompletionNotification();
3299                 return;
3300             }
3301
3302             // Not a single; it must be a list.
3303             List<object> continuations = (List<object>)continuationObject;
3304
3305             //
3306             // Begin processing of continuation list
3307             //
3308
3309             // Wait for any concurrent adds or removes to be retired
3310             lock (continuations) { }
3311             int continuationCount = continuations.Count;
3312
3313             // Fire the asynchronous continuations first ...
3314             for (int i = 0; i < continuationCount; i++)
3315             {
3316                 // Synchronous continuation tasks will have the ExecuteSynchronously option,
3317                 // and we're looking for asynchronous tasks...
3318                 var tc = continuations[i] as StandardTaskContinuation;
3319                 if (tc != null && (tc.m_options & TaskContinuationOptions.ExecuteSynchronously) == 0)
3320                 {
3321                     if (tplEtwProviderLoggingEnabled)
3322                     {
3323                         etw.RunningContinuationList(Id, i, tc);
3324                     }
3325                     continuations[i] = null; // so that we can skip this later
3326                     tc.Run(this, bCanInlineContinuations);
3327                 }
3328             }
3329
3330             // ... and then fire the synchronous continuations (if there are any).
3331             // This includes ITaskCompletionAction, AwaitTaskContinuations, and
3332             // Action delegates, which are all by default implicitly synchronous.
3333             for (int i = 0; i < continuationCount; i++)
3334             {
3335                 object currentContinuation = continuations[i];
3336                 if (currentContinuation == null) continue;
3337                 continuations[i] = null; // to enable free'ing up memory earlier
3338                 if (tplEtwProviderLoggingEnabled)
3339                 {
3340                     etw.RunningContinuationList(Id, i, currentContinuation);
3341                 }
3342
3343                 // If the continuation is an Action delegate, it came from an await continuation,
3344                 // and we should use AwaitTaskContinuation to run it.
3345                 Action ad = currentContinuation as Action;
3346                 if (ad != null)
3347                 {
3348                     AwaitTaskContinuation.RunOrScheduleAction(ad, bCanInlineContinuations, ref t_currentTask);
3349                 }
3350                 else
3351                 {
3352                     // If it's a TaskContinuation object of some kind, invoke it.
3353                     TaskContinuation tc = currentContinuation as TaskContinuation;
3354                     if (tc != null)
3355                     {
3356                         // We know that this is a synchronous continuation because the
3357                         // asynchronous ones have been weeded out
3358                         tc.Run(this, bCanInlineContinuations);
3359                     }
3360                     // Otherwise, it must be an ITaskCompletionAction, so invoke it.
3361                     else
3362                     {
3363                         Debug.Assert(currentContinuation is ITaskCompletionAction, "Expected continuation element to be Action, TaskContinuation, or ITaskContinuationAction");
3364                         var action = (ITaskCompletionAction)currentContinuation;
3365
3366                         if (bCanInlineContinuations || !action.InvokeMayRunArbitraryCode)
3367                         {
3368                             action.Invoke(this);
3369                         }
3370                         else
3371                         {
3372                             ThreadPool.UnsafeQueueCustomWorkItem(new CompletionActionInvoker(action, this), forceGlobal: false);
3373                         }
3374                     }
3375                 }
3376             }
3377
3378             LogFinishCompletionNotification();
3379         }
3380
3381         private void LogFinishCompletionNotification()
3382         {
3383             if (AsyncCausalityTracer.LoggingOn)
3384                 AsyncCausalityTracer.TraceSynchronousWorkCompletion(CausalityTraceLevel.Required, CausalitySynchronousWork.CompletionNotification);
3385         }
3386
3387         #region Continuation methods
3388
3389         #region Action<Task> continuation
3390         /// <summary>
3391         /// Creates a continuation that executes when the target <see cref="Task"/> completes.
3392         /// </summary>
3393         /// <param name="continuationAction">
3394         /// An action to run when the <see cref="Task"/> completes. When run, the delegate will be
3395         /// passed the completed task as an argument.
3396         /// </param>
3397         /// <returns>A new continuation <see cref="Task"/>.</returns>
3398         /// <remarks>
3399         /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
3400         /// completed, whether it completes due to running to completion successfully, faulting due to an
3401         /// unhandled exception, or exiting out early due to being canceled.
3402         /// </remarks>
3403         /// <exception cref="T:System.ArgumentNullException">
3404         /// The <paramref name="continuationAction"/> argument is null.
3405         /// </exception>
3406         public Task ContinueWith(Action<Task> continuationAction)
3407         {
3408             return ContinueWith(continuationAction, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None);
3409         }
3410
3411         /// <summary>
3412         /// Creates a continuation that executes when the target <see cref="Task"/> completes.
3413         /// </summary>
3414         /// <param name="continuationAction">
3415         /// An action to run when the <see cref="Task"/> completes. When run, the delegate will be
3416         /// passed the completed task as an argument.
3417         /// </param>
3418         /// <param name="cancellationToken"> The <see cref="CancellationToken"/> that will be assigned to the new continuation task.</param>
3419         /// <returns>A new continuation <see cref="Task"/>.</returns>
3420         /// <remarks>
3421         /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
3422         /// completed, whether it completes due to running to completion successfully, faulting due to an
3423         /// unhandled exception, or exiting out early due to being canceled.
3424         /// </remarks>
3425         /// <exception cref="T:System.ArgumentNullException">
3426         /// The <paramref name="continuationAction"/> argument is null.
3427         /// </exception>
3428         /// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
3429         /// has already been disposed.
3430         /// </exception>
3431         public Task ContinueWith(Action<Task> continuationAction, CancellationToken cancellationToken)
3432         {
3433             return ContinueWith(continuationAction, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None);
3434         }
3435
3436         /// <summary>
3437         /// Creates a continuation that executes when the target <see cref="Task"/> completes.
3438         /// </summary>
3439         /// <param name="continuationAction">
3440         /// An action to run when the <see cref="Task"/> completes.  When run, the delegate will be
3441         /// passed the completed task as an argument.
3442         /// </param>
3443         /// <param name="scheduler">
3444         /// The <see cref="TaskScheduler"/> to associate with the continuation task and to use for its execution.
3445         /// </param>
3446         /// <returns>A new continuation <see cref="Task"/>.</returns>
3447         /// <remarks>
3448         /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
3449         /// completed, whether it completes due to running to completion successfully, faulting due to an
3450         /// unhandled exception, or exiting out early due to being canceled.
3451         /// </remarks>
3452         /// <exception cref="T:System.ArgumentNullException">
3453         /// The <paramref name="continuationAction"/> argument is null.
3454         /// </exception>
3455         /// <exception cref="T:System.ArgumentNullException">
3456         /// The <paramref name="scheduler"/> argument is null.
3457         /// </exception>
3458         public Task ContinueWith(Action<Task> continuationAction, TaskScheduler scheduler)
3459         {
3460             return ContinueWith(continuationAction, scheduler, default(CancellationToken), TaskContinuationOptions.None);
3461         }
3462
3463         /// <summary>
3464         /// Creates a continuation that executes when the target <see cref="Task"/> completes.
3465         /// </summary>
3466         /// <param name="continuationAction">
3467         /// An action to run when the <see cref="Task"/> completes. When run, the delegate will be
3468         /// passed the completed task as an argument.
3469         /// </param>
3470         /// <param name="continuationOptions">
3471         /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such
3472         /// as <see
3473         /// cref="System.Threading.Tasks.TaskContinuationOptions.OnlyOnCanceled">OnlyOnCanceled</see>, as
3474         /// well as execution options, such as <see
3475         /// cref="System.Threading.Tasks.TaskContinuationOptions.ExecuteSynchronously">ExecuteSynchronously</see>.
3476         /// </param>
3477         /// <returns>A new continuation <see cref="Task"/>.</returns>
3478         /// <remarks>
3479         /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
3480         /// completed. If the continuation criteria specified through the <paramref
3481         /// name="continuationOptions"/> parameter are not met, the continuation task will be canceled
3482         /// instead of scheduled.
3483         /// </remarks>
3484         /// <exception cref="T:System.ArgumentNullException">
3485         /// The <paramref name="continuationAction"/> argument is null.
3486         /// </exception>
3487         /// <exception cref="T:System.ArgumentOutOfRangeException">
3488         /// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
3489         /// cref="T:System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
3490         /// </exception>
3491         public Task ContinueWith(Action<Task> continuationAction, TaskContinuationOptions continuationOptions)
3492         {
3493             return ContinueWith(continuationAction, TaskScheduler.Current, default(CancellationToken), continuationOptions);
3494         }
3495
3496         /// <summary>
3497         /// Creates a continuation that executes when the target <see cref="Task"/> completes.
3498         /// </summary>
3499         /// <param name="continuationAction">
3500         /// An action to run when the <see cref="Task"/> completes. When run, the delegate will be
3501         /// passed the completed task as an argument.
3502         /// </param>
3503         /// <param name="continuationOptions">
3504         /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such
3505         /// as <see
3506         /// cref="System.Threading.Tasks.TaskContinuationOptions.OnlyOnCanceled">OnlyOnCanceled</see>, as
3507         /// well as execution options, such as <see
3508         /// cref="System.Threading.Tasks.TaskContinuationOptions.ExecuteSynchronously">ExecuteSynchronously</see>.
3509         /// </param>
3510         /// <param name="cancellationToken">The <see cref="CancellationToken"/> that will be assigned to the new continuation task.</param>
3511         /// <param name="scheduler">
3512         /// The <see cref="TaskScheduler"/> to associate with the continuation task and to use for its
3513         /// execution.
3514         /// </param>
3515         /// <returns>A new continuation <see cref="Task"/>.</returns>
3516         /// <remarks>
3517         /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
3518         /// completed. If the criteria specified through the <paramref name="continuationOptions"/> parameter
3519         /// are not met, the continuation task will be canceled instead of scheduled.
3520         /// </remarks>
3521         /// <exception cref="T:System.ArgumentNullException">
3522         /// The <paramref name="continuationAction"/> argument is null.
3523         /// </exception>
3524         /// <exception cref="T:System.ArgumentOutOfRangeException">
3525         /// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
3526         /// cref="T:System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
3527         /// </exception>
3528         /// <exception cref="T:System.ArgumentNullException">
3529         /// The <paramref name="scheduler"/> argument is null.
3530         /// </exception>
3531         /// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
3532         /// has already been disposed.
3533         /// </exception>
3534         public Task ContinueWith(Action<Task> continuationAction, CancellationToken cancellationToken,
3535                                  TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
3536         {
3537             return ContinueWith(continuationAction, scheduler, cancellationToken, continuationOptions);
3538         }
3539
3540         // Same as the above overload, just with a stack mark parameter.
3541         private Task ContinueWith(Action<Task> continuationAction, TaskScheduler scheduler,
3542             CancellationToken cancellationToken, TaskContinuationOptions continuationOptions)
3543         {
3544             // Throw on continuation with null action
3545             if (continuationAction == null)
3546             {
3547                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.continuationAction);
3548             }
3549
3550             // Throw on continuation with null TaskScheduler
3551             if (scheduler == null)
3552             {
3553                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.scheduler);
3554             }
3555
3556             TaskCreationOptions creationOptions;
3557             InternalTaskOptions internalOptions;
3558             CreationOptionsFromContinuationOptions(continuationOptions, out creationOptions, out internalOptions);
3559
3560             Task continuationTask = new ContinuationTaskFromTask(
3561                 this, continuationAction, null,
3562                 creationOptions, internalOptions
3563             );
3564
3565             // Register the continuation.  If synchronous execution is requested, this may
3566             // actually invoke the continuation before returning.
3567             ContinueWithCore(continuationTask, scheduler, cancellationToken, continuationOptions);
3568
3569             return continuationTask;
3570         }
3571         #endregion
3572
3573         #region Action<Task, Object> continuation
3574
3575         /// <summary>
3576         /// Creates a continuation that executes when the target <see cref="Task"/> completes.
3577         /// </summary>
3578         /// <param name="continuationAction">
3579         /// An action to run when the <see cref="Task"/> completes. When run, the delegate will be
3580         /// passed the completed task as and the caller-supplied state object as arguments.
3581         /// </param>
3582         /// <param name="state">An object representing data to be used by the continuation action.</param>
3583         /// <returns>A new continuation <see cref="Task"/>.</returns>
3584         /// <remarks>
3585         /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
3586         /// completed, whether it completes due to running to completion successfully, faulting due to an
3587         /// unhandled exception, or exiting out early due to being canceled.
3588         /// </remarks>
3589         /// <exception cref="T:System.ArgumentNullException">
3590         /// The <paramref name="continuationAction"/> argument is null.
3591         /// </exception>
3592         public Task ContinueWith(Action<Task, Object> continuationAction, Object state)
3593         {
3594             return ContinueWith(continuationAction, state, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None);
3595         }
3596
3597         /// <summary>
3598         /// Creates a continuation that executes when the target <see cref="Task"/> completes.
3599         /// </summary>
3600         /// <param name="continuationAction">
3601         /// An action to run when the <see cref="Task"/> completes. When run, the delegate will be
3602         /// passed the completed task and the caller-supplied state object as arguments.
3603         /// </param>
3604         /// <param name="state">An object representing data to be used by the continuation action.</param>
3605         /// <param name="cancellationToken"> The <see cref="CancellationToken"/> that will be assigned to the new continuation task.</param>
3606         /// <returns>A new continuation <see cref="Task"/>.</returns>
3607         /// <remarks>
3608         /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
3609         /// completed, whether it completes due to running to completion successfully, faulting due to an
3610         /// unhandled exception, or exiting out early due to being canceled.
3611         /// </remarks>
3612         /// <exception cref="T:System.ArgumentNullException">
3613         /// The <paramref name="continuationAction"/> argument is null.
3614         /// </exception>
3615         /// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
3616         /// has already been disposed.
3617         /// </exception>
3618         public Task ContinueWith(Action<Task, Object> continuationAction, Object state, CancellationToken cancellationToken)
3619         {
3620             return ContinueWith(continuationAction, state, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None);
3621         }
3622
3623         /// <summary>
3624         /// Creates a continuation that executes when the target <see cref="Task"/> completes.
3625         /// </summary>
3626         /// <param name="continuationAction">
3627         /// An action to run when the <see cref="Task"/> completes.  When run, the delegate will be
3628         /// passed the completed task and the caller-supplied state object as arguments.
3629         /// </param>
3630         /// <param name="state">An object representing data to be used by the continuation action.</param>
3631         /// <param name="scheduler">
3632         /// The <see cref="TaskScheduler"/> to associate with the continuation task and to use for its execution.
3633         /// </param>
3634         /// <returns>A new continuation <see cref="Task"/>.</returns>
3635         /// <remarks>
3636         /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
3637         /// completed, whether it completes due to running to completion successfully, faulting due to an
3638         /// unhandled exception, or exiting out early due to being canceled.
3639         /// </remarks>
3640         /// <exception cref="T:System.ArgumentNullException">
3641         /// The <paramref name="continuationAction"/> argument is null.
3642         /// </exception>
3643         /// <exception cref="T:System.ArgumentNullException">
3644         /// The <paramref name="scheduler"/> argument is null.
3645         /// </exception>
3646         public Task ContinueWith(Action<Task, Object> continuationAction, Object state, TaskScheduler scheduler)
3647         {
3648             return ContinueWith(continuationAction, state, scheduler, default(CancellationToken), TaskContinuationOptions.None);
3649         }
3650
3651         /// <summary>
3652         /// Creates a continuation that executes when the target <see cref="Task"/> completes.
3653         /// </summary>
3654         /// <param name="continuationAction">
3655         /// An action to run when the <see cref="Task"/> completes. When run, the delegate will be
3656         /// passed the completed task and the caller-supplied state object as arguments.
3657         /// </param>
3658         /// <param name="state">An object representing data to be used by the continuation action.</param>
3659         /// <param name="continuationOptions">
3660         /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such
3661         /// as <see
3662         /// cref="System.Threading.Tasks.TaskContinuationOptions.OnlyOnCanceled">OnlyOnCanceled</see>, as
3663         /// well as execution options, such as <see
3664         /// cref="System.Threading.Tasks.TaskContinuationOptions.ExecuteSynchronously">ExecuteSynchronously</see>.
3665         /// </param>
3666         /// <returns>A new continuation <see cref="Task"/>.</returns>
3667         /// <remarks>
3668         /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
3669         /// completed. If the continuation criteria specified through the <paramref
3670         /// name="continuationOptions"/> parameter are not met, the continuation task will be canceled
3671         /// instead of scheduled.
3672         /// </remarks>
3673         /// <exception cref="T:System.ArgumentNullException">
3674         /// The <paramref name="continuationAction"/> argument is null.
3675         /// </exception>
3676         /// <exception cref="T:System.ArgumentOutOfRangeException">
3677         /// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
3678         /// cref="T:System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
3679         /// </exception>
3680         public Task ContinueWith(Action<Task, Object> continuationAction, Object state, TaskContinuationOptions continuationOptions)
3681         {
3682             return ContinueWith(continuationAction, state, TaskScheduler.Current, default(CancellationToken), continuationOptions);
3683         }
3684
3685         /// <summary>
3686         /// Creates a continuation that executes when the target <see cref="Task"/> completes.
3687         /// </summary>
3688         /// <param name="continuationAction">
3689         /// An action to run when the <see cref="Task"/> completes. When run, the delegate will be
3690         /// passed the completed task and the caller-supplied state object as arguments.
3691         /// </param>
3692         /// <param name="state">An object representing data to be used by the continuation action.</param>
3693         /// <param name="continuationOptions">
3694         /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such
3695         /// as <see
3696         /// cref="System.Threading.Tasks.TaskContinuationOptions.OnlyOnCanceled">OnlyOnCanceled</see>, as
3697         /// well as execution options, such as <see
3698         /// cref="System.Threading.Tasks.TaskContinuationOptions.ExecuteSynchronously">ExecuteSynchronously</see>.
3699         /// </param>
3700         /// <param name="cancellationToken">The <see cref="CancellationToken"/> that will be assigned to the new continuation task.</param>
3701         /// <param name="scheduler">
3702         /// The <see cref="TaskScheduler"/> to associate with the continuation task and to use for its
3703         /// execution.
3704         /// </param>
3705         /// <returns>A new continuation <see cref="Task"/>.</returns>
3706         /// <remarks>
3707         /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
3708         /// completed. If the criteria specified through the <paramref name="continuationOptions"/> parameter
3709         /// are not met, the continuation task will be canceled instead of scheduled.
3710         /// </remarks>
3711         /// <exception cref="T:System.ArgumentNullException">
3712         /// The <paramref name="continuationAction"/> argument is null.
3713         /// </exception>
3714         /// <exception cref="T:System.ArgumentOutOfRangeException">
3715         /// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
3716         /// cref="T:System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
3717         /// </exception>
3718         /// <exception cref="T:System.ArgumentNullException">
3719         /// The <paramref name="scheduler"/> argument is null.
3720         /// </exception>
3721         /// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
3722         /// has already been disposed.
3723         /// </exception>
3724         public Task ContinueWith(Action<Task, Object> continuationAction, Object state, CancellationToken cancellationToken,
3725                                  TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
3726         {
3727             return ContinueWith(continuationAction, state, scheduler, cancellationToken, continuationOptions);
3728         }
3729
3730         // Same as the above overload, just with a stack mark parameter.
3731         private Task ContinueWith(Action<Task, Object> continuationAction, Object state, TaskScheduler scheduler,
3732             CancellationToken cancellationToken, TaskContinuationOptions continuationOptions)
3733         {
3734             // Throw on continuation with null action
3735             if (continuationAction == null)
3736             {
3737                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.continuationAction);
3738             }
3739
3740             // Throw on continuation with null TaskScheduler
3741             if (scheduler == null)
3742             {
3743                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.scheduler);
3744             }
3745
3746             TaskCreationOptions creationOptions;
3747             InternalTaskOptions internalOptions;
3748             CreationOptionsFromContinuationOptions(continuationOptions, out creationOptions, out internalOptions);
3749
3750             Task continuationTask = new ContinuationTaskFromTask(
3751                 this, continuationAction, state,
3752                 creationOptions, internalOptions
3753             );
3754
3755             // Register the continuation.  If synchronous execution is requested, this may
3756             // actually invoke the continuation before returning.
3757             ContinueWithCore(continuationTask, scheduler, cancellationToken, continuationOptions);
3758
3759             return continuationTask;
3760         }
3761
3762         #endregion
3763
3764         #region Func<Task, TResult> continuation
3765
3766         /// <summary>
3767         /// Creates a continuation that executes when the target <see cref="Task"/> completes.
3768         /// </summary>
3769         /// <typeparam name="TResult">
3770         /// The type of the result produced by the continuation.
3771         /// </typeparam>
3772         /// <param name="continuationFunction">
3773         /// A function to run when the <see cref="Task"/> completes. When run, the delegate will be
3774         /// passed the completed task as an argument.
3775         /// </param>
3776         /// <returns>A new continuation <see cref="Task{TResult}"/>.</returns>
3777         /// <remarks>
3778         /// The returned <see cref="Task{TResult}"/> will not be scheduled for execution until the current task has
3779         /// completed, whether it completes due to running to completion successfully, faulting due to an
3780         /// unhandled exception, or exiting out early due to being canceled.
3781         /// </remarks>
3782         /// <exception cref="T:System.ArgumentNullException">
3783         /// The <paramref name="continuationFunction"/> argument is null.
3784         /// </exception>
3785         public Task<TResult> ContinueWith<TResult>(Func<Task, TResult> continuationFunction)
3786         {
3787             return ContinueWith<TResult>(continuationFunction, TaskScheduler.Current, default(CancellationToken),
3788                 TaskContinuationOptions.None);
3789         }
3790
3791
3792         /// <summary>
3793         /// Creates a continuation that executes when the target <see cref="Task"/> completes.
3794         /// </summary>
3795         /// <typeparam name="TResult">
3796         /// The type of the result produced by the continuation.
3797         /// </typeparam>
3798         /// <param name="continuationFunction">
3799         /// A function to run when the <see cref="Task"/> completes. When run, the delegate will be
3800         /// passed the completed task as an argument.
3801         /// </param>
3802         /// <param name="cancellationToken">The <see cref="CancellationToken"/> that will be assigned to the new continuation task.</param>
3803         /// <returns>A new continuation <see cref="Task{TResult}"/>.</returns>
3804         /// <remarks>
3805         /// The returned <see cref="Task{TResult}"/> will not be scheduled for execution until the current task has
3806         /// completed, whether it completes due to running to completion successfully, faulting due to an
3807         /// unhandled exception, or exiting out early due to being canceled.
3808         /// </remarks>
3809         /// <exception cref="T:System.ArgumentNullException">
3810         /// The <paramref name="continuationFunction"/> argument is null.
3811         /// </exception>
3812         /// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
3813         /// has already been disposed.
3814         /// </exception>
3815         public Task<TResult> ContinueWith<TResult>(Func<Task, TResult> continuationFunction, CancellationToken cancellationToken)
3816         {
3817             return ContinueWith<TResult>(continuationFunction, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None);
3818         }
3819
3820         /// <summary>
3821         /// Creates a continuation that executes when the target <see cref="Task"/> completes.
3822         /// </summary>
3823         /// <typeparam name="TResult">
3824         /// The type of the result produced by the continuation.
3825         /// </typeparam>
3826         /// <param name="continuationFunction">
3827         /// A function to run when the <see cref="Task"/> completes.  When run, the delegate will be
3828         /// passed the completed task as an argument.
3829         /// </param>
3830         /// <param name="scheduler">
3831         /// The <see cref="TaskScheduler"/> to associate with the continuation task and to use for its execution.
3832         /// </param>
3833         /// <returns>A new continuation <see cref="Task{TResult}"/>.</returns>
3834         /// <remarks>
3835         /// The returned <see cref="Task{TResult}"/> will not be scheduled for execution until the current task has
3836         /// completed, whether it completes due to running to completion successfully, faulting due to an
3837         /// unhandled exception, or exiting out early due to being canceled.
3838         /// </remarks>
3839         /// <exception cref="T:System.ArgumentNullException">
3840         /// The <paramref name="continuationFunction"/> argument is null.
3841         /// </exception>
3842         /// <exception cref="T:System.ArgumentNullException">
3843         /// The <paramref name="scheduler"/> argument is null.
3844         /// </exception>
3845         public Task<TResult> ContinueWith<TResult>(Func<Task, TResult> continuationFunction, TaskScheduler scheduler)
3846         {
3847             return ContinueWith<TResult>(continuationFunction, scheduler, default(CancellationToken), TaskContinuationOptions.None);
3848         }
3849
3850         /// <summary>
3851         /// Creates a continuation that executes when the target <see cref="Task"/> completes.
3852         /// </summary>
3853         /// <typeparam name="TResult">
3854         /// The type of the result produced by the continuation.
3855         /// </typeparam>
3856         /// <param name="continuationFunction">
3857         /// A function to run when the <see cref="Task"/> completes. When run, the delegate will be
3858         /// passed the completed task as an argument.
3859         /// </param>
3860         /// <param name="continuationOptions">
3861         /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such
3862         /// as <see
3863         /// cref="System.Threading.Tasks.TaskContinuationOptions.OnlyOnCanceled">OnlyOnCanceled</see>, as
3864         /// well as execution options, such as <see
3865         /// cref="System.Threading.Tasks.TaskContinuationOptions.ExecuteSynchronously">ExecuteSynchronously</see>.
3866         /// </param>
3867         /// <returns>A new continuation <see cref="Task{TResult}"/>.</returns>
3868         /// <remarks>
3869         /// The returned <see cref="Task{TResult}"/> will not be scheduled for execution until the current task has
3870         /// completed. If the continuation criteria specified through the <paramref
3871         /// name="continuationOptions"/> parameter are not met, the continuation task will be canceled
3872         /// instead of scheduled.
3873         /// </remarks>
3874         /// <exception cref="T:System.ArgumentNullException">
3875         /// The <paramref name="continuationFunction"/> argument is null.
3876         /// </exception>
3877         /// <exception cref="T:System.ArgumentOutOfRangeException">
3878         /// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
3879         /// cref="T:System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
3880         /// </exception>
3881         public Task<TResult> ContinueWith<TResult>(Func<Task, TResult> continuationFunction, TaskContinuationOptions continuationOptions)
3882         {
3883             return ContinueWith<TResult>(continuationFunction, TaskScheduler.Current, default(CancellationToken), continuationOptions);
3884         }
3885
3886         /// <summary>
3887         /// Creates a continuation that executes when the target <see cref="Task"/> completes.
3888         /// </summary>
3889         /// <typeparam name="TResult">
3890         /// The type of the result produced by the continuation.
3891         /// </typeparam>
3892         /// <param name="continuationFunction">
3893         /// A function to run when the <see cref="Task"/> completes. When run, the delegate will be
3894         /// passed the completed task as an argument.
3895         /// </param>
3896         /// <param name="cancellationToken">The <see cref="CancellationToken"/> that will be assigned to the new continuation task.</param>
3897         /// <param name="continuationOptions">
3898         /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such
3899         /// as <see
3900         /// cref="System.Threading.Tasks.TaskContinuationOptions.OnlyOnCanceled">OnlyOnCanceled</see>, as
3901         /// well as execution options, such as <see
3902         /// cref="System.Threading.Tasks.TaskContinuationOptions.ExecuteSynchronously">ExecuteSynchronously</see>.
3903         /// </param>
3904         /// <param name="scheduler">
3905         /// The <see cref="TaskScheduler"/> to associate with the continuation task and to use for its
3906         /// execution.
3907         /// </param>
3908         /// <returns>A new continuation <see cref="Task{TResult}"/>.</returns>
3909         /// <remarks>
3910         /// The returned <see cref="Task{TResult}"/> will not be scheduled for execution until the current task has
3911         /// completed. If the criteria specified through the <paramref name="continuationOptions"/> parameter
3912         /// are not met, the continuation task will be canceled instead of scheduled.
3913         /// </remarks>
3914         /// <exception cref="T:System.ArgumentNullException">
3915         /// The <paramref name="continuationFunction"/> argument is null.
3916         /// </exception>
3917         /// <exception cref="T:System.ArgumentOutOfRangeException">
3918         /// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
3919         /// cref="T:System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
3920         /// </exception>
3921         /// <exception cref="T:System.ArgumentNullException">
3922         /// The <paramref name="scheduler"/> argument is null.
3923         /// </exception>
3924         /// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
3925         /// has already been disposed.
3926         /// </exception>
3927         public Task<TResult> ContinueWith<TResult>(Func<Task, TResult> continuationFunction, CancellationToken cancellationToken,
3928                                                    TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
3929         {
3930             return ContinueWith<TResult>(continuationFunction, scheduler, cancellationToken, continuationOptions);
3931         }
3932
3933         // Same as the above overload, just with a stack mark parameter.
3934         private Task<TResult> ContinueWith<TResult>(Func<Task, TResult> continuationFunction, TaskScheduler scheduler,
3935             CancellationToken cancellationToken, TaskContinuationOptions continuationOptions)
3936         {
3937             // Throw on continuation with null function
3938             if (continuationFunction == null)
3939             {
3940                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.continuationFunction);
3941             }
3942
3943             // Throw on continuation with null task scheduler
3944             if (scheduler == null)
3945             {
3946                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.scheduler);
3947             }
3948
3949             TaskCreationOptions creationOptions;
3950             InternalTaskOptions internalOptions;
3951             CreationOptionsFromContinuationOptions(continuationOptions, out creationOptions, out internalOptions);
3952
3953             Task<TResult> continuationTask = new ContinuationResultTaskFromTask<TResult>(
3954                 this, continuationFunction, null,
3955                 creationOptions, internalOptions
3956             );
3957
3958             // Register the continuation.  If synchronous execution is requested, this may
3959             // actually invoke the continuation before returning.
3960             ContinueWithCore(continuationTask, scheduler, cancellationToken, continuationOptions);
3961
3962             return continuationTask;
3963         }
3964         #endregion
3965
3966         #region Func<Task, Object, TResult> continuation
3967
3968         /// <summary>
3969         /// Creates a continuation that executes when the target <see cref="Task"/> completes.
3970         /// </summary>
3971         /// <typeparam name="TResult">
3972         /// The type of the result produced by the continuation.
3973         /// </typeparam>
3974         /// <param name="continuationFunction">
3975         /// A function to run when the <see cref="Task"/> completes. When run, the delegate will be
3976         /// passed the completed task and the caller-supplied state object as arguments.
3977         /// </param>
3978         /// <param name="state">An object representing data to be used by the continuation function.</param>
3979         /// <returns>A new continuation <see cref="Task{TResult}"/>.</returns>
3980         /// <remarks>
3981         /// The returned <see cref="Task{TResult}"/> will not be scheduled for execution until the current task has
3982         /// completed, whether it completes due to running to completion successfully, faulting due to an
3983         /// unhandled exception, or exiting out early due to being canceled.
3984         /// </remarks>
3985         /// <exception cref="T:System.ArgumentNullException">
3986         /// The <paramref name="continuationFunction"/> argument is null.
3987         /// </exception>
3988         public Task<TResult> ContinueWith<TResult>(Func<Task, Object, TResult> continuationFunction, Object state)
3989         {
3990             return ContinueWith<TResult>(continuationFunction, state, TaskScheduler.Current, default(CancellationToken),
3991                 TaskContinuationOptions.None);
3992         }
3993
3994
3995         /// <summary>
3996         /// Creates a continuation that executes when the target <see cref="Task"/> completes.
3997         /// </summary>
3998         /// <typeparam name="TResult">
3999         /// The type of the result produced by the continuation.
4000         /// </typeparam>
4001         /// <param name="continuationFunction">
4002         /// A function to run when the <see cref="Task"/> completes. When run, the delegate will be
4003         /// passed the completed task and the caller-supplied state object as arguments.
4004         /// </param>
4005         /// <param name="state">An object representing data to be used by the continuation function.</param>
4006         /// <param name="cancellationToken">The <see cref="CancellationToken"/> that will be assigned to the new continuation task.</param>
4007         /// <returns>A new continuation <see cref="Task{TResult}"/>.</returns>
4008         /// <remarks>
4009         /// The returned <see cref="Task{TResult}"/> will not be scheduled for execution until the current task has
4010         /// completed, whether it completes due to running to completion successfully, faulting due to an
4011         /// unhandled exception, or exiting out early due to being canceled.
4012         /// </remarks>
4013         /// <exception cref="T:System.ArgumentNullException">
4014         /// The <paramref name="continuationFunction"/> argument is null.
4015         /// </exception>
4016         /// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
4017         /// has already been disposed.
4018         /// </exception>
4019         public Task<TResult> ContinueWith<TResult>(Func<Task, Object, TResult> continuationFunction, Object state, CancellationToken cancellationToken)
4020         {
4021             return ContinueWith<TResult>(continuationFunction, state, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None);
4022         }
4023
4024         /// <summary>
4025         /// Creates a continuation that executes when the target <see cref="Task"/> completes.
4026         /// </summary>
4027         /// <typeparam name="TResult">
4028         /// The type of the result produced by the continuation.
4029         /// </typeparam>
4030         /// <param name="continuationFunction">
4031         /// A function to run when the <see cref="Task"/> completes.  When run, the delegate will be
4032         /// passed the completed task and the caller-supplied state object as arguments.
4033         /// </param>
4034         /// <param name="state">An object representing data to be used by the continuation function.</param>
4035         /// <param name="scheduler">
4036         /// The <see cref="TaskScheduler"/> to associate with the continuation task and to use for its execution.
4037         /// </param>
4038         /// <returns>A new continuation <see cref="Task{TResult}"/>.</returns>
4039         /// <remarks>
4040         /// The returned <see cref="Task{TResult}"/> will not be scheduled for execution until the current task has
4041         /// completed, whether it completes due to running to completion successfully, faulting due to an
4042         /// unhandled exception, or exiting out early due to being canceled.
4043         /// </remarks>
4044         /// <exception cref="T:System.ArgumentNullException">
4045         /// The <paramref name="continuationFunction"/> argument is null.
4046         /// </exception>
4047         /// <exception cref="T:System.ArgumentNullException">
4048         /// The <paramref name="scheduler"/> argument is null.
4049         /// </exception>
4050         public Task<TResult> ContinueWith<TResult>(Func<Task, Object, TResult> continuationFunction, Object state, TaskScheduler scheduler)
4051         {
4052             return ContinueWith<TResult>(continuationFunction, state, scheduler, default(CancellationToken), TaskContinuationOptions.None);
4053         }
4054
4055         /// <summary>
4056         /// Creates a continuation that executes when the target <see cref="Task"/> completes.
4057         /// </summary>
4058         /// <typeparam name="TResult">
4059         /// The type of the result produced by the continuation.
4060         /// </typeparam>
4061         /// <param name="continuationFunction">
4062         /// A function to run when the <see cref="Task"/> completes. When run, the delegate will be
4063         /// passed the completed task and the caller-supplied state object as arguments.
4064         /// </param>
4065         /// <param name="state">An object representing data to be used by the continuation function.</param>
4066         /// <param name="continuationOptions">
4067         /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such
4068         /// as <see
4069         /// cref="System.Threading.Tasks.TaskContinuationOptions.OnlyOnCanceled">OnlyOnCanceled</see>, as
4070         /// well as execution options, such as <see
4071         /// cref="System.Threading.Tasks.TaskContinuationOptions.ExecuteSynchronously">ExecuteSynchronously</see>.
4072         /// </param>
4073         /// <returns>A new continuation <see cref="Task{TResult}"/>.</returns>
4074         /// <remarks>
4075         /// The returned <see cref="Task{TResult}"/> will not be scheduled for execution until the current task has
4076         /// completed. If the continuation criteria specified through the <paramref
4077         /// name="continuationOptions"/> parameter are not met, the continuation task will be canceled
4078         /// instead of scheduled.
4079         /// </remarks>
4080         /// <exception cref="T:System.ArgumentNullException">
4081         /// The <paramref name="continuationFunction"/> argument is null.
4082         /// </exception>
4083         /// <exception cref="T:System.ArgumentOutOfRangeException">
4084         /// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
4085         /// cref="T:System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
4086         /// </exception>
4087         public Task<TResult> ContinueWith<TResult>(Func<Task, Object, TResult> continuationFunction, Object state, TaskContinuationOptions continuationOptions)
4088         {
4089             return ContinueWith<TResult>(continuationFunction, state, TaskScheduler.Current, default(CancellationToken), continuationOptions);
4090         }
4091
4092         /// <summary>
4093         /// Creates a continuation that executes when the target <see cref="Task"/> completes.
4094         /// </summary>
4095         /// <typeparam name="TResult">
4096         /// The type of the result produced by the continuation.
4097         /// </typeparam>
4098         /// <param name="continuationFunction">
4099         /// A function to run when the <see cref="Task"/> completes. When run, the delegate will be
4100         /// passed the completed task and the caller-supplied state object as arguments.
4101         /// </param>
4102         /// <param name="state">An object representing data to be used by the continuation function.</param>
4103         /// <param name="cancellationToken">The <see cref="CancellationToken"/> that will be assigned to the new continuation task.</param>
4104         /// <param name="continuationOptions">
4105         /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such
4106         /// as <see
4107         /// cref="System.Threading.Tasks.TaskContinuationOptions.OnlyOnCanceled">OnlyOnCanceled</see>, as
4108         /// well as execution options, such as <see
4109         /// cref="System.Threading.Tasks.TaskContinuationOptions.ExecuteSynchronously">ExecuteSynchronously</see>.
4110         /// </param>
4111         /// <param name="scheduler">
4112         /// The <see cref="TaskScheduler"/> to associate with the continuation task and to use for its
4113         /// execution.
4114         /// </param>
4115         /// <returns>A new continuation <see cref="Task{TResult}"/>.</returns>
4116         /// <remarks>
4117         /// The returned <see cref="Task{TResult}"/> will not be scheduled for execution until the current task has
4118         /// completed. If the criteria specified through the <paramref name="continuationOptions"/> parameter
4119         /// are not met, the continuation task will be canceled instead of scheduled.
4120         /// </remarks>
4121         /// <exception cref="T:System.ArgumentNullException">
4122         /// The <paramref name="continuationFunction"/> argument is null.
4123         /// </exception>
4124         /// <exception cref="T:System.ArgumentOutOfRangeException">
4125         /// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
4126         /// cref="T:System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
4127         /// </exception>
4128         /// <exception cref="T:System.ArgumentNullException">
4129         /// The <paramref name="scheduler"/> argument is null.
4130         /// </exception>
4131         /// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
4132         /// has already been disposed.
4133         /// </exception>
4134         public Task<TResult> ContinueWith<TResult>(Func<Task, Object, TResult> continuationFunction, Object state, CancellationToken cancellationToken,
4135                                                    TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
4136         {
4137             return ContinueWith<TResult>(continuationFunction, state, scheduler, cancellationToken, continuationOptions);
4138         }
4139
4140         // Same as the above overload, just with a stack mark parameter.
4141         private Task<TResult> ContinueWith<TResult>(Func<Task, Object, TResult> continuationFunction, Object state, TaskScheduler scheduler,
4142             CancellationToken cancellationToken, TaskContinuationOptions continuationOptions)
4143         {
4144             // Throw on continuation with null function
4145             if (continuationFunction == null)
4146             {
4147                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.continuationFunction);
4148             }
4149
4150             // Throw on continuation with null task scheduler
4151             if (scheduler == null)
4152             {
4153                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.scheduler);
4154             }
4155
4156             TaskCreationOptions creationOptions;
4157             InternalTaskOptions internalOptions;
4158             CreationOptionsFromContinuationOptions(continuationOptions, out creationOptions, out internalOptions);
4159
4160             Task<TResult> continuationTask = new ContinuationResultTaskFromTask<TResult>(
4161                 this, continuationFunction, state,
4162                 creationOptions, internalOptions
4163             );
4164
4165             // Register the continuation.  If synchronous execution is requested, this may
4166             // actually invoke the continuation before returning.
4167             ContinueWithCore(continuationTask, scheduler, cancellationToken, continuationOptions);
4168
4169             return continuationTask;
4170         }
4171         #endregion
4172
4173         /// <summary>
4174         /// Converts TaskContinuationOptions to TaskCreationOptions, and also does
4175         /// some validity checking along the way.
4176         /// </summary>
4177         /// <param name="continuationOptions">Incoming TaskContinuationOptions</param>
4178         /// <param name="creationOptions">Outgoing TaskCreationOptions</param>
4179         /// <param name="internalOptions">Outgoing InternalTaskOptions</param>
4180         internal static void CreationOptionsFromContinuationOptions(
4181             TaskContinuationOptions continuationOptions,
4182             out TaskCreationOptions creationOptions,
4183             out InternalTaskOptions internalOptions)
4184         {
4185             // This is used a couple of times below
4186             const TaskContinuationOptions NotOnAnything =
4187                 TaskContinuationOptions.NotOnCanceled |
4188                 TaskContinuationOptions.NotOnFaulted |
4189                 TaskContinuationOptions.NotOnRanToCompletion;
4190
4191             const TaskContinuationOptions CreationOptionsMask =
4192                 TaskContinuationOptions.PreferFairness |
4193                 TaskContinuationOptions.LongRunning |
4194                 TaskContinuationOptions.DenyChildAttach |
4195                 TaskContinuationOptions.HideScheduler |
4196                 TaskContinuationOptions.AttachedToParent |
4197                 TaskContinuationOptions.RunContinuationsAsynchronously;
4198
4199             // Check that LongRunning and ExecuteSynchronously are not specified together
4200             const TaskContinuationOptions IllegalMask = TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.LongRunning;
4201             if ((continuationOptions & IllegalMask) == IllegalMask)
4202             {
4203                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.continuationOptions, ExceptionResource.Task_ContinueWith_ESandLR);
4204             }
4205
4206             // Check that no illegal options were specified
4207             if ((continuationOptions &
4208                 ~(CreationOptionsMask | NotOnAnything |
4209                     TaskContinuationOptions.LazyCancellation | TaskContinuationOptions.ExecuteSynchronously)) != 0)
4210             {
4211                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.continuationOptions);
4212             }
4213
4214             // Check that we didn't specify "not on anything"
4215             if ((continuationOptions & NotOnAnything) == NotOnAnything)
4216             {
4217                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.continuationOptions, ExceptionResource.Task_ContinueWith_NotOnAnything);
4218             }
4219
4220             // This passes over all but LazyCancellation, which has no representation in TaskCreationOptions
4221             creationOptions = (TaskCreationOptions)(continuationOptions & CreationOptionsMask);
4222
4223             // internalOptions has at least ContinuationTask and possibly LazyCancellation
4224             internalOptions = (continuationOptions & TaskContinuationOptions.LazyCancellation) != 0 ?
4225                 InternalTaskOptions.ContinuationTask | InternalTaskOptions.LazyCancellation :
4226                 InternalTaskOptions.ContinuationTask;
4227         }
4228
4229
4230         /// <summary>
4231         /// Registers the continuation and possibly runs it (if the task is already finished).
4232         /// </summary>
4233         /// <param name="continuationTask">The continuation task itself.</param>
4234         /// <param name="scheduler">TaskScheduler with which to associate continuation task.</param>
4235         /// <param name="options">Restrictions on when the continuation becomes active.</param>
4236         internal void ContinueWithCore(Task continuationTask,
4237                                        TaskScheduler scheduler,
4238                                        CancellationToken cancellationToken,
4239                                        TaskContinuationOptions options)
4240         {
4241             Debug.Assert(continuationTask != null, "Task.ContinueWithCore(): null continuationTask");
4242             Debug.Assert(scheduler != null, "Task.ContinueWithCore(): null scheduler");
4243             Debug.Assert(!continuationTask.IsCompleted, "Did not expect continuationTask to be completed");
4244
4245             // Create a TaskContinuation
4246             TaskContinuation continuation = new StandardTaskContinuation(continuationTask, options, scheduler);
4247
4248             // If cancellationToken is cancellable, then assign it.  
4249             if (cancellationToken.CanBeCanceled)
4250             {
4251                 if (IsCompleted || cancellationToken.IsCancellationRequested)
4252                 {
4253                     // If the antecedent has completed, then we will not be queuing up
4254                     // the continuation in the antecedent's continuation list.  Likewise,
4255                     // if the cancellationToken has been canceled, continuationTask will
4256                     // be completed in the AssignCancellationToken call below, and there
4257                     // is no need to queue the continuation to the antecedent's continuation
4258                     // list.  In either of these two cases, we will pass "null" for the antecedent,
4259                     // meaning "the cancellation callback should not attempt to remove the
4260                     // continuation from its antecedent's continuation list".
4261                     continuationTask.AssignCancellationToken(cancellationToken, null, null);
4262                 }
4263                 else
4264                 {
4265                     // The antecedent is not yet complete, so there is a pretty good chance
4266                     // that the continuation will be queued up in the antecedent.  Assign the
4267                     // cancellation token with information about the antecedent, so that the
4268                     // continuation can be dequeued upon the signalling of the token.
4269                     //
4270                     // It's possible that the antecedent completes before the call to AddTaskContinuation,
4271                     // and that is a benign race condition.  It just means that the cancellation will result in
4272                     // a futile search of the antecedent's continuation list.
4273                     continuationTask.AssignCancellationToken(cancellationToken, this, continuation);
4274                 }
4275             }
4276
4277             // In the case of a pre-canceled token, continuationTask will have been completed
4278             // in a Canceled state by now.  If such is the case, there is no need to go through
4279             // the motions of queuing up the continuation for eventual execution.
4280             if (!continuationTask.IsCompleted)
4281             {
4282                 // We need additional correlation produced here to ensure that at least the continuation 
4283                 // code will be correlatable to the currrent activity that initiated "this" task:
4284                 //  . when the antecendent ("this") is a promise we have very little control over where 
4285                 //    the code for the promise will run (e.g. it can be a task from a user provided 
4286                 //    TaskCompletionSource or from a classic Begin/End async operation); this user or 
4287                 //    system code will likely not have stamped an activity id on the thread, so there's
4288                 //    generally no easy correlation that can be provided between the current activity
4289                 //    and the promise. Also the continuation code may run practically on any thread. 
4290                 //    Since there may be no correlation between the current activity and the TCS's task
4291                 //    activity, we ensure we at least create a correlation from the current activity to
4292                 //    the continuation that runs when the promise completes.
4293                 if ((this.Options & (TaskCreationOptions)InternalTaskOptions.PromiseTask) != 0 &&
4294                     !(this is ITaskCompletionAction))
4295                 {
4296                     var etwLog = TplEtwProvider.Log;
4297                     if (etwLog.IsEnabled())
4298                     {
4299                         etwLog.AwaitTaskContinuationScheduled(TaskScheduler.Current.Id, Task.CurrentId ?? 0, continuationTask.Id);
4300                     }
4301                 }
4302
4303                 // Attempt to enqueue the continuation
4304                 bool continuationQueued = AddTaskContinuation(continuation, addBeforeOthers: false);
4305
4306                 // If the continuation was not queued (because the task completed), then run it now.
4307                 if (!continuationQueued) continuation.Run(this, bCanInlineContinuationTask: true);
4308             }
4309         }
4310         #endregion
4311
4312         // Adds a lightweight completion action to a task.  This is similar to a continuation
4313         // task except that it is stored as an action, and thus does not require the allocation/
4314         // execution resources of a continuation task.
4315         //
4316         // Used internally by ContinueWhenAll() and ContinueWhenAny().
4317         internal void AddCompletionAction(ITaskCompletionAction action)
4318         {
4319             AddCompletionAction(action, addBeforeOthers: false);
4320         }
4321
4322         private void AddCompletionAction(ITaskCompletionAction action, bool addBeforeOthers)
4323         {
4324             if (!AddTaskContinuation(action, addBeforeOthers))
4325                 action.Invoke(this); // run the action directly if we failed to queue the continuation (i.e., the task completed)
4326         }
4327
4328         // Support method for AddTaskContinuation that takes care of multi-continuation logic.
4329         // Returns true if and only if the continuation was successfully queued.
4330         // THIS METHOD ASSUMES THAT m_continuationObject IS NOT NULL.  That case was taken
4331         // care of in the calling method, AddTaskContinuation().
4332         private bool AddTaskContinuationComplex(object tc, bool addBeforeOthers)
4333         {
4334             Debug.Assert(tc != null, "Expected non-null tc object in AddTaskContinuationComplex");
4335
4336             object oldValue = m_continuationObject;
4337
4338             // Logic for the case where we were previously storing a single continuation
4339             if ((oldValue != s_taskCompletionSentinel) && (!(oldValue is List<object>)))
4340             {
4341                 // Construct a new TaskContinuation list
4342                 List<object> newList = new List<object>();
4343
4344                 // Add in the old single value
4345                 newList.Add(oldValue);
4346
4347                 // Now CAS in the new list
4348                 Interlocked.CompareExchange(ref m_continuationObject, newList, oldValue);
4349
4350                 // We might be racing against another thread converting the single into
4351                 // a list, or we might be racing against task completion, so resample "list"
4352                 // below.
4353             }
4354
4355             // m_continuationObject is guaranteed at this point to be either a List or
4356             // s_taskCompletionSentinel.
4357             List<object> list = m_continuationObject as List<object>;
4358             Debug.Assert((list != null) || (m_continuationObject == s_taskCompletionSentinel),
4359                 "Expected m_continuationObject to be list or sentinel");
4360
4361             // If list is null, it can only mean that s_taskCompletionSentinel has been exchanged
4362             // into m_continuationObject.  Thus, the task has completed and we should return false
4363             // from this method, as we will not be queuing up the continuation.
4364             if (list != null)
4365             {
4366                 lock (list)
4367                 {
4368                     // It is possible for the task to complete right after we snap the copy of
4369                     // the list.  If so, then fall through and return false without queuing the
4370                     // continuation.
4371                     if (m_continuationObject != s_taskCompletionSentinel)
4372                     {
4373                         // Before growing the list we remove possible null entries that are the
4374                         // result from RemoveContinuations()
4375                         if (list.Count == list.Capacity)
4376                         {
4377                             list.RemoveAll(s_IsTaskContinuationNullPredicate);
4378                         }
4379
4380                         if (addBeforeOthers)
4381                             list.Insert(0, tc);
4382                         else
4383                             list.Add(tc);
4384
4385                         return true; // continuation successfully queued, so return true.
4386                     }
4387                 }
4388             }
4389
4390             // We didn't succeed in queuing the continuation, so return false.
4391             return false;
4392         }
4393
4394         // Record a continuation task or action.
4395         // Return true if and only if we successfully queued a continuation.
4396         private bool AddTaskContinuation(object tc, bool addBeforeOthers)
4397         {
4398             Debug.Assert(tc != null);
4399
4400             // Make sure that, if someone calls ContinueWith() right after waiting for the predecessor to complete,
4401             // we don't queue up a continuation.
4402             if (IsCompleted) return false;
4403
4404             // Try to just jam tc into m_continuationObject
4405             if ((m_continuationObject != null) || (Interlocked.CompareExchange(ref m_continuationObject, tc, null) != null))
4406             {
4407                 // If we get here, it means that we failed to CAS tc into m_continuationObject.
4408                 // Therefore, we must go the more complicated route.
4409                 return AddTaskContinuationComplex(tc, addBeforeOthers);
4410             }
4411             else return true;
4412         }
4413
4414         // Removes a continuation task from m_continuations
4415         internal void RemoveContinuation(object continuationObject) // could be TaskContinuation or Action<Task>
4416         {
4417             // We need to snap a local reference to m_continuations since reading a volatile object is more costly.
4418             // Also to prevent the value to be changed as result of a race condition with another method.
4419             object continuationsLocalRef = m_continuationObject;
4420
4421             // Task is completed. Nothing to do here.
4422             if (continuationsLocalRef == s_taskCompletionSentinel) return;
4423
4424             List<object> continuationsLocalListRef = continuationsLocalRef as List<object>;
4425
4426             if (continuationsLocalListRef == null)
4427             {
4428                 // This is not a list. If we have a single object (the one we want to remove) we try to replace it with an empty list.
4429                 // Note we cannot go back to a null state, since it will mess up the AddTaskContinuation logic.
4430                 if (Interlocked.CompareExchange(ref m_continuationObject, new List<object>(), continuationObject) != continuationObject)
4431                 {
4432                     // If we fail it means that either AddContinuationComplex won the race condition and m_continuationObject is now a List
4433                     // that contains the element we want to remove. Or FinishContinuations set the s_taskCompletionSentinel.
4434                     // So we should try to get a list one more time
4435                     continuationsLocalListRef = m_continuationObject as List<object>;
4436                 }
4437                 else
4438                 {
4439                     // Exchange was successful so we can skip the last comparison
4440                     return;
4441                 }
4442             }
4443
4444             // if continuationsLocalRef == null it means s_taskCompletionSentinel has been set already and there is nothing else to do.
4445             if (continuationsLocalListRef != null)
4446             {
4447                 lock (continuationsLocalListRef)
4448                 {
4449                     // There is a small chance that this task completed since we took a local snapshot into
4450                     // continuationsLocalRef.  In that case, just return; we don't want to be manipulating the
4451                     // continuation list as it is being processed.
4452                     if (m_continuationObject == s_taskCompletionSentinel) return;
4453
4454                     // Find continuationObject in the continuation list
4455                     int index = continuationsLocalListRef.IndexOf(continuationObject);
4456
4457                     if (index != -1)
4458                     {
4459                         // null out that TaskContinuation entry, which will be interpreted as "to be cleaned up"
4460                         continuationsLocalListRef[index] = null;
4461                     }
4462                 }
4463             }
4464         }
4465
4466         // statically allocated delegate for the RemoveAll expression in RemoveContinuations() and AddContinuationComplex()
4467         private readonly static Predicate<object> s_IsTaskContinuationNullPredicate =
4468             new Predicate<object>((tc) => { return (tc == null); });
4469
4470
4471         //
4472         // Wait methods
4473         //
4474
4475         /// <summary>
4476         /// Waits for all of the provided <see cref="Task"/> objects to complete execution.
4477         /// </summary>
4478         /// <param name="tasks">
4479         /// An array of <see cref="Task"/> instances on which to wait.
4480         /// </param>
4481         /// <exception cref="T:System.ArgumentNullException">
4482         /// The <paramref name="tasks"/> argument is null.
4483         /// </exception>
4484         /// <exception cref="T:System.ArgumentNullException">
4485         /// The <paramref name="tasks"/> argument contains a null element.
4486         /// </exception>
4487         /// <exception cref="T:System.AggregateException">
4488         /// At least one of the <see cref="Task"/> instances was canceled -or- an exception was thrown during
4489         /// the execution of at least one of the <see cref="Task"/> instances.
4490         /// </exception>
4491         [MethodImpl(MethodImplOptions.NoOptimization)]  // this is needed for the parallel debugger
4492         public static void WaitAll(params Task[] tasks)
4493         {
4494 #if DEBUG
4495             bool waitResult =
4496 #endif
4497             WaitAllCore(tasks, Timeout.Infinite, default(CancellationToken));
4498
4499 #if DEBUG
4500             Debug.Assert(waitResult, "expected wait to succeed");
4501 #endif
4502         }
4503
4504         /// <summary>
4505         /// Waits for all of the provided <see cref="Task"/> objects to complete execution.
4506         /// </summary>
4507         /// <returns>
4508         /// true if all of the <see cref="Task"/> instances completed execution within the allotted time;
4509         /// otherwise, false.
4510         /// </returns>
4511         /// <param name="tasks">
4512         /// An array of <see cref="Task"/> instances on which to wait.
4513         /// </param>
4514         /// <param name="timeout">
4515         /// A <see cref="System.TimeSpan"/> that represents the number of milliseconds to wait, or a <see
4516         /// cref="System.TimeSpan"/> that represents -1 milliseconds to wait indefinitely.
4517         /// </param>
4518         /// <exception cref="T:System.ArgumentNullException">
4519         /// The <paramref name="tasks"/> argument is null.
4520         /// </exception>
4521         /// <exception cref="T:System.ArgumentException">
4522         /// The <paramref name="tasks"/> argument contains a null element.
4523         /// </exception>
4524         /// <exception cref="T:System.AggregateException">
4525         /// At least one of the <see cref="Task"/> instances was canceled -or- an exception was thrown during
4526         /// the execution of at least one of the <see cref="Task"/> instances.
4527         /// </exception>
4528         /// <exception cref="T:System.ArgumentOutOfRangeException">
4529         /// <paramref name="timeout"/> is a negative number other than -1 milliseconds, which represents an
4530         /// infinite time-out -or- timeout is greater than
4531         /// <see cref="System.Int32.MaxValue"/>.
4532         /// </exception>
4533         [MethodImpl(MethodImplOptions.NoOptimization)]  // this is needed for the parallel debugger
4534         public static bool WaitAll(Task[] tasks, TimeSpan timeout)
4535         {
4536             long totalMilliseconds = (long)timeout.TotalMilliseconds;
4537             if (totalMilliseconds < -1 || totalMilliseconds > Int32.MaxValue)
4538             {
4539                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.timeout);
4540             }
4541
4542             return WaitAllCore(tasks, (int)totalMilliseconds, default(CancellationToken));
4543         }
4544
4545         /// <summary>
4546         /// Waits for all of the provided <see cref="Task"/> objects to complete execution.
4547         /// </summary>
4548         /// <returns>
4549         /// true if all of the <see cref="Task"/> instances completed execution within the allotted time;
4550         /// otherwise, false.
4551         /// </returns>
4552         /// <param name="millisecondsTimeout">
4553         /// The number of milliseconds to wait, or <see cref="System.Threading.Timeout.Infinite"/> (-1) to
4554         /// wait indefinitely.</param>
4555         /// <param name="tasks">An array of <see cref="Task"/> instances on which to wait.
4556         /// </param>
4557         /// <exception cref="T:System.ArgumentNullException">
4558         /// The <paramref name="tasks"/> argument is null.
4559         /// </exception>
4560         /// <exception cref="T:System.ArgumentException">
4561         /// The <paramref name="tasks"/> argument contains a null element.
4562         /// </exception>
4563         /// <exception cref="T:System.AggregateException">
4564         /// At least one of the <see cref="Task"/> instances was canceled -or- an exception was thrown during
4565         /// the execution of at least one of the <see cref="Task"/> instances.
4566         /// </exception>
4567         /// <exception cref="T:System.ArgumentOutOfRangeException">
4568         /// <paramref name="millisecondsTimeout"/> is a negative number other than -1, which represents an
4569         /// infinite time-out.
4570         /// </exception>
4571         [MethodImpl(MethodImplOptions.NoOptimization)]  // this is needed for the parallel debugger
4572         public static bool WaitAll(Task[] tasks, int millisecondsTimeout)
4573         {
4574             return WaitAllCore(tasks, millisecondsTimeout, default(CancellationToken));
4575         }
4576
4577         /// <summary>
4578         /// Waits for all of the provided <see cref="Task"/> objects to complete execution.
4579         /// </summary>
4580         /// <returns>
4581         /// true if all of the <see cref="Task"/> instances completed execution within the allotted time;
4582         /// otherwise, false.
4583         /// </returns>
4584         /// <param name="tasks">
4585         /// An array of <see cref="Task"/> instances on which to wait.
4586         /// </param>
4587         /// <param name="cancellationToken">
4588         /// A <see cref="CancellationToken"/> to observe while waiting for the tasks to complete.
4589         /// </param>
4590         /// <exception cref="T:System.ArgumentNullException">
4591         /// The <paramref name="tasks"/> argument is null.
4592         /// </exception>
4593         /// <exception cref="T:System.ArgumentException">
4594         /// The <paramref name="tasks"/> argument contains a null element.
4595         /// </exception>
4596         /// <exception cref="T:System.AggregateException">
4597         /// At least one of the <see cref="Task"/> instances was canceled -or- an exception was thrown during
4598         /// the execution of at least one of the <see cref="Task"/> instances.
4599         /// </exception>
4600         /// <exception cref="T:System.OperationCanceledException">
4601         /// The <paramref name="cancellationToken"/> was canceled.
4602         /// </exception>
4603         [MethodImpl(MethodImplOptions.NoOptimization)]  // this is needed for the parallel debugger
4604         public static void WaitAll(Task[] tasks, CancellationToken cancellationToken)
4605         {
4606             WaitAllCore(tasks, Timeout.Infinite, cancellationToken);
4607         }
4608
4609         /// <summary>
4610         /// Waits for all of the provided <see cref="Task"/> objects to complete execution.
4611         /// </summary>
4612         /// <returns>
4613         /// true if all of the <see cref="Task"/> instances completed execution within the allotted time;
4614         /// otherwise, false.
4615         /// </returns>
4616         /// <param name="tasks">
4617         /// An array of <see cref="Task"/> instances on which to wait.
4618         /// </param>
4619         /// <param name="millisecondsTimeout">
4620         /// The number of milliseconds to wait, or <see cref="System.Threading.Timeout.Infinite"/> (-1) to
4621         /// wait indefinitely.
4622         /// </param>
4623         /// <param name="cancellationToken">
4624         /// A <see cref="CancellationToken"/> to observe while waiting for the tasks to complete.
4625         /// </param>
4626         /// <exception cref="T:System.ArgumentNullException">
4627         /// The <paramref name="tasks"/> argument is null.
4628         /// </exception>
4629         /// <exception cref="T:System.ArgumentException">
4630         /// The <paramref name="tasks"/> argument contains a null element.
4631         /// </exception>
4632         /// <exception cref="T:System.AggregateException">
4633         /// At least one of the <see cref="Task"/> instances was canceled -or- an exception was thrown during
4634         /// the execution of at least one of the <see cref="Task"/> instances.
4635         /// </exception>
4636         /// <exception cref="T:System.ArgumentOutOfRangeException">
4637         /// <paramref name="millisecondsTimeout"/> is a negative number other than -1, which represents an
4638         /// infinite time-out.
4639         /// </exception>
4640         /// <exception cref="T:System.OperationCanceledException">
4641         /// The <paramref name="cancellationToken"/> was canceled.
4642         /// </exception>
4643         [MethodImpl(MethodImplOptions.NoOptimization)]  // this is needed for the parallel debugger
4644         public static bool WaitAll(Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken) =>
4645             WaitAllCore(tasks, millisecondsTimeout, cancellationToken);
4646
4647         // Separated out to allow it to be optimized (caller is marked NoOptimization for VS parallel debugger
4648         // to be able to see the method on the stack and inspect arguments).
4649         private static bool WaitAllCore(Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
4650         {
4651             if (tasks == null)
4652             {
4653                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.tasks);
4654             }
4655             if (millisecondsTimeout < -1)
4656             {
4657                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.millisecondsTimeout);
4658             }
4659
4660             cancellationToken.ThrowIfCancellationRequested(); // early check before we make any allocations
4661
4662             //
4663             // In this WaitAll() implementation we have 2 alternate code paths for a task to be handled:
4664             // CODEPATH1: skip an already completed task, CODEPATH2: actually wait on tasks
4665             // We make sure that the exception behavior of Task.Wait() is replicated the same for tasks handled in either of these codepaths
4666             //
4667
4668             List<Exception> exceptions = null;
4669             List<Task> waitedOnTaskList = null;
4670             List<Task> notificationTasks = null;
4671
4672             // If any of the waited-upon tasks end as Faulted or Canceled, set these to true.
4673             bool exceptionSeen = false, cancellationSeen = false;
4674
4675             bool returnValue = true;
4676
4677             // Collects incomplete tasks in "waitedOnTaskList"
4678             for (int i = tasks.Length - 1; i >= 0; i--)
4679             {
4680                 Task task = tasks[i];
4681
4682                 if (task == null)
4683                 {
4684                     ThrowHelper.ThrowArgumentException(ExceptionResource.Task_WaitMulti_NullTask, ExceptionArgument.tasks);
4685                 }
4686
4687                 bool taskIsCompleted = task.IsCompleted;
4688                 if (!taskIsCompleted)
4689                 {
4690                     // try inlining the task only if we have an infinite timeout and an empty cancellation token
4691                     if (millisecondsTimeout != Timeout.Infinite || cancellationToken.CanBeCanceled)
4692                     {
4693                         // We either didn't attempt inline execution because we had a non-infinite timeout or we had a cancellable token.
4694                         // In all cases we need to do a full wait on the task (=> add its event into the list.)
4695                         AddToList(task, ref waitedOnTaskList, initSize: tasks.Length);
4696                     }
4697                     else
4698                     {
4699                         // We are eligible for inlining.  If it doesn't work, we'll do a full wait.
4700                         taskIsCompleted = task.WrappedTryRunInline() && task.IsCompleted; // A successful TryRunInline doesn't guarantee completion
4701                         if (!taskIsCompleted) AddToList(task, ref waitedOnTaskList, initSize: tasks.Length);
4702                     }
4703                 }
4704
4705                 if (taskIsCompleted)
4706                 {
4707                     if (task.IsFaulted) exceptionSeen = true;
4708                     else if (task.IsCanceled) cancellationSeen = true;
4709                     if (task.IsWaitNotificationEnabled) AddToList(task, ref notificationTasks, initSize: 1);
4710                 }
4711             }
4712
4713             if (waitedOnTaskList != null)
4714             {
4715                 // Block waiting for the tasks to complete.
4716                 returnValue = WaitAllBlockingCore(waitedOnTaskList, millisecondsTimeout, cancellationToken);
4717
4718                 // If the wait didn't time out, ensure exceptions are propagated, and if a debugger is
4719                 // attached and one of these tasks requires it, that we notify the debugger of a wait completion.
4720                 if (returnValue)
4721                 {
4722                     // Add any exceptions for this task to the collection, and if it's wait
4723                     // notification bit is set, store it to operate on at the end.
4724                     foreach (var task in waitedOnTaskList)
4725                     {
4726                         if (task.IsFaulted) exceptionSeen = true;
4727                         else if (task.IsCanceled) cancellationSeen = true;
4728                         if (task.IsWaitNotificationEnabled) AddToList(task, ref notificationTasks, initSize: 1);
4729                     }
4730                 }
4731
4732                 // We need to prevent the tasks array from being GC'ed until we come out of the wait.
4733                 // This is necessary so that the Parallel Debugger can traverse it during the long wait and 
4734                 // deduce waiter/waitee relationships
4735                 GC.KeepAlive(tasks);
4736             }
4737
4738             // Now that we're done and about to exit, if the wait completed and if we have 
4739             // any tasks with a notification bit set, signal the debugger if any requires it.
4740             if (returnValue && notificationTasks != null)
4741             {
4742                 // Loop through each task tha that had its bit set, and notify the debugger
4743                 // about the first one that requires it.  The debugger will reset the bit
4744                 // for any tasks we don't notify of as soon as we break, so we only need to notify
4745                 // for one.
4746                 foreach (var task in notificationTasks)
4747                 {
4748                     if (task.NotifyDebuggerOfWaitCompletionIfNecessary()) break;
4749                 }
4750             }
4751
4752             // If one or more threw exceptions, aggregate and throw them.
4753             if (returnValue && (exceptionSeen || cancellationSeen))
4754             {
4755                 // If the WaitAll was canceled and tasks were canceled but not faulted, 
4756                 // prioritize throwing an OCE for canceling the WaitAll over throwing an 
4757                 // AggregateException for all of the canceled Tasks.  This helps
4758                 // to bring determinism to an otherwise non-determistic case of using
4759                 // the same token to cancel both the WaitAll and the Tasks.
4760                 if (!exceptionSeen) cancellationToken.ThrowIfCancellationRequested();
4761
4762                 // Now gather up and throw all of the exceptions.
4763                 foreach (var task in tasks) AddExceptionsForCompletedTask(ref exceptions, task);
4764                 Debug.Assert(exceptions != null, "Should have seen at least one exception");
4765                 ThrowHelper.ThrowAggregateException(exceptions);
4766             }
4767
4768             return returnValue;
4769         }
4770
4771         /// <summary>Adds an element to the list, initializing the list if it's null.</summary>
4772         /// <typeparam name="T">Specifies the type of data stored in the list.</typeparam>
4773         /// <param name="item">The item to add.</param>
4774         /// <param name="list">The list.</param>
4775         /// <param name="initSize">The size to which to initialize the list if the list is null.</param>
4776         private static void AddToList<T>(T item, ref List<T> list, int initSize)
4777         {
4778             if (list == null) list = new List<T>(initSize);
4779             list.Add(item);
4780         }
4781
4782         /// <summary>Performs a blocking WaitAll on the vetted list of tasks.</summary>
4783         /// <param name="tasks">The tasks, which have already been checked and filtered for completion.</param>
4784         /// <param name="millisecondsTimeout">The timeout.</param>
4785         /// <param name="cancellationToken">The cancellation token.</param>
4786         /// <returns>true if all of the tasks completed; otherwise, false.</returns>
4787         private static bool WaitAllBlockingCore(List<Task> tasks, int millisecondsTimeout, CancellationToken cancellationToken)
4788         {
4789             Debug.Assert(tasks != null, "Expected a non-null list of tasks");
4790             Debug.Assert(tasks.Count > 0, "Expected at least one task");
4791
4792             bool waitCompleted = false;
4793             var mres = new SetOnCountdownMres(tasks.Count);
4794             try
4795             {
4796                 foreach (var task in tasks)
4797                 {
4798                     task.AddCompletionAction(mres, addBeforeOthers: true);
4799                 }
4800                 waitCompleted = mres.Wait(millisecondsTimeout, cancellationToken);
4801             }
4802             finally
4803             {
4804                 if (!waitCompleted)
4805                 {
4806                     foreach (var task in tasks)
4807                     {
4808                         if (!task.IsCompleted) task.RemoveContinuation(mres);
4809                     }
4810                 }
4811                 // It's ok that we don't dispose of the MRES here, as we never
4812                 // access the MRES' WaitHandle, and thus no finalizable resources
4813                 // are actually created.  We don't always just Dispose it because
4814                 // a continuation that's accessing the MRES could still be executing.
4815             }
4816             return waitCompleted;
4817         }
4818
4819         // A ManualResetEventSlim that will get Set after Invoke is called count times.
4820         // This allows us to replace this logic:
4821         //      var mres = new ManualResetEventSlim(tasks.Count);
4822         //      Action<Task> completionAction = delegate { if(Interlocked.Decrement(ref count) == 0) mres.Set(); };
4823         //      foreach(var task in tasks) task.AddCompletionAction(completionAction);
4824         // with this logic:
4825         //      var mres = new SetOnCountdownMres(tasks.Count);
4826         //      foreach(var task in tasks) task.AddCompletionAction(mres);
4827         // which saves a couple of allocations.
4828         //
4829         // Used in WaitAllBlockingCore (above).
4830         private sealed class SetOnCountdownMres : ManualResetEventSlim, ITaskCompletionAction
4831         {
4832             private int _count;
4833
4834             internal SetOnCountdownMres(int count)
4835             {
4836                 Debug.Assert(count > 0, "Expected count > 0");
4837                 _count = count;
4838             }
4839
4840             public void Invoke(Task completingTask)
4841             {
4842                 if (Interlocked.Decrement(ref _count) == 0) Set();
4843                 Debug.Assert(_count >= 0, "Count should never go below 0");
4844             }
4845
4846             public bool InvokeMayRunArbitraryCode { get { return false; } }
4847         }
4848
4849         /// <summary>
4850         /// This internal function is only meant to be called by WaitAll()
4851         /// If the completed task is canceled or it has other exceptions, here we will add those
4852         /// into the passed in exception list (which will be lazily initialized here).
4853         /// </summary>
4854         internal static void AddExceptionsForCompletedTask(ref List<Exception> exceptions, Task t)
4855         {
4856             AggregateException ex = t.GetExceptions(true);
4857             if (ex != null)
4858             {
4859                 // make sure the task's exception observed status is set appropriately
4860                 // it's possible that WaitAll was called by the parent of an attached child,
4861                 // this will make sure it won't throw again in the implicit wait
4862                 t.UpdateExceptionObservedStatus();
4863
4864                 if (exceptions == null)
4865                 {
4866                     exceptions = new List<Exception>(ex.InnerExceptions.Count);
4867                 }
4868
4869                 exceptions.AddRange(ex.InnerExceptions);
4870             }
4871         }
4872
4873
4874         /// <summary>
4875         /// Waits for any of the provided <see cref="Task"/> objects to complete execution.
4876         /// </summary>
4877         /// <param name="tasks">
4878         /// An array of <see cref="Task"/> instances on which to wait.
4879         /// </param>
4880         /// <returns>The index of the completed task in the <paramref name="tasks"/> array argument.</returns>
4881         /// <exception cref="T:System.ArgumentNullException">
4882         /// The <paramref name="tasks"/> argument is null.
4883         /// </exception>
4884         /// <exception cref="T:System.ArgumentException">
4885         /// The <paramref name="tasks"/> argument contains a null element.
4886         /// </exception>
4887         [MethodImpl(MethodImplOptions.NoOptimization)]  // this is needed for the parallel debugger
4888         public static int WaitAny(params Task[] tasks)
4889         {
4890             int waitResult = WaitAnyCore(tasks, Timeout.Infinite, default(CancellationToken));
4891             Debug.Assert(tasks.Length == 0 || waitResult != -1, "expected wait to succeed");
4892             return waitResult;
4893         }
4894
4895         /// <summary>
4896         /// Waits for any of the provided <see cref="Task"/> objects to complete execution.
4897         /// </summary>
4898         /// <param name="tasks">
4899         /// An array of <see cref="Task"/> instances on which to wait.
4900         /// </param>
4901         /// <param name="timeout">
4902         /// A <see cref="System.TimeSpan"/> that represents the number of milliseconds to wait, or a <see
4903         /// cref="System.TimeSpan"/> that represents -1 milliseconds to wait indefinitely.
4904         /// </param>
4905         /// <returns>
4906         /// The index of the completed task in the <paramref name="tasks"/> array argument, or -1 if the
4907         /// timeout occurred.
4908         /// </returns>
4909         /// <exception cref="T:System.ArgumentNullException">
4910         /// The <paramref name="tasks"/> argument is null.
4911         /// </exception>
4912         /// <exception cref="T:System.ArgumentException">
4913         /// The <paramref name="tasks"/> argument contains a null element.
4914         /// </exception>
4915         /// <exception cref="T:System.ArgumentOutOfRangeException">
4916         /// <paramref name="timeout"/> is a negative number other than -1 milliseconds, which represents an
4917         /// infinite time-out -or- timeout is greater than
4918         /// <see cref="System.Int32.MaxValue"/>.
4919         /// </exception>
4920         [MethodImpl(MethodImplOptions.NoOptimization)]  // this is needed for the parallel debugger
4921         public static int WaitAny(Task[] tasks, TimeSpan timeout)
4922         {
4923             long totalMilliseconds = (long)timeout.TotalMilliseconds;
4924             if (totalMilliseconds < -1 || totalMilliseconds > Int32.MaxValue)
4925             {
4926                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.timeout);
4927             }
4928
4929             return WaitAnyCore(tasks, (int)totalMilliseconds, default(CancellationToken));
4930         }
4931
4932         /// <summary>
4933         /// Waits for any of the provided <see cref="Task"/> objects to complete execution.
4934         /// </summary>
4935         /// <param name="tasks">
4936         /// An array of <see cref="Task"/> instances on which to wait.
4937         /// </param>
4938         /// <param name="cancellationToken">
4939         /// A <see cref="CancellationToken"/> to observe while waiting for a task to complete.
4940         /// </param>
4941         /// <returns>
4942         /// The index of the completed task in the <paramref name="tasks"/> array argument.
4943         /// </returns>
4944         /// <exception cref="T:System.ArgumentNullException">
4945         /// The <paramref name="tasks"/> argument is null.
4946         /// </exception>
4947         /// <exception cref="T:System.ArgumentException">
4948         /// The <paramref name="tasks"/> argument contains a null element.
4949         /// </exception>
4950         /// <exception cref="T:System.OperationCanceledException">
4951         /// The <paramref name="cancellationToken"/> was canceled.
4952         /// </exception>
4953         [MethodImpl(MethodImplOptions.NoOptimization)]  // this is needed for the parallel debugger
4954         public static int WaitAny(Task[] tasks, CancellationToken cancellationToken)
4955         {
4956             return WaitAnyCore(tasks, Timeout.Infinite, cancellationToken);
4957         }
4958
4959         /// <summary>
4960         /// Waits for any of the provided <see cref="Task"/> objects to complete execution.
4961         /// </summary>
4962         /// <param name="tasks">
4963         /// An array of <see cref="Task"/> instances on which to wait.
4964         /// </param>
4965         /// <param name="millisecondsTimeout">
4966         /// The number of milliseconds to wait, or <see cref="System.Threading.Timeout.Infinite"/> (-1) to
4967         /// wait indefinitely.
4968         /// </param>
4969         /// <returns>
4970         /// The index of the completed task in the <paramref name="tasks"/> array argument, or -1 if the
4971         /// timeout occurred.
4972         /// </returns>
4973         /// <exception cref="T:System.ArgumentNullException">
4974         /// The <paramref name="tasks"/> argument is null.
4975         /// </exception>
4976         /// <exception cref="T:System.ArgumentException">
4977         /// The <paramref name="tasks"/> argument contains a null element.
4978         /// </exception>
4979         /// <exception cref="T:System.ArgumentOutOfRangeException">
4980         /// <paramref name="millisecondsTimeout"/> is a negative number other than -1, which represents an
4981         /// infinite time-out.
4982         /// </exception>
4983         [MethodImpl(MethodImplOptions.NoOptimization)]  // this is needed for the parallel debugger
4984         public static int WaitAny(Task[] tasks, int millisecondsTimeout)
4985         {
4986             return WaitAnyCore(tasks, millisecondsTimeout, default(CancellationToken));
4987         }
4988
4989         /// <summary>
4990         /// Waits for any of the provided <see cref="Task"/> objects to complete execution.
4991         /// </summary>
4992         /// <param name="tasks">
4993         /// An array of <see cref="Task"/> instances on which to wait.
4994         /// </param>
4995         /// <param name="millisecondsTimeout">
4996         /// The number of milliseconds to wait, or <see cref="System.Threading.Timeout.Infinite"/> (-1) to
4997         /// wait indefinitely.
4998         /// </param>
4999         /// <param name="cancellationToken">
5000         /// A <see cref="CancellationToken"/> to observe while waiting for a task to complete.
5001         /// </param>
5002         /// <returns>
5003         /// The index of the completed task in the <paramref name="tasks"/> array argument, or -1 if the
5004         /// timeout occurred.
5005         /// </returns>
5006         /// <exception cref="T:System.ArgumentNullException">
5007         /// The <paramref name="tasks"/> argument is null.
5008         /// </exception>
5009         /// <exception cref="T:System.ArgumentException">
5010         /// The <paramref name="tasks"/> argument contains a null element.
5011         /// </exception>
5012         /// <exception cref="T:System.ArgumentOutOfRangeException">
5013         /// <paramref name="millisecondsTimeout"/> is a negative number other than -1, which represents an
5014         /// infinite time-out.
5015         /// </exception>
5016         /// <exception cref="T:System.OperationCanceledException">
5017         /// The <paramref name="cancellationToken"/> was canceled.
5018         /// </exception>
5019         [MethodImpl(MethodImplOptions.NoOptimization)]  // this is needed for the parallel debugger
5020         public static int WaitAny(Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken) =>
5021             WaitAnyCore(tasks, millisecondsTimeout, cancellationToken);
5022
5023         // Separated out to allow it to be optimized (caller is marked NoOptimization for VS parallel debugger
5024         // to be able to inspect arguments).
5025         private static int WaitAnyCore(Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
5026         {
5027             if (tasks == null)
5028             {
5029                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.tasks);
5030             }
5031             if (millisecondsTimeout < -1)
5032             {
5033                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.millisecondsTimeout);
5034             }
5035
5036             cancellationToken.ThrowIfCancellationRequested(); // early check before we make any allocations
5037
5038             int signaledTaskIndex = -1;
5039
5040             // Make a pass through the loop to check for any tasks that may have
5041             // already been completed, and to verify that no tasks are null.
5042
5043             for (int taskIndex = 0; taskIndex < tasks.Length; taskIndex++)
5044             {
5045                 Task task = tasks[taskIndex];
5046
5047                 if (task == null)
5048                 {
5049                     ThrowHelper.ThrowArgumentException(ExceptionResource.Task_WaitMulti_NullTask, ExceptionArgument.tasks);
5050                 }
5051
5052                 if (signaledTaskIndex == -1 && task.IsCompleted)
5053                 {
5054                     // We found our first completed task.  Store it, but we can't just return here,
5055                     // as we still need to validate the whole array for nulls.
5056                     signaledTaskIndex = taskIndex;
5057                 }
5058             }
5059
5060             if (signaledTaskIndex == -1 && tasks.Length != 0)
5061             {
5062                 Task<Task> firstCompleted = TaskFactory.CommonCWAnyLogic(tasks);
5063                 bool waitCompleted = firstCompleted.Wait(millisecondsTimeout, cancellationToken);
5064                 if (waitCompleted)
5065                 {
5066                     Debug.Assert(firstCompleted.Status == TaskStatus.RanToCompletion);
5067                     signaledTaskIndex = Array.IndexOf(tasks, firstCompleted.Result);
5068                     Debug.Assert(signaledTaskIndex >= 0);
5069                 }
5070                 else
5071                 {
5072                     TaskFactory.CommonCWAnyLogicCleanup(firstCompleted);
5073                 }
5074             }
5075
5076             // We need to prevent the tasks array from being GC'ed until we come out of the wait.
5077             // This is necessary so that the Parallel Debugger can traverse it during the long wait 
5078             // and deduce waiter/waitee relationships
5079             GC.KeepAlive(tasks);
5080
5081             // Return the index
5082             return signaledTaskIndex;
5083         }
5084
5085         #region FromResult / FromException / FromCanceled
5086
5087         /// <summary>Creates a <see cref="Task{TResult}"/> that's completed successfully with the specified result.</summary>
5088         /// <typeparam name="TResult">The type of the result returned by the task.</typeparam>
5089         /// <param name="result">The result to store into the completed task.</param>
5090         /// <returns>The successfully completed task.</returns>
5091         public static Task<TResult> FromResult<TResult>(TResult result)
5092         {
5093             return new Task<TResult>(result);
5094         }
5095
5096         /// <summary>Creates a <see cref="Task{TResult}"/> that's completed exceptionally with the specified exception.</summary>
5097         /// <typeparam name="TResult">The type of the result returned by the task.</typeparam>
5098         /// <param name="exception">The exception with which to complete the task.</param>
5099         /// <returns>The faulted task.</returns>
5100         public static Task FromException(Exception exception)
5101         {
5102             return FromException<VoidTaskResult>(exception);
5103         }
5104
5105         /// <summary>Creates a <see cref="Task{TResult}"/> that's completed exceptionally with the specified exception.</summary>
5106         /// <typeparam name="TResult">The type of the result returned by the task.</typeparam>
5107         /// <param name="exception">The exception with which to complete the task.</param>
5108         /// <returns>The faulted task.</returns>
5109         public static Task<TResult> FromException<TResult>(Exception exception)
5110         {
5111             if (exception == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.exception);
5112
5113             var task = new Task<TResult>();
5114             bool succeeded = task.TrySetException(exception);
5115             Debug.Assert(succeeded, "This should always succeed on a new task.");
5116             return task;
5117         }
5118
5119         /// <summary>Creates a <see cref="Task"/> that's completed due to cancellation with the specified token.</summary>
5120         /// <param name="cancellationToken">The token with which to complete the task.</param>
5121         /// <returns>The canceled task.</returns>
5122         public static Task FromCanceled(CancellationToken cancellationToken)
5123         {
5124             if (!cancellationToken.IsCancellationRequested)
5125                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.cancellationToken);
5126             return new Task(true, TaskCreationOptions.None, cancellationToken);
5127         }
5128
5129         /// <summary>Creates a <see cref="Task{TResult}"/> that's completed due to cancellation with the specified token.</summary>
5130         /// <typeparam name="TResult">The type of the result returned by the task.</typeparam>
5131         /// <param name="cancellationToken">The token with which to complete the task.</param>
5132         /// <returns>The canceled task.</returns>
5133         public static Task<TResult> FromCanceled<TResult>(CancellationToken cancellationToken)
5134         {
5135             if (!cancellationToken.IsCancellationRequested)
5136                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.cancellationToken);
5137             return new Task<TResult>(true, default(TResult), TaskCreationOptions.None, cancellationToken);
5138         }
5139
5140         /// <summary>Creates a <see cref="Task{TResult}"/> that's completed due to cancellation with the specified exception.</summary>
5141         /// <typeparam name="TResult">The type of the result returned by the task.</typeparam>
5142         /// <param name="exception">The exception with which to complete the task.</param>
5143         /// <returns>The canceled task.</returns>
5144         internal static Task<TResult> FromCancellation<TResult>(OperationCanceledException exception)
5145         {
5146             if (exception == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.exception);
5147
5148             var task = new Task<TResult>();
5149             bool succeeded = task.TrySetCanceled(exception.CancellationToken, exception);
5150             Debug.Assert(succeeded, "This should always succeed on a new task.");
5151             return task;
5152         }
5153
5154         #endregion
5155
5156         #region Run methods
5157
5158
5159         /// <summary>
5160         /// Queues the specified work to run on the ThreadPool and returns a Task handle for that work.
5161         /// </summary>
5162         /// <param name="action">The work to execute asynchronously</param>
5163         /// <returns>A Task that represents the work queued to execute in the ThreadPool.</returns>
5164         /// <exception cref="T:System.ArgumentNullException">
5165         /// The <paramref name="action"/> parameter was null.
5166         /// </exception>
5167         public static Task Run(Action action)
5168         {
5169             return Task.InternalStartNew(null, action, null, default(CancellationToken), TaskScheduler.Default,
5170                 TaskCreationOptions.DenyChildAttach, InternalTaskOptions.None);
5171         }
5172
5173         /// <summary>
5174         /// Queues the specified work to run on the ThreadPool and returns a Task handle for that work.
5175         /// </summary>
5176         /// <param name="action">The work to execute asynchronously</param>
5177         /// <param name="cancellationToken">A cancellation token that should be used to cancel the work</param>
5178         /// <returns>A Task that represents the work queued to execute in the ThreadPool.</returns>
5179         /// <exception cref="T:System.ArgumentNullException">
5180         /// The <paramref name="action"/> parameter was null.
5181         /// </exception>
5182         /// <exception cref="T:System.ObjectDisposedException">
5183         /// The <see cref="T:System.CancellationTokenSource"/> associated with <paramref name="cancellationToken"/> was disposed.
5184         /// </exception>
5185         public static Task Run(Action action, CancellationToken cancellationToken)
5186         {
5187             return Task.InternalStartNew(null, action, null, cancellationToken, TaskScheduler.Default,
5188                 TaskCreationOptions.DenyChildAttach, InternalTaskOptions.None);
5189         }
5190
5191         /// <summary>
5192         /// Queues the specified work to run on the ThreadPool and returns a Task(TResult) handle for that work.
5193         /// </summary>
5194         /// <param name="function">The work to execute asynchronously</param>
5195         /// <returns>A Task(TResult) that represents the work queued to execute in the ThreadPool.</returns>
5196         /// <exception cref="T:System.ArgumentNullException">
5197         /// The <paramref name="function"/> parameter was null.
5198         /// </exception>
5199         public static Task<TResult> Run<TResult>(Func<TResult> function)
5200         {
5201             return Task<TResult>.StartNew(null, function, default(CancellationToken),
5202                 TaskCreationOptions.DenyChildAttach, InternalTaskOptions.None, TaskScheduler.Default);
5203         }
5204
5205         /// <summary>
5206         /// Queues the specified work to run on the ThreadPool and returns a Task(TResult) handle for that work.
5207         /// </summary>
5208         /// <param name="function">The work to execute asynchronously</param>
5209         /// <param name="cancellationToken">A cancellation token that should be used to cancel the work</param>
5210         /// <returns>A Task(TResult) that represents the work queued to execute in the ThreadPool.</returns>
5211         /// <exception cref="T:System.ArgumentNullException">
5212         /// The <paramref name="function"/> parameter was null.
5213         /// </exception>
5214         /// <exception cref="T:System.ObjectDisposedException">
5215         /// The <see cref="T:System.CancellationTokenSource"/> associated with <paramref name="cancellationToken"/> was disposed.
5216         /// </exception>
5217         public static Task<TResult> Run<TResult>(Func<TResult> function, CancellationToken cancellationToken)
5218         {
5219             return Task<TResult>.StartNew(null, function, cancellationToken,
5220                 TaskCreationOptions.DenyChildAttach, InternalTaskOptions.None, TaskScheduler.Default);
5221         }
5222
5223         /// <summary>
5224         /// Queues the specified work to run on the ThreadPool and returns a proxy for the
5225         /// Task returned by <paramref name="function"/>.
5226         /// </summary>
5227         /// <param name="function">The work to execute asynchronously</param>
5228         /// <returns>A Task that represents a proxy for the Task returned by <paramref name="function"/>.</returns>
5229         /// <exception cref="T:System.ArgumentNullException">
5230         /// The <paramref name="function"/> parameter was null.
5231         /// </exception>
5232         public static Task Run(Func<Task> function)
5233         {
5234             return Run(function, default(CancellationToken));
5235         }
5236
5237
5238         /// <summary>
5239         /// Queues the specified work to run on the ThreadPool and returns a proxy for the
5240         /// Task returned by <paramref name="function"/>.
5241         /// </summary>
5242         /// <param name="function">The work to execute asynchronously</param>
5243         /// <param name="cancellationToken">A cancellation token that should be used to cancel the work</param>
5244         /// <returns>A Task that represents a proxy for the Task returned by <paramref name="function"/>.</returns>
5245         /// <exception cref="T:System.ArgumentNullException">
5246         /// The <paramref name="function"/> parameter was null.
5247         /// </exception>
5248         /// <exception cref="T:System.ObjectDisposedException">
5249         /// The <see cref="T:System.CancellationTokenSource"/> associated with <paramref name="cancellationToken"/> was disposed.
5250         /// </exception>
5251         public static Task Run(Func<Task> function, CancellationToken cancellationToken)
5252         {
5253             // Check arguments
5254             if (function == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.function);
5255
5256             // Short-circuit if we are given a pre-canceled token
5257             if (cancellationToken.IsCancellationRequested)
5258                 return Task.FromCanceled(cancellationToken);
5259
5260             // Kick off initial Task, which will call the user-supplied function and yield a Task.
5261             Task<Task> task1 = Task<Task>.Factory.StartNew(function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
5262
5263             // Create a promise-style Task to be used as a proxy for the operation
5264             // Set lookForOce == true so that unwrap logic can be on the lookout for OCEs thrown as faults from task1, to support in-delegate cancellation.
5265             UnwrapPromise<VoidTaskResult> promise = new UnwrapPromise<VoidTaskResult>(task1, lookForOce: true);
5266
5267             return promise;
5268         }
5269
5270         /// <summary>
5271         /// Queues the specified work to run on the ThreadPool and returns a proxy for the
5272         /// Task(TResult) returned by <paramref name="function"/>.
5273         /// </summary>
5274         /// <typeparam name="TResult">The type of the result returned by the proxy Task.</typeparam>
5275         /// <param name="function">The work to execute asynchronously</param>
5276         /// <returns>A Task(TResult) that represents a proxy for the Task(TResult) returned by <paramref name="function"/>.</returns>
5277         /// <exception cref="T:System.ArgumentNullException">
5278         /// The <paramref name="function"/> parameter was null.
5279         /// </exception>
5280         public static Task<TResult> Run<TResult>(Func<Task<TResult>> function)
5281         {
5282             return Run(function, default(CancellationToken));
5283         }
5284
5285         /// <summary>
5286         /// Queues the specified work to run on the ThreadPool and returns a proxy for the
5287         /// Task(TResult) returned by <paramref name="function"/>.
5288         /// </summary>
5289         /// <typeparam name="TResult">The type of the result returned by the proxy Task.</typeparam>
5290         /// <param name="function">The work to execute asynchronously</param>
5291         /// <param name="cancellationToken">A cancellation token that should be used to cancel the work</param>
5292         /// <returns>A Task(TResult) that represents a proxy for the Task(TResult) returned by <paramref name="function"/>.</returns>
5293         /// <exception cref="T:System.ArgumentNullException">
5294         /// The <paramref name="function"/> parameter was null.
5295         /// </exception>
5296         public static Task<TResult> Run<TResult>(Func<Task<TResult>> function, CancellationToken cancellationToken)
5297         {
5298             // Check arguments
5299             if (function == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.function);
5300
5301             // Short-circuit if we are given a pre-canceled token
5302             if (cancellationToken.IsCancellationRequested)
5303                 return Task.FromCanceled<TResult>(cancellationToken);
5304
5305             // Kick off initial Task, which will call the user-supplied function and yield a Task.
5306             Task<Task<TResult>> task1 = Task<Task<TResult>>.Factory.StartNew(function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
5307
5308             // Create a promise-style Task to be used as a proxy for the operation
5309             // Set lookForOce == true so that unwrap logic can be on the lookout for OCEs thrown as faults from task1, to support in-delegate cancellation.
5310             UnwrapPromise<TResult> promise = new UnwrapPromise<TResult>(task1, lookForOce: true);
5311
5312             return promise;
5313         }
5314
5315
5316         #endregion
5317
5318         #region Delay methods
5319
5320         /// <summary>
5321         /// Creates a Task that will complete after a time delay.
5322         /// </summary>
5323         /// <param name="delay">The time span to wait before completing the returned Task</param>
5324         /// <returns>A Task that represents the time delay</returns>
5325         /// <exception cref="T:System.ArgumentOutOfRangeException">
5326         /// The <paramref name="delay"/> is less than -1 or greater than Int32.MaxValue.
5327         /// </exception>
5328         /// <remarks>
5329         /// After the specified time delay, the Task is completed in RanToCompletion state.
5330         /// </remarks>
5331         public static Task Delay(TimeSpan delay)
5332         {
5333             return Delay(delay, default(CancellationToken));
5334         }
5335
5336         /// <summary>
5337         /// Creates a Task that will complete after a time delay.
5338         /// </summary>
5339         /// <param name="delay">The time span to wait before completing the returned Task</param>
5340         /// <param name="cancellationToken">The cancellation token that will be checked prior to completing the returned Task</param>
5341         /// <returns>A Task that represents the time delay</returns>
5342         /// <exception cref="T:System.ArgumentOutOfRangeException">
5343         /// The <paramref name="delay"/> is less than -1 or greater than Int32.MaxValue.
5344         /// </exception>
5345         /// <exception cref="T:System.ObjectDisposedException">
5346         /// The provided <paramref name="cancellationToken"/> has already been disposed.
5347         /// </exception>        
5348         /// <remarks>
5349         /// If the cancellation token is signaled before the specified time delay, then the Task is completed in
5350         /// Canceled state.  Otherwise, the Task is completed in RanToCompletion state once the specified time
5351         /// delay has expired.
5352         /// </remarks>        
5353         public static Task Delay(TimeSpan delay, CancellationToken cancellationToken)
5354         {
5355             long totalMilliseconds = (long)delay.TotalMilliseconds;
5356             if (totalMilliseconds < -1 || totalMilliseconds > Int32.MaxValue)
5357             {
5358                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.delay, ExceptionResource.Task_Delay_InvalidDelay);
5359             }
5360
5361             return Delay((int)totalMilliseconds, cancellationToken);
5362         }
5363
5364         /// <summary>
5365         /// Creates a Task that will complete after a time delay.
5366         /// </summary>
5367         /// <param name="millisecondsDelay">The number of milliseconds to wait before completing the returned Task</param>
5368         /// <returns>A Task that represents the time delay</returns>
5369         /// <exception cref="T:System.ArgumentOutOfRangeException">
5370         /// The <paramref name="millisecondsDelay"/> is less than -1.
5371         /// </exception>
5372         /// <remarks>
5373         /// After the specified time delay, the Task is completed in RanToCompletion state.
5374         /// </remarks>
5375         public static Task Delay(int millisecondsDelay)
5376         {
5377             return Delay(millisecondsDelay, default(CancellationToken));
5378         }
5379
5380         /// <summary>
5381         /// Creates a Task that will complete after a time delay.
5382         /// </summary>
5383         /// <param name="millisecondsDelay">The number of milliseconds to wait before completing the returned Task</param>
5384         /// <param name="cancellationToken">The cancellation token that will be checked prior to completing the returned Task</param>
5385         /// <returns>A Task that represents the time delay</returns>
5386         /// <exception cref="T:System.ArgumentOutOfRangeException">
5387         /// The <paramref name="millisecondsDelay"/> is less than -1.
5388         /// </exception>
5389         /// <exception cref="T:System.ObjectDisposedException">
5390         /// The provided <paramref name="cancellationToken"/> has already been disposed.
5391         /// </exception>        
5392         /// <remarks>
5393         /// If the cancellation token is signaled before the specified time delay, then the Task is completed in
5394         /// Canceled state.  Otherwise, the Task is completed in RanToCompletion state once the specified time
5395         /// delay has expired.
5396         /// </remarks>        
5397         public static Task Delay(int millisecondsDelay, CancellationToken cancellationToken)
5398         {
5399             // Throw on non-sensical time
5400             if (millisecondsDelay < -1)
5401             {
5402                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.millisecondsDelay, ExceptionResource.Task_Delay_InvalidMillisecondsDelay);
5403             }
5404
5405             // some short-cuts in case quick completion is in order
5406             if (cancellationToken.IsCancellationRequested)
5407             {
5408                 // return a Task created as already-Canceled
5409                 return Task.FromCanceled(cancellationToken);
5410             }
5411             else if (millisecondsDelay == 0)
5412             {
5413                 // return a Task created as already-RanToCompletion
5414                 return Task.CompletedTask;
5415             }
5416
5417             // Construct a promise-style Task to encapsulate our return value
5418             var promise = new DelayPromise(cancellationToken);
5419
5420             // Register our cancellation token, if necessary.
5421             if (cancellationToken.CanBeCanceled)
5422             {
5423                 promise.Registration = cancellationToken.InternalRegisterWithoutEC(state => ((DelayPromise)state).Complete(), promise);
5424             }
5425
5426             // ... and create our timer and make sure that it stays rooted.
5427             if (millisecondsDelay != Timeout.Infinite) // no need to create the timer if it's an infinite timeout
5428             {
5429                 promise.Timer = new TimerQueueTimer(state => ((DelayPromise)state).Complete(), promise, (uint)millisecondsDelay, Timeout.UnsignedInfinite);
5430             }
5431
5432             // Return the timer proxy task
5433             return promise;
5434         }
5435
5436         /// <summary>Task that also stores the completion closure and logic for Task.Delay implementation.</summary>
5437         private sealed class DelayPromise : Task<VoidTaskResult>
5438         {
5439             internal DelayPromise(CancellationToken token)
5440                 : base()
5441             {
5442                 this.Token = token;
5443                 if (AsyncCausalityTracer.LoggingOn)
5444                     AsyncCausalityTracer.TraceOperationCreation(CausalityTraceLevel.Required, this.Id, "Task.Delay", 0);
5445
5446                 if (Task.s_asyncDebuggingEnabled)
5447                 {
5448                     AddToActiveTasks(this);
5449                 }
5450             }
5451
5452             internal readonly CancellationToken Token;
5453             internal CancellationTokenRegistration Registration;
5454             internal TimerQueueTimer Timer;
5455
5456             internal void Complete()
5457             {
5458                 // Transition the task to completed.
5459                 bool setSucceeded;
5460
5461                 if (Token.IsCancellationRequested)
5462                 {
5463                     setSucceeded = TrySetCanceled(Token);
5464                 }
5465                 else
5466                 {
5467                     if (AsyncCausalityTracer.LoggingOn)
5468                         AsyncCausalityTracer.TraceOperationCompletion(CausalityTraceLevel.Required, this.Id, AsyncCausalityStatus.Completed);
5469
5470                     if (Task.s_asyncDebuggingEnabled)
5471                     {
5472                         RemoveFromActiveTasks(this.Id);
5473                     }
5474                     setSucceeded = TrySetResult(default(VoidTaskResult));
5475                 }
5476
5477                 // If we set the value, also clean up.
5478                 if (setSucceeded)
5479                 {
5480                     Timer?.Close();
5481                     Registration.Dispose();
5482                 }
5483             }
5484         }
5485         #endregion
5486
5487         #region WhenAll
5488         /// <summary>
5489         /// Creates a task that will complete when all of the supplied tasks have completed.
5490         /// </summary>
5491         /// <param name="tasks">The tasks to wait on for completion.</param>
5492         /// <returns>A task that represents the completion of all of the supplied tasks.</returns>
5493         /// <remarks>
5494         /// <para>
5495         /// If any of the supplied tasks completes in a faulted state, the returned task will also complete in a Faulted state, 
5496         /// where its exceptions will contain the aggregation of the set of unwrapped exceptions from each of the supplied tasks.  
5497         /// </para>
5498         /// <para>
5499         /// If none of the supplied tasks faulted but at least one of them was canceled, the returned task will end in the Canceled state.
5500         /// </para>
5501         /// <para>
5502         /// If none of the tasks faulted and none of the tasks were canceled, the resulting task will end in the RanToCompletion state.   
5503         /// </para>
5504         /// <para>
5505         /// If the supplied array/enumerable contains no tasks, the returned task will immediately transition to a RanToCompletion 
5506         /// state before it's returned to the caller.  
5507         /// </para>
5508         /// </remarks>
5509         /// <exception cref="T:System.ArgumentNullException">
5510         /// The <paramref name="tasks"/> argument was null.
5511         /// </exception>
5512         /// <exception cref="T:System.ArgumentException">
5513         /// The <paramref name="tasks"/> collection contained a null task.
5514         /// </exception>
5515         public static Task WhenAll(IEnumerable<Task> tasks)
5516         {
5517             // Take a more efficient path if tasks is actually an array
5518             Task[] taskArray = tasks as Task[];
5519             if (taskArray != null)
5520             {
5521                 return WhenAll(taskArray);
5522             }
5523
5524             // Skip a List allocation/copy if tasks is a collection
5525             ICollection<Task> taskCollection = tasks as ICollection<Task>;
5526             if (taskCollection != null)
5527             {
5528                 int index = 0;
5529                 taskArray = new Task[taskCollection.Count];
5530                 foreach (var task in tasks)
5531                 {
5532                     if (task == null) ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_NullTask, ExceptionArgument.tasks);
5533                     taskArray[index++] = task;
5534                 }
5535                 return InternalWhenAll(taskArray);
5536             }
5537
5538             // Do some argument checking and convert tasks to a List (and later an array).
5539             if (tasks == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.tasks);
5540             List<Task> taskList = new List<Task>();
5541             foreach (Task task in tasks)
5542             {
5543                 if (task == null) ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_NullTask, ExceptionArgument.tasks);
5544                 taskList.Add(task);
5545             }
5546
5547             // Delegate the rest to InternalWhenAll()
5548             return InternalWhenAll(taskList.ToArray());
5549         }
5550
5551         /// <summary>
5552         /// Creates a task that will complete when all of the supplied tasks have completed.
5553         /// </summary>
5554         /// <param name="tasks">The tasks to wait on for completion.</param>
5555         /// <returns>A task that represents the completion of all of the supplied tasks.</returns>
5556         /// <remarks>
5557         /// <para>
5558         /// If any of the supplied tasks completes in a faulted state, the returned task will also complete in a Faulted state, 
5559         /// where its exceptions will contain the aggregation of the set of unwrapped exceptions from each of the supplied tasks.  
5560         /// </para>
5561         /// <para>
5562         /// If none of the supplied tasks faulted but at least one of them was canceled, the returned task will end in the Canceled state.
5563         /// </para>
5564         /// <para>
5565         /// If none of the tasks faulted and none of the tasks were canceled, the resulting task will end in the RanToCompletion state.   
5566         /// </para>
5567         /// <para>
5568         /// If the supplied array/enumerable contains no tasks, the returned task will immediately transition to a RanToCompletion 
5569         /// state before it's returned to the caller.  
5570         /// </para>
5571         /// </remarks>
5572         /// <exception cref="T:System.ArgumentNullException">
5573         /// The <paramref name="tasks"/> argument was null.
5574         /// </exception>
5575         /// <exception cref="T:System.ArgumentException">
5576         /// The <paramref name="tasks"/> array contained a null task.
5577         /// </exception>
5578         public static Task WhenAll(params Task[] tasks)
5579         {
5580             // Do some argument checking and make a defensive copy of the tasks array
5581             if (tasks == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.tasks);
5582
5583             int taskCount = tasks.Length;
5584             if (taskCount == 0) return InternalWhenAll(tasks); // Small optimization in the case of an empty array.
5585
5586             Task[] tasksCopy = new Task[taskCount];
5587             for (int i = 0; i < taskCount; i++)
5588             {
5589                 Task task = tasks[i];
5590                 if (task == null) ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_NullTask, ExceptionArgument.tasks);
5591                 tasksCopy[i] = task;
5592             }
5593
5594             // The rest can be delegated to InternalWhenAll()
5595             return InternalWhenAll(tasksCopy);
5596         }
5597
5598         // Some common logic to support WhenAll() methods
5599         // tasks should be a defensive copy.
5600         private static Task InternalWhenAll(Task[] tasks)
5601         {
5602             Debug.Assert(tasks != null, "Expected a non-null tasks array");
5603             return (tasks.Length == 0) ? // take shortcut if there are no tasks upon which to wait
5604                 Task.CompletedTask :
5605                 new WhenAllPromise(tasks);
5606         }
5607
5608         // A Task<VoidTaskResult> that gets completed when all of its constituent tasks complete.
5609         // Completion logic will analyze the antecedents in order to choose completion status.
5610         // This type allows us to replace this logic:
5611         //      Task<VoidTaskResult> promise = new Task<VoidTaskResult>(...);
5612         //      Action<Task> completionAction = delegate { <completion logic>};
5613         //      TaskFactory.CommonCWAllLogic(tasksCopy).AddCompletionAction(completionAction);
5614         //      return promise;
5615         // which involves several allocations, with this logic:
5616         //      return new WhenAllPromise(tasksCopy);
5617         // which saves a couple of allocations and enables debugger notification specialization.
5618         //
5619         // Used in InternalWhenAll(Task[])
5620         private sealed class WhenAllPromise : Task<VoidTaskResult>, ITaskCompletionAction
5621         {
5622             /// <summary>
5623             /// Stores all of the constituent tasks.  Tasks clear themselves out of this
5624             /// array as they complete, but only if they don't have their wait notification bit set.
5625             /// </summary>
5626             private readonly Task[] m_tasks;
5627             /// <summary>The number of tasks remaining to complete.</summary>
5628             private int m_count;
5629
5630             internal WhenAllPromise(Task[] tasks) :
5631                 base()
5632             {
5633                 Debug.Assert(tasks != null, "Expected a non-null task array");
5634                 Debug.Assert(tasks.Length > 0, "Expected a non-zero length task array");
5635
5636                 if (AsyncCausalityTracer.LoggingOn)
5637                     AsyncCausalityTracer.TraceOperationCreation(CausalityTraceLevel.Required, this.Id, "Task.WhenAll", 0);
5638
5639                 if (s_asyncDebuggingEnabled)
5640                 {
5641                     AddToActiveTasks(this);
5642                 }
5643
5644                 m_tasks = tasks;
5645                 m_count = tasks.Length;
5646
5647                 foreach (var task in tasks)
5648                 {
5649                     if (task.IsCompleted) this.Invoke(task); // short-circuit the completion action, if possible
5650                     else task.AddCompletionAction(this); // simple completion action
5651                 }
5652             }
5653
5654             public void Invoke(Task completedTask)
5655             {
5656                 if (AsyncCausalityTracer.LoggingOn)
5657                     AsyncCausalityTracer.TraceOperationRelation(CausalityTraceLevel.Important, this.Id, CausalityRelation.Join);
5658
5659                 // Decrement the count, and only continue to complete the promise if we're the last one.
5660                 if (Interlocked.Decrement(ref m_count) == 0)
5661                 {
5662                     // Set up some accounting variables
5663                     List<ExceptionDispatchInfo> observedExceptions = null;
5664                     Task canceledTask = null;
5665
5666                     // Loop through antecedents:
5667                     //   If any one of them faults, the result will be faulted
5668                     //   If none fault, but at least one is canceled, the result will be canceled
5669                     //   If none fault or are canceled, then result will be RanToCompletion
5670                     for (int i = 0; i < m_tasks.Length; i++)
5671                     {
5672                         var task = m_tasks[i];
5673                         Debug.Assert(task != null, "Constituent task in WhenAll should never be null");
5674
5675                         if (task.IsFaulted)
5676                         {
5677                             if (observedExceptions == null) observedExceptions = new List<ExceptionDispatchInfo>();
5678                             observedExceptions.AddRange(task.GetExceptionDispatchInfos());
5679                         }
5680                         else if (task.IsCanceled)
5681                         {
5682                             if (canceledTask == null) canceledTask = task; // use the first task that's canceled
5683                         }
5684
5685                         // Regardless of completion state, if the task has its debug bit set, transfer it to the
5686                         // WhenAll task.  We must do this before we complete the task.
5687                         if (task.IsWaitNotificationEnabled) this.SetNotificationForWaitCompletion(enabled: true);
5688                         else m_tasks[i] = null; // avoid holding onto tasks unnecessarily
5689                     }
5690
5691                     if (observedExceptions != null)
5692                     {
5693                         Debug.Assert(observedExceptions.Count > 0, "Expected at least one exception");
5694
5695                         //We don't need to TraceOperationCompleted here because TrySetException will call Finish and we'll log it there
5696
5697                         TrySetException(observedExceptions);
5698                     }
5699                     else if (canceledTask != null)
5700                     {
5701                         TrySetCanceled(canceledTask.CancellationToken, canceledTask.GetCancellationExceptionDispatchInfo());
5702                     }
5703                     else
5704                     {
5705                         if (AsyncCausalityTracer.LoggingOn)
5706                             AsyncCausalityTracer.TraceOperationCompletion(CausalityTraceLevel.Required, this.Id, AsyncCausalityStatus.Completed);
5707
5708                         if (Task.s_asyncDebuggingEnabled)
5709                         {
5710                             RemoveFromActiveTasks(this.Id);
5711                         }
5712                         TrySetResult(default(VoidTaskResult));
5713                     }
5714                 }
5715                 Debug.Assert(m_count >= 0, "Count should never go below 0");
5716             }
5717
5718             public bool InvokeMayRunArbitraryCode { get { return true; } }
5719
5720             /// <summary>
5721             /// Returns whether we should notify the debugger of a wait completion.  This returns 
5722             /// true iff at least one constituent task has its bit set.
5723             /// </summary>
5724             internal override bool ShouldNotifyDebuggerOfWaitCompletion
5725             {
5726                 get
5727                 {
5728                     return
5729                         base.ShouldNotifyDebuggerOfWaitCompletion &&
5730                         Task.AnyTaskRequiresNotifyDebuggerOfWaitCompletion(m_tasks);
5731                 }
5732             }
5733         }
5734
5735         /// <summary>
5736         /// Creates a task that will complete when all of the supplied tasks have completed.
5737         /// </summary>
5738         /// <param name="tasks">The tasks to wait on for completion.</param>
5739         /// <returns>A task that represents the completion of all of the supplied tasks.</returns>
5740         /// <remarks>
5741         /// <para>
5742         /// If any of the supplied tasks completes in a faulted state, the returned task will also complete in a Faulted state, 
5743         /// where its exceptions will contain the aggregation of the set of unwrapped exceptions from each of the supplied tasks.  
5744         /// </para>
5745         /// <para>
5746         /// If none of the supplied tasks faulted but at least one of them was canceled, the returned task will end in the Canceled state.
5747         /// </para>
5748         /// <para>
5749         /// If none of the tasks faulted and none of the tasks were canceled, the resulting task will end in the RanToCompletion state.  
5750         /// The Result of the returned task will be set to an array containing all of the results of the 
5751         /// supplied tasks in the same order as they were provided (e.g. if the input tasks array contained t1, t2, t3, the output 
5752         /// task's Result will return an TResult[] where arr[0] == t1.Result, arr[1] == t2.Result, and arr[2] == t3.Result). 
5753         /// </para>
5754         /// <para>
5755         /// If the supplied array/enumerable contains no tasks, the returned task will immediately transition to a RanToCompletion 
5756         /// state before it's returned to the caller.  The returned TResult[] will be an array of 0 elements.
5757         /// </para>
5758         /// </remarks>
5759         /// <exception cref="T:System.ArgumentNullException">
5760         /// The <paramref name="tasks"/> argument was null.
5761         /// </exception>
5762         /// <exception cref="T:System.ArgumentException">
5763         /// The <paramref name="tasks"/> collection contained a null task.
5764         /// </exception>       
5765         public static Task<TResult[]> WhenAll<TResult>(IEnumerable<Task<TResult>> tasks)
5766         {
5767             // Take a more efficient route if tasks is actually an array
5768             Task<TResult>[] taskArray = tasks as Task<TResult>[];
5769             if (taskArray != null)
5770             {
5771                 return WhenAll<TResult>(taskArray);
5772             }
5773
5774             // Skip a List allocation/copy if tasks is a collection
5775             ICollection<Task<TResult>> taskCollection = tasks as ICollection<Task<TResult>>;
5776             if (taskCollection != null)
5777             {
5778                 int index = 0;
5779                 taskArray = new Task<TResult>[taskCollection.Count];
5780                 foreach (var task in tasks)
5781                 {
5782                     if (task == null) ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_NullTask, ExceptionArgument.tasks);
5783                     taskArray[index++] = task;
5784                 }
5785                 return InternalWhenAll<TResult>(taskArray);
5786             }
5787
5788             // Do some argument checking and convert tasks into a List (later an array)
5789             if (tasks == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.tasks);
5790             List<Task<TResult>> taskList = new List<Task<TResult>>();
5791             foreach (Task<TResult> task in tasks)
5792             {
5793                 if (task == null) ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_NullTask, ExceptionArgument.tasks);
5794                 taskList.Add(task);
5795             }
5796
5797             // Delegate the rest to InternalWhenAll<TResult>().
5798             return InternalWhenAll<TResult>(taskList.ToArray());
5799         }
5800
5801         /// <summary>
5802         /// Creates a task that will complete when all of the supplied tasks have completed.
5803         /// </summary>
5804         /// <param name="tasks">The tasks to wait on for completion.</param>
5805         /// <returns>A task that represents the completion of all of the supplied tasks.</returns>
5806         /// <remarks>
5807         /// <para>
5808         /// If any of the supplied tasks completes in a faulted state, the returned task will also complete in a Faulted state, 
5809         /// where its exceptions will contain the aggregation of the set of unwrapped exceptions from each of the supplied tasks.  
5810         /// </para>
5811         /// <para>
5812         /// If none of the supplied tasks faulted but at least one of them was canceled, the returned task will end in the Canceled state.
5813         /// </para>
5814         /// <para>
5815         /// If none of the tasks faulted and none of the tasks were canceled, the resulting task will end in the RanToCompletion state.  
5816         /// The Result of the returned task will be set to an array containing all of the results of the 
5817         /// supplied tasks in the same order as they were provided (e.g. if the input tasks array contained t1, t2, t3, the output 
5818         /// task's Result will return an TResult[] where arr[0] == t1.Result, arr[1] == t2.Result, and arr[2] == t3.Result). 
5819         /// </para>
5820         /// <para>
5821         /// If the supplied array/enumerable contains no tasks, the returned task will immediately transition to a RanToCompletion 
5822         /// state before it's returned to the caller.  The returned TResult[] will be an array of 0 elements.
5823         /// </para>
5824         /// </remarks>
5825         /// <exception cref="T:System.ArgumentNullException">
5826         /// The <paramref name="tasks"/> argument was null.
5827         /// </exception>
5828         /// <exception cref="T:System.ArgumentException">
5829         /// The <paramref name="tasks"/> array contained a null task.
5830         /// </exception>
5831         public static Task<TResult[]> WhenAll<TResult>(params Task<TResult>[] tasks)
5832         {
5833             // Do some argument checking and make a defensive copy of the tasks array
5834             if (tasks == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.tasks);
5835
5836             int taskCount = tasks.Length;
5837             if (taskCount == 0) return InternalWhenAll<TResult>(tasks); // small optimization in the case of an empty task array
5838
5839             Task<TResult>[] tasksCopy = new Task<TResult>[taskCount];
5840             for (int i = 0; i < taskCount; i++)
5841             {
5842                 Task<TResult> task = tasks[i];
5843                 if (task == null) ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_NullTask, ExceptionArgument.tasks);
5844                 tasksCopy[i] = task;
5845             }
5846
5847             // Delegate the rest to InternalWhenAll<TResult>()
5848             return InternalWhenAll<TResult>(tasksCopy);
5849         }
5850
5851         // Some common logic to support WhenAll<TResult> methods
5852         private static Task<TResult[]> InternalWhenAll<TResult>(Task<TResult>[] tasks)
5853         {
5854             Debug.Assert(tasks != null, "Expected a non-null tasks array");
5855             return (tasks.Length == 0) ? // take shortcut if there are no tasks upon which to wait
5856                 new Task<TResult[]>(false, new TResult[0], TaskCreationOptions.None, default(CancellationToken)) :
5857                 new WhenAllPromise<TResult>(tasks);
5858         }
5859
5860         // A Task<T> that gets completed when all of its constituent tasks complete.
5861         // Completion logic will analyze the antecedents in order to choose completion status.
5862         // See comments for non-generic version of WhenAllPromise class.
5863         //
5864         // Used in InternalWhenAll<TResult>(Task<TResult>[])
5865         private sealed class WhenAllPromise<T> : Task<T[]>, ITaskCompletionAction
5866         {
5867             /// <summary>
5868             /// Stores all of the constituent tasks.  Tasks clear themselves out of this
5869             /// array as they complete, but only if they don't have their wait notification bit set.
5870             /// </summary>
5871             private readonly Task<T>[] m_tasks;
5872             /// <summary>The number of tasks remaining to complete.</summary>
5873             private int m_count;
5874
5875             internal WhenAllPromise(Task<T>[] tasks) :
5876                 base()
5877             {
5878                 Debug.Assert(tasks != null, "Expected a non-null task array");
5879                 Debug.Assert(tasks.Length > 0, "Expected a non-zero length task array");
5880
5881                 m_tasks = tasks;
5882                 m_count = tasks.Length;
5883
5884                 if (AsyncCausalityTracer.LoggingOn)
5885                     AsyncCausalityTracer.TraceOperationCreation(CausalityTraceLevel.Required, this.Id, "Task.WhenAll", 0);
5886
5887                 if (s_asyncDebuggingEnabled)
5888                 {
5889                     AddToActiveTasks(this);
5890                 }
5891
5892                 foreach (var task in tasks)
5893                 {
5894                     if (task.IsCompleted) this.Invoke(task); // short-circuit the completion action, if possible
5895                     else task.AddCompletionAction(this); // simple completion action
5896                 }
5897             }
5898
5899             public void Invoke(Task ignored)
5900             {
5901                 if (AsyncCausalityTracer.LoggingOn)
5902                     AsyncCausalityTracer.TraceOperationRelation(CausalityTraceLevel.Important, this.Id, CausalityRelation.Join);
5903
5904                 // Decrement the count, and only continue to complete the promise if we're the last one.
5905                 if (Interlocked.Decrement(ref m_count) == 0)
5906                 {
5907                     // Set up some accounting variables
5908                     T[] results = new T[m_tasks.Length];
5909                     List<ExceptionDispatchInfo> observedExceptions = null;
5910                     Task canceledTask = null;
5911
5912                     // Loop through antecedents:
5913                     //   If any one of them faults, the result will be faulted
5914                     //   If none fault, but at least one is canceled, the result will be canceled
5915                     //   If none fault or are canceled, then result will be RanToCompletion
5916                     for (int i = 0; i < m_tasks.Length; i++)
5917                     {
5918                         Task<T> task = m_tasks[i];
5919                         Debug.Assert(task != null, "Constituent task in WhenAll should never be null");
5920
5921                         if (task.IsFaulted)
5922                         {
5923                             if (observedExceptions == null) observedExceptions = new List<ExceptionDispatchInfo>();
5924                             observedExceptions.AddRange(task.GetExceptionDispatchInfos());
5925                         }
5926                         else if (task.IsCanceled)
5927                         {
5928                             if (canceledTask == null) canceledTask = task; // use the first task that's canceled
5929                         }
5930                         else
5931                         {
5932                             Debug.Assert(task.Status == TaskStatus.RanToCompletion);
5933                             results[i] = task.GetResultCore(waitCompletionNotification: false); // avoid Result, which would triggering debug notification
5934                         }
5935
5936                         // Regardless of completion state, if the task has its debug bit set, transfer it to the
5937                         // WhenAll task.  We must do this before we complete the task.
5938                         if (task.IsWaitNotificationEnabled) this.SetNotificationForWaitCompletion(enabled: true);
5939                         else m_tasks[i] = null; // avoid holding onto tasks unnecessarily
5940                     }
5941
5942                     if (observedExceptions != null)
5943                     {
5944                         Debug.Assert(observedExceptions.Count > 0, "Expected at least one exception");
5945
5946                         //We don't need to TraceOperationCompleted here because TrySetException will call Finish and we'll log it there
5947
5948                         TrySetException(observedExceptions);
5949                     }
5950                     else if (canceledTask != null)
5951                     {
5952                         TrySetCanceled(canceledTask.CancellationToken, canceledTask.GetCancellationExceptionDispatchInfo());
5953                     }
5954                     else
5955                     {
5956                         if (AsyncCausalityTracer.LoggingOn)
5957                             AsyncCausalityTracer.TraceOperationCompletion(CausalityTraceLevel.Required, this.Id, AsyncCausalityStatus.Completed);
5958
5959                         if (Task.s_asyncDebuggingEnabled)
5960                         {
5961                             RemoveFromActiveTasks(this.Id);
5962                         }
5963                         TrySetResult(results);
5964                     }
5965                 }
5966                 Debug.Assert(m_count >= 0, "Count should never go below 0");
5967             }
5968
5969             public bool InvokeMayRunArbitraryCode { get { return true; } }
5970
5971             /// <summary>
5972             /// Returns whether we should notify the debugger of a wait completion.  This returns true
5973             /// iff at least one constituent task has its bit set.
5974             /// </summary>
5975             internal override bool ShouldNotifyDebuggerOfWaitCompletion
5976             {
5977                 get
5978                 {
5979                     return
5980                         base.ShouldNotifyDebuggerOfWaitCompletion &&
5981                         Task.AnyTaskRequiresNotifyDebuggerOfWaitCompletion(m_tasks);
5982                 }
5983             }
5984         }
5985         #endregion
5986
5987         #region WhenAny
5988         /// <summary>
5989         /// Creates a task that will complete when any of the supplied tasks have completed.
5990         /// </summary>
5991         /// <param name="tasks">The tasks to wait on for completion.</param>
5992         /// <returns>A task that represents the completion of one of the supplied tasks.  The return Task's Result is the task that completed.</returns>
5993         /// <remarks>
5994         /// The returned task will complete when any of the supplied tasks has completed.  The returned task will always end in the RanToCompletion state 
5995         /// with its Result set to the first task to complete.  This is true even if the first task to complete ended in the Canceled or Faulted state.
5996         /// </remarks>
5997         /// <exception cref="T:System.ArgumentNullException">
5998         /// The <paramref name="tasks"/> argument was null.
5999         /// </exception>
6000         /// <exception cref="T:System.ArgumentException">
6001         /// The <paramref name="tasks"/> array contained a null task, or was empty.
6002         /// </exception>
6003         public static Task<Task> WhenAny(params Task[] tasks)
6004         {
6005             if (tasks == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.tasks);
6006             if (tasks.Length == 0)
6007             {
6008                 ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_EmptyTaskList, ExceptionArgument.tasks);
6009             }
6010
6011             // Make a defensive copy, as the user may manipulate the tasks array
6012             // after we return but before the WhenAny asynchronously completes.
6013             int taskCount = tasks.Length;
6014             Task[] tasksCopy = new Task[taskCount];
6015             for (int i = 0; i < taskCount; i++)
6016             {
6017                 Task task = tasks[i];
6018                 if (task == null) ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_NullTask, ExceptionArgument.tasks);
6019                 tasksCopy[i] = task;
6020             }
6021
6022             // Previously implemented CommonCWAnyLogic() can handle the rest
6023             return TaskFactory.CommonCWAnyLogic(tasksCopy);
6024         }
6025
6026         /// <summary>
6027         /// Creates a task that will complete when any of the supplied tasks have completed.
6028         /// </summary>
6029         /// <param name="tasks">The tasks to wait on for completion.</param>
6030         /// <returns>A task that represents the completion of one of the supplied tasks.  The return Task's Result is the task that completed.</returns>
6031         /// <remarks>
6032         /// The returned task will complete when any of the supplied tasks has completed.  The returned task will always end in the RanToCompletion state 
6033         /// with its Result set to the first task to complete.  This is true even if the first task to complete ended in the Canceled or Faulted state.
6034         /// </remarks>
6035         /// <exception cref="T:System.ArgumentNullException">
6036         /// The <paramref name="tasks"/> argument was null.
6037         /// </exception>
6038         /// <exception cref="T:System.ArgumentException">
6039         /// The <paramref name="tasks"/> collection contained a null task, or was empty.
6040         /// </exception>
6041         public static Task<Task> WhenAny(IEnumerable<Task> tasks)
6042         {
6043             if (tasks == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.tasks);
6044
6045             // Make a defensive copy, as the user may manipulate the tasks collection
6046             // after we return but before the WhenAny asynchronously completes.
6047             List<Task> taskList = new List<Task>();
6048             foreach (Task task in tasks)
6049             {
6050                 if (task == null) ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_NullTask, ExceptionArgument.tasks);
6051                 taskList.Add(task);
6052             }
6053
6054             if (taskList.Count == 0)
6055             {
6056                 ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_EmptyTaskList, ExceptionArgument.tasks);
6057             }
6058
6059             // Previously implemented CommonCWAnyLogic() can handle the rest
6060             return TaskFactory.CommonCWAnyLogic(taskList);
6061         }
6062
6063         /// <summary>
6064         /// Creates a task that will complete when any of the supplied tasks have completed.
6065         /// </summary>
6066         /// <param name="tasks">The tasks to wait on for completion.</param>
6067         /// <returns>A task that represents the completion of one of the supplied tasks.  The return Task's Result is the task that completed.</returns>
6068         /// <remarks>
6069         /// The returned task will complete when any of the supplied tasks has completed.  The returned task will always end in the RanToCompletion state 
6070         /// with its Result set to the first task to complete.  This is true even if the first task to complete ended in the Canceled or Faulted state.
6071         /// </remarks>
6072         /// <exception cref="T:System.ArgumentNullException">
6073         /// The <paramref name="tasks"/> argument was null.
6074         /// </exception>
6075         /// <exception cref="T:System.ArgumentException">
6076         /// The <paramref name="tasks"/> array contained a null task, or was empty.
6077         /// </exception>
6078         public static Task<Task<TResult>> WhenAny<TResult>(params Task<TResult>[] tasks)
6079         {
6080             // We would just like to do this:
6081             //    return (Task<Task<TResult>>) WhenAny( (Task[]) tasks);
6082             // but classes are not covariant to enable casting Task<TResult> to Task<Task<TResult>>.
6083
6084             // Call WhenAny(Task[]) for basic functionality
6085             Task<Task> intermediate = WhenAny((Task[])tasks);
6086
6087             // Return a continuation task with the correct result type
6088             return intermediate.ContinueWith(Task<TResult>.TaskWhenAnyCast, default(CancellationToken),
6089                 TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.DenyChildAttach, TaskScheduler.Default);
6090         }
6091
6092         /// <summary>
6093         /// Creates a task that will complete when any of the supplied tasks have completed.
6094         /// </summary>
6095         /// <param name="tasks">The tasks to wait on for completion.</param>
6096         /// <returns>A task that represents the completion of one of the supplied tasks.  The return Task's Result is the task that completed.</returns>
6097         /// <remarks>
6098         /// The returned task will complete when any of the supplied tasks has completed.  The returned task will always end in the RanToCompletion state 
6099         /// with its Result set to the first task to complete.  This is true even if the first task to complete ended in the Canceled or Faulted state.
6100         /// </remarks>
6101         /// <exception cref="T:System.ArgumentNullException">
6102         /// The <paramref name="tasks"/> argument was null.
6103         /// </exception>
6104         /// <exception cref="T:System.ArgumentException">
6105         /// The <paramref name="tasks"/> collection contained a null task, or was empty.
6106         /// </exception>
6107         public static Task<Task<TResult>> WhenAny<TResult>(IEnumerable<Task<TResult>> tasks)
6108         {
6109             // We would just like to do this:
6110             //    return (Task<Task<TResult>>) WhenAny( (IEnumerable<Task>) tasks);
6111             // but classes are not covariant to enable casting Task<TResult> to Task<Task<TResult>>.
6112
6113             // Call WhenAny(IEnumerable<Task>) for basic functionality
6114             Task<Task> intermediate = WhenAny((IEnumerable<Task>)tasks);
6115
6116             // Return a continuation task with the correct result type
6117             return intermediate.ContinueWith(Task<TResult>.TaskWhenAnyCast, default(CancellationToken),
6118                 TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.DenyChildAttach, TaskScheduler.Default);
6119         }
6120         #endregion
6121
6122         internal static Task<TResult> CreateUnwrapPromise<TResult>(Task outerTask, bool lookForOce)
6123         {
6124             Debug.Assert(outerTask != null);
6125
6126             return new UnwrapPromise<TResult>(outerTask, lookForOce);
6127         }
6128
6129         internal virtual Delegate[] GetDelegateContinuationsForDebugger()
6130         {
6131             //Avoid an infinite loop by making sure the continuation object is not a reference to istelf.
6132             if (m_continuationObject != this)
6133                 return GetDelegatesFromContinuationObject(m_continuationObject);
6134             else
6135                 return null;
6136         }
6137
6138         internal static Delegate[] GetDelegatesFromContinuationObject(object continuationObject)
6139         {
6140             if (continuationObject != null)
6141             {
6142                 Action singleAction = continuationObject as Action;
6143                 if (singleAction != null)
6144                 {
6145                     return new Delegate[] { AsyncMethodBuilderCore.TryGetStateMachineForDebugger(singleAction) };
6146                 }
6147
6148                 TaskContinuation taskContinuation = continuationObject as TaskContinuation;
6149                 if (taskContinuation != null)
6150                 {
6151                     return taskContinuation.GetDelegateContinuationsForDebugger();
6152                 }
6153
6154                 Task continuationTask = continuationObject as Task;
6155                 if (continuationTask != null)
6156                 {
6157                     Debug.Assert(continuationTask.m_action == null);
6158                     Delegate[] delegates = continuationTask.GetDelegateContinuationsForDebugger();
6159                     if (delegates != null)
6160                         return delegates;
6161                 }
6162
6163                 //We need this ITaskCompletionAction after the Task because in the case of UnwrapPromise
6164                 //the VS debugger is more interested in the continuation than the internal invoke()
6165                 ITaskCompletionAction singleCompletionAction = continuationObject as ITaskCompletionAction;
6166                 if (singleCompletionAction != null)
6167                 {
6168                     return new Delegate[] { new Action<Task>(singleCompletionAction.Invoke) };
6169                 }
6170
6171                 List<object> continuationList = continuationObject as List<object>;
6172                 if (continuationList != null)
6173                 {
6174                     List<Delegate> result = new List<Delegate>();
6175                     foreach (object obj in continuationList)
6176                     {
6177                         var innerDelegates = GetDelegatesFromContinuationObject(obj);
6178                         if (innerDelegates != null)
6179                         {
6180                             foreach (var del in innerDelegates)
6181                             {
6182                                 if (del != null)
6183                                     result.Add(del);
6184                             }
6185                         }
6186                     }
6187
6188                     return result.ToArray();
6189                 }
6190             }
6191
6192             return null;
6193         }
6194
6195         private static Task GetActiveTaskFromId(int taskId)
6196         {
6197             Task task = null;
6198             s_currentActiveTasks.TryGetValue(taskId, out task);
6199             return task;
6200         }
6201
6202         private static Task[] GetActiveTasks()
6203         {
6204             return new List<Task>(s_currentActiveTasks.Values).ToArray();
6205         }
6206     }
6207
6208     internal sealed class CompletionActionInvoker : IThreadPoolWorkItem
6209     {
6210         private readonly ITaskCompletionAction m_action;
6211         private readonly Task m_completingTask;
6212
6213         internal CompletionActionInvoker(ITaskCompletionAction action, Task completingTask)
6214         {
6215             m_action = action;
6216             m_completingTask = completingTask;
6217         }
6218
6219         void IThreadPoolWorkItem.ExecuteWorkItem()
6220         {
6221             m_action.Invoke(m_completingTask);
6222         }
6223
6224         void IThreadPoolWorkItem.MarkAborted(ThreadAbortException tae)
6225         {
6226             /* NOP */
6227         }
6228     }
6229
6230     // Proxy class for better debugging experience
6231     internal class SystemThreadingTasks_TaskDebugView
6232     {
6233         private Task m_task;
6234
6235         public SystemThreadingTasks_TaskDebugView(Task task)
6236         {
6237             m_task = task;
6238         }
6239
6240         public object AsyncState { get { return m_task.AsyncState; } }
6241         public TaskCreationOptions CreationOptions { get { return m_task.CreationOptions; } }
6242         public Exception Exception { get { return m_task.Exception; } }
6243         public int Id { get { return m_task.Id; } }
6244         public bool CancellationPending { get { return (m_task.Status == TaskStatus.WaitingToRun) && m_task.CancellationToken.IsCancellationRequested; } }
6245         public TaskStatus Status { get { return m_task.Status; } }
6246     }
6247
6248     /// <summary>
6249     /// Specifies flags that control optional behavior for the creation and execution of tasks.
6250     /// </summary>
6251     // NOTE: These options are a subset of TaskContinuationsOptions, thus before adding a flag check it is
6252     // not already in use.
6253     [Flags]
6254     public enum TaskCreationOptions
6255     {
6256         /// <summary>
6257         /// Specifies that the default behavior should be used.
6258         /// </summary>
6259         None = 0x0,
6260
6261         /// <summary>
6262         /// A hint to a <see cref="System.Threading.Tasks.TaskScheduler">TaskScheduler</see> to schedule a
6263         /// task in as fair a manner as possible, meaning that tasks scheduled sooner will be more likely to
6264         /// be run sooner, and tasks scheduled later will be more likely to be run later.
6265         /// </summary>
6266         PreferFairness = 0x01,
6267
6268         /// <summary>
6269         /// Specifies that a task will be a long-running, course-grained operation. It provides a hint to the
6270         /// <see cref="System.Threading.Tasks.TaskScheduler">TaskScheduler</see> that oversubscription may be
6271         /// warranted. 
6272         /// </summary>
6273         LongRunning = 0x02,
6274
6275         /// <summary>
6276         /// Specifies that a task is attached to a parent in the task hierarchy.
6277         /// </summary>
6278         AttachedToParent = 0x04,
6279
6280         /// <summary>
6281         /// Specifies that an InvalidOperationException will be thrown if an attempt is made to attach a child task to the created task.
6282         /// </summary>
6283         DenyChildAttach = 0x08,
6284
6285         /// <summary>
6286         /// Prevents the ambient scheduler from being seen as the current scheduler in the created task.  This means that operations
6287         /// like StartNew or ContinueWith that are performed in the created task will see TaskScheduler.Default as the current scheduler.
6288         /// </summary>
6289         HideScheduler = 0x10,
6290
6291         // 0x20 is already being used in TaskContinuationOptions
6292
6293         /// <summary>
6294         /// Forces continuations added to the current task to be executed asynchronously.
6295         /// This option has precedence over TaskContinuationOptions.ExecuteSynchronously
6296         /// </summary>
6297         RunContinuationsAsynchronously = 0x40
6298     }
6299
6300
6301     /// <summary>
6302     /// Task creation flags which are only used internally.
6303     /// </summary>
6304     [Flags]
6305     internal enum InternalTaskOptions
6306     {
6307         /// <summary> Specifies "No internal task options" </summary>
6308         None,
6309
6310         /// <summary>Used to filter out internal vs. public task creation options.</summary>
6311         InternalOptionsMask = 0x0000FF00,
6312
6313         ContinuationTask = 0x0200,
6314         PromiseTask = 0x0400,
6315
6316         /// <summary>
6317         /// Store the presence of TaskContinuationOptions.LazyCancellation, since it does not directly
6318         /// translate into any TaskCreationOptions.
6319         /// </summary>
6320         LazyCancellation = 0x1000,
6321
6322         /// <summary>Specifies that the task will be queued by the runtime before handing it over to the user. 
6323         /// This flag will be used to skip the cancellationtoken registration step, which is only meant for unstarted tasks.</summary>
6324         QueuedByRuntime = 0x2000,
6325
6326         /// <summary>
6327         /// Denotes that Dispose should be a complete nop for a Task.  Used when constructing tasks that are meant to be cached/reused.
6328         /// </summary>
6329         DoNotDispose = 0x4000
6330     }
6331
6332     /// <summary>
6333     /// Specifies flags that control optional behavior for the creation and execution of continuation tasks.
6334     /// </summary>
6335     [Flags]
6336     public enum TaskContinuationOptions
6337     {
6338         /// <summary>
6339         /// Default = "Continue on any, no task options, run asynchronously"
6340         /// Specifies that the default behavior should be used.  Continuations, by default, will
6341         /// be scheduled when the antecedent task completes, regardless of the task's final <see
6342         /// cref="System.Threading.Tasks.TaskStatus">TaskStatus</see>.
6343         /// </summary>
6344         None = 0,
6345
6346         // These are identical to their meanings and values in TaskCreationOptions
6347
6348         /// <summary>
6349         /// A hint to a <see cref="System.Threading.Tasks.TaskScheduler">TaskScheduler</see> to schedule a
6350         /// task in as fair a manner as possible, meaning that tasks scheduled sooner will be more likely to
6351         /// be run sooner, and tasks scheduled later will be more likely to be run later.
6352         /// </summary>
6353         PreferFairness = 0x01,
6354
6355         /// <summary>
6356         /// Specifies that a task will be a long-running, course-grained operation.  It provides
6357         /// a hint to the <see cref="System.Threading.Tasks.TaskScheduler">TaskScheduler</see> that
6358         /// oversubscription may be warranted.
6359         /// </summary>
6360         LongRunning = 0x02,
6361         /// <summary>
6362         /// Specifies that a task is attached to a parent in the task hierarchy.
6363         /// </summary>
6364         AttachedToParent = 0x04,
6365
6366         /// <summary>
6367         /// Specifies that an InvalidOperationException will be thrown if an attempt is made to attach a child task to the created task.
6368         /// </summary>
6369         DenyChildAttach = 0x08,
6370         /// <summary>
6371         /// Prevents the ambient scheduler from being seen as the current scheduler in the created task.  This means that operations
6372         /// like StartNew or ContinueWith that are performed in the created task will see TaskScheduler.Default as the current scheduler.
6373         /// </summary>
6374         HideScheduler = 0x10,
6375
6376         /// <summary>
6377         /// In the case of continuation cancellation, prevents completion of the continuation until the antecedent has completed.
6378         /// </summary>
6379         LazyCancellation = 0x20,
6380
6381         RunContinuationsAsynchronously = 0x40,
6382
6383         // These are specific to continuations
6384
6385         /// <summary>
6386         /// Specifies that the continuation task should not be scheduled if its antecedent ran to completion.
6387         /// This option is not valid for multi-task continuations.
6388         /// </summary>
6389         NotOnRanToCompletion = 0x10000,
6390         /// <summary>
6391         /// Specifies that the continuation task should not be scheduled if its antecedent threw an unhandled
6392         /// exception. This option is not valid for multi-task continuations.
6393         /// </summary>
6394         NotOnFaulted = 0x20000,
6395         /// <summary>
6396         /// Specifies that the continuation task should not be scheduled if its antecedent was canceled. This
6397         /// option is not valid for multi-task continuations.
6398         /// </summary>
6399         NotOnCanceled = 0x40000,
6400         /// <summary>
6401         /// Specifies that the continuation task should be scheduled only if its antecedent ran to
6402         /// completion. This option is not valid for multi-task continuations.
6403         /// </summary>
6404         OnlyOnRanToCompletion = NotOnFaulted | NotOnCanceled,
6405         /// <summary>
6406         /// Specifies that the continuation task should be scheduled only if its antecedent threw an
6407         /// unhandled exception. This option is not valid for multi-task continuations.
6408         /// </summary>
6409         OnlyOnFaulted = NotOnRanToCompletion | NotOnCanceled,
6410         /// <summary>
6411         /// Specifies that the continuation task should be scheduled only if its antecedent was canceled.
6412         /// This option is not valid for multi-task continuations.
6413         /// </summary>
6414         OnlyOnCanceled = NotOnRanToCompletion | NotOnFaulted,
6415         /// <summary>
6416         /// Specifies that the continuation task should be executed synchronously. With this option
6417         /// specified, the continuation will be run on the same thread that causes the antecedent task to
6418         /// transition into its final state. If the antecedent is already complete when the continuation is
6419         /// created, the continuation will run on the thread creating the continuation.  Only very
6420         /// short-running continuations should be executed synchronously.
6421         /// </summary>
6422         ExecuteSynchronously = 0x80000
6423     }
6424
6425     /// <summary>
6426     /// Internal helper class to keep track of stack depth and decide whether we should inline or not.
6427     /// </summary>
6428     internal class StackGuard
6429     {
6430         // current thread's depth of nested inline task executions
6431         private int m_inliningDepth = 0;
6432
6433         // For relatively small inlining depths we don't want to get into the business of stack probing etc.
6434         // This clearly leaves a window of opportunity for the user code to SO. However a piece of code
6435         // that can SO in 20 inlines on a typical 1MB stack size probably needs to be revisited anyway.
6436         private const int MAX_UNCHECKED_INLINING_DEPTH = 20;
6437
6438         /// <summary>
6439         /// This method needs to be called before attempting inline execution on the current thread. 
6440         /// If false is returned, it means we are too close to the end of the stack and should give up inlining.
6441         /// Each call to TryBeginInliningScope() that returns true must be matched with a 
6442         /// call to EndInliningScope() regardless of whether inlining actually took place.
6443         /// </summary>
6444         internal bool TryBeginInliningScope()
6445         {
6446             // If we're still under the 'safe' limit we'll just skip the stack probe to save p/invoke calls
6447             if (m_inliningDepth < MAX_UNCHECKED_INLINING_DEPTH || CheckForSufficientStack())
6448             {
6449                 m_inliningDepth++;
6450                 return true;
6451             }
6452             else
6453                 return false;
6454         }
6455
6456         /// <summary>
6457         /// This needs to be called once for each previous successful TryBeginInliningScope() call after
6458         /// inlining related logic runs.
6459         /// </summary>
6460         internal void EndInliningScope()
6461         {
6462             m_inliningDepth--;
6463             Debug.Assert(m_inliningDepth >= 0, "Inlining depth count should never go negative.");
6464
6465             // do the right thing just in case...
6466             if (m_inliningDepth < 0) m_inliningDepth = 0;
6467         }
6468
6469         private unsafe bool CheckForSufficientStack()
6470         {
6471             return RuntimeHelpers.TryEnsureSufficientExecutionStack();
6472         }
6473     }
6474
6475     // Special internal struct that we use to signify that we are not interested in
6476     // a Task<VoidTaskResult>'s result.
6477     internal struct VoidTaskResult { }
6478
6479     // Interface to which all completion actions must conform.
6480     // This interface allows us to combine functionality and reduce allocations.
6481     // For example, see Task.SetOnInvokeMres, and its use in Task.SpinThenBlockingWait().
6482     // This code:
6483     //      ManualResetEvent mres = new ManualResetEventSlim(false, 0);
6484     //      Action<Task> completionAction = delegate { mres.Set() ; };
6485     //      AddCompletionAction(completionAction);
6486     // gets replaced with this:
6487     //      SetOnInvokeMres mres = new SetOnInvokeMres();
6488     //      AddCompletionAction(mres);
6489     // For additional examples of where this is used, see internal classes Task.SignalOnInvokeCDE,
6490     // Task.WhenAllPromise, Task.WhenAllPromise<T>, TaskFactory.CompleteOnCountdownPromise,
6491     // TaskFactory.CompleteOnCountdownPromise<T>, and TaskFactory.CompleteOnInvokePromise.
6492     internal interface ITaskCompletionAction
6493     {
6494         /// <summary>Invoked to run the completion action.</summary>
6495         void Invoke(Task completingTask);
6496
6497         /// <summary>
6498         /// Some completion actions are considered internal implementation details of tasks,
6499         /// using the continuation mechanism only for performance reasons.  Such actions perform
6500         /// known quantities and types of work, and can be invoked safely as a continuation even
6501         /// if the system wants to prevent arbitrary continuations from running synchronously.
6502         /// This should only return false for a limited set of implementations where a small amount
6503         /// of work is guaranteed to be performed, e.g. setting a ManualResetEventSlim.
6504         /// </summary>
6505         bool InvokeMayRunArbitraryCode { get; }
6506     }
6507
6508     // This class encapsulates all "unwrap" logic, and also implements ITaskCompletionAction,
6509     // which minimizes the allocations needed for queuing it to its antecedent.  This
6510     // logic is used by both the Unwrap extension methods and the unwrap-style Task.Run methods.
6511     internal sealed class UnwrapPromise<TResult> : Task<TResult>, ITaskCompletionAction
6512     {
6513         // The possible states for our UnwrapPromise, used by Invoke() to determine which logic to execute
6514         private const byte STATE_WAITING_ON_OUTER_TASK = 0; // Invoke() means "process completed outer task"
6515         private const byte STATE_WAITING_ON_INNER_TASK = 1; // Invoke() means "process completed inner task"
6516         private const byte STATE_DONE = 2;                  // Invoke() means "something went wrong and we are hosed!"
6517
6518         // Keep track of our state; initialized to STATE_WAITING_ON_OUTER_TASK in the constructor
6519         private byte _state;
6520
6521         // "Should we check for OperationCanceledExceptions on the outer task and interpret them as proxy cancellation?"
6522         // Unwrap() sets this to false, Run() sets it to true.
6523         private readonly bool _lookForOce;
6524
6525         public UnwrapPromise(Task outerTask, bool lookForOce)
6526             : base((object)null, outerTask.CreationOptions & TaskCreationOptions.AttachedToParent)
6527         {
6528             Debug.Assert(outerTask != null, "Expected non-null outerTask");
6529             _lookForOce = lookForOce;
6530             _state = STATE_WAITING_ON_OUTER_TASK;
6531
6532             if (AsyncCausalityTracer.LoggingOn)
6533                 AsyncCausalityTracer.TraceOperationCreation(CausalityTraceLevel.Required, this.Id, "Task.Unwrap", 0);
6534
6535             if (Task.s_asyncDebuggingEnabled)
6536             {
6537                 AddToActiveTasks(this);
6538             }
6539
6540             // Link ourselves to the outer task.
6541             // If the outer task has already completed, take the fast path
6542             // of immediately transferring its results or processing the inner task.
6543             if (outerTask.IsCompleted)
6544             {
6545                 ProcessCompletedOuterTask(outerTask);
6546             }
6547             else // Otherwise, process its completion asynchronously.
6548             {
6549                 outerTask.AddCompletionAction(this);
6550             }
6551         }
6552
6553         // For ITaskCompletionAction 
6554         public void Invoke(Task completingTask)
6555         {
6556             // Check the current stack guard.  If we're ok to inline,
6557             // process the task, and reset the guard when we're done.
6558             var sg = Task.CurrentStackGuard;
6559             if (sg.TryBeginInliningScope())
6560             {
6561                 try { InvokeCore(completingTask); }
6562                 finally { sg.EndInliningScope(); }
6563             }
6564             // Otherwise, we're too deep on the stack, and
6565             // we shouldn't run the continuation chain here, so queue a work
6566             // item to call back here to Invoke asynchronously.
6567             else InvokeCoreAsync(completingTask);
6568         }
6569
6570         /// <summary>
6571         /// Processes the completed task. InvokeCore could be called twice:
6572         /// once for the outer task, once for the inner task.
6573         /// </summary>
6574         /// <param name="completingTask">The completing outer or inner task.</param>
6575         private void InvokeCore(Task completingTask)
6576         {
6577             switch (_state)
6578             {
6579                 case STATE_WAITING_ON_OUTER_TASK:
6580                     ProcessCompletedOuterTask(completingTask);
6581                     // We bump the state inside of ProcessCompletedOuterTask because it can also be called from the constructor.
6582                     break;
6583                 case STATE_WAITING_ON_INNER_TASK:
6584                     bool result = TrySetFromTask(completingTask, lookForOce: false);
6585                     _state = STATE_DONE; // bump the state
6586                     Debug.Assert(result, "Expected TrySetFromTask from inner task to succeed");
6587                     break;
6588                 default:
6589                     Debug.Fail("UnwrapPromise in illegal state");
6590                     break;
6591             }
6592         }
6593
6594         // Calls InvokeCore asynchronously.
6595         private void InvokeCoreAsync(Task completingTask)
6596         {
6597             // Queue a call to Invoke.  If we're so deep on the stack that we're at risk of overflowing,
6598             // there's a high liklihood this thread is going to be doing lots more work before
6599             // returning to the thread pool (at the very least unwinding through thousands of
6600             // stack frames).  So we queue to the global queue.
6601             ThreadPool.UnsafeQueueUserWorkItem(state =>
6602             {
6603                 // InvokeCore(completingTask);
6604                 var tuple = (Tuple<UnwrapPromise<TResult>, Task>)state;
6605                 tuple.Item1.InvokeCore(tuple.Item2);
6606             }, Tuple.Create<UnwrapPromise<TResult>, Task>(this, completingTask));
6607         }
6608
6609         /// <summary>Processes the outer task once it's completed.</summary>
6610         /// <param name="task">The now-completed outer task.</param>
6611         private void ProcessCompletedOuterTask(Task task)
6612         {
6613             Debug.Assert(task != null && task.IsCompleted, "Expected non-null, completed outer task");
6614             Debug.Assert(_state == STATE_WAITING_ON_OUTER_TASK, "We're in the wrong state!");
6615
6616             // Bump our state before proceeding any further
6617             _state = STATE_WAITING_ON_INNER_TASK;
6618
6619             switch (task.Status)
6620             {
6621                 // If the outer task did not complete successfully, then record the 
6622                 // cancellation/fault information to tcs.Task.
6623                 case TaskStatus.Canceled:
6624                 case TaskStatus.Faulted:
6625                     bool result = TrySetFromTask(task, _lookForOce);
6626                     Debug.Assert(result, "Expected TrySetFromTask from outer task to succeed");
6627                     break;
6628
6629                 // Otherwise, process the inner task it returned.
6630                 case TaskStatus.RanToCompletion:
6631                     var taskOfTaskOfTResult = task as Task<Task<TResult>>; // it's either a Task<Task> or Task<Task<TResult>>
6632                     ProcessInnerTask(taskOfTaskOfTResult != null ?
6633                         taskOfTaskOfTResult.Result : ((Task<Task>)task).Result);
6634                     break;
6635             }
6636         }
6637
6638         /// <summary>Transfer the completion status from "task" to ourself.</summary>
6639         /// <param name="task">The source task whose results should be transfered to <paramref name="promise"/>.</param>
6640         /// <param name="lookForOce">Whether or not to look for OperationCanceledExceptions in task's exceptions if it faults.</param>
6641         /// <returns>true if the transfer was successful; otherwise, false.</returns>
6642         private bool TrySetFromTask(Task task, bool lookForOce)
6643         {
6644             Debug.Assert(task != null && task.IsCompleted, "TrySetFromTask: Expected task to have completed.");
6645
6646             if (AsyncCausalityTracer.LoggingOn)
6647                 AsyncCausalityTracer.TraceOperationRelation(CausalityTraceLevel.Important, this.Id, CausalityRelation.Join);
6648
6649             bool result = false;
6650             switch (task.Status)
6651             {
6652                 case TaskStatus.Canceled:
6653                     result = TrySetCanceled(task.CancellationToken, task.GetCancellationExceptionDispatchInfo());
6654                     break;
6655
6656                 case TaskStatus.Faulted:
6657                     var edis = task.GetExceptionDispatchInfos();
6658                     ExceptionDispatchInfo oceEdi;
6659                     OperationCanceledException oce;
6660                     if (lookForOce && edis.Count > 0 &&
6661                         (oceEdi = edis[0]) != null &&
6662                         (oce = oceEdi.SourceException as OperationCanceledException) != null)
6663                     {
6664                         result = TrySetCanceled(oce.CancellationToken, oceEdi);
6665                     }
6666                     else
6667                     {
6668                         result = TrySetException(edis);
6669                     }
6670                     break;
6671
6672                 case TaskStatus.RanToCompletion:
6673                     var taskTResult = task as Task<TResult>;
6674
6675                     if (AsyncCausalityTracer.LoggingOn)
6676                         AsyncCausalityTracer.TraceOperationCompletion(CausalityTraceLevel.Required, this.Id, AsyncCausalityStatus.Completed);
6677
6678                     if (Task.s_asyncDebuggingEnabled)
6679                     {
6680                         RemoveFromActiveTasks(this.Id);
6681                     }
6682
6683                     result = TrySetResult(taskTResult != null ? taskTResult.Result : default(TResult));
6684                     break;
6685             }
6686             return result;
6687         }
6688
6689         /// <summary>
6690         /// Processes the inner task of a Task{Task} or Task{Task{TResult}}, 
6691         /// transferring the appropriate results to ourself.
6692         /// </summary>
6693         /// <param name="task">The inner task returned by the task provided by the user.</param>
6694         private void ProcessInnerTask(Task task)
6695         {
6696             // If the inner task is null, the proxy should be canceled.
6697             if (task == null)
6698             {
6699                 TrySetCanceled(default(CancellationToken));
6700                 _state = STATE_DONE; // ... and record that we are done
6701             }
6702
6703             // Fast path for if the inner task is already completed
6704             else if (task.IsCompleted)
6705             {
6706                 TrySetFromTask(task, lookForOce: false);
6707                 _state = STATE_DONE; // ... and record that we are done
6708             }
6709
6710             // The inner task exists but is not yet complete, so when it does complete,
6711             // take some action to set our completion state.
6712             else
6713             {
6714                 task.AddCompletionAction(this);
6715                 // We'll record that we are done when Invoke() is called.
6716             }
6717         }
6718
6719         public bool InvokeMayRunArbitraryCode { get { return true; } }
6720     }
6721 }