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");
185 SetupScheduler (scheduler);
189 internal void SetupScheduler (TaskScheduler scheduler)
191 this.scheduler = scheduler;
192 Status = TaskStatus.WaitingForActivation;
195 public void RunSynchronously ()
197 RunSynchronously (TaskScheduler.Current);
200 public void RunSynchronously (TaskScheduler scheduler)
202 if (scheduler == null)
203 throw new ArgumentNullException ("scheduler");
205 if (Status > TaskStatus.WaitingForActivation)
206 throw new InvalidOperationException ("The task is not in a valid state to be started");
209 throw new InvalidOperationException ("RunSynchronously may not be called on a continuation task");
211 RunSynchronouslyCore (scheduler);
214 internal void RunSynchronouslyCore (TaskScheduler scheduler)
216 SetupScheduler (scheduler);
217 Status = TaskStatus.WaitingToRun;
220 if (scheduler.RunInline (this, false))
222 } catch (Exception inner) {
223 throw new TaskSchedulerException (inner);
227 WaitCore (Timeout.Infinite, CancellationToken.None, false);
232 public Task ContinueWith (Action<Task> continuationAction)
234 return ContinueWith (continuationAction, TaskContinuationOptions.None);
237 public Task ContinueWith (Action<Task> continuationAction, TaskContinuationOptions continuationOptions)
239 return ContinueWith (continuationAction, CancellationToken.None, continuationOptions, TaskScheduler.Current);
242 public Task ContinueWith (Action<Task> continuationAction, CancellationToken cancellationToken)
244 return ContinueWith (continuationAction, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
247 public Task ContinueWith (Action<Task> continuationAction, TaskScheduler scheduler)
249 return ContinueWith (continuationAction, CancellationToken.None, TaskContinuationOptions.None, scheduler);
252 public Task ContinueWith (Action<Task> continuationAction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
254 if (continuationAction == null)
255 throw new ArgumentNullException ("continuationAction");
256 if (scheduler == null)
257 throw new ArgumentNullException ("scheduler");
259 return ContinueWith (TaskActionInvoker.Create (continuationAction), cancellationToken, continuationOptions, scheduler);
262 internal Task ContinueWith (TaskActionInvoker invoker, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
264 var lazyCancellation = false;
266 lazyCancellation = (continuationOptions & TaskContinuationOptions.LazyCancellation) > 0;
268 var continuation = new Task (invoker, null, cancellationToken, GetCreationOptions (continuationOptions), null, this, lazyCancellation);
269 ContinueWithCore (continuation, continuationOptions, scheduler);
274 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction)
276 return ContinueWith<TResult> (continuationFunction, TaskContinuationOptions.None);
279 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, TaskContinuationOptions continuationOptions)
281 return ContinueWith<TResult> (continuationFunction, CancellationToken.None, continuationOptions, TaskScheduler.Current);
284 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, CancellationToken cancellationToken)
286 return ContinueWith<TResult> (continuationFunction, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
289 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, TaskScheduler scheduler)
291 return ContinueWith<TResult> (continuationFunction, CancellationToken.None, TaskContinuationOptions.None, scheduler);
294 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, CancellationToken cancellationToken,
295 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
297 if (continuationFunction == null)
298 throw new ArgumentNullException ("continuationFunction");
299 if (scheduler == null)
300 throw new ArgumentNullException ("scheduler");
302 return ContinueWith<TResult> (TaskActionInvoker.Create (continuationFunction), cancellationToken, continuationOptions, scheduler);
305 internal Task<TResult> ContinueWith<TResult> (TaskActionInvoker invoker, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
307 var lazyCancellation = false;
309 lazyCancellation = (continuationOptions & TaskContinuationOptions.LazyCancellation) > 0;
311 var continuation = new Task<TResult> (invoker, null, cancellationToken, GetCreationOptions (continuationOptions), parent, this, lazyCancellation);
312 ContinueWithCore (continuation, continuationOptions, scheduler);
317 internal void ContinueWithCore (Task continuation, TaskContinuationOptions options, TaskScheduler scheduler)
319 const TaskContinuationOptions wrongRan = TaskContinuationOptions.NotOnRanToCompletion | TaskContinuationOptions.OnlyOnRanToCompletion;
320 const TaskContinuationOptions wrongCanceled = TaskContinuationOptions.NotOnCanceled | TaskContinuationOptions.OnlyOnCanceled;
321 const TaskContinuationOptions wrongFaulted = TaskContinuationOptions.NotOnFaulted | TaskContinuationOptions.OnlyOnFaulted;
323 if (((options & wrongRan) == wrongRan) || ((options & wrongCanceled) == wrongCanceled) || ((options & wrongFaulted) == wrongFaulted))
324 throw new ArgumentException ("continuationOptions", "Some options are mutually exclusive");
326 // Already set the scheduler so that user can call Wait and that sort of stuff
327 continuation.scheduler = scheduler;
328 continuation.Status = TaskStatus.WaitingForActivation;
330 ContinueWith (new TaskContinuation (continuation, options));
333 internal bool ContinueWith (IContinuation continuation, bool canExecuteInline = true)
336 if (!canExecuteInline)
339 continuation.Execute ();
343 continuations.Add (continuation);
345 // Retry in case completion was achieved but event adding was too late
347 continuations.Remove (continuation);
348 if (!canExecuteInline)
351 continuation.Execute ();
357 internal void RemoveContinuation (IContinuation continuation)
359 continuations.Remove (continuation);
362 static internal TaskCreationOptions GetCreationOptions (TaskContinuationOptions kind)
364 TaskCreationOptions options = TaskCreationOptions.None;
365 if ((kind & TaskContinuationOptions.AttachedToParent) > 0)
366 options |= TaskCreationOptions.AttachedToParent;
367 if ((kind & TaskContinuationOptions.PreferFairness) > 0)
368 options |= TaskCreationOptions.PreferFairness;
369 if ((kind & TaskContinuationOptions.LongRunning) > 0)
370 options |= TaskCreationOptions.LongRunning;
376 #region Internal and protected thingies
377 internal void Schedule ()
379 Status = TaskStatus.WaitingToRun;
380 scheduler.QueueTask (this);
385 /* Allow scheduler to break fairness of deque ordering without
386 * breaking its semantic (the task can be executed twice but the
387 * second time it will return immediately
389 if (!executing.TryRelaxedSet ())
392 // Disable CancellationToken direct cancellation
393 if (cancellationRegistration != null) {
394 cancellationRegistration.Value.Dispose ();
395 cancellationRegistration = null;
398 // If Task are ran inline on the same thread we might trash these values
399 var saveCurrent = current;
400 var saveScheduler = TaskScheduler.Current;
404 TaskScheduler.Current = HasFlag (creationOptions, TaskCreationOptions.HideScheduler) ? TaskScheduler.Default : scheduler;
406 TaskScheduler.Current = scheduler;
409 if (!token.IsCancellationRequested) {
411 status = TaskStatus.Running;
415 } catch (OperationCanceledException oce) {
416 if (token != CancellationToken.None && oce.CancellationToken == token)
419 HandleGenericException (oce);
420 } catch (Exception e) {
421 HandleGenericException (e);
427 if (saveCurrent != null)
428 current = saveCurrent;
429 if (saveScheduler != null)
430 TaskScheduler.Current = saveScheduler;
434 internal bool TrySetCanceled ()
439 if (!executing.TryRelaxedSet ()) {
440 var sw = new SpinWait ();
451 internal bool TrySetException (AggregateException aggregate, bool cancellation)
456 if (!executing.TryRelaxedSet ()) {
457 var sw = new SpinWait ();
465 ExceptionSlot.Exception = aggregate;
466 Thread.MemoryBarrier ();
470 HandleGenericException (aggregate);
476 internal bool TrySetExceptionObserved ()
478 if (exSlot != null) {
479 exSlot.Observed = true;
485 internal void Execute ()
490 internal void AddChild ()
492 if (childTasks == null)
493 Interlocked.CompareExchange (ref childTasks, new CountdownEvent (1), null);
494 childTasks.AddCount ();
497 internal void ChildCompleted (AggregateException childEx)
499 if (childEx != null) {
500 if (ExceptionSlot.ChildExceptions == null)
501 Interlocked.CompareExchange (ref ExceptionSlot.ChildExceptions, new ConcurrentQueue<AggregateException> (), null);
502 ExceptionSlot.ChildExceptions.Enqueue (childEx);
505 if (childTasks.Signal () && status == TaskStatus.WaitingForChildrenToComplete) {
506 ProcessChildExceptions ();
507 Status = exSlot == null ? TaskStatus.RanToCompletion : TaskStatus.Faulted;
508 ProcessCompleteDelegates ();
509 if (parent != null &&
511 !HasFlag (parent.CreationOptions, TaskCreationOptions.DenyChildAttach) &&
513 HasFlag (creationOptions, TaskCreationOptions.AttachedToParent))
514 parent.ChildCompleted (this.Exception);
520 if (IsContinuation) {
521 var ancestor = contAncestor;
523 invoker.Invoke (ancestor, state, this);
525 invoker.Invoke (this, state, this);
529 internal void Finish ()
531 // If there was children created and they all finished, we set the countdown
532 if (childTasks != null) {
533 if (childTasks.Signal ())
534 ProcessChildExceptions (true);
537 // Don't override Canceled or Faulted
538 if (status == TaskStatus.Running) {
539 if (childTasks == null || childTasks.IsSet)
540 Status = TaskStatus.RanToCompletion;
542 Status = TaskStatus.WaitingForChildrenToComplete;
545 if (wait_handle != null)
548 // Tell parent that we are finished
549 if (parent != null && HasFlag (creationOptions, TaskCreationOptions.AttachedToParent) &&
551 !HasFlag (parent.CreationOptions, TaskCreationOptions.DenyChildAttach) &&
553 status != TaskStatus.WaitingForChildrenToComplete) {
554 parent.ChildCompleted (this.Exception);
557 // Completions are already processed when task is canceled or faulted
558 if (status == TaskStatus.RanToCompletion)
559 ProcessCompleteDelegates ();
561 // Reset the current thingies
564 if (TaskScheduler.Current == scheduler)
565 TaskScheduler.Current = null;
567 if (cancellationRegistration.HasValue)
568 cancellationRegistration.Value.Dispose ();
571 void ProcessCompleteDelegates ()
573 if (continuations.HasElements) {
574 IContinuation continuation;
575 while (continuations.TryGetNextCompletion (out continuation))
576 continuation.Execute ();
580 void ProcessChildExceptions (bool isParent = false)
582 if (exSlot == null || exSlot.ChildExceptions == null)
585 if (ExceptionSlot.Exception == null)
586 exSlot.Exception = new AggregateException ();
588 AggregateException childEx;
589 while (exSlot.ChildExceptions.TryDequeue (out childEx))
590 exSlot.Exception.AddChildException (childEx);
593 Status = TaskStatus.Faulted;
594 ProcessCompleteDelegates ();
599 #region Cancel and Wait related method
601 internal void CancelReal ()
603 Status = TaskStatus.Canceled;
605 if (wait_handle != null)
608 ProcessCompleteDelegates ();
611 void HandleGenericException (Exception e)
613 HandleGenericException (new AggregateException (e));
616 void HandleGenericException (AggregateException e)
618 ExceptionSlot.Exception = e;
619 Thread.MemoryBarrier ();
620 Status = TaskStatus.Faulted;
622 if (wait_handle != null)
625 ProcessCompleteDelegates ();
628 internal bool WaitOnChildren ()
630 if (Status == TaskStatus.WaitingForChildrenToComplete && childTasks != null) {
639 Wait (Timeout.Infinite, CancellationToken.None);
642 public void Wait (CancellationToken cancellationToken)
644 Wait (Timeout.Infinite, cancellationToken);
647 public bool Wait (TimeSpan timeout)
649 return Wait (CheckTimeout (timeout), CancellationToken.None);
652 public bool Wait (int millisecondsTimeout)
654 return Wait (millisecondsTimeout, CancellationToken.None);
657 public bool Wait (int millisecondsTimeout, CancellationToken cancellationToken)
659 if (millisecondsTimeout < -1)
660 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
662 bool result = WaitCore (millisecondsTimeout, cancellationToken, true);
665 throw new AggregateException (new TaskCanceledException (this));
667 var exception = Exception;
668 if (exception != null)
674 internal bool WaitCore (int millisecondsTimeout, CancellationToken cancellationToken, bool runInline)
679 // If the task is ready to be run and we were supposed to wait on it indefinitely without cancellation, just run it
680 if (runInline && Status == TaskStatus.WaitingToRun && millisecondsTimeout == Timeout.Infinite && scheduler != null && !cancellationToken.CanBeCanceled)
681 scheduler.RunInline (this, true);
686 var continuation = new ManualResetContinuation ();
688 ContinueWith (continuation);
689 result = continuation.Event.Wait (millisecondsTimeout, cancellationToken);
692 RemoveContinuation (continuation);
693 continuation.Dispose ();
700 public static void WaitAll (params Task[] tasks)
702 WaitAll (tasks, Timeout.Infinite, CancellationToken.None);
705 public static void WaitAll (Task[] tasks, CancellationToken cancellationToken)
707 WaitAll (tasks, Timeout.Infinite, cancellationToken);
710 public static bool WaitAll (Task[] tasks, TimeSpan timeout)
712 return WaitAll (tasks, CheckTimeout (timeout), CancellationToken.None);
715 public static bool WaitAll (Task[] tasks, int millisecondsTimeout)
717 return WaitAll (tasks, millisecondsTimeout, CancellationToken.None);
720 public static bool WaitAll (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
723 throw new ArgumentNullException ("tasks");
726 foreach (var t in tasks) {
728 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
730 result &= t.Status == TaskStatus.RanToCompletion;
734 var continuation = new CountdownContinuation (tasks.Length);
736 foreach (var t in tasks)
737 t.ContinueWith (continuation);
739 result = continuation.Event.Wait (millisecondsTimeout, cancellationToken);
741 List<Exception> exceptions = null;
743 foreach (var t in tasks) {
745 if (t.Status == TaskStatus.RanToCompletion)
747 if (exceptions == null)
748 exceptions = new List<Exception> ();
749 if (t.Exception != null)
750 exceptions.AddRange (t.Exception.InnerExceptions);
752 exceptions.Add (new TaskCanceledException (t));
754 t.RemoveContinuation (continuation);
758 continuation.Dispose ();
760 if (exceptions != null)
761 throw new AggregateException (exceptions);
768 public static int WaitAny (params Task[] tasks)
770 return WaitAny (tasks, Timeout.Infinite, CancellationToken.None);
773 public static int WaitAny (Task[] tasks, TimeSpan timeout)
775 return WaitAny (tasks, CheckTimeout (timeout));
778 public static int WaitAny (Task[] tasks, int millisecondsTimeout)
780 return WaitAny (tasks, millisecondsTimeout, CancellationToken.None);
783 public static int WaitAny (Task[] tasks, CancellationToken cancellationToken)
785 return WaitAny (tasks, Timeout.Infinite, cancellationToken);
788 public static int WaitAny (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
791 throw new ArgumentNullException ("tasks");
792 if (millisecondsTimeout < -1)
793 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
794 CheckForNullTasks (tasks);
796 if (tasks.Length > 0) {
797 var continuation = new ManualResetContinuation ();
800 for (int i = 0; i < tasks.Length; i++) {
804 t.ContinueWith (continuation);
807 if (!(result = continuation.Event.Wait (millisecondsTimeout, cancellationToken)))
811 foreach (var t in tasks)
812 t.RemoveContinuation (continuation);
813 continuation.Dispose ();
817 int firstFinished = -1;
818 for (int i = 0; i < tasks.Length; i++) {
826 return firstFinished;
829 static int CheckTimeout (TimeSpan timeout)
832 return checked ((int)timeout.TotalMilliseconds);
833 } catch (System.OverflowException) {
834 throw new ArgumentOutOfRangeException ("timeout");
838 static void CheckForNullTasks (Task[] tasks)
840 foreach (var t in tasks)
842 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
847 public void Dispose ()
852 protected virtual void Dispose (bool disposing)
855 throw new InvalidOperationException ("A task may only be disposed if it is in a completion state");
857 // Set action to null so that the GC can collect the delegate and thus
858 // any big object references that the user might have captured in a anonymous method
862 if (cancellationRegistration != null)
863 cancellationRegistration.Value.Dispose ();
864 if (wait_handle != null)
865 wait_handle.Dispose ();
875 Task ContinueWith (Action<Task, object> continuationAction, object state, CancellationToken cancellationToken,
876 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
878 if (continuationAction == null)
879 throw new ArgumentNullException ("continuationAction");
880 if (scheduler == null)
881 throw new ArgumentNullException ("scheduler");
883 Task continuation = new Task (TaskActionInvoker.Create (continuationAction),
884 state, cancellationToken,
885 GetCreationOptions (continuationOptions),
888 ContinueWithCore (continuation, continuationOptions, scheduler);
895 public ConfiguredTaskAwaitable ConfigureAwait (bool continueOnCapturedContext)
897 return new ConfiguredTaskAwaitable (this, continueOnCapturedContext);
900 public Task ContinueWith (Action<Task, object> continuationAction, object state)
902 return ContinueWith (continuationAction, state, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current);
905 public Task ContinueWith (Action<Task, object> continuationAction, object state, CancellationToken cancellationToken)
907 return ContinueWith (continuationAction, state, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
910 public Task ContinueWith (Action<Task, object> continuationAction, object state, TaskContinuationOptions continuationOptions)
912 return ContinueWith (continuationAction, state, CancellationToken.None, continuationOptions, TaskScheduler.Current);
915 public Task ContinueWith (Action<Task, object> continuationAction, object state, TaskScheduler scheduler)
917 return ContinueWith (continuationAction, state, CancellationToken.None, TaskContinuationOptions.None, scheduler);
920 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state)
922 return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current);
925 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, TaskContinuationOptions continuationOptions)
927 return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, continuationOptions, TaskScheduler.Current);
930 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, CancellationToken cancellationToken)
932 return ContinueWith<TResult> (continuationFunction, state, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
935 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, TaskScheduler scheduler)
937 return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, TaskContinuationOptions.None, scheduler);
940 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, CancellationToken cancellationToken,
941 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
943 if (continuationFunction == null)
944 throw new ArgumentNullException ("continuationFunction");
945 if (scheduler == null)
946 throw new ArgumentNullException ("scheduler");
948 var t = new Task<TResult> (TaskActionInvoker.Create (continuationFunction),
951 GetCreationOptions (continuationOptions),
955 ContinueWithCore (t, continuationOptions, scheduler);
960 public static Task Delay (int millisecondsDelay)
962 return Delay (millisecondsDelay, CancellationToken.None);
965 public static Task Delay (TimeSpan delay)
967 return Delay (CheckTimeout (delay), CancellationToken.None);
970 public static Task Delay (TimeSpan delay, CancellationToken cancellationToken)
972 return Delay (CheckTimeout (delay), cancellationToken);
975 public static Task Delay (int millisecondsDelay, CancellationToken cancellationToken)
977 if (millisecondsDelay < -1)
978 throw new ArgumentOutOfRangeException ("millisecondsDelay");
980 if (cancellationToken.IsCancellationRequested)
981 return TaskConstants.Canceled;
983 var task = new Task (TaskActionInvoker.Empty, null, cancellationToken, TaskCreationOptions.None, null, null);
984 task.SetupScheduler (TaskScheduler.Default);
986 if (millisecondsDelay != Timeout.Infinite) {
987 var timer = new Timer (delegate (object state) {
988 var t = (Task) state;
989 if (t.Status == TaskStatus.WaitingForActivation) {
990 t.Status = TaskStatus.Running;
993 }, task, millisecondsDelay, -1);
995 task.ContinueWith (new DisposeContinuation (timer));
1001 public static Task<TResult> FromResult<TResult> (TResult result)
1003 var tcs = new TaskCompletionSource<TResult> ();
1004 tcs.SetResult (result);
1008 public TaskAwaiter GetAwaiter ()
1010 return new TaskAwaiter (this);
1013 public static Task Run (Action action)
1015 return Run (action, CancellationToken.None);
1018 public static Task Run (Action action, CancellationToken cancellationToken)
1020 if (cancellationToken.IsCancellationRequested)
1021 return TaskConstants.Canceled;
1023 return Task.Factory.StartNew (action, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
1026 public static Task Run (Func<Task> function)
1028 return Run (function, CancellationToken.None);
1031 public static Task Run (Func<Task> function, CancellationToken cancellationToken)
1033 if (cancellationToken.IsCancellationRequested)
1034 return TaskConstants.Canceled;
1036 return TaskExtensionsImpl.Unwrap (Task.Factory.StartNew (function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default));
1039 public static Task<TResult> Run<TResult> (Func<TResult> function)
1041 return Run (function, CancellationToken.None);
1044 public static Task<TResult> Run<TResult> (Func<TResult> function, CancellationToken cancellationToken)
1046 if (cancellationToken.IsCancellationRequested)
1047 return TaskConstants<TResult>.Canceled;
1049 return Task.Factory.StartNew (function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
1052 public static Task<TResult> Run<TResult> (Func<Task<TResult>> function)
1054 return Run (function, CancellationToken.None);
1057 public static Task<TResult> Run<TResult> (Func<Task<TResult>> function, CancellationToken cancellationToken)
1059 if (cancellationToken.IsCancellationRequested)
1060 return TaskConstants<TResult>.Canceled;
1062 return TaskExtensionsImpl.Unwrap (Task.Factory.StartNew (function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default));
1065 public static Task WhenAll (params Task[] tasks)
1068 throw new ArgumentNullException ("tasks");
1070 return WhenAllCore (tasks);
1073 public static Task WhenAll (IEnumerable<Task> tasks)
1076 throw new ArgumentNullException ("tasks");
1078 // Call ToList on input enumeration or we end up
1079 // enumerating it more than once
1080 return WhenAllCore (new List<Task> (tasks));
1083 public static Task<TResult[]> WhenAll<TResult> (params Task<TResult>[] tasks)
1086 throw new ArgumentNullException ("tasks");
1088 return WhenAllCore<TResult> (tasks);
1091 public static Task<TResult[]> WhenAll<TResult> (IEnumerable<Task<TResult>> tasks)
1094 throw new ArgumentNullException ("tasks");
1096 // Call ToList on input enumeration or we end up
1097 // enumerating it more than once
1098 return WhenAllCore<TResult> (new List<Task<TResult>> (tasks));
1101 internal static Task<TResult[]> WhenAllCore<TResult> (IList<Task<TResult>> tasks)
1103 if (tasks.Count == 0)
1104 return FromResult(new TResult[0]);
1106 foreach (var t in tasks) {
1108 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1111 var task = new Task<TResult[]> (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1112 task.SetupScheduler (TaskScheduler.Current);
1114 var continuation = new WhenAllContinuation<TResult> (task, tasks);
1115 foreach (var t in tasks)
1116 t.ContinueWith (continuation);
1121 public static Task<Task> WhenAny (params Task[] tasks)
1124 throw new ArgumentNullException ("tasks");
1126 return WhenAnyCore (tasks);
1129 public static Task<Task> WhenAny (IEnumerable<Task> tasks)
1132 throw new ArgumentNullException ("tasks");
1134 return WhenAnyCore (new List<Task> (tasks));
1137 public static Task<Task<TResult>> WhenAny<TResult> (params Task<TResult>[] tasks)
1140 throw new ArgumentNullException ("tasks");
1142 return WhenAnyCore<TResult> (tasks);
1145 public static Task<Task<TResult>> WhenAny<TResult> (IEnumerable<Task<TResult>> tasks)
1148 throw new ArgumentNullException ("tasks");
1150 return WhenAnyCore<TResult> (new List<Task<TResult>> (tasks));
1153 static Task<Task<TResult>> WhenAnyCore<TResult> (IList<Task<TResult>> tasks)
1155 if (tasks.Count == 0)
1156 throw new ArgumentException ("The tasks argument contains no tasks", "tasks");
1158 int completed_index = -1;
1159 for (int i = 0; i < tasks.Count; ++i) {
1162 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1164 if (t.IsCompleted && completed_index < 0)
1165 completed_index = i;
1168 var task = new Task<Task<TResult>> (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1170 if (completed_index > 0) {
1171 task.TrySetResult (tasks[completed_index]);
1175 task.SetupScheduler (TaskScheduler.Current);
1177 var continuation = new WhenAnyContinuation<Task<TResult>> (task, tasks);
1178 foreach (var t in tasks)
1179 t.ContinueWith (continuation);
1184 public static YieldAwaitable Yield ()
1186 return new YieldAwaitable ();
1190 internal static Task WhenAllCore (IList<Task> tasks)
1192 bool all_completed = true;
1193 foreach (var t in tasks) {
1195 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1197 all_completed &= t.Status == TaskStatus.RanToCompletion;
1201 return TaskConstants.Finished;
1203 var task = new Task (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1204 task.SetupScheduler (TaskScheduler.Current);
1206 var continuation = new WhenAllContinuation (task, tasks);
1207 foreach (var t in tasks)
1208 t.ContinueWith (continuation);
1213 internal static Task<Task> WhenAnyCore (IList<Task> tasks)
1215 if (tasks.Count == 0)
1216 throw new ArgumentException ("The tasks argument contains no tasks", "tasks");
1218 int completed_index = -1;
1219 for (int i = 0; i < tasks.Count; ++i) {
1222 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1224 if (t.IsCompleted && completed_index < 0)
1225 completed_index = i;
1228 var task = new Task<Task> (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1230 if (completed_index > 0) {
1231 task.TrySetResult (tasks[completed_index]);
1235 task.SetupScheduler (TaskScheduler.Current);
1237 var continuation = new WhenAnyContinuation<Task> (task, tasks);
1238 foreach (var t in tasks)
1239 t.ContinueWith (continuation);
1245 internal CancellationToken CancellationToken {
1251 public static TaskFactory Factory {
1253 return defaultFactory;
1257 public static int? CurrentId {
1260 return t == null ? (int?)null : t.Id;
1264 public AggregateException Exception {
1266 if (exSlot == null || !IsFaulted)
1268 exSlot.Observed = true;
1269 return exSlot.Exception;
1273 public bool IsCanceled {
1275 return status == TaskStatus.Canceled;
1279 public bool IsCompleted {
1281 return status >= TaskStatus.RanToCompletion;
1285 public bool IsFaulted {
1287 return status == TaskStatus.Faulted;
1291 public TaskCreationOptions CreationOptions {
1293 return creationOptions & MaxTaskCreationOptions;
1297 public TaskStatus Status {
1303 Thread.MemoryBarrier ();
1307 internal TaskExceptionSlot ExceptionSlot {
1311 Interlocked.CompareExchange (ref exSlot, new TaskExceptionSlot (this), null);
1316 public object AsyncState {
1322 bool IAsyncResult.CompletedSynchronously {
1328 WaitHandle IAsyncResult.AsyncWaitHandle {
1330 if (invoker == null)
1331 throw new ObjectDisposedException (GetType ().ToString ());
1333 if (wait_handle == null)
1334 Interlocked.CompareExchange (ref wait_handle, new ManualResetEvent (IsCompleted), null);
1346 bool IsContinuation {
1348 return contAncestor != null;
1352 internal Task ContinuationAncestor {
1354 return contAncestor;
1358 internal string DisplayActionMethod {
1360 Delegate d = invoker.Action;
1361 return d == null ? "<none>" : d.Method.ToString ();