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-2013 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 // parent is the outer task in which this task is created
52 // A reference to a Task on which this continuation is attached to
56 static readonly TaskFactory defaultFactory = new TaskFactory ();
58 CountdownEvent childTasks;
61 TaskCreationOptions creationOptions;
63 internal TaskScheduler scheduler;
65 TaskExceptionSlot exSlot;
66 ManualResetEvent wait_handle;
70 TaskActionInvoker invoker;
72 internal AtomicBooleanValue executing;
74 TaskCompletionQueue<IContinuation> continuations;
76 CancellationToken token;
77 CancellationTokenRegistration? cancellationRegistration;
79 internal const TaskCreationOptions WorkerTaskNotSupportedOptions = TaskCreationOptions.LongRunning | TaskCreationOptions.PreferFairness;
81 const TaskCreationOptions MaxTaskCreationOptions =
83 TaskCreationOptions.DenyChildAttach | TaskCreationOptions.HideScheduler |
85 TaskCreationOptions.PreferFairness | TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent;
87 public Task (Action action)
88 : this (action, TaskCreationOptions.None)
93 public Task (Action action, TaskCreationOptions creationOptions)
94 : this (action, CancellationToken.None, creationOptions)
99 public Task (Action action, CancellationToken cancellationToken)
100 : this (action, cancellationToken, TaskCreationOptions.None)
105 public Task (Action action, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
106 : this (TaskActionInvoker.Create (action), null, cancellationToken, creationOptions, current)
109 throw new ArgumentNullException ("action");
110 if (creationOptions > MaxTaskCreationOptions || creationOptions < TaskCreationOptions.None)
111 throw new ArgumentOutOfRangeException ("creationOptions");
114 public Task (Action<object> action, object state)
115 : this (action, state, TaskCreationOptions.None)
119 public Task (Action<object> action, object state, TaskCreationOptions creationOptions)
120 : this (action, state, CancellationToken.None, creationOptions)
124 public Task (Action<object> action, object state, CancellationToken cancellationToken)
125 : this (action, state, cancellationToken, TaskCreationOptions.None)
129 public Task (Action<object> action, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
130 : this (TaskActionInvoker.Create (action), state, cancellationToken, creationOptions, current)
133 throw new ArgumentNullException ("action");
134 if (creationOptions > MaxTaskCreationOptions || creationOptions < TaskCreationOptions.None)
135 throw new ArgumentOutOfRangeException ("creationOptions");
138 internal Task (TaskActionInvoker invoker, object state, CancellationToken cancellationToken,
139 TaskCreationOptions creationOptions, Task parent = null, Task contAncestor = null, bool ignoreCancellation = false)
141 this.invoker = invoker;
142 this.creationOptions = creationOptions;
144 this.taskId = Interlocked.Increment (ref id);
145 this.token = cancellationToken;
146 this.parent = parent = parent == null ? current : parent;
147 this.contAncestor = contAncestor;
148 this.status = cancellationToken.IsCancellationRequested && !ignoreCancellation ? TaskStatus.Canceled : TaskStatus.Created;
150 // Process creationOptions
152 if (parent != null && HasFlag (creationOptions, TaskCreationOptions.AttachedToParent)
153 && !HasFlag (parent.CreationOptions, TaskCreationOptions.DenyChildAttach))
155 if (parent != null && HasFlag (creationOptions, TaskCreationOptions.AttachedToParent))
159 if (token.CanBeCanceled && !ignoreCancellation)
160 cancellationRegistration = token.Register (l => ((Task) l).CancelReal (), this);
163 static bool HasFlag (TaskCreationOptions opt, TaskCreationOptions member)
165 return (opt & member) == member;
171 Start (TaskScheduler.Current);
174 public void Start (TaskScheduler scheduler)
176 if (scheduler == null)
177 throw new ArgumentNullException ("scheduler");
179 if (status >= TaskStatus.WaitingToRun)
180 throw new InvalidOperationException ("The Task is not in a valid state to be started.");
183 throw new InvalidOperationException ("Start may not be called on a continuation task");
186 throw new InvalidOperationException ("Start may not be called on a promise-style task");
188 SetupScheduler (scheduler);
192 internal void SetupScheduler (TaskScheduler scheduler)
194 this.scheduler = scheduler;
195 Status = TaskStatus.WaitingForActivation;
198 public void RunSynchronously ()
200 RunSynchronously (TaskScheduler.Current);
203 public void RunSynchronously (TaskScheduler scheduler)
205 if (scheduler == null)
206 throw new ArgumentNullException ("scheduler");
208 if (Status > TaskStatus.WaitingForActivation)
209 throw new InvalidOperationException ("The task is not in a valid state to be started");
212 throw new InvalidOperationException ("RunSynchronously may not be called on a continuation task");
215 throw new InvalidOperationException ("RunSynchronously may not be called on a promise-style task");
217 RunSynchronouslyCore (scheduler);
220 internal void RunSynchronouslyCore (TaskScheduler scheduler)
222 SetupScheduler (scheduler);
223 Status = TaskStatus.WaitingToRun;
226 if (scheduler.RunInline (this, false))
228 } catch (Exception inner) {
229 var ex = new TaskSchedulerException (inner);
230 TrySetException (new AggregateException (ex), false, true);
235 WaitCore (Timeout.Infinite, CancellationToken.None, false);
240 public Task ContinueWith (Action<Task> continuationAction)
242 return ContinueWith (continuationAction, TaskContinuationOptions.None);
245 public Task ContinueWith (Action<Task> continuationAction, TaskContinuationOptions continuationOptions)
247 return ContinueWith (continuationAction, CancellationToken.None, continuationOptions, TaskScheduler.Current);
250 public Task ContinueWith (Action<Task> continuationAction, CancellationToken cancellationToken)
252 return ContinueWith (continuationAction, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
255 public Task ContinueWith (Action<Task> continuationAction, TaskScheduler scheduler)
257 return ContinueWith (continuationAction, CancellationToken.None, TaskContinuationOptions.None, scheduler);
260 public Task ContinueWith (Action<Task> continuationAction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
262 if (continuationAction == null)
263 throw new ArgumentNullException ("continuationAction");
264 if (scheduler == null)
265 throw new ArgumentNullException ("scheduler");
267 return ContinueWith (TaskActionInvoker.Create (continuationAction), cancellationToken, continuationOptions, scheduler);
270 internal Task ContinueWith (TaskActionInvoker invoker, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
272 var lazyCancellation = false;
274 lazyCancellation = (continuationOptions & TaskContinuationOptions.LazyCancellation) > 0;
276 var continuation = new Task (invoker, null, cancellationToken, GetCreationOptions (continuationOptions), null, this, lazyCancellation);
277 ContinueWithCore (continuation, continuationOptions, scheduler);
282 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction)
284 return ContinueWith<TResult> (continuationFunction, TaskContinuationOptions.None);
287 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, TaskContinuationOptions continuationOptions)
289 return ContinueWith<TResult> (continuationFunction, CancellationToken.None, continuationOptions, TaskScheduler.Current);
292 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, CancellationToken cancellationToken)
294 return ContinueWith<TResult> (continuationFunction, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
297 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, TaskScheduler scheduler)
299 return ContinueWith<TResult> (continuationFunction, CancellationToken.None, TaskContinuationOptions.None, scheduler);
302 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, CancellationToken cancellationToken,
303 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
305 if (continuationFunction == null)
306 throw new ArgumentNullException ("continuationFunction");
307 if (scheduler == null)
308 throw new ArgumentNullException ("scheduler");
310 return ContinueWith<TResult> (TaskActionInvoker.Create (continuationFunction), cancellationToken, continuationOptions, scheduler);
313 internal Task<TResult> ContinueWith<TResult> (TaskActionInvoker invoker, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
315 var lazyCancellation = false;
317 lazyCancellation = (continuationOptions & TaskContinuationOptions.LazyCancellation) > 0;
319 var continuation = new Task<TResult> (invoker, null, cancellationToken, GetCreationOptions (continuationOptions), parent, this, lazyCancellation);
320 ContinueWithCore (continuation, continuationOptions, scheduler);
325 internal void ContinueWithCore (Task continuation, TaskContinuationOptions options, TaskScheduler scheduler)
327 const TaskContinuationOptions wrongRan = TaskContinuationOptions.NotOnRanToCompletion | TaskContinuationOptions.OnlyOnRanToCompletion;
328 const TaskContinuationOptions wrongCanceled = TaskContinuationOptions.NotOnCanceled | TaskContinuationOptions.OnlyOnCanceled;
329 const TaskContinuationOptions wrongFaulted = TaskContinuationOptions.NotOnFaulted | TaskContinuationOptions.OnlyOnFaulted;
331 if (((options & wrongRan) == wrongRan) || ((options & wrongCanceled) == wrongCanceled) || ((options & wrongFaulted) == wrongFaulted))
332 throw new ArgumentException ("continuationOptions", "Some options are mutually exclusive");
334 // Already set the scheduler so that user can call Wait and that sort of stuff
335 continuation.scheduler = scheduler;
336 continuation.Status = TaskStatus.WaitingForActivation;
338 ContinueWith (new TaskContinuation (continuation, options));
341 internal bool ContinueWith (IContinuation continuation, bool canExecuteInline = true)
344 if (!canExecuteInline)
347 continuation.Execute ();
351 continuations.Add (continuation);
353 // Retry in case completion was achieved but event adding was too late
355 continuations.Remove (continuation);
356 if (!canExecuteInline)
359 continuation.Execute ();
365 internal void RemoveContinuation (IContinuation continuation)
367 continuations.Remove (continuation);
370 static internal TaskCreationOptions GetCreationOptions (TaskContinuationOptions kind)
372 TaskCreationOptions options = TaskCreationOptions.None;
373 if ((kind & TaskContinuationOptions.AttachedToParent) > 0)
374 options |= TaskCreationOptions.AttachedToParent;
375 if ((kind & TaskContinuationOptions.PreferFairness) > 0)
376 options |= TaskCreationOptions.PreferFairness;
377 if ((kind & TaskContinuationOptions.LongRunning) > 0)
378 options |= TaskCreationOptions.LongRunning;
384 #region Internal and protected thingies
385 internal void Schedule ()
387 Status = TaskStatus.WaitingToRun;
388 scheduler.QueueTask (this);
393 /* Allow scheduler to break fairness of deque ordering without
394 * breaking its semantic (the task can be executed twice but the
395 * second time it will return immediately
397 if (!executing.TryRelaxedSet ())
400 // Disable CancellationToken direct cancellation
401 if (cancellationRegistration != null) {
402 cancellationRegistration.Value.Dispose ();
403 cancellationRegistration = null;
406 // If Task are ran inline on the same thread we might trash these values
407 var saveCurrent = current;
408 var saveScheduler = TaskScheduler.Current;
412 TaskScheduler.Current = HasFlag (creationOptions, TaskCreationOptions.HideScheduler) ? TaskScheduler.Default : scheduler;
414 TaskScheduler.Current = scheduler;
417 if (!token.IsCancellationRequested) {
419 status = TaskStatus.Running;
423 } catch (OperationCanceledException oce) {
424 if (token != CancellationToken.None && oce.CancellationToken == token)
427 HandleGenericException (oce);
428 } catch (Exception e) {
429 HandleGenericException (e);
435 if (saveCurrent != null)
436 current = saveCurrent;
437 if (saveScheduler != null)
438 TaskScheduler.Current = saveScheduler;
442 internal bool TrySetCanceled ()
447 if (!executing.TryRelaxedSet ()) {
448 var sw = new SpinWait ();
459 internal bool TrySetException (AggregateException aggregate, bool cancellation, bool observed)
464 if (!executing.TryRelaxedSet ()) {
465 var sw = new SpinWait ();
473 ExceptionSlot.Exception = aggregate;
474 Thread.MemoryBarrier ();
478 HandleGenericException (aggregate);
482 exSlot.Observed = true;
487 internal bool TrySetExceptionObserved ()
489 if (exSlot != null) {
490 exSlot.Observed = true;
496 internal void Execute ()
501 internal void AddChild ()
503 if (childTasks == null)
504 Interlocked.CompareExchange (ref childTasks, new CountdownEvent (1), null);
505 childTasks.AddCount ();
508 internal void ChildCompleted (AggregateException childEx)
510 if (childEx != null) {
511 if (ExceptionSlot.ChildExceptions == null)
512 Interlocked.CompareExchange (ref ExceptionSlot.ChildExceptions, new ConcurrentQueue<AggregateException> (), null);
513 ExceptionSlot.ChildExceptions.Enqueue (childEx);
516 if (childTasks.Signal () && status == TaskStatus.WaitingForChildrenToComplete) {
517 ProcessChildExceptions ();
518 Status = exSlot == null ? TaskStatus.RanToCompletion : TaskStatus.Faulted;
519 ProcessCompleteDelegates ();
520 if (parent != null &&
522 !HasFlag (parent.CreationOptions, TaskCreationOptions.DenyChildAttach) &&
524 HasFlag (creationOptions, TaskCreationOptions.AttachedToParent))
525 parent.ChildCompleted (this.Exception);
531 if (IsContinuation) {
532 var ancestor = contAncestor;
534 invoker.Invoke (ancestor, state, this);
536 invoker.Invoke (this, state, this);
540 internal void Finish ()
542 // If there was children created and they all finished, we set the countdown
543 if (childTasks != null) {
544 if (childTasks.Signal ())
545 ProcessChildExceptions (true);
548 // Don't override Canceled or Faulted
549 if (status == TaskStatus.Running) {
550 if (childTasks == null || childTasks.IsSet)
551 Status = TaskStatus.RanToCompletion;
553 Status = TaskStatus.WaitingForChildrenToComplete;
556 if (wait_handle != null)
559 // Tell parent that we are finished
560 if (parent != null && HasFlag (creationOptions, TaskCreationOptions.AttachedToParent) &&
562 !HasFlag (parent.CreationOptions, TaskCreationOptions.DenyChildAttach) &&
564 status != TaskStatus.WaitingForChildrenToComplete) {
565 parent.ChildCompleted (this.Exception);
568 // Completions are already processed when task is canceled or faulted
569 if (status == TaskStatus.RanToCompletion)
570 ProcessCompleteDelegates ();
572 // Reset the current thingies
575 if (TaskScheduler.Current == scheduler)
576 TaskScheduler.Current = null;
578 if (cancellationRegistration.HasValue)
579 cancellationRegistration.Value.Dispose ();
582 void ProcessCompleteDelegates ()
584 if (continuations.HasElements) {
585 IContinuation continuation;
586 while (continuations.TryGetNextCompletion (out continuation))
587 continuation.Execute ();
591 void ProcessChildExceptions (bool isParent = false)
593 if (exSlot == null || exSlot.ChildExceptions == null)
596 if (ExceptionSlot.Exception == null)
597 exSlot.Exception = new AggregateException ();
599 AggregateException childEx;
600 while (exSlot.ChildExceptions.TryDequeue (out childEx))
601 exSlot.Exception.AddChildException (childEx);
604 Status = TaskStatus.Faulted;
605 ProcessCompleteDelegates ();
610 #region Cancel and Wait related method
612 internal void CancelReal ()
614 Status = TaskStatus.Canceled;
616 if (wait_handle != null)
619 ProcessCompleteDelegates ();
622 void HandleGenericException (Exception e)
624 HandleGenericException (new AggregateException (e));
627 void HandleGenericException (AggregateException e)
629 ExceptionSlot.Exception = e;
630 Thread.MemoryBarrier ();
631 Status = TaskStatus.Faulted;
633 if (wait_handle != null)
636 ProcessCompleteDelegates ();
639 internal bool WaitOnChildren ()
641 if (Status == TaskStatus.WaitingForChildrenToComplete && childTasks != null) {
650 Wait (Timeout.Infinite, CancellationToken.None);
653 public void Wait (CancellationToken cancellationToken)
655 Wait (Timeout.Infinite, cancellationToken);
658 public bool Wait (TimeSpan timeout)
660 return Wait (CheckTimeout (timeout), CancellationToken.None);
663 public bool Wait (int millisecondsTimeout)
665 return Wait (millisecondsTimeout, CancellationToken.None);
668 public bool Wait (int millisecondsTimeout, CancellationToken cancellationToken)
670 if (millisecondsTimeout < -1)
671 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
673 bool result = WaitCore (millisecondsTimeout, cancellationToken, true);
676 throw new AggregateException (new TaskCanceledException (this));
678 var exception = Exception;
679 if (exception != null)
685 internal bool WaitCore (int millisecondsTimeout, CancellationToken cancellationToken, bool runInline)
690 // If the task is ready to be run and we were supposed to wait on it indefinitely without cancellation, just run it
691 if (runInline && Status == TaskStatus.WaitingToRun && millisecondsTimeout == Timeout.Infinite && scheduler != null && !cancellationToken.CanBeCanceled)
692 scheduler.RunInline (this, true);
697 var continuation = new ManualResetContinuation ();
699 ContinueWith (continuation);
700 result = continuation.Event.Wait (millisecondsTimeout, cancellationToken);
703 RemoveContinuation (continuation);
704 continuation.Dispose ();
711 public static void WaitAll (params Task[] tasks)
713 WaitAll (tasks, Timeout.Infinite, CancellationToken.None);
716 public static void WaitAll (Task[] tasks, CancellationToken cancellationToken)
718 WaitAll (tasks, Timeout.Infinite, cancellationToken);
721 public static bool WaitAll (Task[] tasks, TimeSpan timeout)
723 return WaitAll (tasks, CheckTimeout (timeout), CancellationToken.None);
726 public static bool WaitAll (Task[] tasks, int millisecondsTimeout)
728 return WaitAll (tasks, millisecondsTimeout, CancellationToken.None);
731 public static bool WaitAll (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
734 throw new ArgumentNullException ("tasks");
737 foreach (var t in tasks) {
739 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
741 result &= t.Status == TaskStatus.RanToCompletion;
745 var continuation = new CountdownContinuation (tasks.Length);
747 foreach (var t in tasks)
748 t.ContinueWith (continuation);
750 result = continuation.Event.Wait (millisecondsTimeout, cancellationToken);
752 List<Exception> exceptions = null;
754 foreach (var t in tasks) {
756 if (t.Status == TaskStatus.RanToCompletion)
758 if (exceptions == null)
759 exceptions = new List<Exception> ();
760 if (t.Exception != null)
761 exceptions.AddRange (t.Exception.InnerExceptions);
763 exceptions.Add (new TaskCanceledException (t));
765 t.RemoveContinuation (continuation);
769 continuation.Dispose ();
771 if (exceptions != null)
772 throw new AggregateException (exceptions);
779 public static int WaitAny (params Task[] tasks)
781 return WaitAny (tasks, Timeout.Infinite, CancellationToken.None);
784 public static int WaitAny (Task[] tasks, TimeSpan timeout)
786 return WaitAny (tasks, CheckTimeout (timeout));
789 public static int WaitAny (Task[] tasks, int millisecondsTimeout)
791 return WaitAny (tasks, millisecondsTimeout, CancellationToken.None);
794 public static int WaitAny (Task[] tasks, CancellationToken cancellationToken)
796 return WaitAny (tasks, Timeout.Infinite, cancellationToken);
799 public static int WaitAny (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
802 throw new ArgumentNullException ("tasks");
803 if (millisecondsTimeout < -1)
804 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
805 CheckForNullTasks (tasks);
807 if (tasks.Length > 0) {
808 var continuation = new ManualResetContinuation ();
811 for (int i = 0; i < tasks.Length; i++) {
815 t.ContinueWith (continuation);
818 if (!(result = continuation.Event.Wait (millisecondsTimeout, cancellationToken)))
822 foreach (var t in tasks)
823 t.RemoveContinuation (continuation);
824 continuation.Dispose ();
828 int firstFinished = -1;
829 for (int i = 0; i < tasks.Length; i++) {
837 return firstFinished;
840 static int CheckTimeout (TimeSpan timeout)
843 return checked ((int)timeout.TotalMilliseconds);
844 } catch (System.OverflowException) {
845 throw new ArgumentOutOfRangeException ("timeout");
849 static void CheckForNullTasks (Task[] tasks)
851 foreach (var t in tasks)
853 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
858 public void Dispose ()
863 protected virtual void Dispose (bool disposing)
866 throw new InvalidOperationException ("A task may only be disposed if it is in a completion state");
868 // Set action to null so that the GC can collect the delegate and thus
869 // any big object references that the user might have captured in a anonymous method
873 if (cancellationRegistration != null)
874 cancellationRegistration.Value.Dispose ();
875 if (wait_handle != null)
876 wait_handle.Dispose ();
886 Task ContinueWith (Action<Task, object> continuationAction, object state, CancellationToken cancellationToken,
887 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
889 if (continuationAction == null)
890 throw new ArgumentNullException ("continuationAction");
891 if (scheduler == null)
892 throw new ArgumentNullException ("scheduler");
894 Task continuation = new Task (TaskActionInvoker.Create (continuationAction),
895 state, cancellationToken,
896 GetCreationOptions (continuationOptions),
899 ContinueWithCore (continuation, continuationOptions, scheduler);
906 public ConfiguredTaskAwaitable ConfigureAwait (bool continueOnCapturedContext)
908 return new ConfiguredTaskAwaitable (this, continueOnCapturedContext);
911 public Task ContinueWith (Action<Task, object> continuationAction, object state)
913 return ContinueWith (continuationAction, state, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current);
916 public Task ContinueWith (Action<Task, object> continuationAction, object state, CancellationToken cancellationToken)
918 return ContinueWith (continuationAction, state, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
921 public Task ContinueWith (Action<Task, object> continuationAction, object state, TaskContinuationOptions continuationOptions)
923 return ContinueWith (continuationAction, state, CancellationToken.None, continuationOptions, TaskScheduler.Current);
926 public Task ContinueWith (Action<Task, object> continuationAction, object state, TaskScheduler scheduler)
928 return ContinueWith (continuationAction, state, CancellationToken.None, TaskContinuationOptions.None, scheduler);
931 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state)
933 return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current);
936 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, TaskContinuationOptions continuationOptions)
938 return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, continuationOptions, TaskScheduler.Current);
941 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, CancellationToken cancellationToken)
943 return ContinueWith<TResult> (continuationFunction, state, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
946 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, TaskScheduler scheduler)
948 return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, TaskContinuationOptions.None, scheduler);
951 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, CancellationToken cancellationToken,
952 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
954 if (continuationFunction == null)
955 throw new ArgumentNullException ("continuationFunction");
956 if (scheduler == null)
957 throw new ArgumentNullException ("scheduler");
959 var t = new Task<TResult> (TaskActionInvoker.Create (continuationFunction),
962 GetCreationOptions (continuationOptions),
966 ContinueWithCore (t, continuationOptions, scheduler);
971 public static Task Delay (int millisecondsDelay)
973 return Delay (millisecondsDelay, CancellationToken.None);
976 public static Task Delay (TimeSpan delay)
978 return Delay (CheckTimeout (delay), CancellationToken.None);
981 public static Task Delay (TimeSpan delay, CancellationToken cancellationToken)
983 return Delay (CheckTimeout (delay), cancellationToken);
986 public static Task Delay (int millisecondsDelay, CancellationToken cancellationToken)
988 if (millisecondsDelay < -1)
989 throw new ArgumentOutOfRangeException ("millisecondsDelay");
991 if (cancellationToken.IsCancellationRequested)
992 return TaskConstants.Canceled;
994 var task = new Task (TaskActionInvoker.Empty, null, cancellationToken, TaskCreationOptions.None, null, null);
995 task.SetupScheduler (TaskScheduler.Default);
997 if (millisecondsDelay != Timeout.Infinite) {
998 var timer = new Timer (delegate (object state) {
999 var t = (Task) state;
1000 if (t.Status == TaskStatus.WaitingForActivation) {
1001 t.Status = TaskStatus.Running;
1004 }, task, millisecondsDelay, -1);
1006 task.ContinueWith (new DisposeContinuation (timer));
1012 public static Task<TResult> FromResult<TResult> (TResult result)
1014 var tcs = new TaskCompletionSource<TResult> ();
1015 tcs.SetResult (result);
1019 public TaskAwaiter GetAwaiter ()
1021 return new TaskAwaiter (this);
1024 public static Task Run (Action action)
1026 return Run (action, CancellationToken.None);
1029 public static Task Run (Action action, CancellationToken cancellationToken)
1031 if (cancellationToken.IsCancellationRequested)
1032 return TaskConstants.Canceled;
1034 return Task.Factory.StartNew (action, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
1037 public static Task Run (Func<Task> function)
1039 return Run (function, CancellationToken.None);
1042 public static Task Run (Func<Task> function, CancellationToken cancellationToken)
1044 if (cancellationToken.IsCancellationRequested)
1045 return TaskConstants.Canceled;
1047 return TaskExtensionsImpl.Unwrap (Task.Factory.StartNew (function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default));
1050 public static Task<TResult> Run<TResult> (Func<TResult> function)
1052 return Run (function, CancellationToken.None);
1055 public static Task<TResult> Run<TResult> (Func<TResult> function, CancellationToken cancellationToken)
1057 if (cancellationToken.IsCancellationRequested)
1058 return TaskConstants<TResult>.Canceled;
1060 return Task.Factory.StartNew (function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
1063 public static Task<TResult> Run<TResult> (Func<Task<TResult>> function)
1065 return Run (function, CancellationToken.None);
1068 public static Task<TResult> Run<TResult> (Func<Task<TResult>> function, CancellationToken cancellationToken)
1070 if (cancellationToken.IsCancellationRequested)
1071 return TaskConstants<TResult>.Canceled;
1073 return TaskExtensionsImpl.Unwrap (Task.Factory.StartNew (function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default));
1076 public static Task WhenAll (params Task[] tasks)
1079 throw new ArgumentNullException ("tasks");
1081 return WhenAllCore (tasks);
1084 public static Task WhenAll (IEnumerable<Task> tasks)
1087 throw new ArgumentNullException ("tasks");
1089 // Call ToList on input enumeration or we end up
1090 // enumerating it more than once
1091 return WhenAllCore (new List<Task> (tasks));
1094 public static Task<TResult[]> WhenAll<TResult> (params Task<TResult>[] tasks)
1097 throw new ArgumentNullException ("tasks");
1099 return WhenAllCore<TResult> (tasks);
1102 public static Task<TResult[]> WhenAll<TResult> (IEnumerable<Task<TResult>> tasks)
1105 throw new ArgumentNullException ("tasks");
1107 // Call ToList on input enumeration or we end up
1108 // enumerating it more than once
1109 return WhenAllCore<TResult> (new List<Task<TResult>> (tasks));
1112 internal static Task<TResult[]> WhenAllCore<TResult> (IList<Task<TResult>> tasks)
1114 if (tasks.Count == 0)
1115 return FromResult(new TResult[0]);
1117 foreach (var t in tasks) {
1119 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1122 var task = new Task<TResult[]> (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1123 task.SetupScheduler (TaskScheduler.Current);
1125 var continuation = new WhenAllContinuation<TResult> (task, tasks);
1126 foreach (var t in tasks)
1127 t.ContinueWith (continuation);
1132 public static Task<Task> WhenAny (params Task[] tasks)
1135 throw new ArgumentNullException ("tasks");
1137 return WhenAnyCore (tasks);
1140 public static Task<Task> WhenAny (IEnumerable<Task> tasks)
1143 throw new ArgumentNullException ("tasks");
1145 return WhenAnyCore (new List<Task> (tasks));
1148 public static Task<Task<TResult>> WhenAny<TResult> (params Task<TResult>[] tasks)
1151 throw new ArgumentNullException ("tasks");
1153 return WhenAnyCore<TResult> (tasks);
1156 public static Task<Task<TResult>> WhenAny<TResult> (IEnumerable<Task<TResult>> tasks)
1159 throw new ArgumentNullException ("tasks");
1161 return WhenAnyCore<TResult> (new List<Task<TResult>> (tasks));
1164 static Task<Task<TResult>> WhenAnyCore<TResult> (IList<Task<TResult>> tasks)
1166 if (tasks.Count == 0)
1167 throw new ArgumentException ("The tasks argument contains no tasks", "tasks");
1169 int completed_index = -1;
1170 for (int i = 0; i < tasks.Count; ++i) {
1173 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1175 if (t.IsCompleted && completed_index < 0)
1176 completed_index = i;
1179 var task = new Task<Task<TResult>> (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1181 if (completed_index > 0) {
1182 task.TrySetResult (tasks[completed_index]);
1186 task.SetupScheduler (TaskScheduler.Current);
1188 var continuation = new WhenAnyContinuation<Task<TResult>> (task, tasks);
1189 foreach (var t in tasks)
1190 t.ContinueWith (continuation);
1195 public static YieldAwaitable Yield ()
1197 return new YieldAwaitable ();
1201 internal static Task WhenAllCore (IList<Task> tasks)
1203 bool all_completed = true;
1204 foreach (var t in tasks) {
1206 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1208 all_completed &= t.Status == TaskStatus.RanToCompletion;
1212 return TaskConstants.Finished;
1214 var task = new Task (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1215 task.SetupScheduler (TaskScheduler.Current);
1217 var continuation = new WhenAllContinuation (task, tasks);
1218 foreach (var t in tasks)
1219 t.ContinueWith (continuation);
1224 internal static Task<Task> WhenAnyCore (IList<Task> tasks)
1226 if (tasks.Count == 0)
1227 throw new ArgumentException ("The tasks argument contains no tasks", "tasks");
1229 int completed_index = -1;
1230 for (int i = 0; i < tasks.Count; ++i) {
1233 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1235 if (t.IsCompleted && completed_index < 0)
1236 completed_index = i;
1239 var task = new Task<Task> (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1241 if (completed_index > 0) {
1242 task.TrySetResult (tasks[completed_index]);
1246 task.SetupScheduler (TaskScheduler.Current);
1248 var continuation = new WhenAnyContinuation<Task> (task, tasks);
1249 foreach (var t in tasks)
1250 t.ContinueWith (continuation);
1256 internal CancellationToken CancellationToken {
1262 public static TaskFactory Factory {
1264 return defaultFactory;
1268 public static int? CurrentId {
1271 return t == null ? (int?)null : t.Id;
1275 public AggregateException Exception {
1277 if (exSlot == null || !IsFaulted)
1279 exSlot.Observed = true;
1280 return exSlot.Exception;
1284 public bool IsCanceled {
1286 return status == TaskStatus.Canceled;
1290 public bool IsCompleted {
1292 return status >= TaskStatus.RanToCompletion;
1296 public bool IsFaulted {
1298 return status == TaskStatus.Faulted;
1302 public TaskCreationOptions CreationOptions {
1304 return creationOptions & MaxTaskCreationOptions;
1308 public TaskStatus Status {
1314 Thread.MemoryBarrier ();
1318 internal TaskExceptionSlot ExceptionSlot {
1322 Interlocked.CompareExchange (ref exSlot, new TaskExceptionSlot (this), null);
1327 public object AsyncState {
1333 bool IAsyncResult.CompletedSynchronously {
1339 WaitHandle IAsyncResult.AsyncWaitHandle {
1341 if (invoker == null)
1342 throw new ObjectDisposedException (GetType ().ToString ());
1344 if (wait_handle == null)
1345 Interlocked.CompareExchange (ref wait_handle, new ManualResetEvent (IsCompleted), null);
1357 bool IsContinuation {
1359 return contAncestor != null;
1365 return invoker == TaskActionInvoker.Promise;
1369 internal Task ContinuationAncestor {
1371 return contAncestor;
1375 internal string DisplayActionMethod {
1377 Delegate d = invoker.Action;
1378 return d == null ? "<none>" : d.Method.ToString ();