5 // Marek Safar <marek.safar@gmail.com>
6 // Jérémie Laval <jeremie dot laval at xamarin dot com>
8 // Copyright (c) 2008 Jérémie "Garuma" Laval
9 // Copyright 2011 Xamarin Inc (http://www.xamarin.com).
11 // Permission is hereby granted, free of charge, to any person obtaining a copy
12 // of this software and associated documentation files (the "Software"), to deal
13 // in the Software without restriction, including without limitation the rights
14 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 // copies of the Software, and to permit persons to whom the Software is
16 // furnished to do so, subject to the following conditions:
18 // The above copyright notice and this permission notice shall be included in
19 // all copies or substantial portions of the Software.
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
34 using System.Threading;
35 using System.Collections.Concurrent;
36 using System.Collections.Generic;
37 using System.Runtime.CompilerServices;
39 namespace System.Threading.Tasks
41 [System.Diagnostics.DebuggerDisplay ("Id = {Id}, Status = {Status}")]
42 [System.Diagnostics.DebuggerTypeProxy (typeof (TaskDebuggerView))]
43 public class Task : IDisposable, IAsyncResult
45 // With this attribute each thread has its own value so that it's correct for our Schedule code
46 // and for Parent property.
50 static Action<Task> childWorkAdder;
52 // parent is the outer task in which this task is created
54 // contAncestor is the Task on which this continuation was setup
55 readonly Task contAncestor;
58 static readonly TaskFactory defaultFactory = new TaskFactory ();
60 CountdownEvent childTasks;
63 TaskCreationOptions taskCreationOptions;
65 internal TaskScheduler scheduler;
67 TaskExceptionSlot exSlot;
71 TaskActionInvoker invoker;
73 internal AtomicBooleanValue executing;
75 TaskCompletionQueue<IContinuation> continuations;
77 CancellationToken token;
78 CancellationTokenRegistration? cancellationRegistration;
80 internal const TaskCreationOptions WorkerTaskNotSupportedOptions = TaskCreationOptions.LongRunning | TaskCreationOptions.PreferFairness;
82 const TaskCreationOptions MaxTaskCreationOptions =
84 TaskCreationOptions.DenyChildAttach | TaskCreationOptions.HideScheduler |
86 TaskCreationOptions.PreferFairness | TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent;
88 public Task (Action action)
89 : this (action, TaskCreationOptions.None)
94 public Task (Action action, TaskCreationOptions creationOptions)
95 : this (action, CancellationToken.None, creationOptions)
100 public Task (Action action, CancellationToken cancellationToken)
101 : this (action, cancellationToken, TaskCreationOptions.None)
106 public Task (Action action, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
107 : this (TaskActionInvoker.Create (action), null, cancellationToken, creationOptions, current)
110 throw new ArgumentNullException ("action");
111 if (creationOptions > MaxTaskCreationOptions || creationOptions < TaskCreationOptions.None)
112 throw new ArgumentOutOfRangeException ("creationOptions");
115 public Task (Action<object> action, object state)
116 : this (action, state, TaskCreationOptions.None)
120 public Task (Action<object> action, object state, TaskCreationOptions creationOptions)
121 : this (action, state, CancellationToken.None, creationOptions)
125 public Task (Action<object> action, object state, CancellationToken cancellationToken)
126 : this (action, state, cancellationToken, TaskCreationOptions.None)
130 public Task (Action<object> action, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
131 : this (TaskActionInvoker.Create (action), state, cancellationToken, creationOptions, current)
134 throw new ArgumentNullException ("action");
135 if (creationOptions > MaxTaskCreationOptions || creationOptions < TaskCreationOptions.None)
136 throw new ArgumentOutOfRangeException ("creationOptions");
139 internal Task (TaskActionInvoker invoker, object state, CancellationToken cancellationToken,
140 TaskCreationOptions creationOptions, Task parent = null, Task contAncestor = null)
142 this.invoker = invoker;
143 this.taskCreationOptions = creationOptions;
145 this.taskId = Interlocked.Increment (ref id);
146 this.status = cancellationToken.IsCancellationRequested ? TaskStatus.Canceled : TaskStatus.Created;
147 this.token = cancellationToken;
148 this.parent = parent = parent == null ? current : parent;
149 this.contAncestor = contAncestor;
151 // Process taskCreationOptions
152 if (CheckTaskOptions (taskCreationOptions, TaskCreationOptions.AttachedToParent) && parent != null)
155 if (token.CanBeCanceled)
156 cancellationRegistration = token.Register (l => ((Task) l).CancelReal (), this);
159 static bool CheckTaskOptions (TaskCreationOptions opt, TaskCreationOptions member)
161 return (opt & member) == member;
167 Start (TaskScheduler.Current);
170 public void Start (TaskScheduler scheduler)
172 if (scheduler == null)
173 throw new ArgumentNullException ("scheduler");
175 if (status >= TaskStatus.WaitingToRun)
176 throw new InvalidOperationException ("The Task is not in a valid state to be started.");
179 throw new InvalidOperationException ("Start may not be called on a continuation task");
181 SetupScheduler (scheduler);
185 internal void SetupScheduler (TaskScheduler scheduler)
187 this.scheduler = scheduler;
188 Status = TaskStatus.WaitingForActivation;
191 public void RunSynchronously ()
193 RunSynchronously (TaskScheduler.Current);
196 public void RunSynchronously (TaskScheduler scheduler)
198 if (scheduler == null)
199 throw new ArgumentNullException ("scheduler");
201 if (Status > TaskStatus.WaitingForActivation)
202 throw new InvalidOperationException ("The task is not in a valid state to be started");
204 SetupScheduler (scheduler);
205 var saveStatus = status;
206 Status = TaskStatus.WaitingToRun;
209 if (scheduler.RunInline (this, false))
211 } catch (Exception inner) {
212 throw new TaskSchedulerException (inner);
222 public Task ContinueWith (Action<Task> continuationAction)
224 return ContinueWith (continuationAction, TaskContinuationOptions.None);
227 public Task ContinueWith (Action<Task> continuationAction, TaskContinuationOptions continuationOptions)
229 return ContinueWith (continuationAction, CancellationToken.None, continuationOptions, TaskScheduler.Current);
232 public Task ContinueWith (Action<Task> continuationAction, CancellationToken cancellationToken)
234 return ContinueWith (continuationAction, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
237 public Task ContinueWith (Action<Task> continuationAction, TaskScheduler scheduler)
239 return ContinueWith (continuationAction, CancellationToken.None, TaskContinuationOptions.None, scheduler);
242 public Task ContinueWith (Action<Task> continuationAction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
244 if (continuationAction == null)
245 throw new ArgumentNullException ("continuationAction");
246 if (scheduler == null)
247 throw new ArgumentNullException ("scheduler");
249 return ContinueWith (TaskActionInvoker.Create (continuationAction), cancellationToken, continuationOptions, scheduler);
252 internal Task ContinueWith (TaskActionInvoker invoker, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
254 var continuation = new Task (invoker, null, cancellationToken, GetCreationOptions (continuationOptions), null, this);
255 ContinueWithCore (continuation, continuationOptions, scheduler);
260 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction)
262 return ContinueWith<TResult> (continuationFunction, TaskContinuationOptions.None);
265 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, TaskContinuationOptions continuationOptions)
267 return ContinueWith<TResult> (continuationFunction, CancellationToken.None, continuationOptions, TaskScheduler.Current);
270 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, CancellationToken cancellationToken)
272 return ContinueWith<TResult> (continuationFunction, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
275 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, TaskScheduler scheduler)
277 return ContinueWith<TResult> (continuationFunction, CancellationToken.None, TaskContinuationOptions.None, scheduler);
280 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, CancellationToken cancellationToken,
281 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
283 if (continuationFunction == null)
284 throw new ArgumentNullException ("continuationFunction");
285 if (scheduler == null)
286 throw new ArgumentNullException ("scheduler");
288 return ContinueWith<TResult> (TaskActionInvoker.Create (continuationFunction), cancellationToken, continuationOptions, scheduler);
291 internal Task<TResult> ContinueWith<TResult> (TaskActionInvoker invoker, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
293 var continuation = new Task<TResult> (invoker, null, cancellationToken, GetCreationOptions (continuationOptions), parent, this);
294 ContinueWithCore (continuation, continuationOptions, scheduler);
299 internal void ContinueWithCore (Task continuation, TaskContinuationOptions options, TaskScheduler scheduler)
301 const TaskContinuationOptions wrongRan = TaskContinuationOptions.NotOnRanToCompletion | TaskContinuationOptions.OnlyOnRanToCompletion;
302 const TaskContinuationOptions wrongCanceled = TaskContinuationOptions.NotOnCanceled | TaskContinuationOptions.OnlyOnCanceled;
303 const TaskContinuationOptions wrongFaulted = TaskContinuationOptions.NotOnFaulted | TaskContinuationOptions.OnlyOnFaulted;
305 if (((options & wrongRan) == wrongRan) || ((options & wrongCanceled) == wrongCanceled) || ((options & wrongFaulted) == wrongFaulted))
306 throw new ArgumentException ("continuationOptions", "Some options are mutually exclusive");
308 // Already set the scheduler so that user can call Wait and that sort of stuff
309 continuation.scheduler = scheduler;
310 continuation.Status = TaskStatus.WaitingForActivation;
312 ContinueWith (new TaskContinuation (continuation, options));
315 internal void ContinueWith (IContinuation continuation)
318 continuation.Execute ();
322 continuations.Add (continuation);
324 // Retry in case completion was achieved but event adding was too late
325 if (IsCompleted && continuations.Remove (continuation))
326 continuation.Execute ();
329 void RemoveContinuation (IContinuation continuation)
331 continuations.Remove (continuation);
334 static internal TaskCreationOptions GetCreationOptions (TaskContinuationOptions kind)
336 TaskCreationOptions options = TaskCreationOptions.None;
337 if ((kind & TaskContinuationOptions.AttachedToParent) > 0)
338 options |= TaskCreationOptions.AttachedToParent;
339 if ((kind & TaskContinuationOptions.PreferFairness) > 0)
340 options |= TaskCreationOptions.PreferFairness;
341 if ((kind & TaskContinuationOptions.LongRunning) > 0)
342 options |= TaskCreationOptions.LongRunning;
348 #region Internal and protected thingies
349 internal void Schedule ()
351 Status = TaskStatus.WaitingToRun;
353 // If worker is null it means it is a local one, revert to the old behavior
354 // If TaskScheduler.Current is not being used, the scheduler was explicitly provided, so we must use that
355 if (scheduler != TaskScheduler.Current || childWorkAdder == null || CheckTaskOptions (taskCreationOptions, TaskCreationOptions.PreferFairness)) {
356 scheduler.QueueTask (this);
358 /* Like the semantic of the ABP paper describe it, we add ourselves to the bottom
359 * of our Parent Task's ThreadWorker deque. It's ok to do that since we are in
360 * the correct Thread during the creation
362 childWorkAdder (this);
368 /* Allow scheduler to break fairness of deque ordering without
369 * breaking its semantic (the task can be executed twice but the
370 * second time it will return immediately
372 if (!executing.TryRelaxedSet ())
375 // Disable CancellationToken direct cancellation
376 if (cancellationRegistration != null) {
377 cancellationRegistration.Value.Dispose ();
378 cancellationRegistration = null;
381 // If Task are ran inline on the same thread we might trash these values
382 var saveCurrent = current;
383 var saveScheduler = TaskScheduler.Current;
386 TaskScheduler.Current = scheduler;
388 if (!token.IsCancellationRequested) {
390 status = TaskStatus.Running;
394 } catch (OperationCanceledException oce) {
395 if (token != CancellationToken.None && oce.CancellationToken == token)
398 HandleGenericException (oce);
399 } catch (Exception e) {
400 HandleGenericException (e);
406 if (saveCurrent != null)
407 current = saveCurrent;
408 if (saveScheduler != null)
409 TaskScheduler.Current = saveScheduler;
413 internal bool TrySetCanceled ()
418 if (!executing.TryRelaxedSet ()) {
419 var sw = new SpinWait ();
430 internal bool TrySetException (AggregateException aggregate)
435 if (!executing.TryRelaxedSet ()) {
436 var sw = new SpinWait ();
443 HandleGenericException (aggregate);
447 internal void Execute ()
452 internal void AddChild ()
454 if (childTasks == null)
455 Interlocked.CompareExchange (ref childTasks, new CountdownEvent (1), null);
456 childTasks.AddCount ();
459 internal void ChildCompleted (AggregateException childEx)
461 if (childEx != null) {
462 if (ExceptionSlot.ChildExceptions == null)
463 Interlocked.CompareExchange (ref ExceptionSlot.ChildExceptions, new ConcurrentQueue<AggregateException> (), null);
464 ExceptionSlot.ChildExceptions.Enqueue (childEx);
467 if (childTasks.Signal () && status == TaskStatus.WaitingForChildrenToComplete) {
468 ProcessChildExceptions ();
469 Status = exSlot == null ? TaskStatus.RanToCompletion : TaskStatus.Faulted;
470 ProcessCompleteDelegates ();
471 if (CheckTaskOptions (taskCreationOptions, TaskCreationOptions.AttachedToParent) && parent != null)
472 parent.ChildCompleted (this.Exception);
478 if (IsContinuation) {
479 invoker.Invoke (contAncestor, state, this);
481 invoker.Invoke (this, state, this);
485 internal void Finish ()
487 // If there was children created and they all finished, we set the countdown
488 if (childTasks != null) {
489 if (childTasks.Signal ())
490 ProcessChildExceptions (true);
493 // Don't override Canceled or Faulted
494 if (status == TaskStatus.Running) {
495 if (childTasks == null || childTasks.IsSet)
496 Status = TaskStatus.RanToCompletion;
498 Status = TaskStatus.WaitingForChildrenToComplete;
501 // Completions are already processed when task is canceled or faulted
502 if (status == TaskStatus.RanToCompletion)
503 ProcessCompleteDelegates ();
505 // Reset the current thingies
508 if (TaskScheduler.Current == scheduler)
509 TaskScheduler.Current = null;
511 if (cancellationRegistration.HasValue)
512 cancellationRegistration.Value.Dispose ();
514 // Tell parent that we are finished
515 if (CheckTaskOptions (taskCreationOptions, TaskCreationOptions.AttachedToParent) && parent != null && status != TaskStatus.WaitingForChildrenToComplete) {
516 parent.ChildCompleted (this.Exception);
520 void ProcessCompleteDelegates ()
522 if (continuations.HasElements) {
523 IContinuation continuation;
524 while (continuations.TryGetNextCompletion (out continuation))
525 continuation.Execute ();
529 void ProcessChildExceptions (bool isParent = false)
531 if (exSlot == null || exSlot.ChildExceptions == null)
534 if (ExceptionSlot.Exception == null)
535 exSlot.Exception = new AggregateException ();
537 AggregateException childEx;
538 while (exSlot.ChildExceptions.TryDequeue (out childEx))
539 exSlot.Exception.AddChildException (childEx);
542 Status = TaskStatus.Faulted;
543 ProcessCompleteDelegates ();
548 #region Cancel and Wait related method
550 internal void CancelReal ()
552 Status = TaskStatus.Canceled;
553 ProcessCompleteDelegates ();
556 void HandleGenericException (Exception e)
558 HandleGenericException (new AggregateException (e));
561 void HandleGenericException (AggregateException e)
563 ExceptionSlot.Exception = e;
564 Thread.MemoryBarrier ();
565 Status = TaskStatus.Faulted;
566 ProcessCompleteDelegates ();
569 internal bool WaitOnChildren ()
571 if (Status == TaskStatus.WaitingForChildrenToComplete && childTasks != null) {
580 Wait (Timeout.Infinite, CancellationToken.None);
583 public void Wait (CancellationToken cancellationToken)
585 Wait (Timeout.Infinite, cancellationToken);
588 public bool Wait (TimeSpan timeout)
590 return Wait (CheckTimeout (timeout), CancellationToken.None);
593 public bool Wait (int millisecondsTimeout)
595 return Wait (millisecondsTimeout, CancellationToken.None);
598 public bool Wait (int millisecondsTimeout, CancellationToken cancellationToken)
600 if (millisecondsTimeout < -1)
601 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
606 // If the task is ready to be run and we were supposed to wait on it indefinitely without cancellation, just run it
607 if (Status == TaskStatus.WaitingToRun && millisecondsTimeout == Timeout.Infinite && scheduler != null && !cancellationToken.CanBeCanceled)
608 scheduler.RunInline (this, true);
611 var continuation = new ManualResetContinuation ();
613 ContinueWith (continuation);
614 result = continuation.Event.Wait (millisecondsTimeout, cancellationToken);
617 RemoveContinuation (continuation);
618 continuation.Dispose ();
624 throw new AggregateException (new TaskCanceledException (this));
626 var exception = Exception;
627 if (exception != null)
630 if (childTasks != null)
636 public static void WaitAll (params Task[] tasks)
638 WaitAll (tasks, Timeout.Infinite, CancellationToken.None);
641 public static void WaitAll (Task[] tasks, CancellationToken cancellationToken)
643 WaitAll (tasks, Timeout.Infinite, cancellationToken);
646 public static bool WaitAll (Task[] tasks, TimeSpan timeout)
648 return WaitAll (tasks, CheckTimeout (timeout), CancellationToken.None);
651 public static bool WaitAll (Task[] tasks, int millisecondsTimeout)
653 return WaitAll (tasks, millisecondsTimeout, CancellationToken.None);
656 public static bool WaitAll (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
659 throw new ArgumentNullException ("tasks");
662 foreach (var t in tasks) {
664 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
666 result &= t.Status == TaskStatus.RanToCompletion;
670 var continuation = new CountdownContinuation (tasks.Length);
672 foreach (var t in tasks)
673 t.ContinueWith (continuation);
675 result = continuation.Event.Wait (millisecondsTimeout, cancellationToken);
677 List<Exception> exceptions = null;
679 foreach (var t in tasks) {
681 if (t.Status == TaskStatus.RanToCompletion)
683 if (exceptions == null)
684 exceptions = new List<Exception> ();
685 if (t.Exception != null)
686 exceptions.AddRange (t.Exception.InnerExceptions);
688 exceptions.Add (new TaskCanceledException (t));
690 t.RemoveContinuation (continuation);
694 continuation.Dispose ();
696 if (exceptions != null)
697 throw new AggregateException (exceptions);
704 public static int WaitAny (params Task[] tasks)
706 return WaitAny (tasks, Timeout.Infinite, CancellationToken.None);
709 public static int WaitAny (Task[] tasks, TimeSpan timeout)
711 return WaitAny (tasks, CheckTimeout (timeout));
714 public static int WaitAny (Task[] tasks, int millisecondsTimeout)
716 return WaitAny (tasks, millisecondsTimeout, CancellationToken.None);
719 public static int WaitAny (Task[] tasks, CancellationToken cancellationToken)
721 return WaitAny (tasks, Timeout.Infinite, cancellationToken);
724 public static int WaitAny (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
727 throw new ArgumentNullException ("tasks");
728 if (millisecondsTimeout < -1)
729 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
730 CheckForNullTasks (tasks);
732 if (tasks.Length > 0) {
733 var continuation = new ManualResetContinuation ();
736 for (int i = 0; i < tasks.Length; i++) {
740 t.ContinueWith (continuation);
743 if (!(result = continuation.Event.Wait (millisecondsTimeout, cancellationToken)))
747 foreach (var t in tasks)
748 t.RemoveContinuation (continuation);
749 continuation.Dispose ();
753 int firstFinished = -1;
754 for (int i = 0; i < tasks.Length; i++) {
762 return firstFinished;
765 static int CheckTimeout (TimeSpan timeout)
768 return checked ((int)timeout.TotalMilliseconds);
769 } catch (System.OverflowException) {
770 throw new ArgumentOutOfRangeException ("timeout");
774 static void CheckForNullTasks (Task[] tasks)
776 foreach (var t in tasks)
778 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
783 public void Dispose ()
788 protected virtual void Dispose (bool disposing)
791 throw new InvalidOperationException ("A task may only be disposed if it is in a completion state");
793 // Set action to null so that the GC can collect the delegate and thus
794 // any big object references that the user might have captured in a anonymous method
798 if (cancellationRegistration != null)
799 cancellationRegistration.Value.Dispose ();
806 public ConfiguredTaskAwaitable ConfigureAwait (bool continueOnCapturedContext)
808 return new ConfiguredTaskAwaitable (this, continueOnCapturedContext);
811 public Task ContinueWith (Action<Task, object> continuationAction, object state)
813 return ContinueWith (continuationAction, state, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current);
816 public Task ContinueWith (Action<Task, object> continuationAction, object state, CancellationToken cancellationToken)
818 return ContinueWith (continuationAction, state, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
821 public Task ContinueWith (Action<Task, object> continuationAction, object state, TaskContinuationOptions continuationOptions)
823 return ContinueWith (continuationAction, state, CancellationToken.None, continuationOptions, TaskScheduler.Current);
826 public Task ContinueWith (Action<Task, object> continuationAction, object state, TaskScheduler scheduler)
828 return ContinueWith (continuationAction, state, CancellationToken.None, TaskContinuationOptions.None, scheduler);
831 public Task ContinueWith (Action<Task, object> continuationAction, object state, CancellationToken cancellationToken,
832 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
834 if (continuationAction == null)
835 throw new ArgumentNullException ("continuationAction");
836 if (scheduler == null)
837 throw new ArgumentNullException ("scheduler");
839 Task continuation = new Task (TaskActionInvoker.Create (continuationAction),
840 state, cancellationToken,
841 GetCreationOptions (continuationOptions),
844 ContinueWithCore (continuation, continuationOptions, scheduler);
849 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state)
851 return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current);
854 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, TaskContinuationOptions continuationOptions)
856 return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, continuationOptions, TaskScheduler.Current);
859 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, CancellationToken cancellationToken)
861 return ContinueWith<TResult> (continuationFunction, state, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
864 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, TaskScheduler scheduler)
866 return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, TaskContinuationOptions.None, scheduler);
869 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, CancellationToken cancellationToken,
870 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
872 if (continuationFunction == null)
873 throw new ArgumentNullException ("continuationFunction");
874 if (scheduler == null)
875 throw new ArgumentNullException ("scheduler");
877 var t = new Task<TResult> (TaskActionInvoker.Create (continuationFunction),
880 GetCreationOptions (continuationOptions),
884 ContinueWithCore (t, continuationOptions, scheduler);
889 public static Task Delay (int millisecondsDelay)
891 return Delay (millisecondsDelay, CancellationToken.None);
894 public static Task Delay (TimeSpan delay)
896 return Delay (CheckTimeout (delay), CancellationToken.None);
899 public static Task Delay (TimeSpan delay, CancellationToken cancellationToken)
901 return Delay (CheckTimeout (delay), cancellationToken);
904 public static Task Delay (int millisecondsDelay, CancellationToken cancellationToken)
906 if (millisecondsDelay < -1)
907 throw new ArgumentOutOfRangeException ("millisecondsDelay");
909 var task = new Task (TaskActionInvoker.Delay, millisecondsDelay, cancellationToken, TaskCreationOptions.None, null, TaskConstants.Finished);
910 task.SetupScheduler (TaskScheduler.Current);
912 if (millisecondsDelay != Timeout.Infinite)
913 task.scheduler.QueueTask (task);
918 public static Task<TResult> FromResult<TResult> (TResult result)
920 var tcs = new TaskCompletionSource<TResult> ();
921 tcs.SetResult (result);
925 public TaskAwaiter GetAwaiter ()
927 return new TaskAwaiter (this);
930 public static Task Run (Action action)
932 return Run (action, CancellationToken.None);
935 public static Task Run (Action action, CancellationToken cancellationToken)
937 if (cancellationToken.IsCancellationRequested)
938 return TaskConstants.Canceled;
940 var t = new Task (action, cancellationToken, TaskCreationOptions.DenyChildAttach);
945 public static Task Run (Func<Task> function)
947 return Run (function, CancellationToken.None);
950 public static Task Run (Func<Task> function, CancellationToken cancellationToken)
952 if (cancellationToken.IsCancellationRequested)
953 return TaskConstants.Canceled;
955 var t = new Task<Task> (function, cancellationToken);
960 public static Task<TResult> Run<TResult> (Func<TResult> function)
962 return Run (function, CancellationToken.None);
965 public static Task<TResult> Run<TResult> (Func<TResult> function, CancellationToken cancellationToken)
967 if (cancellationToken.IsCancellationRequested)
968 return TaskConstants<TResult>.Canceled;
970 var t = new Task<TResult> (function, cancellationToken, TaskCreationOptions.DenyChildAttach);
975 public static Task<TResult> Run<TResult> (Func<Task<TResult>> function)
977 return Run (function, CancellationToken.None);
980 public static Task<TResult> Run<TResult> (Func<Task<TResult>> function, CancellationToken cancellationToken)
982 if (cancellationToken.IsCancellationRequested)
983 return TaskConstants<TResult>.Canceled;
985 var t = Task<Task<TResult>>.Factory.StartNew (function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
986 return GetTaskResult (t);
989 async static Task<TResult> GetTaskResult<TResult> (Task<Task<TResult>> task)
991 var r = await task.ConfigureAwait (false);
995 public static Task WhenAll (params Task[] tasks)
998 throw new ArgumentNullException ("tasks");
1000 return WhenAllCore (tasks);
1003 public static Task WhenAll (IEnumerable<Task> tasks)
1006 throw new ArgumentNullException ("tasks");
1008 // Call ToList on input enumeration or we end up
1009 // enumerating it more than once
1010 return WhenAllCore (new List<Task> (tasks));
1013 public static Task<TResult[]> WhenAll<TResult> (params Task<TResult>[] tasks)
1016 throw new ArgumentNullException ("tasks");
1018 return WhenAllCore<TResult> (tasks);
1021 public static Task<TResult[]> WhenAll<TResult> (IEnumerable<Task<TResult>> tasks)
1024 throw new ArgumentNullException ("tasks");
1026 // Call ToList on input enumeration or we end up
1027 // enumerating it more than once
1028 return WhenAllCore<TResult> (new List<Task<TResult>> (tasks));
1031 internal static Task<TResult[]> WhenAllCore<TResult> (IList<Task<TResult>> tasks)
1033 foreach (var t in tasks) {
1035 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1038 var task = new Task<TResult[]> (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1039 task.SetupScheduler (TaskScheduler.Current);
1041 var continuation = new WhenAllContinuation<TResult> (task, tasks);
1042 foreach (var t in tasks)
1043 t.ContinueWith (continuation);
1048 public static Task<Task> WhenAny (params Task[] tasks)
1051 throw new ArgumentNullException ("tasks");
1053 return WhenAnyCore (tasks);
1056 public static Task<Task> WhenAny (IEnumerable<Task> tasks)
1059 throw new ArgumentNullException ("tasks");
1061 return WhenAnyCore (new List<Task> (tasks));
1064 public static Task<Task<TResult>> WhenAny<TResult> (params Task<TResult>[] tasks)
1067 throw new ArgumentNullException ("tasks");
1069 return WhenAnyCore<TResult> (tasks);
1072 public static Task<Task<TResult>> WhenAny<TResult> (IEnumerable<Task<TResult>> tasks)
1075 throw new ArgumentNullException ("tasks");
1077 return WhenAnyCore<TResult> (new List<Task<TResult>> (tasks));
1080 static Task<Task<TResult>> WhenAnyCore<TResult> (IList<Task<TResult>> tasks)
1082 if (tasks.Count == 0)
1083 throw new ArgumentException ("The tasks argument contains no tasks", "tasks");
1085 int completed_index = -1;
1086 for (int i = 0; i < tasks.Count; ++i) {
1089 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1091 if (t.IsCompleted && completed_index < 0)
1092 completed_index = i;
1095 var task = new Task<Task<TResult>> (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1097 if (completed_index > 0) {
1098 task.TrySetResult (tasks[completed_index]);
1102 task.SetupScheduler (TaskScheduler.Current);
1104 var continuation = new WhenAnyContinuation<Task<TResult>> (task, tasks);
1105 foreach (var t in tasks)
1106 t.ContinueWith (continuation);
1111 public static YieldAwaitable Yield ()
1113 return new YieldAwaitable ();
1117 internal static Task WhenAllCore (IList<Task> tasks)
1119 bool all_completed = true;
1120 foreach (var t in tasks) {
1122 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1124 all_completed &= t.Status == TaskStatus.RanToCompletion;
1128 return TaskConstants.Finished;
1130 var task = new Task (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1131 task.SetupScheduler (TaskScheduler.Current);
1133 var continuation = new WhenAllContinuation (task, tasks);
1134 foreach (var t in tasks)
1135 t.ContinueWith (continuation);
1140 internal static Task<Task> WhenAnyCore (IList<Task> tasks)
1142 if (tasks.Count == 0)
1143 throw new ArgumentException ("The tasks argument contains no tasks", "tasks");
1145 int completed_index = -1;
1146 for (int i = 0; i < tasks.Count; ++i) {
1149 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1151 if (t.IsCompleted && completed_index < 0)
1152 completed_index = i;
1155 var task = new Task<Task> (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1157 if (completed_index > 0) {
1158 task.TrySetResult (tasks[completed_index]);
1162 task.SetupScheduler (TaskScheduler.Current);
1164 var continuation = new WhenAnyContinuation<Task> (task, tasks);
1165 foreach (var t in tasks)
1166 t.ContinueWith (continuation);
1172 internal CancellationToken CancellationToken {
1178 public static TaskFactory Factory {
1180 return defaultFactory;
1184 public static int? CurrentId {
1187 return t == null ? (int?)null : t.Id;
1191 public AggregateException Exception {
1195 exSlot.Observed = true;
1196 return exSlot.Exception;
1200 public bool IsCanceled {
1202 return status == TaskStatus.Canceled;
1206 public bool IsCompleted {
1208 return status >= TaskStatus.RanToCompletion;
1212 public bool IsFaulted {
1214 return status == TaskStatus.Faulted;
1218 public TaskCreationOptions CreationOptions {
1220 return taskCreationOptions & MaxTaskCreationOptions;
1224 public TaskStatus Status {
1230 Thread.MemoryBarrier ();
1234 TaskExceptionSlot ExceptionSlot {
1238 Interlocked.CompareExchange (ref exSlot, new TaskExceptionSlot (this), null);
1243 public object AsyncState {
1249 bool IAsyncResult.CompletedSynchronously {
1255 WaitHandle IAsyncResult.AsyncWaitHandle {
1267 bool IsContinuation {
1269 return contAncestor != null;
1273 internal Task ContinuationAncestor {
1275 return contAncestor;
1279 internal string DisplayActionMethod {
1281 Delegate d = invoker.Action;
1282 return d == null ? "<none>" : d.Method.ToString ();