5 // Marek Safar <marek.safar@gmail.com>
7 // Copyright (c) 2008 Jérémie "Garuma" Laval
8 // Copyright 2011 Xamarin Inc (http://www.xamarin.com).
10 // Permission is hereby granted, free of charge, to any person obtaining a copy
11 // of this software and associated documentation files (the "Software"), to deal
12 // in the Software without restriction, including without limitation the rights
13 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 // copies of the Software, and to permit persons to whom the Software is
15 // furnished to do so, subject to the following conditions:
17 // The above copyright notice and this permission notice shall be included in
18 // all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
33 using System.Threading;
34 using System.Collections.Concurrent;
35 using System.Collections.Generic;
36 using System.Runtime.CompilerServices;
38 namespace System.Threading.Tasks
40 [System.Diagnostics.DebuggerDisplay ("Id = {Id}, Status = {Status}")]
41 [System.Diagnostics.DebuggerTypeProxy (typeof (TaskDebuggerView))]
42 public class Task : IDisposable, IAsyncResult
44 // With this attribute each thread has its own value so that it's correct for our Schedule code
45 // and for Parent property.
49 static Action<Task> childWorkAdder;
54 static readonly TaskFactory defaultFactory = new TaskFactory ();
56 CountdownEvent childTasks;
59 TaskCreationOptions taskCreationOptions;
61 TaskScheduler scheduler;
63 ManualResetEventSlim schedWait = new ManualResetEventSlim (false);
65 volatile AggregateException exception;
66 volatile bool exceptionObserved;
67 ConcurrentQueue<AggregateException> childExceptions;
71 Action<object> action;
74 AtomicBooleanValue executing;
76 TaskCompletionQueue completed;
77 // If this task is a continuation, this stuff gets filled
80 CancellationToken token;
81 CancellationTokenRegistration? cancelation_registration;
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 cancelation_registration = token.Register (l => ((Task) l).CancelReal (), this);
164 if (exception != null && !exceptionObserved)
168 bool CheckTaskOptions (TaskCreationOptions opt, TaskCreationOptions member)
170 return (opt & member) == member;
176 Start (TaskScheduler.Current);
179 public void Start (TaskScheduler scheduler)
181 if (scheduler == null)
182 throw new ArgumentNullException ("scheduler");
184 if (status >= TaskStatus.WaitingToRun)
185 throw new InvalidOperationException ("The Task is not in a valid state to be started.");
187 if (Slot.Initialized)
188 throw new InvalidOperationException ("Start may not be called on a continuation task");
190 SetupScheduler (scheduler);
194 internal void SetupScheduler (TaskScheduler scheduler)
196 this.scheduler = scheduler;
197 status = TaskStatus.WaitingForActivation;
201 public void RunSynchronously ()
203 RunSynchronously (TaskScheduler.Current);
206 public void RunSynchronously (TaskScheduler scheduler)
208 if (scheduler == null)
209 throw new ArgumentNullException ("scheduler");
211 if (Status > TaskStatus.WaitingForActivation)
212 throw new InvalidOperationException ("The task is not in a valid state to be started");
214 SetupScheduler (scheduler);
215 var saveStatus = status;
216 status = TaskStatus.WaitingToRun;
219 if (scheduler.RunInline (this))
221 } catch (Exception inner) {
222 throw new TaskSchedulerException (inner);
232 public Task ContinueWith (Action<Task> continuationAction)
234 return ContinueWith (continuationAction, TaskContinuationOptions.None);
237 public Task ContinueWith (Action<Task> continuationAction, TaskContinuationOptions continuationOptions)
239 return ContinueWith (continuationAction, CancellationToken.None, continuationOptions, TaskScheduler.Current);
242 public Task ContinueWith (Action<Task> continuationAction, CancellationToken cancellationToken)
244 return ContinueWith (continuationAction, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
247 public Task ContinueWith (Action<Task> continuationAction, TaskScheduler scheduler)
249 return ContinueWith (continuationAction, CancellationToken.None, TaskContinuationOptions.None, scheduler);
252 public Task ContinueWith (Action<Task> continuationAction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
254 if (continuationAction == null)
255 throw new ArgumentNullException ("continuationAction");
256 if (scheduler == null)
257 throw new ArgumentNullException ("scheduler");
259 Task continuation = new Task (l => continuationAction ((Task)l),
262 GetCreationOptions (continuationOptions),
264 ContinueWithCore (continuation, continuationOptions, scheduler);
269 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction)
271 return ContinueWith<TResult> (continuationFunction, TaskContinuationOptions.None);
274 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, TaskContinuationOptions continuationOptions)
276 return ContinueWith<TResult> (continuationFunction, CancellationToken.None, continuationOptions, TaskScheduler.Current);
279 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, CancellationToken cancellationToken)
281 return ContinueWith<TResult> (continuationFunction, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
284 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, TaskScheduler scheduler)
286 return ContinueWith<TResult> (continuationFunction, CancellationToken.None, TaskContinuationOptions.None, scheduler);
289 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, CancellationToken cancellationToken,
290 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
292 if (continuationFunction == null)
293 throw new ArgumentNullException ("continuationFunction");
294 if (scheduler == null)
295 throw new ArgumentNullException ("scheduler");
297 Task<TResult> t = new Task<TResult> ((o) => continuationFunction ((Task)o),
300 GetCreationOptions (continuationOptions),
303 ContinueWithCore (t, continuationOptions, scheduler);
308 internal void ContinueWithCore (Task continuation, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
310 ContinueWithCore (continuation, continuationOptions, scheduler, null);
313 internal void ContinueWithCore (Task continuation, TaskContinuationOptions kind,
314 TaskScheduler scheduler, Func<bool> predicate)
316 // Already set the scheduler so that user can call Wait and that sort of stuff
317 continuation.scheduler = scheduler;
318 continuation.schedWait.Set ();
319 continuation.status = TaskStatus.WaitingForActivation;
320 continuation.Slot = new CompletionSlot (kind, predicate);
323 CompletionTaskExecutor (continuation);
327 completed.Add (continuation);
329 // Retry in case completion was achieved but event adding was too late
331 CompletionTaskExecutor (continuation);
335 bool ContinuationStatusCheck (TaskContinuationOptions kind)
337 if (kind == TaskContinuationOptions.None)
340 int kindCode = (int)kind;
342 if (kindCode >= ((int)TaskContinuationOptions.NotOnRanToCompletion)) {
343 // Remove other options
344 kind &= ~(TaskContinuationOptions.PreferFairness
345 | TaskContinuationOptions.LongRunning
346 | TaskContinuationOptions.AttachedToParent
347 | TaskContinuationOptions.ExecuteSynchronously);
349 if (status == TaskStatus.Canceled) {
350 if (kind == TaskContinuationOptions.NotOnCanceled)
352 if (kind == TaskContinuationOptions.OnlyOnFaulted)
354 if (kind == TaskContinuationOptions.OnlyOnRanToCompletion)
356 } else if (status == TaskStatus.Faulted) {
357 if (kind == TaskContinuationOptions.NotOnFaulted)
359 if (kind == TaskContinuationOptions.OnlyOnCanceled)
361 if (kind == TaskContinuationOptions.OnlyOnRanToCompletion)
363 } else if (status == TaskStatus.RanToCompletion) {
364 if (kind == TaskContinuationOptions.NotOnRanToCompletion)
366 if (kind == TaskContinuationOptions.OnlyOnFaulted)
368 if (kind == TaskContinuationOptions.OnlyOnCanceled)
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 ()
393 status = TaskStatus.WaitingToRun;
395 // If worker is null it means it is a local one, revert to the old behavior
396 // If TaskScheduler.Current is not being used, the scheduler was explicitly provided, so we must use that
397 if (scheduler != TaskScheduler.Current || childWorkAdder == null || CheckTaskOptions (taskCreationOptions, TaskCreationOptions.PreferFairness)) {
398 scheduler.QueueTask (this);
400 /* Like the semantic of the ABP paper describe it, we add ourselves to the bottom
401 * of our Parent Task's ThreadWorker deque. It's ok to do that since we are in
402 * the correct Thread during the creation
404 childWorkAdder (this);
410 /* Allow scheduler to break fairness of deque ordering without
411 * breaking its semantic (the task can be executed twice but the
412 * second time it will return immediately
414 if (!executing.TryRelaxedSet ())
418 TaskScheduler.Current = scheduler;
420 if (!token.IsCancellationRequested) {
422 status = TaskStatus.Running;
426 } catch (OperationCanceledException oce) {
427 if (token != CancellationToken.None && oce.CancellationToken == token)
430 HandleGenericException (oce);
431 } catch (Exception e) {
432 HandleGenericException (e);
441 internal void Execute (Action<Task> childAdder)
443 childWorkAdder = childAdder;
447 internal void AddChild ()
449 if (childTasks == null)
450 Interlocked.CompareExchange (ref childTasks, new CountdownEvent (1), null);
451 childTasks.AddCount ();
454 internal void ChildCompleted (AggregateException childEx)
456 if (childEx != null) {
457 if (childExceptions == null)
458 Interlocked.CompareExchange (ref childExceptions, new ConcurrentQueue<AggregateException> (), null);
459 childExceptions.Enqueue (childEx);
462 if (childTasks.Signal () && status == TaskStatus.WaitingForChildrenToComplete) {
463 status = TaskStatus.RanToCompletion;
464 ProcessChildExceptions ();
465 ProcessCompleteDelegates ();
469 internal virtual void InnerInvoke ()
471 if (action == null && simpleAction != null)
473 else if (action != null)
475 // Set action to null so that the GC can collect the delegate and thus
476 // any big object references that the user might have captured in an anonymous method
482 internal void Finish ()
484 // If there was children created and they all finished, we set the countdown
485 if (childTasks != null)
486 childTasks.Signal ();
488 // Don't override Canceled or Faulted
489 if (status == TaskStatus.Running) {
490 if (childTasks == null || childTasks.IsSet)
491 status = TaskStatus.RanToCompletion;
493 status = TaskStatus.WaitingForChildrenToComplete;
496 if (status != TaskStatus.WaitingForChildrenToComplete)
497 ProcessCompleteDelegates ();
499 // Reset the current thingies
501 TaskScheduler.Current = null;
503 if (cancelation_registration.HasValue)
504 cancelation_registration.Value.Dispose ();
506 // Tell parent that we are finished
507 if (CheckTaskOptions (taskCreationOptions, TaskCreationOptions.AttachedToParent) && parent != null) {
508 parent.ChildCompleted (this.Exception);
512 void ProcessCompleteDelegates ()
514 if (!completed.HasElements)
518 while (completed.TryGetNext (out value)) {
519 var t = value as Task;
521 CompletionTaskExecutor (t);
525 var mre = value as ManualResetEventSlim;
531 throw new NotImplementedException ("Unknown completition type " + t.GetType ());
535 void CompletionTaskExecutor (Task cont)
537 if (cont.Slot.Predicate != null && !cont.Slot.Predicate ())
540 if (!cont.Slot.Launched.TryRelaxedSet ())
543 if (!ContinuationStatusCheck (cont.Slot.Kind)) {
550 if ((cont.Slot.Kind & TaskContinuationOptions.ExecuteSynchronously) != 0)
551 cont.RunSynchronously (cont.scheduler);
556 void ProcessChildExceptions ()
558 if (childExceptions == null)
561 if (exception == null)
562 exception = new AggregateException ();
564 AggregateException childEx;
565 while (childExceptions.TryDequeue (out childEx))
566 exception.AddChildException (childEx);
570 #region Cancel and Wait related method
572 internal void CancelReal ()
574 status = TaskStatus.Canceled;
575 ProcessCompleteDelegates ();
578 internal void HandleGenericException (Exception e)
580 HandleGenericException (new AggregateException (e));
583 internal void HandleGenericException (AggregateException e)
586 Thread.MemoryBarrier ();
587 status = TaskStatus.Faulted;
588 if (scheduler != null && scheduler.FireUnobservedEvent (exception).Observed)
589 exceptionObserved = true;
594 Wait (Timeout.Infinite, CancellationToken.None);
597 public void Wait (CancellationToken cancellationToken)
599 Wait (Timeout.Infinite, cancellationToken);
602 public bool Wait (TimeSpan timeout)
604 return Wait (CheckTimeout (timeout), CancellationToken.None);
607 public bool Wait (int millisecondsTimeout)
609 return Wait (millisecondsTimeout, CancellationToken.None);
612 public bool Wait (int millisecondsTimeout, CancellationToken cancellationToken)
614 if (millisecondsTimeout < -1)
615 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
617 bool result = IsCompleted;
619 CancellationTokenRegistration? registration = null;
620 var completed_event = new ManualResetEventSlim (false);
623 if (cancellationToken.CanBeCanceled) {
624 registration = cancellationToken.Register (completed_event.Set);
627 completed.Add (completed_event);
629 // Task could complete while we were setting things up
631 // Don't bother removing completed_event, GC can handle it
634 result = completed_event.Wait (millisecondsTimeout);
637 if (registration.HasValue)
638 registration.Value.Dispose ();
640 // Try to remove completition event when timeout expired
642 completed.TryRemove (completed_event);
644 completed_event.Dispose ();
649 throw new AggregateException (new TaskCanceledException (this));
651 if (exception != null)
657 public static void WaitAll (params Task[] tasks)
659 WaitAll (tasks, Timeout.Infinite, CancellationToken.None);
662 public static void WaitAll (Task[] tasks, CancellationToken cancellationToken)
664 WaitAll (tasks, Timeout.Infinite, cancellationToken);
667 public static bool WaitAll (Task[] tasks, TimeSpan timeout)
669 return WaitAll (tasks, CheckTimeout (timeout), CancellationToken.None);
672 public static bool WaitAll (Task[] tasks, int millisecondsTimeout)
674 return WaitAll (tasks, millisecondsTimeout, CancellationToken.None);
677 public static bool WaitAll (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
680 throw new ArgumentNullException ("tasks");
682 if (millisecondsTimeout < -1)
683 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
686 bool simple_run = millisecondsTimeout == Timeout.Infinite || tasks.Length == 1;
687 List<Exception> exceptions = null;
689 foreach (var t in tasks) {
691 throw new ArgumentNullException ("tasks", "the tasks argument contains a null element");
695 result &= t.Wait (millisecondsTimeout, cancellationToken);
696 } catch (AggregateException e) {
697 if (exceptions == null)
698 exceptions = new List<Exception> ();
700 exceptions.AddRange (e.InnerExceptions);
705 // FIXME: Wrong implementation, millisecondsTimeout is total time not time per task
707 foreach (var t in tasks) {
709 result &= t.Wait (millisecondsTimeout, cancellationToken);
710 } catch (AggregateException e) {
711 if (exceptions == null)
712 exceptions = new List<Exception> ();
714 exceptions.AddRange (e.InnerExceptions);
719 if (exceptions != null)
720 throw new AggregateException (exceptions);
725 public static int WaitAny (params Task[] tasks)
727 return WaitAny (tasks, Timeout.Infinite, CancellationToken.None);
730 public static int WaitAny (Task[] tasks, TimeSpan timeout)
732 return WaitAny (tasks, CheckTimeout (timeout));
735 public static int WaitAny (Task[] tasks, int millisecondsTimeout)
737 return WaitAny (tasks, millisecondsTimeout, CancellationToken.None);
740 public static int WaitAny (Task[] tasks, CancellationToken cancellationToken)
742 return WaitAny (tasks, Timeout.Infinite, cancellationToken);
745 public static int WaitAny (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
748 throw new ArgumentNullException ("tasks");
750 int first_finished = -1;
751 for (int i = 0; i < tasks.Length; ++i) {
755 throw new ArgumentNullException ("tasks", "the tasks argument contains a null element");
757 if (first_finished < 0 && t.IsCompleted)
761 if (first_finished >= 0 || tasks.Length == 0)
762 return first_finished;
764 using (var completed_event = new ManualResetEventSlim (false)) {
766 foreach (var t in tasks) {
767 t.completed.Add (completed_event);
770 completed_event.Wait (millisecondsTimeout, cancellationToken);
772 for (int i = 0; i < tasks.Length; ++i) {
774 if (first_finished < 0 && t.IsCompleted)
777 t.completed.TryRemove (completed_event);
781 return first_finished;
784 static int CheckTimeout (TimeSpan timeout)
787 return checked ((int)timeout.TotalMilliseconds);
788 } catch (System.OverflowException) {
789 throw new ArgumentOutOfRangeException ("timeout");
793 static int ComputeTimeout (int millisecondsTimeout, Watch watch)
795 return millisecondsTimeout == -1 ? -1 : (int)Math.Max (watch.ElapsedMilliseconds - millisecondsTimeout, 1);
801 public void Dispose ()
806 protected virtual void Dispose (bool disposing)
809 throw new InvalidOperationException ("A task may only be disposed if it is in a completion state");
811 // Set action to null so that the GC can collect the delegate and thus
812 // any big object references that the user might have captured in a anonymous method
822 public ConfiguredTaskAwaitable ConfigureAwait (bool continueOnCapturedContext)
824 return new ConfiguredTaskAwaitable (this, continueOnCapturedContext);
827 public Task ContinueWith (Action<Task, object> continuationAction, object state)
829 return ContinueWith (continuationAction, state, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current);
832 public Task ContinueWith (Action<Task, object> continuationAction, object state, CancellationToken cancellationToken)
834 return ContinueWith (continuationAction, state, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
837 public Task ContinueWith (Action<Task, object> continuationAction, object state, TaskContinuationOptions continuationOptions)
839 return ContinueWith (continuationAction, state, CancellationToken.None, continuationOptions, TaskScheduler.Current);
842 public Task ContinueWith (Action<Task, object> continuationAction, object state, TaskScheduler scheduler)
844 return ContinueWith (continuationAction, state, CancellationToken.None, TaskContinuationOptions.None, scheduler);
847 public Task ContinueWith (Action<Task, object> continuationAction, object state, CancellationToken cancellationToken,
848 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
850 if (continuationAction == null)
851 throw new ArgumentNullException ("continuationAction");
852 if (scheduler == null)
853 throw new ArgumentNullException ("scheduler");
855 Task continuation = new Task (l => continuationAction (this, l), state,
857 GetCreationOptions (continuationOptions),
859 ContinueWithCore (continuation, continuationOptions, scheduler);
864 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state)
866 return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current);
869 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, TaskContinuationOptions continuationOptions)
871 return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, continuationOptions, TaskScheduler.Current);
874 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, CancellationToken cancellationToken)
876 return ContinueWith<TResult> (continuationFunction, state, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
879 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, TaskScheduler scheduler)
881 return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, TaskContinuationOptions.None, scheduler);
884 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, CancellationToken cancellationToken,
885 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
887 if (continuationFunction == null)
888 throw new ArgumentNullException ("continuationFunction");
889 if (scheduler == null)
890 throw new ArgumentNullException ("scheduler");
892 var t = new Task<TResult> (l => continuationFunction (this, l),
895 GetCreationOptions (continuationOptions),
898 ContinueWithCore (t, continuationOptions, scheduler);
903 public static Task<TResult> FromResult<TResult> (TResult result)
905 var tcs = new TaskCompletionSource<TResult> ();
906 tcs.SetResult (result);
910 public TaskAwaiter GetAwaiter ()
912 return new TaskAwaiter (this);
915 public static Task Run (Action action)
917 return Run (action, CancellationToken.None);
920 public static Task Run (Action action, CancellationToken cancellationToken)
922 if (cancellationToken.IsCancellationRequested)
923 return TaskConstants.Canceled;
925 var t = new Task (action, cancellationToken, TaskCreationOptions.DenyChildAttach);
930 public static Task Run (Func<Task> function)
932 return Run (function, CancellationToken.None);
935 public static Task Run (Func<Task> function, CancellationToken cancellationToken)
937 if (cancellationToken.IsCancellationRequested)
938 return TaskConstants.Canceled;
940 var t = new Task<Task> (function, cancellationToken);
945 public static Task<TResult> Run<TResult> (Func<TResult> function)
947 return Run (function, CancellationToken.None);
950 public static Task<TResult> Run<TResult> (Func<TResult> function, CancellationToken cancellationToken)
952 if (cancellationToken.IsCancellationRequested)
953 return TaskConstants<TResult>.Canceled;
955 var t = new Task<TResult> (function, cancellationToken, TaskCreationOptions.DenyChildAttach);
960 public static Task<TResult> Run<TResult> (Func<Task<TResult>> function)
962 return Run (function, CancellationToken.None);
965 public static Task<TResult> Run<TResult> (Func<Task<TResult>> function, CancellationToken cancellationToken)
967 if (cancellationToken.IsCancellationRequested)
968 return TaskConstants<TResult>.Canceled;
970 var t = Task<Task<TResult>>.Factory.StartNew (function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
971 return GetTaskResult (t);
974 async static Task<TResult> GetTaskResult<TResult> (Task<Task<TResult>> task)
976 var r = await task.ConfigureAwait (false);
980 public static YieldAwaitable Yield ()
982 return new YieldAwaitable ();
987 public static TaskFactory Factory {
989 return defaultFactory;
993 public static int? CurrentId {
996 return t == null ? (int?)null : t.Id;
1000 public AggregateException Exception {
1002 exceptionObserved = true;
1011 public bool IsCanceled {
1013 return status == TaskStatus.Canceled;
1017 public bool IsCompleted {
1019 return status == TaskStatus.RanToCompletion ||
1020 status == TaskStatus.Canceled || status == TaskStatus.Faulted;
1024 public bool IsFaulted {
1026 return status == TaskStatus.Faulted;
1030 public TaskCreationOptions CreationOptions {
1032 return taskCreationOptions;
1036 public TaskStatus Status {
1045 public object AsyncState {
1051 bool IAsyncResult.CompletedSynchronously {
1057 WaitHandle IAsyncResult.AsyncWaitHandle {
1069 internal Task Parent {
1075 internal string DisplayActionMethod {
1077 Delegate d = simpleAction ?? (Delegate) action;
1078 return d == null ? "<none>" : d.Method.ToString ();