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 static Action<Task> childWorkAdder;
52 // parent is the outer task in which this task is created
54 // contAncestor is the Task on which this continuation was setup
55 readonly Task contAncestor;
58 static readonly TaskFactory defaultFactory = new TaskFactory ();
60 CountdownEvent childTasks;
63 TaskCreationOptions creationOptions;
65 internal TaskScheduler scheduler;
67 TaskExceptionSlot exSlot;
68 ManualResetEvent wait_handle;
72 TaskActionInvoker invoker;
74 internal AtomicBooleanValue executing;
76 TaskCompletionQueue<IContinuation> continuations;
78 CancellationToken token;
79 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);
165 static bool HasFlag (TaskCreationOptions opt, TaskCreationOptions member)
167 return (opt & member) == member;
173 Start (TaskScheduler.Current);
176 public void Start (TaskScheduler scheduler)
178 if (scheduler == null)
179 throw new ArgumentNullException ("scheduler");
181 if (status >= TaskStatus.WaitingToRun)
182 throw new InvalidOperationException ("The Task is not in a valid state to be started.");
185 throw new InvalidOperationException ("Start may not be called on a continuation task");
187 SetupScheduler (scheduler);
191 internal void SetupScheduler (TaskScheduler scheduler)
193 this.scheduler = scheduler;
194 Status = TaskStatus.WaitingForActivation;
197 public void RunSynchronously ()
199 RunSynchronously (TaskScheduler.Current);
202 public void RunSynchronously (TaskScheduler scheduler)
204 if (scheduler == null)
205 throw new ArgumentNullException ("scheduler");
207 if (Status > TaskStatus.WaitingForActivation)
208 throw new InvalidOperationException ("The task is not in a valid state to be started");
211 throw new InvalidOperationException ("RunSynchronously may not be called on a continuation task");
213 RunSynchronouslyCore (scheduler);
216 internal void RunSynchronouslyCore (TaskScheduler scheduler)
218 SetupScheduler (scheduler);
219 var saveStatus = status;
220 Status = TaskStatus.WaitingToRun;
223 if (scheduler.RunInline (this, false))
225 } catch (Exception inner) {
226 throw new TaskSchedulerException (inner);
236 public Task ContinueWith (Action<Task> continuationAction)
238 return ContinueWith (continuationAction, TaskContinuationOptions.None);
241 public Task ContinueWith (Action<Task> continuationAction, TaskContinuationOptions continuationOptions)
243 return ContinueWith (continuationAction, CancellationToken.None, continuationOptions, TaskScheduler.Current);
246 public Task ContinueWith (Action<Task> continuationAction, CancellationToken cancellationToken)
248 return ContinueWith (continuationAction, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
251 public Task ContinueWith (Action<Task> continuationAction, TaskScheduler scheduler)
253 return ContinueWith (continuationAction, CancellationToken.None, TaskContinuationOptions.None, scheduler);
256 public Task ContinueWith (Action<Task> continuationAction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
258 if (continuationAction == null)
259 throw new ArgumentNullException ("continuationAction");
260 if (scheduler == null)
261 throw new ArgumentNullException ("scheduler");
263 return ContinueWith (TaskActionInvoker.Create (continuationAction), cancellationToken, continuationOptions, scheduler);
266 internal Task ContinueWith (TaskActionInvoker invoker, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
268 var lazyCancellation = false;
270 lazyCancellation = (continuationOptions & TaskContinuationOptions.LazyCancellation) > 0;
272 var continuation = new Task (invoker, null, cancellationToken, GetCreationOptions (continuationOptions), null, this, lazyCancellation);
273 ContinueWithCore (continuation, continuationOptions, scheduler);
278 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction)
280 return ContinueWith<TResult> (continuationFunction, TaskContinuationOptions.None);
283 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, TaskContinuationOptions continuationOptions)
285 return ContinueWith<TResult> (continuationFunction, CancellationToken.None, continuationOptions, TaskScheduler.Current);
288 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, CancellationToken cancellationToken)
290 return ContinueWith<TResult> (continuationFunction, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
293 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, TaskScheduler scheduler)
295 return ContinueWith<TResult> (continuationFunction, CancellationToken.None, TaskContinuationOptions.None, scheduler);
298 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, CancellationToken cancellationToken,
299 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
301 if (continuationFunction == null)
302 throw new ArgumentNullException ("continuationFunction");
303 if (scheduler == null)
304 throw new ArgumentNullException ("scheduler");
306 return ContinueWith<TResult> (TaskActionInvoker.Create (continuationFunction), cancellationToken, continuationOptions, scheduler);
309 internal Task<TResult> ContinueWith<TResult> (TaskActionInvoker invoker, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
311 var lazyCancellation = false;
313 lazyCancellation = (continuationOptions & TaskContinuationOptions.LazyCancellation) > 0;
315 var continuation = new Task<TResult> (invoker, null, cancellationToken, GetCreationOptions (continuationOptions), parent, this, lazyCancellation);
316 ContinueWithCore (continuation, continuationOptions, scheduler);
321 internal void ContinueWithCore (Task continuation, TaskContinuationOptions options, TaskScheduler scheduler)
323 const TaskContinuationOptions wrongRan = TaskContinuationOptions.NotOnRanToCompletion | TaskContinuationOptions.OnlyOnRanToCompletion;
324 const TaskContinuationOptions wrongCanceled = TaskContinuationOptions.NotOnCanceled | TaskContinuationOptions.OnlyOnCanceled;
325 const TaskContinuationOptions wrongFaulted = TaskContinuationOptions.NotOnFaulted | TaskContinuationOptions.OnlyOnFaulted;
327 if (((options & wrongRan) == wrongRan) || ((options & wrongCanceled) == wrongCanceled) || ((options & wrongFaulted) == wrongFaulted))
328 throw new ArgumentException ("continuationOptions", "Some options are mutually exclusive");
330 // Already set the scheduler so that user can call Wait and that sort of stuff
331 continuation.scheduler = scheduler;
332 continuation.Status = TaskStatus.WaitingForActivation;
334 ContinueWith (new TaskContinuation (continuation, options));
337 internal void ContinueWith (IContinuation continuation)
340 continuation.Execute ();
344 continuations.Add (continuation);
346 // Retry in case completion was achieved but event adding was too late
347 if (IsCompleted && continuations.Remove (continuation))
348 continuation.Execute ();
351 internal void RemoveContinuation (IContinuation continuation)
353 continuations.Remove (continuation);
356 static internal TaskCreationOptions GetCreationOptions (TaskContinuationOptions kind)
358 TaskCreationOptions options = TaskCreationOptions.None;
359 if ((kind & TaskContinuationOptions.AttachedToParent) > 0)
360 options |= TaskCreationOptions.AttachedToParent;
361 if ((kind & TaskContinuationOptions.PreferFairness) > 0)
362 options |= TaskCreationOptions.PreferFairness;
363 if ((kind & TaskContinuationOptions.LongRunning) > 0)
364 options |= TaskCreationOptions.LongRunning;
370 #region Internal and protected thingies
371 internal void Schedule ()
373 Status = TaskStatus.WaitingToRun;
375 // If worker is null it means it is a local one, revert to the old behavior
376 // If TaskScheduler.Current is not being used, the scheduler was explicitly provided, so we must use that
377 if (scheduler != TaskScheduler.Current || childWorkAdder == null || HasFlag (creationOptions, TaskCreationOptions.PreferFairness)) {
378 scheduler.QueueTask (this);
380 /* Like the semantic of the ABP paper describe it, we add ourselves to the bottom
381 * of our Parent Task's ThreadWorker deque. It's ok to do that since we are in
382 * the correct Thread during the creation
384 childWorkAdder (this);
390 /* Allow scheduler to break fairness of deque ordering without
391 * breaking its semantic (the task can be executed twice but the
392 * second time it will return immediately
394 if (!executing.TryRelaxedSet ())
397 // Disable CancellationToken direct cancellation
398 if (cancellationRegistration != null) {
399 cancellationRegistration.Value.Dispose ();
400 cancellationRegistration = null;
403 // If Task are ran inline on the same thread we might trash these values
404 var saveCurrent = current;
405 var saveScheduler = TaskScheduler.Current;
409 TaskScheduler.Current = HasFlag (creationOptions, TaskCreationOptions.HideScheduler) ? TaskScheduler.Default : scheduler;
411 TaskScheduler.Current = scheduler;
414 if (!token.IsCancellationRequested) {
416 status = TaskStatus.Running;
420 } catch (OperationCanceledException oce) {
421 if (token != CancellationToken.None && oce.CancellationToken == token)
424 HandleGenericException (oce);
425 } catch (Exception e) {
426 HandleGenericException (e);
432 if (saveCurrent != null)
433 current = saveCurrent;
434 if (saveScheduler != null)
435 TaskScheduler.Current = saveScheduler;
439 internal bool TrySetCanceled ()
444 if (!executing.TryRelaxedSet ()) {
445 var sw = new SpinWait ();
456 internal bool TrySetException (AggregateException aggregate)
461 if (!executing.TryRelaxedSet ()) {
462 var sw = new SpinWait ();
469 HandleGenericException (aggregate);
473 internal bool TrySetExceptionObserved ()
475 if (exSlot != null) {
476 exSlot.Observed = true;
482 internal void Execute ()
487 internal void AddChild ()
489 if (childTasks == null)
490 Interlocked.CompareExchange (ref childTasks, new CountdownEvent (1), null);
491 childTasks.AddCount ();
494 internal void ChildCompleted (AggregateException childEx)
496 if (childEx != null) {
497 if (ExceptionSlot.ChildExceptions == null)
498 Interlocked.CompareExchange (ref ExceptionSlot.ChildExceptions, new ConcurrentQueue<AggregateException> (), null);
499 ExceptionSlot.ChildExceptions.Enqueue (childEx);
502 if (childTasks.Signal () && status == TaskStatus.WaitingForChildrenToComplete) {
503 ProcessChildExceptions ();
504 Status = exSlot == null ? TaskStatus.RanToCompletion : TaskStatus.Faulted;
505 ProcessCompleteDelegates ();
506 if (parent != null &&
508 !HasFlag (parent.CreationOptions, TaskCreationOptions.DenyChildAttach) &&
510 HasFlag (creationOptions, TaskCreationOptions.AttachedToParent))
511 parent.ChildCompleted (this.Exception);
517 if (IsContinuation) {
518 invoker.Invoke (contAncestor, state, this);
520 invoker.Invoke (this, state, this);
524 internal void Finish ()
526 // If there was children created and they all finished, we set the countdown
527 if (childTasks != null) {
528 if (childTasks.Signal ())
529 ProcessChildExceptions (true);
532 // Don't override Canceled or Faulted
533 if (status == TaskStatus.Running) {
534 if (childTasks == null || childTasks.IsSet)
535 Status = TaskStatus.RanToCompletion;
537 Status = TaskStatus.WaitingForChildrenToComplete;
540 if (wait_handle != null)
543 // Tell parent that we are finished
544 if (parent != null && HasFlag (creationOptions, TaskCreationOptions.AttachedToParent) &&
546 !HasFlag (parent.CreationOptions, TaskCreationOptions.DenyChildAttach) &&
548 status != TaskStatus.WaitingForChildrenToComplete) {
549 parent.ChildCompleted (this.Exception);
552 // Completions are already processed when task is canceled or faulted
553 if (status == TaskStatus.RanToCompletion)
554 ProcessCompleteDelegates ();
556 // Reset the current thingies
559 if (TaskScheduler.Current == scheduler)
560 TaskScheduler.Current = null;
562 if (cancellationRegistration.HasValue)
563 cancellationRegistration.Value.Dispose ();
566 void ProcessCompleteDelegates ()
568 if (continuations.HasElements) {
569 IContinuation continuation;
570 while (continuations.TryGetNextCompletion (out continuation))
571 continuation.Execute ();
575 void ProcessChildExceptions (bool isParent = false)
577 if (exSlot == null || exSlot.ChildExceptions == null)
580 if (ExceptionSlot.Exception == null)
581 exSlot.Exception = new AggregateException ();
583 AggregateException childEx;
584 while (exSlot.ChildExceptions.TryDequeue (out childEx))
585 exSlot.Exception.AddChildException (childEx);
588 Status = TaskStatus.Faulted;
589 ProcessCompleteDelegates ();
594 #region Cancel and Wait related method
596 internal void CancelReal ()
598 Status = TaskStatus.Canceled;
600 if (wait_handle != null)
603 ProcessCompleteDelegates ();
606 void HandleGenericException (Exception e)
608 HandleGenericException (new AggregateException (e));
611 void HandleGenericException (AggregateException e)
613 ExceptionSlot.Exception = e;
614 Thread.MemoryBarrier ();
615 Status = TaskStatus.Faulted;
617 if (wait_handle != null)
620 ProcessCompleteDelegates ();
623 internal bool WaitOnChildren ()
625 if (Status == TaskStatus.WaitingForChildrenToComplete && childTasks != null) {
634 Wait (Timeout.Infinite, CancellationToken.None);
637 public void Wait (CancellationToken cancellationToken)
639 Wait (Timeout.Infinite, cancellationToken);
642 public bool Wait (TimeSpan timeout)
644 return Wait (CheckTimeout (timeout), CancellationToken.None);
647 public bool Wait (int millisecondsTimeout)
649 return Wait (millisecondsTimeout, CancellationToken.None);
652 public bool Wait (int millisecondsTimeout, CancellationToken cancellationToken)
654 if (millisecondsTimeout < -1)
655 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
660 // If the task is ready to be run and we were supposed to wait on it indefinitely without cancellation, just run it
661 if (Status == TaskStatus.WaitingToRun && millisecondsTimeout == Timeout.Infinite && scheduler != null && !cancellationToken.CanBeCanceled)
662 scheduler.RunInline (this, true);
665 var continuation = new ManualResetContinuation ();
667 ContinueWith (continuation);
668 result = continuation.Event.Wait (millisecondsTimeout, cancellationToken);
671 RemoveContinuation (continuation);
672 continuation.Dispose ();
678 throw new AggregateException (new TaskCanceledException (this));
680 var exception = Exception;
681 if (exception != null)
687 public static void WaitAll (params Task[] tasks)
689 WaitAll (tasks, Timeout.Infinite, CancellationToken.None);
692 public static void WaitAll (Task[] tasks, CancellationToken cancellationToken)
694 WaitAll (tasks, Timeout.Infinite, cancellationToken);
697 public static bool WaitAll (Task[] tasks, TimeSpan timeout)
699 return WaitAll (tasks, CheckTimeout (timeout), CancellationToken.None);
702 public static bool WaitAll (Task[] tasks, int millisecondsTimeout)
704 return WaitAll (tasks, millisecondsTimeout, CancellationToken.None);
707 public static bool WaitAll (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
710 throw new ArgumentNullException ("tasks");
713 foreach (var t in tasks) {
715 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
717 result &= t.Status == TaskStatus.RanToCompletion;
721 var continuation = new CountdownContinuation (tasks.Length);
723 foreach (var t in tasks)
724 t.ContinueWith (continuation);
726 result = continuation.Event.Wait (millisecondsTimeout, cancellationToken);
728 List<Exception> exceptions = null;
730 foreach (var t in tasks) {
732 if (t.Status == TaskStatus.RanToCompletion)
734 if (exceptions == null)
735 exceptions = new List<Exception> ();
736 if (t.Exception != null)
737 exceptions.AddRange (t.Exception.InnerExceptions);
739 exceptions.Add (new TaskCanceledException (t));
741 t.RemoveContinuation (continuation);
745 continuation.Dispose ();
747 if (exceptions != null)
748 throw new AggregateException (exceptions);
755 public static int WaitAny (params Task[] tasks)
757 return WaitAny (tasks, Timeout.Infinite, CancellationToken.None);
760 public static int WaitAny (Task[] tasks, TimeSpan timeout)
762 return WaitAny (tasks, CheckTimeout (timeout));
765 public static int WaitAny (Task[] tasks, int millisecondsTimeout)
767 return WaitAny (tasks, millisecondsTimeout, CancellationToken.None);
770 public static int WaitAny (Task[] tasks, CancellationToken cancellationToken)
772 return WaitAny (tasks, Timeout.Infinite, cancellationToken);
775 public static int WaitAny (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
778 throw new ArgumentNullException ("tasks");
779 if (millisecondsTimeout < -1)
780 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
781 CheckForNullTasks (tasks);
783 if (tasks.Length > 0) {
784 var continuation = new ManualResetContinuation ();
787 for (int i = 0; i < tasks.Length; i++) {
791 t.ContinueWith (continuation);
794 if (!(result = continuation.Event.Wait (millisecondsTimeout, cancellationToken)))
798 foreach (var t in tasks)
799 t.RemoveContinuation (continuation);
800 continuation.Dispose ();
804 int firstFinished = -1;
805 for (int i = 0; i < tasks.Length; i++) {
813 return firstFinished;
816 static int CheckTimeout (TimeSpan timeout)
819 return checked ((int)timeout.TotalMilliseconds);
820 } catch (System.OverflowException) {
821 throw new ArgumentOutOfRangeException ("timeout");
825 static void CheckForNullTasks (Task[] tasks)
827 foreach (var t in tasks)
829 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
834 public void Dispose ()
839 protected virtual void Dispose (bool disposing)
842 throw new InvalidOperationException ("A task may only be disposed if it is in a completion state");
844 // Set action to null so that the GC can collect the delegate and thus
845 // any big object references that the user might have captured in a anonymous method
849 if (cancellationRegistration != null)
850 cancellationRegistration.Value.Dispose ();
851 if (wait_handle != null)
852 wait_handle.Dispose ();
862 Task ContinueWith (Action<Task, object> continuationAction, object state, CancellationToken cancellationToken,
863 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
865 if (continuationAction == null)
866 throw new ArgumentNullException ("continuationAction");
867 if (scheduler == null)
868 throw new ArgumentNullException ("scheduler");
870 Task continuation = new Task (TaskActionInvoker.Create (continuationAction),
871 state, cancellationToken,
872 GetCreationOptions (continuationOptions),
875 ContinueWithCore (continuation, continuationOptions, scheduler);
882 public ConfiguredTaskAwaitable ConfigureAwait (bool continueOnCapturedContext)
884 return new ConfiguredTaskAwaitable (this, continueOnCapturedContext);
887 public Task ContinueWith (Action<Task, object> continuationAction, object state)
889 return ContinueWith (continuationAction, state, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current);
892 public Task ContinueWith (Action<Task, object> continuationAction, object state, CancellationToken cancellationToken)
894 return ContinueWith (continuationAction, state, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
897 public Task ContinueWith (Action<Task, object> continuationAction, object state, TaskContinuationOptions continuationOptions)
899 return ContinueWith (continuationAction, state, CancellationToken.None, continuationOptions, TaskScheduler.Current);
902 public Task ContinueWith (Action<Task, object> continuationAction, object state, TaskScheduler scheduler)
904 return ContinueWith (continuationAction, state, CancellationToken.None, TaskContinuationOptions.None, scheduler);
907 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state)
909 return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current);
912 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, TaskContinuationOptions continuationOptions)
914 return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, continuationOptions, TaskScheduler.Current);
917 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, CancellationToken cancellationToken)
919 return ContinueWith<TResult> (continuationFunction, state, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
922 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, TaskScheduler scheduler)
924 return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, TaskContinuationOptions.None, scheduler);
927 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, CancellationToken cancellationToken,
928 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
930 if (continuationFunction == null)
931 throw new ArgumentNullException ("continuationFunction");
932 if (scheduler == null)
933 throw new ArgumentNullException ("scheduler");
935 var t = new Task<TResult> (TaskActionInvoker.Create (continuationFunction),
938 GetCreationOptions (continuationOptions),
942 ContinueWithCore (t, continuationOptions, scheduler);
947 public static Task Delay (int millisecondsDelay)
949 return Delay (millisecondsDelay, CancellationToken.None);
952 public static Task Delay (TimeSpan delay)
954 return Delay (CheckTimeout (delay), CancellationToken.None);
957 public static Task Delay (TimeSpan delay, CancellationToken cancellationToken)
959 return Delay (CheckTimeout (delay), cancellationToken);
962 public static Task Delay (int millisecondsDelay, CancellationToken cancellationToken)
964 if (millisecondsDelay < -1)
965 throw new ArgumentOutOfRangeException ("millisecondsDelay");
967 var task = new Task (TaskActionInvoker.Delay, millisecondsDelay, cancellationToken, TaskCreationOptions.None, null, TaskConstants.Finished);
968 task.SetupScheduler (TaskScheduler.Current);
970 if (millisecondsDelay != Timeout.Infinite)
971 task.scheduler.QueueTask (task);
976 public static Task<TResult> FromResult<TResult> (TResult result)
978 var tcs = new TaskCompletionSource<TResult> ();
979 tcs.SetResult (result);
983 public TaskAwaiter GetAwaiter ()
985 return new TaskAwaiter (this);
988 public static Task Run (Action action)
990 return Run (action, CancellationToken.None);
993 public static Task Run (Action action, CancellationToken cancellationToken)
995 if (cancellationToken.IsCancellationRequested)
996 return TaskConstants.Canceled;
998 return Task.Factory.StartNew (action, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
1001 public static Task Run (Func<Task> function)
1003 return Run (function, CancellationToken.None);
1006 public static Task Run (Func<Task> function, CancellationToken cancellationToken)
1008 if (cancellationToken.IsCancellationRequested)
1009 return TaskConstants.Canceled;
1011 return TaskExtensionsImpl.Unwrap (Task.Factory.StartNew (function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default));
1014 public static Task<TResult> Run<TResult> (Func<TResult> function)
1016 return Run (function, CancellationToken.None);
1019 public static Task<TResult> Run<TResult> (Func<TResult> function, CancellationToken cancellationToken)
1021 if (cancellationToken.IsCancellationRequested)
1022 return TaskConstants<TResult>.Canceled;
1024 return Task.Factory.StartNew (function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
1027 public static Task<TResult> Run<TResult> (Func<Task<TResult>> function)
1029 return Run (function, CancellationToken.None);
1032 public static Task<TResult> Run<TResult> (Func<Task<TResult>> function, CancellationToken cancellationToken)
1034 if (cancellationToken.IsCancellationRequested)
1035 return TaskConstants<TResult>.Canceled;
1037 return TaskExtensionsImpl.Unwrap (Task.Factory.StartNew (function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default));
1040 public static Task WhenAll (params Task[] tasks)
1043 throw new ArgumentNullException ("tasks");
1045 return WhenAllCore (tasks);
1048 public static Task WhenAll (IEnumerable<Task> tasks)
1051 throw new ArgumentNullException ("tasks");
1053 // Call ToList on input enumeration or we end up
1054 // enumerating it more than once
1055 return WhenAllCore (new List<Task> (tasks));
1058 public static Task<TResult[]> WhenAll<TResult> (params Task<TResult>[] tasks)
1061 throw new ArgumentNullException ("tasks");
1063 return WhenAllCore<TResult> (tasks);
1066 public static Task<TResult[]> WhenAll<TResult> (IEnumerable<Task<TResult>> tasks)
1069 throw new ArgumentNullException ("tasks");
1071 // Call ToList on input enumeration or we end up
1072 // enumerating it more than once
1073 return WhenAllCore<TResult> (new List<Task<TResult>> (tasks));
1076 internal static Task<TResult[]> WhenAllCore<TResult> (IList<Task<TResult>> tasks)
1078 foreach (var t in tasks) {
1080 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1083 var task = new Task<TResult[]> (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1084 task.SetupScheduler (TaskScheduler.Current);
1086 var continuation = new WhenAllContinuation<TResult> (task, tasks);
1087 foreach (var t in tasks)
1088 t.ContinueWith (continuation);
1093 public static Task<Task> WhenAny (params Task[] tasks)
1096 throw new ArgumentNullException ("tasks");
1098 return WhenAnyCore (tasks);
1101 public static Task<Task> WhenAny (IEnumerable<Task> tasks)
1104 throw new ArgumentNullException ("tasks");
1106 return WhenAnyCore (new List<Task> (tasks));
1109 public static Task<Task<TResult>> WhenAny<TResult> (params Task<TResult>[] tasks)
1112 throw new ArgumentNullException ("tasks");
1114 return WhenAnyCore<TResult> (tasks);
1117 public static Task<Task<TResult>> WhenAny<TResult> (IEnumerable<Task<TResult>> tasks)
1120 throw new ArgumentNullException ("tasks");
1122 return WhenAnyCore<TResult> (new List<Task<TResult>> (tasks));
1125 static Task<Task<TResult>> WhenAnyCore<TResult> (IList<Task<TResult>> tasks)
1127 if (tasks.Count == 0)
1128 throw new ArgumentException ("The tasks argument contains no tasks", "tasks");
1130 int completed_index = -1;
1131 for (int i = 0; i < tasks.Count; ++i) {
1134 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1136 if (t.IsCompleted && completed_index < 0)
1137 completed_index = i;
1140 var task = new Task<Task<TResult>> (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1142 if (completed_index > 0) {
1143 task.TrySetResult (tasks[completed_index]);
1147 task.SetupScheduler (TaskScheduler.Current);
1149 var continuation = new WhenAnyContinuation<Task<TResult>> (task, tasks);
1150 foreach (var t in tasks)
1151 t.ContinueWith (continuation);
1156 public static YieldAwaitable Yield ()
1158 return new YieldAwaitable ();
1162 internal static Task WhenAllCore (IList<Task> tasks)
1164 bool all_completed = true;
1165 foreach (var t in tasks) {
1167 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1169 all_completed &= t.Status == TaskStatus.RanToCompletion;
1173 return TaskConstants.Finished;
1175 var task = new Task (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1176 task.SetupScheduler (TaskScheduler.Current);
1178 var continuation = new WhenAllContinuation (task, tasks);
1179 foreach (var t in tasks)
1180 t.ContinueWith (continuation);
1185 internal static Task<Task> WhenAnyCore (IList<Task> tasks)
1187 if (tasks.Count == 0)
1188 throw new ArgumentException ("The tasks argument contains no tasks", "tasks");
1190 int completed_index = -1;
1191 for (int i = 0; i < tasks.Count; ++i) {
1194 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1196 if (t.IsCompleted && completed_index < 0)
1197 completed_index = i;
1200 var task = new Task<Task> (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1202 if (completed_index > 0) {
1203 task.TrySetResult (tasks[completed_index]);
1207 task.SetupScheduler (TaskScheduler.Current);
1209 var continuation = new WhenAnyContinuation<Task> (task, tasks);
1210 foreach (var t in tasks)
1211 t.ContinueWith (continuation);
1217 internal CancellationToken CancellationToken {
1223 public static TaskFactory Factory {
1225 return defaultFactory;
1229 public static int? CurrentId {
1232 return t == null ? (int?)null : t.Id;
1236 public AggregateException Exception {
1240 exSlot.Observed = true;
1241 return exSlot.Exception;
1245 public bool IsCanceled {
1247 return status == TaskStatus.Canceled;
1251 public bool IsCompleted {
1253 return status >= TaskStatus.RanToCompletion;
1257 public bool IsFaulted {
1259 return status == TaskStatus.Faulted;
1263 public TaskCreationOptions CreationOptions {
1265 return creationOptions & MaxTaskCreationOptions;
1269 public TaskStatus Status {
1275 Thread.MemoryBarrier ();
1279 TaskExceptionSlot ExceptionSlot {
1283 Interlocked.CompareExchange (ref exSlot, new TaskExceptionSlot (this), null);
1288 public object AsyncState {
1294 bool IAsyncResult.CompletedSynchronously {
1300 WaitHandle IAsyncResult.AsyncWaitHandle {
1302 if (invoker == null)
1303 throw new ObjectDisposedException (GetType ().ToString ());
1305 if (wait_handle == null)
1306 Interlocked.CompareExchange (ref wait_handle, new ManualResetEvent (IsCompleted), null);
1318 bool IsContinuation {
1320 return contAncestor != null;
1324 internal Task ContinuationAncestor {
1326 return contAncestor;
1330 internal string DisplayActionMethod {
1332 Delegate d = invoker.Action;
1333 return d == null ? "<none>" : d.Method.ToString ();