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 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;
55 static readonly TaskFactory defaultFactory = new TaskFactory ();
57 CountdownEvent childTasks;
60 TaskCreationOptions taskCreationOptions;
62 TaskScheduler scheduler;
64 volatile AggregateException exception;
65 volatile bool exceptionObserved;
66 ConcurrentQueue<AggregateException> childExceptions;
70 Action<object> action;
73 AtomicBooleanValue executing;
75 TaskCompletionQueue<Task> completed;
76 TaskCompletionQueue<IEventSlot> registeredEvts;
77 // If this task is a continuation, this stuff gets filled
80 CancellationToken token;
81 CancellationTokenRegistration? cancellationRegistration;
83 internal const TaskCreationOptions WorkerTaskNotSupportedOptions = TaskCreationOptions.LongRunning | TaskCreationOptions.PreferFairness;
85 const TaskCreationOptions MaxTaskCreationOptions =
87 TaskCreationOptions.DenyChildAttach | TaskCreationOptions.HideScheduler |
89 TaskCreationOptions.PreferFairness | TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent;
91 public Task (Action action) : this (action, TaskCreationOptions.None)
96 public Task (Action action, TaskCreationOptions creationOptions) : this (action, CancellationToken.None, creationOptions)
101 public Task (Action action, CancellationToken cancellationToken) : this (action, cancellationToken, TaskCreationOptions.None)
106 public Task (Action action, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
107 : this (null, null, cancellationToken, creationOptions, current)
110 throw new ArgumentNullException ("action");
111 if (creationOptions > MaxTaskCreationOptions || creationOptions < TaskCreationOptions.None)
112 throw new ArgumentOutOfRangeException ("creationOptions");
113 this.simpleAction = action;
116 public Task (Action<object> action, object state) : this (action, state, TaskCreationOptions.None)
120 public Task (Action<object> action, object state, TaskCreationOptions creationOptions)
121 : this (action, state, CancellationToken.None, creationOptions)
125 public Task (Action<object> action, object state, CancellationToken cancellationToken)
126 : this (action, state, cancellationToken, TaskCreationOptions.None)
130 public Task (Action<object> action, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
131 : this (action, state, cancellationToken, creationOptions, current)
134 throw new ArgumentNullException ("action");
135 if (creationOptions > MaxTaskCreationOptions || creationOptions < TaskCreationOptions.None)
136 throw new ArgumentOutOfRangeException ("creationOptions");
139 internal Task (Action<object> action,
141 CancellationToken cancellationToken,
142 TaskCreationOptions creationOptions,
145 this.taskCreationOptions = creationOptions;
146 this.action = action;
148 this.taskId = Interlocked.Increment (ref id);
149 this.status = cancellationToken.IsCancellationRequested ? TaskStatus.Canceled : TaskStatus.Created;
150 this.token = cancellationToken;
151 this.parent = parent;
153 // Process taskCreationOptions
154 if (CheckTaskOptions (taskCreationOptions, TaskCreationOptions.AttachedToParent) && parent != null)
157 if (token.CanBeCanceled)
158 cancellationRegistration = token.Register (l => ((Task) l).CancelReal (), this);
163 if (exception != null && !exceptionObserved)
167 bool CheckTaskOptions (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.");
186 if (Slot.Initialized)
187 throw new InvalidOperationException ("Start may not be called on a continuation task");
189 SetupScheduler (scheduler);
193 internal void SetupScheduler (TaskScheduler scheduler)
195 this.scheduler = scheduler;
196 status = TaskStatus.WaitingForActivation;
199 public void RunSynchronously ()
201 RunSynchronously (TaskScheduler.Current);
204 public void RunSynchronously (TaskScheduler scheduler)
206 if (scheduler == null)
207 throw new ArgumentNullException ("scheduler");
209 if (Status > TaskStatus.WaitingForActivation)
210 throw new InvalidOperationException ("The task is not in a valid state to be started");
212 SetupScheduler (scheduler);
213 var saveStatus = status;
214 status = TaskStatus.WaitingToRun;
217 if (scheduler.RunInline (this))
219 } catch (Exception inner) {
220 throw new TaskSchedulerException (inner);
230 public Task ContinueWith (Action<Task> continuationAction)
232 return ContinueWith (continuationAction, TaskContinuationOptions.None);
235 public Task ContinueWith (Action<Task> continuationAction, TaskContinuationOptions continuationOptions)
237 return ContinueWith (continuationAction, CancellationToken.None, continuationOptions, TaskScheduler.Current);
240 public Task ContinueWith (Action<Task> continuationAction, CancellationToken cancellationToken)
242 return ContinueWith (continuationAction, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
245 public Task ContinueWith (Action<Task> continuationAction, TaskScheduler scheduler)
247 return ContinueWith (continuationAction, CancellationToken.None, TaskContinuationOptions.None, scheduler);
250 public Task ContinueWith (Action<Task> continuationAction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
252 if (continuationAction == null)
253 throw new ArgumentNullException ("continuationAction");
254 if (scheduler == null)
255 throw new ArgumentNullException ("scheduler");
257 Task continuation = new Task (l => continuationAction ((Task)l),
260 GetCreationOptions (continuationOptions),
262 ContinueWithCore (continuation, continuationOptions, scheduler);
267 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction)
269 return ContinueWith<TResult> (continuationFunction, TaskContinuationOptions.None);
272 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, TaskContinuationOptions continuationOptions)
274 return ContinueWith<TResult> (continuationFunction, CancellationToken.None, continuationOptions, TaskScheduler.Current);
277 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, CancellationToken cancellationToken)
279 return ContinueWith<TResult> (continuationFunction, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
282 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, TaskScheduler scheduler)
284 return ContinueWith<TResult> (continuationFunction, CancellationToken.None, TaskContinuationOptions.None, scheduler);
287 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, CancellationToken cancellationToken,
288 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
290 if (continuationFunction == null)
291 throw new ArgumentNullException ("continuationFunction");
292 if (scheduler == null)
293 throw new ArgumentNullException ("scheduler");
295 Task<TResult> t = new Task<TResult> ((o) => continuationFunction ((Task)o),
298 GetCreationOptions (continuationOptions),
301 ContinueWithCore (t, continuationOptions, scheduler);
306 internal void ContinueWithCore (Task continuation, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
308 ContinueWithCore (continuation, continuationOptions, scheduler, null);
311 internal void ContinueWithCore (Task continuation, TaskContinuationOptions kind,
312 TaskScheduler scheduler, Func<bool> predicate)
314 CheckTaskCompletionCompatibility (kind);
316 // Already set the scheduler so that user can call Wait and that sort of stuff
317 continuation.scheduler = scheduler;
318 continuation.status = TaskStatus.WaitingForActivation;
319 continuation.Slot = new CompletionSlot (kind, predicate);
322 CompletionExecutor (continuation);
326 completed.Add (continuation);
328 // Retry in case completion was achieved but event adding was too late
330 CompletionExecutor (continuation);
333 bool ContinuationStatusCheck (TaskContinuationOptions kind)
335 if (kind == TaskContinuationOptions.None)
338 int kindCode = (int)kind;
340 if (kindCode >= ((int)TaskContinuationOptions.NotOnRanToCompletion)) {
341 // Remove other options
342 kind &= ~(TaskContinuationOptions.PreferFairness
343 | TaskContinuationOptions.LongRunning
344 | TaskContinuationOptions.AttachedToParent
345 | TaskContinuationOptions.ExecuteSynchronously);
347 if (status == TaskStatus.Canceled) {
348 if (kind == TaskContinuationOptions.NotOnCanceled)
350 if (kind == TaskContinuationOptions.OnlyOnFaulted)
352 if (kind == TaskContinuationOptions.OnlyOnRanToCompletion)
354 } else if (status == TaskStatus.Faulted) {
355 if (kind == TaskContinuationOptions.NotOnFaulted)
357 if (kind == TaskContinuationOptions.OnlyOnCanceled)
359 if (kind == TaskContinuationOptions.OnlyOnRanToCompletion)
361 } else if (status == TaskStatus.RanToCompletion) {
362 if (kind == TaskContinuationOptions.NotOnRanToCompletion)
364 if (kind == TaskContinuationOptions.OnlyOnFaulted)
366 if (kind == TaskContinuationOptions.OnlyOnCanceled)
374 static internal void CheckTaskCompletionCompatibility (TaskContinuationOptions options)
376 if (options == TaskContinuationOptions.None)
379 const TaskContinuationOptions wrongRan = TaskContinuationOptions.NotOnRanToCompletion | TaskContinuationOptions.OnlyOnRanToCompletion;
380 const TaskContinuationOptions wrongCanceled = TaskContinuationOptions.NotOnCanceled | TaskContinuationOptions.OnlyOnCanceled;
381 const TaskContinuationOptions wrongFaulted = TaskContinuationOptions.NotOnFaulted | TaskContinuationOptions.OnlyOnFaulted;
383 if (((options & wrongRan) == wrongRan)
384 || ((options & wrongCanceled) == wrongCanceled)
385 || ((options & wrongFaulted) == wrongFaulted))
386 throw new ArgumentException ("continuationOptions", "Some options are mutually exclusive");
389 static internal TaskCreationOptions GetCreationOptions (TaskContinuationOptions kind)
391 TaskCreationOptions options = TaskCreationOptions.None;
392 if ((kind & TaskContinuationOptions.AttachedToParent) > 0)
393 options |= TaskCreationOptions.AttachedToParent;
394 if ((kind & TaskContinuationOptions.PreferFairness) > 0)
395 options |= TaskCreationOptions.PreferFairness;
396 if ((kind & TaskContinuationOptions.LongRunning) > 0)
397 options |= TaskCreationOptions.LongRunning;
402 void RegisterWaitEvent (IEventSlot slot)
409 registeredEvts.Add (slot);
410 if (IsCompleted && registeredEvts.Remove (slot))
414 void UnregisterWaitEvent (IEventSlot slot)
416 registeredEvts.Remove (slot);
420 #region Internal and protected thingies
421 internal void Schedule ()
423 status = TaskStatus.WaitingToRun;
425 // If worker is null it means it is a local one, revert to the old behavior
426 // If TaskScheduler.Current is not being used, the scheduler was explicitly provided, so we must use that
427 if (scheduler != TaskScheduler.Current || childWorkAdder == null || CheckTaskOptions (taskCreationOptions, TaskCreationOptions.PreferFairness)) {
428 scheduler.QueueTask (this);
430 /* Like the semantic of the ABP paper describe it, we add ourselves to the bottom
431 * of our Parent Task's ThreadWorker deque. It's ok to do that since we are in
432 * the correct Thread during the creation
434 childWorkAdder (this);
440 /* Allow scheduler to break fairness of deque ordering without
441 * breaking its semantic (the task can be executed twice but the
442 * second time it will return immediately
444 if (!executing.TryRelaxedSet ())
447 // Disable CancellationToken direct cancellation
448 if (cancellationRegistration != null) {
449 cancellationRegistration.Value.Dispose ();
450 cancellationRegistration = null;
453 TaskScheduler.Current = scheduler;
455 if (!token.IsCancellationRequested) {
457 status = TaskStatus.Running;
461 } catch (OperationCanceledException oce) {
462 if (token != CancellationToken.None && oce.CancellationToken == token)
465 HandleGenericException (oce);
466 } catch (Exception e) {
467 HandleGenericException (e);
476 internal void Execute (Action<Task> childAdder)
478 childWorkAdder = childAdder;
482 internal void AddChild ()
484 if (childTasks == null)
485 Interlocked.CompareExchange (ref childTasks, new CountdownEvent (1), null);
486 childTasks.AddCount ();
489 internal void ChildCompleted (AggregateException childEx)
491 if (childEx != null) {
492 if (childExceptions == null)
493 Interlocked.CompareExchange (ref childExceptions, new ConcurrentQueue<AggregateException> (), null);
494 childExceptions.Enqueue (childEx);
497 if (childTasks.Signal () && status == TaskStatus.WaitingForChildrenToComplete) {
498 status = TaskStatus.RanToCompletion;
499 ProcessChildExceptions ();
500 ProcessCompleteDelegates ();
504 internal virtual void InnerInvoke ()
506 if (action == null && simpleAction != null)
508 else if (action != null)
510 // Set action to null so that the GC can collect the delegate and thus
511 // any big object references that the user might have captured in an anonymous method
517 internal void Finish ()
519 // If there was children created and they all finished, we set the countdown
520 if (childTasks != null)
521 childTasks.Signal ();
523 // Don't override Canceled or Faulted
524 if (status == TaskStatus.Running) {
525 if (childTasks == null || childTasks.IsSet)
526 status = TaskStatus.RanToCompletion;
528 status = TaskStatus.WaitingForChildrenToComplete;
531 if (status != TaskStatus.WaitingForChildrenToComplete)
532 ProcessCompleteDelegates ();
534 // Reset the current thingies
536 TaskScheduler.Current = null;
538 if (cancellationRegistration.HasValue)
539 cancellationRegistration.Value.Dispose ();
541 // Tell parent that we are finished
542 if (CheckTaskOptions (taskCreationOptions, TaskCreationOptions.AttachedToParent) && parent != null) {
543 parent.ChildCompleted (this.Exception);
547 void CompletionExecutor (Task cont)
549 if (cont.Slot.Predicate != null && !cont.Slot.Predicate ())
552 if (!cont.Slot.Launched.TryRelaxedSet ())
555 if (!ContinuationStatusCheck (cont.Slot.Kind)) {
562 if ((cont.Slot.Kind & TaskContinuationOptions.ExecuteSynchronously) != 0)
563 cont.RunSynchronously (cont.scheduler);
568 void ProcessCompleteDelegates ()
570 if (completed.HasElements) {
572 while (completed.TryGetNextCompletion (out continuation))
573 CompletionExecutor (continuation);
575 if (registeredEvts.HasElements) {
577 while (registeredEvts.TryGetNextCompletion (out evt))
582 void ProcessChildExceptions ()
584 if (childExceptions == null)
587 if (exception == null)
588 exception = new AggregateException ();
590 AggregateException childEx;
591 while (childExceptions.TryDequeue (out childEx))
592 exception.AddChildException (childEx);
596 #region Cancel and Wait related method
598 internal void CancelReal ()
600 status = TaskStatus.Canceled;
601 ProcessCompleteDelegates ();
604 internal void HandleGenericException (Exception e)
606 HandleGenericException (new AggregateException (e));
609 internal void HandleGenericException (AggregateException e)
612 Thread.MemoryBarrier ();
613 status = TaskStatus.Faulted;
614 if (scheduler != null && scheduler.FireUnobservedEvent (exception).Observed)
615 exceptionObserved = true;
620 Wait (Timeout.Infinite, CancellationToken.None);
623 public void Wait (CancellationToken cancellationToken)
625 Wait (Timeout.Infinite, cancellationToken);
628 public bool Wait (TimeSpan timeout)
630 return Wait (CheckTimeout (timeout), CancellationToken.None);
633 public bool Wait (int millisecondsTimeout)
635 return Wait (millisecondsTimeout, CancellationToken.None);
638 public bool Wait (int millisecondsTimeout, CancellationToken cancellationToken)
640 if (millisecondsTimeout < -1)
641 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
646 // If the task is ready to be run and we were supposed to wait on it indefinitely, just run it
647 if (Status == TaskStatus.WaitingToRun && millisecondsTimeout == -1 && scheduler != null)
651 var evt = new ManualResetEventSlim ();
652 var slot = new ManualEventSlot (evt);
654 RegisterWaitEvent (slot);
655 result = evt.Wait (millisecondsTimeout, cancellationToken);
658 UnregisterWaitEvent (slot);
665 throw new AggregateException (new TaskCanceledException (this));
667 if (exception != null)
673 public static void WaitAll (params Task[] tasks)
675 WaitAll (tasks, Timeout.Infinite, CancellationToken.None);
678 public static void WaitAll (Task[] tasks, CancellationToken cancellationToken)
680 WaitAll (tasks, Timeout.Infinite, cancellationToken);
683 public static bool WaitAll (Task[] tasks, TimeSpan timeout)
685 return WaitAll (tasks, CheckTimeout (timeout), CancellationToken.None);
688 public static bool WaitAll (Task[] tasks, int millisecondsTimeout)
690 return WaitAll (tasks, millisecondsTimeout, CancellationToken.None);
693 public static bool WaitAll (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
696 throw new ArgumentNullException ("tasks");
697 CheckForNullTasks (tasks);
700 List<Exception> exceptions = null;
702 if (tasks.Length > 0) {
703 var evt = new CountdownEvent (tasks.Length);
704 var slot = new CountdownEventSlot (evt);
706 foreach (var t in tasks)
707 t.RegisterWaitEvent (slot);
709 result = evt.Wait (millisecondsTimeout, cancellationToken);
711 foreach (var t in tasks) {
713 if (t.Status == TaskStatus.RanToCompletion)
715 if (exceptions == null)
716 exceptions = new List<Exception> ();
717 if (t.Exception != null)
718 exceptions.AddRange (t.Exception.InnerExceptions);
720 exceptions.Add (new TaskCanceledException (t));
722 t.UnregisterWaitEvent (slot);
730 if (exceptions != null)
731 throw new AggregateException (exceptions);
736 public static int WaitAny (params Task[] tasks)
738 return WaitAny (tasks, Timeout.Infinite, CancellationToken.None);
741 public static int WaitAny (Task[] tasks, TimeSpan timeout)
743 return WaitAny (tasks, CheckTimeout (timeout));
746 public static int WaitAny (Task[] tasks, int millisecondsTimeout)
748 return WaitAny (tasks, millisecondsTimeout, CancellationToken.None);
751 public static int WaitAny (Task[] tasks, CancellationToken cancellationToken)
753 return WaitAny (tasks, Timeout.Infinite, cancellationToken);
756 public static int WaitAny (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
759 throw new ArgumentNullException ("tasks");
760 if (millisecondsTimeout < -1)
761 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
762 CheckForNullTasks (tasks);
764 if (tasks.Length > 0) {
765 var evt = new ManualResetEventSlim ();
766 var slot = new ManualEventSlot (evt);
769 for (int i = 0; i < tasks.Length; i++) {
773 t.RegisterWaitEvent (slot);
776 if (!(result = evt.Wait (millisecondsTimeout, cancellationToken)))
780 foreach (var t in tasks)
781 t.UnregisterWaitEvent (slot);
786 int firstFinished = -1;
787 for (int i = 0; i < tasks.Length; i++) {
795 return firstFinished;
798 static int CheckTimeout (TimeSpan timeout)
801 return checked ((int)timeout.TotalMilliseconds);
802 } catch (System.OverflowException) {
803 throw new ArgumentOutOfRangeException ("timeout");
807 static void CheckForNullTasks (Task[] tasks)
809 foreach (var t in tasks)
811 throw new ArgumentNullException ("tasks", "the tasks argument contains a null element");
816 public void Dispose ()
821 protected virtual void Dispose (bool disposing)
824 throw new InvalidOperationException ("A task may only be disposed if it is in a completion state");
826 // Set action to null so that the GC can collect the delegate and thus
827 // any big object references that the user might have captured in a anonymous method
831 if (cancellationRegistration != null)
832 cancellationRegistration.Value.Dispose ();
839 public ConfiguredTaskAwaitable ConfigureAwait (bool continueOnCapturedContext)
841 return new ConfiguredTaskAwaitable (this, continueOnCapturedContext);
844 public Task ContinueWith (Action<Task, object> continuationAction, object state)
846 return ContinueWith (continuationAction, state, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current);
849 public Task ContinueWith (Action<Task, object> continuationAction, object state, CancellationToken cancellationToken)
851 return ContinueWith (continuationAction, state, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
854 public Task ContinueWith (Action<Task, object> continuationAction, object state, TaskContinuationOptions continuationOptions)
856 return ContinueWith (continuationAction, state, CancellationToken.None, continuationOptions, TaskScheduler.Current);
859 public Task ContinueWith (Action<Task, object> continuationAction, object state, TaskScheduler scheduler)
861 return ContinueWith (continuationAction, state, CancellationToken.None, TaskContinuationOptions.None, scheduler);
864 public Task ContinueWith (Action<Task, object> continuationAction, object state, CancellationToken cancellationToken,
865 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
867 if (continuationAction == null)
868 throw new ArgumentNullException ("continuationAction");
869 if (scheduler == null)
870 throw new ArgumentNullException ("scheduler");
872 Task continuation = new Task (l => continuationAction (this, l), state,
874 GetCreationOptions (continuationOptions),
876 ContinueWithCore (continuation, continuationOptions, scheduler);
881 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state)
883 return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current);
886 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, TaskContinuationOptions continuationOptions)
888 return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, continuationOptions, TaskScheduler.Current);
891 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, CancellationToken cancellationToken)
893 return ContinueWith<TResult> (continuationFunction, state, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
896 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, TaskScheduler scheduler)
898 return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, TaskContinuationOptions.None, scheduler);
901 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, CancellationToken cancellationToken,
902 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
904 if (continuationFunction == null)
905 throw new ArgumentNullException ("continuationFunction");
906 if (scheduler == null)
907 throw new ArgumentNullException ("scheduler");
909 var t = new Task<TResult> (l => continuationFunction (this, l),
912 GetCreationOptions (continuationOptions),
915 ContinueWithCore (t, continuationOptions, scheduler);
920 public static Task<TResult> FromResult<TResult> (TResult result)
922 var tcs = new TaskCompletionSource<TResult> ();
923 tcs.SetResult (result);
927 public TaskAwaiter GetAwaiter ()
929 return new TaskAwaiter (this);
932 public static Task Run (Action action)
934 return Run (action, CancellationToken.None);
937 public static Task Run (Action action, CancellationToken cancellationToken)
939 if (cancellationToken.IsCancellationRequested)
940 return TaskConstants.Canceled;
942 var t = new Task (action, cancellationToken, TaskCreationOptions.DenyChildAttach);
947 public static Task Run (Func<Task> function)
949 return Run (function, CancellationToken.None);
952 public static Task Run (Func<Task> function, CancellationToken cancellationToken)
954 if (cancellationToken.IsCancellationRequested)
955 return TaskConstants.Canceled;
957 var t = new Task<Task> (function, cancellationToken);
962 public static Task<TResult> Run<TResult> (Func<TResult> function)
964 return Run (function, CancellationToken.None);
967 public static Task<TResult> Run<TResult> (Func<TResult> function, CancellationToken cancellationToken)
969 if (cancellationToken.IsCancellationRequested)
970 return TaskConstants<TResult>.Canceled;
972 var t = new Task<TResult> (function, cancellationToken, TaskCreationOptions.DenyChildAttach);
977 public static Task<TResult> Run<TResult> (Func<Task<TResult>> function)
979 return Run (function, CancellationToken.None);
982 public static Task<TResult> Run<TResult> (Func<Task<TResult>> function, CancellationToken cancellationToken)
984 if (cancellationToken.IsCancellationRequested)
985 return TaskConstants<TResult>.Canceled;
987 var t = Task<Task<TResult>>.Factory.StartNew (function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
988 return GetTaskResult (t);
991 async static Task<TResult> GetTaskResult<TResult> (Task<Task<TResult>> task)
993 var r = await task.ConfigureAwait (false);
997 public static YieldAwaitable Yield ()
999 return new YieldAwaitable ();
1004 public static TaskFactory Factory {
1006 return defaultFactory;
1010 public static int? CurrentId {
1013 return t == null ? (int?)null : t.Id;
1017 public AggregateException Exception {
1019 exceptionObserved = true;
1028 public bool IsCanceled {
1030 return status == TaskStatus.Canceled;
1034 public bool IsCompleted {
1036 return status >= TaskStatus.RanToCompletion;
1040 public bool IsFaulted {
1042 return status == TaskStatus.Faulted;
1046 public TaskCreationOptions CreationOptions {
1048 return taskCreationOptions;
1052 public TaskStatus Status {
1061 public object AsyncState {
1067 bool IAsyncResult.CompletedSynchronously {
1073 WaitHandle IAsyncResult.AsyncWaitHandle {
1085 internal Task Parent {
1091 internal string DisplayActionMethod {
1093 Delegate d = simpleAction ?? (Delegate) action;
1094 return d == null ? "<none>" : d.Method.ToString ();