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;
81 internal const TaskCreationOptions WorkerTaskNotSupportedOptions = TaskCreationOptions.LongRunning | TaskCreationOptions.PreferFairness;
83 const TaskCreationOptions MaxTaskCreationOptions =
85 TaskCreationOptions.DenyChildAttach | TaskCreationOptions.HideScheduler |
87 TaskCreationOptions.PreferFairness | TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent;
89 public Task (Action action)
90 : this (action, TaskCreationOptions.None)
95 public Task (Action action, TaskCreationOptions creationOptions)
96 : this (action, CancellationToken.None, creationOptions)
101 public Task (Action action, CancellationToken cancellationToken)
102 : this (action, cancellationToken, TaskCreationOptions.None)
107 public Task (Action action, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
108 : this (TaskActionInvoker.Create (action), null, cancellationToken, creationOptions, current)
111 throw new ArgumentNullException ("action");
112 if (creationOptions > MaxTaskCreationOptions || creationOptions < TaskCreationOptions.None)
113 throw new ArgumentOutOfRangeException ("creationOptions");
116 public Task (Action<object> action, object state)
117 : this (action, state, TaskCreationOptions.None)
121 public Task (Action<object> action, object state, TaskCreationOptions creationOptions)
122 : this (action, state, CancellationToken.None, creationOptions)
126 public Task (Action<object> action, object state, CancellationToken cancellationToken)
127 : this (action, state, cancellationToken, TaskCreationOptions.None)
131 public Task (Action<object> action, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
132 : this (TaskActionInvoker.Create (action), state, cancellationToken, creationOptions, current)
135 throw new ArgumentNullException ("action");
136 if (creationOptions > MaxTaskCreationOptions || creationOptions < TaskCreationOptions.None)
137 throw new ArgumentOutOfRangeException ("creationOptions");
140 internal Task (TaskActionInvoker invoker, object state, CancellationToken cancellationToken,
141 TaskCreationOptions creationOptions, Task parent = null, Task contAncestor = null, bool ignoreCancellation = false)
143 this.invoker = invoker;
144 this.creationOptions = creationOptions;
146 this.taskId = Interlocked.Increment (ref id);
147 this.token = cancellationToken;
148 this.parent = parent = parent == null ? current : parent;
149 this.contAncestor = contAncestor;
150 this.status = cancellationToken.IsCancellationRequested && !ignoreCancellation ? TaskStatus.Canceled : TaskStatus.Created;
152 // Process creationOptions
154 if (parent != null && HasFlag (creationOptions, TaskCreationOptions.AttachedToParent)
155 && !HasFlag (parent.CreationOptions, TaskCreationOptions.DenyChildAttach))
157 if (parent != null && HasFlag (creationOptions, TaskCreationOptions.AttachedToParent))
161 if (token.CanBeCanceled && !ignoreCancellation)
162 cancellationRegistration = token.Register (l => ((Task) l).CancelReal (), this);
164 ec = ExecutionContext.Capture (false, true);
167 static bool HasFlag (TaskCreationOptions opt, TaskCreationOptions member)
169 return (opt & member) == member;
175 Start (TaskScheduler.Current);
178 public void Start (TaskScheduler scheduler)
180 if (scheduler == null)
181 throw new ArgumentNullException ("scheduler");
183 if (status >= TaskStatus.WaitingToRun)
184 throw new InvalidOperationException ("The Task is not in a valid state to be started.");
187 throw new InvalidOperationException ("Start may not be called on a continuation task");
190 throw new InvalidOperationException ("Start may not be called on a promise-style task");
192 SetupScheduler (scheduler);
196 internal void SetupScheduler (TaskScheduler scheduler)
198 this.scheduler = scheduler;
199 Status = TaskStatus.WaitingForActivation;
202 public void RunSynchronously ()
204 RunSynchronously (TaskScheduler.Current);
207 public void RunSynchronously (TaskScheduler scheduler)
209 if (scheduler == null)
210 throw new ArgumentNullException ("scheduler");
212 if (Status > TaskStatus.WaitingForActivation)
213 throw new InvalidOperationException ("The task is not in a valid state to be started");
216 throw new InvalidOperationException ("RunSynchronously may not be called on a continuation task");
219 throw new InvalidOperationException ("RunSynchronously may not be called on a promise-style task");
221 RunSynchronouslyCore (scheduler, true);
224 internal void RunSynchronouslyCore (TaskScheduler scheduler, bool throwException)
226 SetupScheduler (scheduler);
227 Status = TaskStatus.WaitingToRun;
230 if (scheduler.RunInline (this, false))
232 } catch (Exception inner) {
233 var ex = new TaskSchedulerException (inner);
234 TrySetException (new AggregateException (ex), false, true);
241 Schedule (throwException);
242 WaitCore (Timeout.Infinite, CancellationToken.None, false);
247 public Task ContinueWith (Action<Task> continuationAction)
249 return ContinueWith (continuationAction, TaskContinuationOptions.None);
252 public Task ContinueWith (Action<Task> continuationAction, TaskContinuationOptions continuationOptions)
254 return ContinueWith (continuationAction, CancellationToken.None, continuationOptions, TaskScheduler.Current);
257 public Task ContinueWith (Action<Task> continuationAction, CancellationToken cancellationToken)
259 return ContinueWith (continuationAction, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
262 public Task ContinueWith (Action<Task> continuationAction, TaskScheduler scheduler)
264 return ContinueWith (continuationAction, CancellationToken.None, TaskContinuationOptions.None, scheduler);
267 public Task ContinueWith (Action<Task> continuationAction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
269 if (continuationAction == null)
270 throw new ArgumentNullException ("continuationAction");
271 if (scheduler == null)
272 throw new ArgumentNullException ("scheduler");
274 return ContinueWith (TaskActionInvoker.Create (continuationAction), cancellationToken, continuationOptions, scheduler);
277 internal Task ContinueWith (TaskActionInvoker invoker, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
279 var lazyCancellation = false;
281 lazyCancellation = (continuationOptions & TaskContinuationOptions.LazyCancellation) > 0;
283 var continuation = new Task (invoker, null, cancellationToken, GetCreationOptions (continuationOptions), null, this, lazyCancellation);
284 ContinueWithCore (continuation, continuationOptions, scheduler);
289 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction)
291 return ContinueWith<TResult> (continuationFunction, TaskContinuationOptions.None);
294 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, TaskContinuationOptions continuationOptions)
296 return ContinueWith<TResult> (continuationFunction, CancellationToken.None, continuationOptions, TaskScheduler.Current);
299 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, CancellationToken cancellationToken)
301 return ContinueWith<TResult> (continuationFunction, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
304 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, TaskScheduler scheduler)
306 return ContinueWith<TResult> (continuationFunction, CancellationToken.None, TaskContinuationOptions.None, scheduler);
309 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, CancellationToken cancellationToken,
310 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
312 if (continuationFunction == null)
313 throw new ArgumentNullException ("continuationFunction");
314 if (scheduler == null)
315 throw new ArgumentNullException ("scheduler");
317 return ContinueWith<TResult> (TaskActionInvoker.Create (continuationFunction), cancellationToken, continuationOptions, scheduler);
320 internal Task<TResult> ContinueWith<TResult> (TaskActionInvoker invoker, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
322 var lazyCancellation = false;
324 lazyCancellation = (continuationOptions & TaskContinuationOptions.LazyCancellation) > 0;
326 var continuation = new Task<TResult> (invoker, null, cancellationToken, GetCreationOptions (continuationOptions), parent, this, lazyCancellation);
327 ContinueWithCore (continuation, continuationOptions, scheduler);
332 internal void ContinueWithCore (Task continuation, TaskContinuationOptions options, TaskScheduler scheduler)
334 const TaskContinuationOptions wrongRan = TaskContinuationOptions.NotOnRanToCompletion | TaskContinuationOptions.OnlyOnRanToCompletion;
335 const TaskContinuationOptions wrongCanceled = TaskContinuationOptions.NotOnCanceled | TaskContinuationOptions.OnlyOnCanceled;
336 const TaskContinuationOptions wrongFaulted = TaskContinuationOptions.NotOnFaulted | TaskContinuationOptions.OnlyOnFaulted;
338 if (((options & wrongRan) == wrongRan) || ((options & wrongCanceled) == wrongCanceled) || ((options & wrongFaulted) == wrongFaulted))
339 throw new ArgumentException ("continuationOptions", "Some options are mutually exclusive");
341 // Already set the scheduler so that user can call Wait and that sort of stuff
342 continuation.scheduler = scheduler;
343 continuation.Status = TaskStatus.WaitingForActivation;
345 ContinueWith (new TaskContinuation (continuation, options));
348 internal bool ContinueWith (IContinuation continuation, bool canExecuteInline = true)
351 if (!canExecuteInline)
354 continuation.Execute ();
358 continuations.Add (continuation);
360 // Retry in case completion was achieved but event adding was too late
361 if (IsCompleted && continuations.Remove (continuation)) {
362 if (!canExecuteInline)
365 continuation.Execute ();
371 internal void RemoveContinuation (IContinuation continuation)
373 continuations.Remove (continuation);
376 static internal TaskCreationOptions GetCreationOptions (TaskContinuationOptions kind)
378 TaskCreationOptions options = TaskCreationOptions.None;
379 if ((kind & TaskContinuationOptions.AttachedToParent) > 0)
380 options |= TaskCreationOptions.AttachedToParent;
381 if ((kind & TaskContinuationOptions.PreferFairness) > 0)
382 options |= TaskCreationOptions.PreferFairness;
383 if ((kind & TaskContinuationOptions.LongRunning) > 0)
384 options |= TaskCreationOptions.LongRunning;
390 #region Internal and protected thingies
391 internal void Schedule (bool throwException)
393 Status = TaskStatus.WaitingToRun;
395 scheduler.QueueTask (this);
396 } catch (Exception inner) {
397 var ex = new TaskSchedulerException (inner);
398 TrySetException (new AggregateException (ex), false, true);
406 /* Allow scheduler to break fairness of deque ordering without
407 * breaking its semantic (the task can be executed twice but the
408 * second time it will return immediately
410 if (!executing.TryRelaxedSet ())
413 // Disable CancellationToken direct cancellation
414 if (cancellationRegistration != null) {
415 cancellationRegistration.Value.Dispose ();
416 cancellationRegistration = null;
419 // If Task are ran inline on the same thread we might trash these values
420 var saveCurrent = current;
421 var saveScheduler = TaskScheduler.Current;
425 TaskScheduler.Current = HasFlag (creationOptions, TaskCreationOptions.HideScheduler) ? TaskScheduler.Default : scheduler;
427 TaskScheduler.Current = scheduler;
430 if (!token.IsCancellationRequested) {
432 status = TaskStatus.Running;
436 ExecutionContext.Run (ec, l => ((Task) l).InnerInvoke (), this);
439 } catch (OperationCanceledException oce) {
440 if (token != CancellationToken.None && oce.CancellationToken == token)
443 HandleGenericException (oce);
444 } catch (Exception e) {
445 HandleGenericException (e);
451 if (saveCurrent != null)
452 current = saveCurrent;
453 if (saveScheduler != null)
454 TaskScheduler.Current = saveScheduler;
458 internal bool TrySetCanceled ()
463 if (!executing.TryRelaxedSet ()) {
464 var sw = new SpinWait ();
475 internal bool TrySetException (AggregateException aggregate, bool cancellation, bool observed)
480 if (!executing.TryRelaxedSet ()) {
481 var sw = new SpinWait ();
489 ExceptionSlot.SetException (aggregate);
492 HandleGenericException (aggregate);
496 exSlot.Observed = true;
501 internal bool TrySetExceptionObserved ()
503 if (exSlot != null) {
504 exSlot.Observed = true;
510 internal void Execute ()
515 internal void AddChild ()
517 if (childTasks == null)
518 Interlocked.CompareExchange (ref childTasks, new CountdownEvent (1), null);
519 childTasks.AddCount ();
522 internal void ChildCompleted (AggregateException childEx)
524 if (childEx != null) {
525 if (ExceptionSlot.ChildExceptions == null)
526 Interlocked.CompareExchange (ref ExceptionSlot.ChildExceptions, new ConcurrentQueue<AggregateException> (), null);
527 ExceptionSlot.ChildExceptions.Enqueue (childEx);
530 if (childTasks.Signal () && status == TaskStatus.WaitingForChildrenToComplete) {
531 ProcessChildExceptions ();
532 Status = exSlot == null ? TaskStatus.RanToCompletion : TaskStatus.Faulted;
533 ProcessCompleteDelegates ();
534 if (parent != null && NotifyParentOnFinish ())
541 if (IsContinuation) {
542 var ancestor = contAncestor;
544 invoker.Invoke (ancestor, state, this);
546 invoker.Invoke (this, state, this);
550 internal void Finish ()
552 // If there was children created and they all finished, we set the countdown
553 if (childTasks != null) {
554 if (childTasks.Signal ())
555 ProcessChildExceptions (true);
558 // Don't override Canceled or Faulted
559 if (status == TaskStatus.Running) {
560 if (childTasks == null || childTasks.IsSet)
561 Status = TaskStatus.RanToCompletion;
563 Status = TaskStatus.WaitingForChildrenToComplete;
566 if (wait_handle != null)
569 // Tell parent that we are finished
570 if (parent != null && NotifyParentOnFinish ()) {
572 // Break the reference back to the parent, otherwise any Tasks created from another Task's thread of
573 // execution will create an undesired linked-list that the GC cannot free. See bug #18398.
578 // Completions are already processed when task is canceled or faulted
579 if (status == TaskStatus.RanToCompletion)
580 ProcessCompleteDelegates ();
582 // Reset the current thingies
585 if (TaskScheduler.Current == scheduler)
586 TaskScheduler.Current = null;
588 if (cancellationRegistration.HasValue)
589 cancellationRegistration.Value.Dispose ();
592 bool NotifyParentOnFinish ()
594 if (!HasFlag (creationOptions, TaskCreationOptions.AttachedToParent))
597 if (HasFlag (parent.CreationOptions, TaskCreationOptions.DenyChildAttach))
600 if (status != TaskStatus.WaitingForChildrenToComplete)
601 parent.ChildCompleted (Exception);
606 void ProcessCompleteDelegates ()
608 if (continuations.HasElements) {
609 IContinuation continuation;
610 while (continuations.TryGetNextCompletion (out continuation))
611 continuation.Execute ();
615 void ProcessChildExceptions (bool isParent = false)
617 if (exSlot == null || exSlot.ChildExceptions == null)
620 var exceptions = new List<Exception> ();
621 if (exSlot.Exception != null)
622 exceptions.AddRange (exSlot.Exception.InnerExceptions);
624 AggregateException childEx;
625 while (exSlot.ChildExceptions.TryDequeue (out childEx))
626 exceptions.Add (childEx);
628 exSlot.SetException (new AggregateException (exceptions));
631 Status = TaskStatus.Faulted;
632 ProcessCompleteDelegates ();
637 #region Cancel and Wait related method
639 internal void CancelReal (bool notifyParent = false)
641 Status = TaskStatus.Canceled;
643 if (wait_handle != null)
646 ProcessCompleteDelegates ();
648 if (notifyParent && parent != null && NotifyParentOnFinish ())
652 void HandleGenericException (Exception e)
654 HandleGenericException (new AggregateException (e));
657 void HandleGenericException (AggregateException e)
659 ExceptionSlot.SetException (e);
660 Thread.MemoryBarrier ();
661 Status = TaskStatus.Faulted;
663 if (wait_handle != null)
666 ProcessCompleteDelegates ();
669 internal bool WaitOnChildren ()
671 if (Status == TaskStatus.WaitingForChildrenToComplete && childTasks != null) {
680 Wait (Timeout.Infinite, CancellationToken.None);
683 public void Wait (CancellationToken cancellationToken)
685 Wait (Timeout.Infinite, cancellationToken);
688 public bool Wait (TimeSpan timeout)
690 return Wait (CheckTimeout (timeout), CancellationToken.None);
693 public bool Wait (int millisecondsTimeout)
695 return Wait (millisecondsTimeout, CancellationToken.None);
698 public bool Wait (int millisecondsTimeout, CancellationToken cancellationToken)
700 if (millisecondsTimeout < -1)
701 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
703 bool result = WaitCore (millisecondsTimeout, cancellationToken, true);
706 throw new AggregateException (new TaskCanceledException (this));
708 var exception = Exception;
709 if (exception != null)
715 internal bool WaitCore (int millisecondsTimeout, CancellationToken cancellationToken, bool runInline)
720 // If the task is ready to be run and we were supposed to wait on it indefinitely without cancellation, just run it
721 if (runInline && Status == TaskStatus.WaitingToRun && millisecondsTimeout == Timeout.Infinite && scheduler != null && !cancellationToken.CanBeCanceled) {
723 scheduler.RunInline (this, true);
724 } catch (Exception e) {
725 throw new TaskSchedulerException (e);
732 var continuation = new ManualResetContinuation ();
734 ContinueWith (continuation);
735 result = continuation.Event.Wait (millisecondsTimeout, cancellationToken);
738 RemoveContinuation (continuation);
739 continuation.Dispose ();
746 public static void WaitAll (params Task[] tasks)
748 WaitAll (tasks, Timeout.Infinite, CancellationToken.None);
751 public static void WaitAll (Task[] tasks, CancellationToken cancellationToken)
753 WaitAll (tasks, Timeout.Infinite, cancellationToken);
756 public static bool WaitAll (Task[] tasks, TimeSpan timeout)
758 return WaitAll (tasks, CheckTimeout (timeout), CancellationToken.None);
761 public static bool WaitAll (Task[] tasks, int millisecondsTimeout)
763 return WaitAll (tasks, millisecondsTimeout, CancellationToken.None);
766 public static bool WaitAll (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
769 throw new ArgumentNullException ("tasks");
772 foreach (var t in tasks) {
774 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
776 result &= t.Status == TaskStatus.RanToCompletion;
780 var continuation = new CountdownContinuation (tasks.Length);
782 foreach (var t in tasks)
783 t.ContinueWith (continuation);
785 result = continuation.Event.Wait (millisecondsTimeout, cancellationToken);
787 List<Exception> exceptions = null;
789 foreach (var t in tasks) {
791 if (t.Status == TaskStatus.RanToCompletion)
793 if (exceptions == null)
794 exceptions = new List<Exception> ();
795 if (t.Exception != null)
796 exceptions.AddRange (t.Exception.InnerExceptions);
798 exceptions.Add (new TaskCanceledException (t));
800 t.RemoveContinuation (continuation);
804 continuation.Dispose ();
806 if (exceptions != null)
807 throw new AggregateException (exceptions);
814 public static int WaitAny (params Task[] tasks)
816 return WaitAny (tasks, Timeout.Infinite, CancellationToken.None);
819 public static int WaitAny (Task[] tasks, TimeSpan timeout)
821 return WaitAny (tasks, CheckTimeout (timeout));
824 public static int WaitAny (Task[] tasks, int millisecondsTimeout)
826 return WaitAny (tasks, millisecondsTimeout, CancellationToken.None);
829 public static int WaitAny (Task[] tasks, CancellationToken cancellationToken)
831 return WaitAny (tasks, Timeout.Infinite, cancellationToken);
834 public static int WaitAny (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
837 throw new ArgumentNullException ("tasks");
838 if (millisecondsTimeout < -1)
839 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
840 CheckForNullTasks (tasks);
842 if (tasks.Length > 0) {
843 var continuation = new ManualResetContinuation ();
846 for (int i = 0; i < tasks.Length; i++) {
850 t.ContinueWith (continuation);
853 if (!(result = continuation.Event.Wait (millisecondsTimeout, cancellationToken)))
857 foreach (var t in tasks)
858 t.RemoveContinuation (continuation);
859 continuation.Dispose ();
863 int firstFinished = -1;
864 for (int i = 0; i < tasks.Length; i++) {
872 return firstFinished;
875 static int CheckTimeout (TimeSpan timeout)
878 return checked ((int)timeout.TotalMilliseconds);
879 } catch (System.OverflowException) {
880 throw new ArgumentOutOfRangeException ("timeout");
884 static void CheckForNullTasks (Task[] tasks)
886 foreach (var t in tasks)
888 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
893 public void Dispose ()
898 protected virtual void Dispose (bool disposing)
901 throw new InvalidOperationException ("A task may only be disposed if it is in a completion state");
903 // Set action to null so that the GC can collect the delegate and thus
904 // any big object references that the user might have captured in a anonymous method
909 if (cancellationRegistration != null)
910 cancellationRegistration.Value.Dispose ();
911 if (wait_handle != null)
912 wait_handle.Dispose ();
922 Task ContinueWith (Action<Task, object> continuationAction, object state, CancellationToken cancellationToken,
923 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
925 if (continuationAction == null)
926 throw new ArgumentNullException ("continuationAction");
927 if (scheduler == null)
928 throw new ArgumentNullException ("scheduler");
930 Task continuation = new Task (TaskActionInvoker.Create (continuationAction),
931 state, cancellationToken,
932 GetCreationOptions (continuationOptions),
935 ContinueWithCore (continuation, continuationOptions, scheduler);
942 public ConfiguredTaskAwaitable ConfigureAwait (bool continueOnCapturedContext)
944 return new ConfiguredTaskAwaitable (this, continueOnCapturedContext);
947 public Task ContinueWith (Action<Task, object> continuationAction, object state)
949 return ContinueWith (continuationAction, state, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current);
952 public Task ContinueWith (Action<Task, object> continuationAction, object state, CancellationToken cancellationToken)
954 return ContinueWith (continuationAction, state, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
957 public Task ContinueWith (Action<Task, object> continuationAction, object state, TaskContinuationOptions continuationOptions)
959 return ContinueWith (continuationAction, state, CancellationToken.None, continuationOptions, TaskScheduler.Current);
962 public Task ContinueWith (Action<Task, object> continuationAction, object state, TaskScheduler scheduler)
964 return ContinueWith (continuationAction, state, CancellationToken.None, TaskContinuationOptions.None, scheduler);
967 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state)
969 return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current);
972 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, TaskContinuationOptions continuationOptions)
974 return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, continuationOptions, TaskScheduler.Current);
977 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, CancellationToken cancellationToken)
979 return ContinueWith<TResult> (continuationFunction, state, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
982 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, TaskScheduler scheduler)
984 return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, TaskContinuationOptions.None, scheduler);
987 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, CancellationToken cancellationToken,
988 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
990 if (continuationFunction == null)
991 throw new ArgumentNullException ("continuationFunction");
992 if (scheduler == null)
993 throw new ArgumentNullException ("scheduler");
995 var t = new Task<TResult> (TaskActionInvoker.Create (continuationFunction),
998 GetCreationOptions (continuationOptions),
1002 ContinueWithCore (t, continuationOptions, scheduler);
1007 public static Task Delay (int millisecondsDelay)
1009 return Delay (millisecondsDelay, CancellationToken.None);
1012 public static Task Delay (TimeSpan delay)
1014 return Delay (CheckTimeout (delay), CancellationToken.None);
1017 public static Task Delay (TimeSpan delay, CancellationToken cancellationToken)
1019 return Delay (CheckTimeout (delay), cancellationToken);
1022 public static Task Delay (int millisecondsDelay, CancellationToken cancellationToken)
1024 if (millisecondsDelay < -1)
1025 throw new ArgumentOutOfRangeException ("millisecondsDelay");
1027 if (cancellationToken.IsCancellationRequested)
1028 return TaskConstants.Canceled;
1030 var task = new Task (TaskActionInvoker.Empty, null, cancellationToken, TaskCreationOptions.None, null, null);
1031 task.SetupScheduler (TaskScheduler.Default);
1033 if (millisecondsDelay != Timeout.Infinite) {
1034 var timer = new Timer (delegate (object state) {
1035 var t = (Task) state;
1036 if (t.Status == TaskStatus.WaitingForActivation) {
1037 t.Status = TaskStatus.Running;
1040 }, task, millisecondsDelay, -1);
1042 task.ContinueWith (new DisposeContinuation (timer));
1048 public static Task<TResult> FromResult<TResult> (TResult result)
1050 var tcs = new TaskCompletionSource<TResult> ();
1051 tcs.SetResult (result);
1055 public TaskAwaiter GetAwaiter ()
1057 return new TaskAwaiter (this);
1060 public static Task Run (Action action)
1062 return Run (action, CancellationToken.None);
1065 public static Task Run (Action action, CancellationToken cancellationToken)
1067 if (cancellationToken.IsCancellationRequested)
1068 return TaskConstants.Canceled;
1070 return Task.Factory.StartNew (action, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
1073 public static Task Run (Func<Task> function)
1075 return Run (function, CancellationToken.None);
1078 public static Task Run (Func<Task> function, CancellationToken cancellationToken)
1080 if (cancellationToken.IsCancellationRequested)
1081 return TaskConstants.Canceled;
1083 return TaskExtensionsImpl.Unwrap (Task.Factory.StartNew (function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default));
1086 public static Task<TResult> Run<TResult> (Func<TResult> function)
1088 return Run (function, CancellationToken.None);
1091 public static Task<TResult> Run<TResult> (Func<TResult> function, CancellationToken cancellationToken)
1093 if (cancellationToken.IsCancellationRequested)
1094 return TaskConstants<TResult>.Canceled;
1096 return Task.Factory.StartNew (function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
1099 public static Task<TResult> Run<TResult> (Func<Task<TResult>> function)
1101 return Run (function, CancellationToken.None);
1104 public static Task<TResult> Run<TResult> (Func<Task<TResult>> function, CancellationToken cancellationToken)
1106 if (cancellationToken.IsCancellationRequested)
1107 return TaskConstants<TResult>.Canceled;
1109 return TaskExtensionsImpl.Unwrap (Task.Factory.StartNew (function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default));
1112 public static Task WhenAll (params Task[] tasks)
1115 throw new ArgumentNullException ("tasks");
1117 return WhenAllCore (tasks);
1120 public static Task WhenAll (IEnumerable<Task> tasks)
1123 throw new ArgumentNullException ("tasks");
1125 // Call ToList on input enumeration or we end up
1126 // enumerating it more than once
1127 return WhenAllCore (new List<Task> (tasks));
1130 public static Task<TResult[]> WhenAll<TResult> (params Task<TResult>[] tasks)
1133 throw new ArgumentNullException ("tasks");
1135 return WhenAllCore<TResult> (tasks);
1138 public static Task<TResult[]> WhenAll<TResult> (IEnumerable<Task<TResult>> tasks)
1141 throw new ArgumentNullException ("tasks");
1143 // Call ToList on input enumeration or we end up
1144 // enumerating it more than once
1145 return WhenAllCore<TResult> (new List<Task<TResult>> (tasks));
1148 internal static Task<TResult[]> WhenAllCore<TResult> (IList<Task<TResult>> tasks)
1150 if (tasks.Count == 0)
1151 return FromResult(new TResult[0]);
1153 foreach (var t in tasks) {
1155 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1158 var task = new Task<TResult[]> (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1159 task.SetupScheduler (TaskScheduler.Current);
1161 var continuation = new WhenAllContinuation<TResult> (task, tasks);
1162 foreach (var t in tasks)
1163 t.ContinueWith (continuation);
1168 public static Task<Task> WhenAny (params Task[] tasks)
1171 throw new ArgumentNullException ("tasks");
1173 return WhenAnyCore (tasks);
1176 public static Task<Task> WhenAny (IEnumerable<Task> tasks)
1179 throw new ArgumentNullException ("tasks");
1181 return WhenAnyCore (new List<Task> (tasks));
1184 public static Task<Task<TResult>> WhenAny<TResult> (params Task<TResult>[] tasks)
1187 throw new ArgumentNullException ("tasks");
1189 return WhenAnyCore<TResult> (tasks);
1192 public static Task<Task<TResult>> WhenAny<TResult> (IEnumerable<Task<TResult>> tasks)
1195 throw new ArgumentNullException ("tasks");
1197 return WhenAnyCore<TResult> (new List<Task<TResult>> (tasks));
1200 static Task<Task<TResult>> WhenAnyCore<TResult> (IList<Task<TResult>> tasks)
1202 if (tasks.Count == 0)
1203 throw new ArgumentException ("The tasks argument contains no tasks", "tasks");
1205 int completed_index = -1;
1206 for (int i = 0; i < tasks.Count; ++i) {
1209 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1211 if (t.IsCompleted && completed_index < 0)
1212 completed_index = i;
1215 var task = new Task<Task<TResult>> (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1217 if (completed_index > 0) {
1218 task.TrySetResult (tasks[completed_index]);
1222 task.SetupScheduler (TaskScheduler.Current);
1224 var continuation = new WhenAnyContinuation<Task<TResult>> (task, tasks);
1225 foreach (var t in tasks)
1226 t.ContinueWith (continuation);
1231 public static YieldAwaitable Yield ()
1233 return new YieldAwaitable ();
1237 internal static Task WhenAllCore (IList<Task> tasks)
1239 bool all_completed = true;
1240 foreach (var t in tasks) {
1242 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1244 all_completed &= t.Status == TaskStatus.RanToCompletion;
1248 return TaskConstants.Finished;
1250 var task = new Task (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1251 task.SetupScheduler (TaskScheduler.Current);
1253 var continuation = new WhenAllContinuation (task, tasks);
1254 foreach (var t in tasks)
1255 t.ContinueWith (continuation);
1260 internal static Task<Task> WhenAnyCore (IList<Task> tasks)
1262 if (tasks.Count == 0)
1263 throw new ArgumentException ("The tasks argument contains no tasks", "tasks");
1265 int completed_index = -1;
1266 for (int i = 0; i < tasks.Count; ++i) {
1269 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1271 if (t.IsCompleted && completed_index < 0)
1272 completed_index = i;
1275 var task = new Task<Task> (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1277 if (completed_index > 0) {
1278 task.TrySetResult (tasks[completed_index]);
1282 task.SetupScheduler (TaskScheduler.Current);
1284 var continuation = new WhenAnyContinuation<Task> (task, tasks);
1285 foreach (var t in tasks)
1286 t.ContinueWith (continuation);
1292 internal CancellationToken CancellationToken {
1298 public static TaskFactory Factory {
1300 return defaultFactory;
1304 public static int? CurrentId {
1307 return t == null ? (int?)null : t.Id;
1311 public AggregateException Exception {
1313 if (exSlot == null || !IsFaulted)
1315 exSlot.Observed = true;
1316 return exSlot.Exception;
1320 public bool IsCanceled {
1322 return status == TaskStatus.Canceled;
1326 public bool IsCompleted {
1328 return status >= TaskStatus.RanToCompletion;
1332 public bool IsFaulted {
1334 return status == TaskStatus.Faulted;
1338 public TaskCreationOptions CreationOptions {
1340 return creationOptions & MaxTaskCreationOptions;
1344 public TaskStatus Status {
1350 Thread.MemoryBarrier ();
1354 internal TaskExceptionSlot ExceptionSlot {
1358 Interlocked.CompareExchange (ref exSlot, new TaskExceptionSlot (this), null);
1363 public object AsyncState {
1369 bool IAsyncResult.CompletedSynchronously {
1375 WaitHandle IAsyncResult.AsyncWaitHandle {
1377 if (invoker == null)
1378 throw new ObjectDisposedException (GetType ().ToString ());
1380 if (wait_handle == null)
1381 Interlocked.CompareExchange (ref wait_handle, new ManualResetEvent (IsCompleted), null);
1393 bool IsContinuation {
1395 return contAncestor != null;
1401 return invoker == TaskActionInvoker.Promise;
1405 internal Task ContinuationAncestor {
1407 return contAncestor;
1411 internal string DisplayActionMethod {
1413 Delegate d = invoker.Action;
1414 return d == null ? "<none>" : d.Method.ToString ();