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, true);
220 internal void RunSynchronouslyCore (TaskScheduler scheduler, bool throwException)
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);
237 Schedule (throwException);
238 WaitCore (Timeout.Infinite, CancellationToken.None, false);
243 public Task ContinueWith (Action<Task> continuationAction)
245 return ContinueWith (continuationAction, TaskContinuationOptions.None);
248 public Task ContinueWith (Action<Task> continuationAction, TaskContinuationOptions continuationOptions)
250 return ContinueWith (continuationAction, CancellationToken.None, continuationOptions, TaskScheduler.Current);
253 public Task ContinueWith (Action<Task> continuationAction, CancellationToken cancellationToken)
255 return ContinueWith (continuationAction, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
258 public Task ContinueWith (Action<Task> continuationAction, TaskScheduler scheduler)
260 return ContinueWith (continuationAction, CancellationToken.None, TaskContinuationOptions.None, scheduler);
263 public Task ContinueWith (Action<Task> continuationAction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
265 if (continuationAction == null)
266 throw new ArgumentNullException ("continuationAction");
267 if (scheduler == null)
268 throw new ArgumentNullException ("scheduler");
270 return ContinueWith (TaskActionInvoker.Create (continuationAction), cancellationToken, continuationOptions, scheduler);
273 internal Task ContinueWith (TaskActionInvoker invoker, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
275 var lazyCancellation = false;
277 lazyCancellation = (continuationOptions & TaskContinuationOptions.LazyCancellation) > 0;
279 var continuation = new Task (invoker, null, cancellationToken, GetCreationOptions (continuationOptions), null, this, lazyCancellation);
280 ContinueWithCore (continuation, continuationOptions, scheduler);
285 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction)
287 return ContinueWith<TResult> (continuationFunction, TaskContinuationOptions.None);
290 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, TaskContinuationOptions continuationOptions)
292 return ContinueWith<TResult> (continuationFunction, CancellationToken.None, continuationOptions, TaskScheduler.Current);
295 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, CancellationToken cancellationToken)
297 return ContinueWith<TResult> (continuationFunction, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
300 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, TaskScheduler scheduler)
302 return ContinueWith<TResult> (continuationFunction, CancellationToken.None, TaskContinuationOptions.None, scheduler);
305 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, CancellationToken cancellationToken,
306 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
308 if (continuationFunction == null)
309 throw new ArgumentNullException ("continuationFunction");
310 if (scheduler == null)
311 throw new ArgumentNullException ("scheduler");
313 return ContinueWith<TResult> (TaskActionInvoker.Create (continuationFunction), cancellationToken, continuationOptions, scheduler);
316 internal Task<TResult> ContinueWith<TResult> (TaskActionInvoker invoker, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
318 var lazyCancellation = false;
320 lazyCancellation = (continuationOptions & TaskContinuationOptions.LazyCancellation) > 0;
322 var continuation = new Task<TResult> (invoker, null, cancellationToken, GetCreationOptions (continuationOptions), parent, this, lazyCancellation);
323 ContinueWithCore (continuation, continuationOptions, scheduler);
328 internal void ContinueWithCore (Task continuation, TaskContinuationOptions options, TaskScheduler scheduler)
330 const TaskContinuationOptions wrongRan = TaskContinuationOptions.NotOnRanToCompletion | TaskContinuationOptions.OnlyOnRanToCompletion;
331 const TaskContinuationOptions wrongCanceled = TaskContinuationOptions.NotOnCanceled | TaskContinuationOptions.OnlyOnCanceled;
332 const TaskContinuationOptions wrongFaulted = TaskContinuationOptions.NotOnFaulted | TaskContinuationOptions.OnlyOnFaulted;
334 if (((options & wrongRan) == wrongRan) || ((options & wrongCanceled) == wrongCanceled) || ((options & wrongFaulted) == wrongFaulted))
335 throw new ArgumentException ("continuationOptions", "Some options are mutually exclusive");
337 // Already set the scheduler so that user can call Wait and that sort of stuff
338 continuation.scheduler = scheduler;
339 continuation.Status = TaskStatus.WaitingForActivation;
341 ContinueWith (new TaskContinuation (continuation, options));
344 internal bool ContinueWith (IContinuation continuation, bool canExecuteInline = true)
347 if (!canExecuteInline)
350 continuation.Execute ();
354 continuations.Add (continuation);
356 // Retry in case completion was achieved but event adding was too late
357 if (IsCompleted && continuations.Remove (continuation)) {
358 if (!canExecuteInline)
361 continuation.Execute ();
367 internal void RemoveContinuation (IContinuation continuation)
369 continuations.Remove (continuation);
372 static internal TaskCreationOptions GetCreationOptions (TaskContinuationOptions kind)
374 TaskCreationOptions options = TaskCreationOptions.None;
375 if ((kind & TaskContinuationOptions.AttachedToParent) > 0)
376 options |= TaskCreationOptions.AttachedToParent;
377 if ((kind & TaskContinuationOptions.PreferFairness) > 0)
378 options |= TaskCreationOptions.PreferFairness;
379 if ((kind & TaskContinuationOptions.LongRunning) > 0)
380 options |= TaskCreationOptions.LongRunning;
386 #region Internal and protected thingies
387 internal void Schedule (bool throwException)
389 Status = TaskStatus.WaitingToRun;
391 scheduler.QueueTask (this);
392 } catch (Exception inner) {
393 var ex = new TaskSchedulerException (inner);
394 TrySetException (new AggregateException (ex), false, true);
402 /* Allow scheduler to break fairness of deque ordering without
403 * breaking its semantic (the task can be executed twice but the
404 * second time it will return immediately
406 if (!executing.TryRelaxedSet ())
409 // Disable CancellationToken direct cancellation
410 if (cancellationRegistration != null) {
411 cancellationRegistration.Value.Dispose ();
412 cancellationRegistration = null;
415 // If Task are ran inline on the same thread we might trash these values
416 var saveCurrent = current;
417 var saveScheduler = TaskScheduler.Current;
421 TaskScheduler.Current = HasFlag (creationOptions, TaskCreationOptions.HideScheduler) ? TaskScheduler.Default : scheduler;
423 TaskScheduler.Current = scheduler;
426 if (!token.IsCancellationRequested) {
428 status = TaskStatus.Running;
432 } catch (OperationCanceledException oce) {
433 if (token != CancellationToken.None && oce.CancellationToken == token)
436 HandleGenericException (oce);
437 } catch (Exception e) {
438 HandleGenericException (e);
444 if (saveCurrent != null)
445 current = saveCurrent;
446 if (saveScheduler != null)
447 TaskScheduler.Current = saveScheduler;
451 internal bool TrySetCanceled ()
456 if (!executing.TryRelaxedSet ()) {
457 var sw = new SpinWait ();
468 internal bool TrySetException (AggregateException aggregate, bool cancellation, bool observed)
473 if (!executing.TryRelaxedSet ()) {
474 var sw = new SpinWait ();
482 ExceptionSlot.Exception = aggregate;
483 Thread.MemoryBarrier ();
487 HandleGenericException (aggregate);
491 exSlot.Observed = true;
496 internal bool TrySetExceptionObserved ()
498 if (exSlot != null) {
499 exSlot.Observed = true;
505 internal void Execute ()
510 internal void AddChild ()
512 if (childTasks == null)
513 Interlocked.CompareExchange (ref childTasks, new CountdownEvent (1), null);
514 childTasks.AddCount ();
517 internal void ChildCompleted (AggregateException childEx)
519 if (childEx != null) {
520 if (ExceptionSlot.ChildExceptions == null)
521 Interlocked.CompareExchange (ref ExceptionSlot.ChildExceptions, new ConcurrentQueue<AggregateException> (), null);
522 ExceptionSlot.ChildExceptions.Enqueue (childEx);
525 if (childTasks.Signal () && status == TaskStatus.WaitingForChildrenToComplete) {
526 ProcessChildExceptions ();
527 Status = exSlot == null ? TaskStatus.RanToCompletion : TaskStatus.Faulted;
528 ProcessCompleteDelegates ();
529 if (parent != null &&
531 !HasFlag (parent.CreationOptions, TaskCreationOptions.DenyChildAttach) &&
533 HasFlag (creationOptions, TaskCreationOptions.AttachedToParent))
534 parent.ChildCompleted (this.Exception);
540 if (IsContinuation) {
541 var ancestor = contAncestor;
543 invoker.Invoke (ancestor, state, this);
545 invoker.Invoke (this, state, this);
549 internal void Finish ()
551 // If there was children created and they all finished, we set the countdown
552 if (childTasks != null) {
553 if (childTasks.Signal ())
554 ProcessChildExceptions (true);
557 // Don't override Canceled or Faulted
558 if (status == TaskStatus.Running) {
559 if (childTasks == null || childTasks.IsSet)
560 Status = TaskStatus.RanToCompletion;
562 Status = TaskStatus.WaitingForChildrenToComplete;
565 if (wait_handle != null)
568 // Tell parent that we are finished
569 if (parent != null && HasFlag (creationOptions, TaskCreationOptions.AttachedToParent) &&
571 !HasFlag (parent.CreationOptions, TaskCreationOptions.DenyChildAttach) &&
573 status != TaskStatus.WaitingForChildrenToComplete) {
574 parent.ChildCompleted (this.Exception);
577 // Completions are already processed when task is canceled or faulted
578 if (status == TaskStatus.RanToCompletion)
579 ProcessCompleteDelegates ();
581 // Reset the current thingies
584 if (TaskScheduler.Current == scheduler)
585 TaskScheduler.Current = null;
587 if (cancellationRegistration.HasValue)
588 cancellationRegistration.Value.Dispose ();
591 void ProcessCompleteDelegates ()
593 if (continuations.HasElements) {
594 IContinuation continuation;
595 while (continuations.TryGetNextCompletion (out continuation))
596 continuation.Execute ();
600 void ProcessChildExceptions (bool isParent = false)
602 if (exSlot == null || exSlot.ChildExceptions == null)
605 if (ExceptionSlot.Exception == null)
606 exSlot.Exception = new AggregateException ();
608 AggregateException childEx;
609 while (exSlot.ChildExceptions.TryDequeue (out childEx))
610 exSlot.Exception.AddChildException (childEx);
613 Status = TaskStatus.Faulted;
614 ProcessCompleteDelegates ();
619 #region Cancel and Wait related method
621 internal void CancelReal ()
623 Status = TaskStatus.Canceled;
625 if (wait_handle != null)
628 ProcessCompleteDelegates ();
631 void HandleGenericException (Exception e)
633 HandleGenericException (new AggregateException (e));
636 void HandleGenericException (AggregateException e)
638 ExceptionSlot.Exception = e;
639 Thread.MemoryBarrier ();
640 Status = TaskStatus.Faulted;
642 if (wait_handle != null)
645 ProcessCompleteDelegates ();
648 internal bool WaitOnChildren ()
650 if (Status == TaskStatus.WaitingForChildrenToComplete && childTasks != null) {
659 Wait (Timeout.Infinite, CancellationToken.None);
662 public void Wait (CancellationToken cancellationToken)
664 Wait (Timeout.Infinite, cancellationToken);
667 public bool Wait (TimeSpan timeout)
669 return Wait (CheckTimeout (timeout), CancellationToken.None);
672 public bool Wait (int millisecondsTimeout)
674 return Wait (millisecondsTimeout, CancellationToken.None);
677 public bool Wait (int millisecondsTimeout, CancellationToken cancellationToken)
679 if (millisecondsTimeout < -1)
680 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
682 bool result = WaitCore (millisecondsTimeout, cancellationToken, true);
685 throw new AggregateException (new TaskCanceledException (this));
687 var exception = Exception;
688 if (exception != null)
694 internal bool WaitCore (int millisecondsTimeout, CancellationToken cancellationToken, bool runInline)
699 // If the task is ready to be run and we were supposed to wait on it indefinitely without cancellation, just run it
700 if (runInline && Status == TaskStatus.WaitingToRun && millisecondsTimeout == Timeout.Infinite && scheduler != null && !cancellationToken.CanBeCanceled) {
702 scheduler.RunInline (this, true);
703 } catch (Exception e) {
704 throw new TaskSchedulerException (e);
711 var continuation = new ManualResetContinuation ();
713 ContinueWith (continuation);
714 result = continuation.Event.Wait (millisecondsTimeout, cancellationToken);
717 RemoveContinuation (continuation);
718 continuation.Dispose ();
725 public static void WaitAll (params Task[] tasks)
727 WaitAll (tasks, Timeout.Infinite, CancellationToken.None);
730 public static void WaitAll (Task[] tasks, CancellationToken cancellationToken)
732 WaitAll (tasks, Timeout.Infinite, cancellationToken);
735 public static bool WaitAll (Task[] tasks, TimeSpan timeout)
737 return WaitAll (tasks, CheckTimeout (timeout), CancellationToken.None);
740 public static bool WaitAll (Task[] tasks, int millisecondsTimeout)
742 return WaitAll (tasks, millisecondsTimeout, CancellationToken.None);
745 public static bool WaitAll (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
748 throw new ArgumentNullException ("tasks");
751 foreach (var t in tasks) {
753 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
755 result &= t.Status == TaskStatus.RanToCompletion;
759 var continuation = new CountdownContinuation (tasks.Length);
761 foreach (var t in tasks)
762 t.ContinueWith (continuation);
764 result = continuation.Event.Wait (millisecondsTimeout, cancellationToken);
766 List<Exception> exceptions = null;
768 foreach (var t in tasks) {
770 if (t.Status == TaskStatus.RanToCompletion)
772 if (exceptions == null)
773 exceptions = new List<Exception> ();
774 if (t.Exception != null)
775 exceptions.AddRange (t.Exception.InnerExceptions);
777 exceptions.Add (new TaskCanceledException (t));
779 t.RemoveContinuation (continuation);
783 continuation.Dispose ();
785 if (exceptions != null)
786 throw new AggregateException (exceptions);
793 public static int WaitAny (params Task[] tasks)
795 return WaitAny (tasks, Timeout.Infinite, CancellationToken.None);
798 public static int WaitAny (Task[] tasks, TimeSpan timeout)
800 return WaitAny (tasks, CheckTimeout (timeout));
803 public static int WaitAny (Task[] tasks, int millisecondsTimeout)
805 return WaitAny (tasks, millisecondsTimeout, CancellationToken.None);
808 public static int WaitAny (Task[] tasks, CancellationToken cancellationToken)
810 return WaitAny (tasks, Timeout.Infinite, cancellationToken);
813 public static int WaitAny (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
816 throw new ArgumentNullException ("tasks");
817 if (millisecondsTimeout < -1)
818 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
819 CheckForNullTasks (tasks);
821 if (tasks.Length > 0) {
822 var continuation = new ManualResetContinuation ();
825 for (int i = 0; i < tasks.Length; i++) {
829 t.ContinueWith (continuation);
832 if (!(result = continuation.Event.Wait (millisecondsTimeout, cancellationToken)))
836 foreach (var t in tasks)
837 t.RemoveContinuation (continuation);
838 continuation.Dispose ();
842 int firstFinished = -1;
843 for (int i = 0; i < tasks.Length; i++) {
851 return firstFinished;
854 static int CheckTimeout (TimeSpan timeout)
857 return checked ((int)timeout.TotalMilliseconds);
858 } catch (System.OverflowException) {
859 throw new ArgumentOutOfRangeException ("timeout");
863 static void CheckForNullTasks (Task[] tasks)
865 foreach (var t in tasks)
867 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
872 public void Dispose ()
877 protected virtual void Dispose (bool disposing)
880 throw new InvalidOperationException ("A task may only be disposed if it is in a completion state");
882 // Set action to null so that the GC can collect the delegate and thus
883 // any big object references that the user might have captured in a anonymous method
887 if (cancellationRegistration != null)
888 cancellationRegistration.Value.Dispose ();
889 if (wait_handle != null)
890 wait_handle.Dispose ();
900 Task ContinueWith (Action<Task, object> continuationAction, object state, CancellationToken cancellationToken,
901 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
903 if (continuationAction == null)
904 throw new ArgumentNullException ("continuationAction");
905 if (scheduler == null)
906 throw new ArgumentNullException ("scheduler");
908 Task continuation = new Task (TaskActionInvoker.Create (continuationAction),
909 state, cancellationToken,
910 GetCreationOptions (continuationOptions),
913 ContinueWithCore (continuation, continuationOptions, scheduler);
920 public ConfiguredTaskAwaitable ConfigureAwait (bool continueOnCapturedContext)
922 return new ConfiguredTaskAwaitable (this, continueOnCapturedContext);
925 public Task ContinueWith (Action<Task, object> continuationAction, object state)
927 return ContinueWith (continuationAction, state, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current);
930 public Task ContinueWith (Action<Task, object> continuationAction, object state, CancellationToken cancellationToken)
932 return ContinueWith (continuationAction, state, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
935 public Task ContinueWith (Action<Task, object> continuationAction, object state, TaskContinuationOptions continuationOptions)
937 return ContinueWith (continuationAction, state, CancellationToken.None, continuationOptions, TaskScheduler.Current);
940 public Task ContinueWith (Action<Task, object> continuationAction, object state, TaskScheduler scheduler)
942 return ContinueWith (continuationAction, state, CancellationToken.None, TaskContinuationOptions.None, scheduler);
945 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state)
947 return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current);
950 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, TaskContinuationOptions continuationOptions)
952 return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, continuationOptions, TaskScheduler.Current);
955 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, CancellationToken cancellationToken)
957 return ContinueWith<TResult> (continuationFunction, state, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
960 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, TaskScheduler scheduler)
962 return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, TaskContinuationOptions.None, scheduler);
965 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, CancellationToken cancellationToken,
966 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
968 if (continuationFunction == null)
969 throw new ArgumentNullException ("continuationFunction");
970 if (scheduler == null)
971 throw new ArgumentNullException ("scheduler");
973 var t = new Task<TResult> (TaskActionInvoker.Create (continuationFunction),
976 GetCreationOptions (continuationOptions),
980 ContinueWithCore (t, continuationOptions, scheduler);
985 public static Task Delay (int millisecondsDelay)
987 return Delay (millisecondsDelay, CancellationToken.None);
990 public static Task Delay (TimeSpan delay)
992 return Delay (CheckTimeout (delay), CancellationToken.None);
995 public static Task Delay (TimeSpan delay, CancellationToken cancellationToken)
997 return Delay (CheckTimeout (delay), cancellationToken);
1000 public static Task Delay (int millisecondsDelay, CancellationToken cancellationToken)
1002 if (millisecondsDelay < -1)
1003 throw new ArgumentOutOfRangeException ("millisecondsDelay");
1005 if (cancellationToken.IsCancellationRequested)
1006 return TaskConstants.Canceled;
1008 var task = new Task (TaskActionInvoker.Empty, null, cancellationToken, TaskCreationOptions.None, null, null);
1009 task.SetupScheduler (TaskScheduler.Default);
1011 if (millisecondsDelay != Timeout.Infinite) {
1012 var timer = new Timer (delegate (object state) {
1013 var t = (Task) state;
1014 if (t.Status == TaskStatus.WaitingForActivation) {
1015 t.Status = TaskStatus.Running;
1018 }, task, millisecondsDelay, -1);
1020 task.ContinueWith (new DisposeContinuation (timer));
1026 public static Task<TResult> FromResult<TResult> (TResult result)
1028 var tcs = new TaskCompletionSource<TResult> ();
1029 tcs.SetResult (result);
1033 public TaskAwaiter GetAwaiter ()
1035 return new TaskAwaiter (this);
1038 public static Task Run (Action action)
1040 return Run (action, CancellationToken.None);
1043 public static Task Run (Action action, CancellationToken cancellationToken)
1045 if (cancellationToken.IsCancellationRequested)
1046 return TaskConstants.Canceled;
1048 return Task.Factory.StartNew (action, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
1051 public static Task Run (Func<Task> function)
1053 return Run (function, CancellationToken.None);
1056 public static Task Run (Func<Task> function, CancellationToken cancellationToken)
1058 if (cancellationToken.IsCancellationRequested)
1059 return TaskConstants.Canceled;
1061 return TaskExtensionsImpl.Unwrap (Task.Factory.StartNew (function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default));
1064 public static Task<TResult> Run<TResult> (Func<TResult> function)
1066 return Run (function, CancellationToken.None);
1069 public static Task<TResult> Run<TResult> (Func<TResult> function, CancellationToken cancellationToken)
1071 if (cancellationToken.IsCancellationRequested)
1072 return TaskConstants<TResult>.Canceled;
1074 return Task.Factory.StartNew (function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
1077 public static Task<TResult> Run<TResult> (Func<Task<TResult>> function)
1079 return Run (function, CancellationToken.None);
1082 public static Task<TResult> Run<TResult> (Func<Task<TResult>> function, CancellationToken cancellationToken)
1084 if (cancellationToken.IsCancellationRequested)
1085 return TaskConstants<TResult>.Canceled;
1087 return TaskExtensionsImpl.Unwrap (Task.Factory.StartNew (function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default));
1090 public static Task WhenAll (params Task[] tasks)
1093 throw new ArgumentNullException ("tasks");
1095 return WhenAllCore (tasks);
1098 public static Task WhenAll (IEnumerable<Task> tasks)
1101 throw new ArgumentNullException ("tasks");
1103 // Call ToList on input enumeration or we end up
1104 // enumerating it more than once
1105 return WhenAllCore (new List<Task> (tasks));
1108 public static Task<TResult[]> WhenAll<TResult> (params Task<TResult>[] tasks)
1111 throw new ArgumentNullException ("tasks");
1113 return WhenAllCore<TResult> (tasks);
1116 public static Task<TResult[]> WhenAll<TResult> (IEnumerable<Task<TResult>> tasks)
1119 throw new ArgumentNullException ("tasks");
1121 // Call ToList on input enumeration or we end up
1122 // enumerating it more than once
1123 return WhenAllCore<TResult> (new List<Task<TResult>> (tasks));
1126 internal static Task<TResult[]> WhenAllCore<TResult> (IList<Task<TResult>> tasks)
1128 if (tasks.Count == 0)
1129 return FromResult(new TResult[0]);
1131 foreach (var t in tasks) {
1133 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1136 var task = new Task<TResult[]> (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1137 task.SetupScheduler (TaskScheduler.Current);
1139 var continuation = new WhenAllContinuation<TResult> (task, tasks);
1140 foreach (var t in tasks)
1141 t.ContinueWith (continuation);
1146 public static Task<Task> WhenAny (params Task[] tasks)
1149 throw new ArgumentNullException ("tasks");
1151 return WhenAnyCore (tasks);
1154 public static Task<Task> WhenAny (IEnumerable<Task> tasks)
1157 throw new ArgumentNullException ("tasks");
1159 return WhenAnyCore (new List<Task> (tasks));
1162 public static Task<Task<TResult>> WhenAny<TResult> (params Task<TResult>[] tasks)
1165 throw new ArgumentNullException ("tasks");
1167 return WhenAnyCore<TResult> (tasks);
1170 public static Task<Task<TResult>> WhenAny<TResult> (IEnumerable<Task<TResult>> tasks)
1173 throw new ArgumentNullException ("tasks");
1175 return WhenAnyCore<TResult> (new List<Task<TResult>> (tasks));
1178 static Task<Task<TResult>> WhenAnyCore<TResult> (IList<Task<TResult>> tasks)
1180 if (tasks.Count == 0)
1181 throw new ArgumentException ("The tasks argument contains no tasks", "tasks");
1183 int completed_index = -1;
1184 for (int i = 0; i < tasks.Count; ++i) {
1187 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1189 if (t.IsCompleted && completed_index < 0)
1190 completed_index = i;
1193 var task = new Task<Task<TResult>> (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1195 if (completed_index > 0) {
1196 task.TrySetResult (tasks[completed_index]);
1200 task.SetupScheduler (TaskScheduler.Current);
1202 var continuation = new WhenAnyContinuation<Task<TResult>> (task, tasks);
1203 foreach (var t in tasks)
1204 t.ContinueWith (continuation);
1209 public static YieldAwaitable Yield ()
1211 return new YieldAwaitable ();
1215 internal static Task WhenAllCore (IList<Task> tasks)
1217 bool all_completed = true;
1218 foreach (var t in tasks) {
1220 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1222 all_completed &= t.Status == TaskStatus.RanToCompletion;
1226 return TaskConstants.Finished;
1228 var task = new Task (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1229 task.SetupScheduler (TaskScheduler.Current);
1231 var continuation = new WhenAllContinuation (task, tasks);
1232 foreach (var t in tasks)
1233 t.ContinueWith (continuation);
1238 internal static Task<Task> WhenAnyCore (IList<Task> tasks)
1240 if (tasks.Count == 0)
1241 throw new ArgumentException ("The tasks argument contains no tasks", "tasks");
1243 int completed_index = -1;
1244 for (int i = 0; i < tasks.Count; ++i) {
1247 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1249 if (t.IsCompleted && completed_index < 0)
1250 completed_index = i;
1253 var task = new Task<Task> (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1255 if (completed_index > 0) {
1256 task.TrySetResult (tasks[completed_index]);
1260 task.SetupScheduler (TaskScheduler.Current);
1262 var continuation = new WhenAnyContinuation<Task> (task, tasks);
1263 foreach (var t in tasks)
1264 t.ContinueWith (continuation);
1270 internal CancellationToken CancellationToken {
1276 public static TaskFactory Factory {
1278 return defaultFactory;
1282 public static int? CurrentId {
1285 return t == null ? (int?)null : t.Id;
1289 public AggregateException Exception {
1291 if (exSlot == null || !IsFaulted)
1293 exSlot.Observed = true;
1294 return exSlot.Exception;
1298 public bool IsCanceled {
1300 return status == TaskStatus.Canceled;
1304 public bool IsCompleted {
1306 return status >= TaskStatus.RanToCompletion;
1310 public bool IsFaulted {
1312 return status == TaskStatus.Faulted;
1316 public TaskCreationOptions CreationOptions {
1318 return creationOptions & MaxTaskCreationOptions;
1322 public TaskStatus Status {
1328 Thread.MemoryBarrier ();
1332 internal TaskExceptionSlot ExceptionSlot {
1336 Interlocked.CompareExchange (ref exSlot, new TaskExceptionSlot (this), null);
1341 public object AsyncState {
1347 bool IAsyncResult.CompletedSynchronously {
1353 WaitHandle IAsyncResult.AsyncWaitHandle {
1355 if (invoker == null)
1356 throw new ObjectDisposedException (GetType ().ToString ());
1358 if (wait_handle == null)
1359 Interlocked.CompareExchange (ref wait_handle, new ManualResetEvent (IsCompleted), null);
1371 bool IsContinuation {
1373 return contAncestor != null;
1379 return invoker == TaskActionInvoker.Promise;
1383 internal Task ContinuationAncestor {
1385 return contAncestor;
1389 internal string DisplayActionMethod {
1391 Delegate d = invoker.Action;
1392 return d == null ? "<none>" : d.Method.ToString ();