Merge pull request #855 from echampet/spec
[mono.git] / mcs / class / corlib / System.Threading.Tasks / Task.cs
1 //
2 // Task.cs
3 //
4 // Authors:
5 //    Marek Safar  <marek.safar@gmail.com>
6 //    Jérémie Laval <jeremie dot laval at xamarin dot com>
7 //
8 // Copyright (c) 2008 Jérémie "Garuma" Laval
9 // Copyright 2011-2013 Xamarin Inc (http://www.xamarin.com).
10 //
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:
17 //
18 // The above copyright notice and this permission notice shall be included in
19 // all copies or substantial portions of the Software.
20 //
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
27 // THE SOFTWARE.
28 //
29 //
30
31 #if NET_4_0
32
33 using System;
34 using System.Threading;
35 using System.Collections.Concurrent;
36 using System.Collections.Generic;
37 using System.Runtime.CompilerServices;
38
39 namespace System.Threading.Tasks
40 {
41         [System.Diagnostics.DebuggerDisplay ("Id = {Id}, Status = {Status}")]
42         [System.Diagnostics.DebuggerTypeProxy (typeof (TaskDebuggerView))]
43         public class Task : IDisposable, IAsyncResult
44         {
45                 // With this attribute each thread has its own value so that it's correct for our Schedule code
46                 // and for Parent property.
47                 [System.ThreadStatic]
48                 static Task current;
49                 
50                 // parent is the outer task in which this task is created
51                 readonly Task parent;
52                 // A reference to a Task on which this continuation is attached to
53                 Task contAncestor;
54                 
55                 static int          id = -1;
56                 static readonly TaskFactory defaultFactory = new TaskFactory ();
57
58                 CountdownEvent childTasks;
59                 
60                 int                 taskId;
61                 TaskCreationOptions creationOptions;
62                 
63                 internal TaskScheduler       scheduler;
64
65                 TaskExceptionSlot exSlot;
66                 ManualResetEvent wait_handle;
67
68                 TaskStatus          status;
69
70                 TaskActionInvoker invoker;
71                 object         state;
72                 internal AtomicBooleanValue executing;
73
74                 TaskCompletionQueue<IContinuation> continuations;
75
76                 CancellationToken token;
77                 CancellationTokenRegistration? cancellationRegistration;
78
79                 internal const TaskCreationOptions WorkerTaskNotSupportedOptions = TaskCreationOptions.LongRunning | TaskCreationOptions.PreferFairness;
80
81                 const TaskCreationOptions MaxTaskCreationOptions =
82 #if NET_4_5
83                         TaskCreationOptions.DenyChildAttach | TaskCreationOptions.HideScheduler |
84 #endif
85                         TaskCreationOptions.PreferFairness | TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent;
86
87                 public Task (Action action)
88                         : this (action, TaskCreationOptions.None)
89                 {
90                         
91                 }
92                 
93                 public Task (Action action, TaskCreationOptions creationOptions)
94                         : this (action, CancellationToken.None, creationOptions)
95                 {
96                         
97                 }
98                 
99                 public Task (Action action, CancellationToken cancellationToken)
100                         : this (action, cancellationToken, TaskCreationOptions.None)
101                 {
102                         
103                 }
104                 
105                 public Task (Action action, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
106                         : this (TaskActionInvoker.Create (action), null, cancellationToken, creationOptions, current)
107                 {
108                         if (action == null)
109                                 throw new ArgumentNullException ("action");
110                         if (creationOptions > MaxTaskCreationOptions || creationOptions < TaskCreationOptions.None)
111                                 throw new ArgumentOutOfRangeException ("creationOptions");
112                 }
113                 
114                 public Task (Action<object> action, object state)
115                         : this (action, state, TaskCreationOptions.None)
116                 {       
117                 }
118                 
119                 public Task (Action<object> action, object state, TaskCreationOptions creationOptions)
120                         : this (action, state, CancellationToken.None, creationOptions)
121                 {
122                 }
123                 
124                 public Task (Action<object> action, object state, CancellationToken cancellationToken)
125                         : this (action, state, cancellationToken, TaskCreationOptions.None)
126                 {       
127                 }
128
129                 public Task (Action<object> action, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
130                         : this (TaskActionInvoker.Create (action), state, cancellationToken, creationOptions, current)
131                 {
132                         if (action == null)
133                                 throw new ArgumentNullException ("action");
134                         if (creationOptions > MaxTaskCreationOptions || creationOptions < TaskCreationOptions.None)
135                                 throw new ArgumentOutOfRangeException ("creationOptions");
136                 }
137
138                 internal Task (TaskActionInvoker invoker, object state, CancellationToken cancellationToken,
139                                TaskCreationOptions creationOptions, Task parent = null, Task contAncestor = null, bool ignoreCancellation = false)
140                 {
141                         this.invoker         = invoker;
142                         this.creationOptions = creationOptions;
143                         this.state           = state;
144                         this.taskId          = Interlocked.Increment (ref id);
145                         this.token           = cancellationToken;
146                         this.parent          = parent = parent == null ? current : parent;
147                         this.contAncestor    = contAncestor;
148                         this.status          = cancellationToken.IsCancellationRequested && !ignoreCancellation ? TaskStatus.Canceled : TaskStatus.Created;
149
150                         // Process creationOptions
151 #if NET_4_5
152                         if (parent != null && HasFlag (creationOptions, TaskCreationOptions.AttachedToParent)
153                             && !HasFlag (parent.CreationOptions, TaskCreationOptions.DenyChildAttach))
154 #else
155                         if (parent != null && HasFlag (creationOptions, TaskCreationOptions.AttachedToParent))
156 #endif
157                                 parent.AddChild ();
158
159                         if (token.CanBeCanceled && !ignoreCancellation)
160                                 cancellationRegistration = token.Register (l => ((Task) l).CancelReal (), this);
161                 }
162
163                 static bool HasFlag (TaskCreationOptions opt, TaskCreationOptions member)
164                 {
165                         return (opt & member) == member;
166                 }
167
168                 #region Start
169                 public void Start ()
170                 {
171                         Start (TaskScheduler.Current);
172                 }
173                 
174                 public void Start (TaskScheduler scheduler)
175                 {
176                         if (scheduler == null)
177                                 throw new ArgumentNullException ("scheduler");
178
179                         if (status >= TaskStatus.WaitingToRun)
180                                 throw new InvalidOperationException ("The Task is not in a valid state to be started.");
181
182                         if (IsContinuation)
183                                 throw new InvalidOperationException ("Start may not be called on a continuation task");
184
185                         if (IsPromise)
186                                 throw new InvalidOperationException ("Start may not be called on a promise-style task");
187
188                         SetupScheduler (scheduler);
189                         Schedule ();
190                 }
191
192                 internal void SetupScheduler (TaskScheduler scheduler)
193                 {
194                         this.scheduler = scheduler;
195                         Status = TaskStatus.WaitingForActivation;
196                 }
197                 
198                 public void RunSynchronously ()
199                 {
200                         RunSynchronously (TaskScheduler.Current);
201                 }
202                 
203                 public void RunSynchronously (TaskScheduler scheduler)
204                 {
205                         if (scheduler == null)
206                                 throw new ArgumentNullException ("scheduler");
207
208                         if (Status > TaskStatus.WaitingForActivation)
209                                 throw new InvalidOperationException ("The task is not in a valid state to be started");
210
211                         if (IsContinuation)
212                                 throw new InvalidOperationException ("RunSynchronously may not be called on a continuation task");
213
214                         if (IsPromise)
215                                 throw new InvalidOperationException ("RunSynchronously may not be called on a promise-style task");
216
217                         RunSynchronouslyCore (scheduler);
218                 }
219
220                 internal void RunSynchronouslyCore (TaskScheduler scheduler)
221                 {
222                         SetupScheduler (scheduler);
223                         Status = TaskStatus.WaitingToRun;
224
225                         try {
226                                 if (scheduler.RunInline (this, false))
227                                         return;
228                         } catch (Exception inner) {
229                                 throw new TaskSchedulerException (inner);
230                         }
231
232                         Schedule ();
233                         WaitCore (Timeout.Infinite, CancellationToken.None, false);
234                 }
235                 #endregion
236                 
237                 #region ContinueWith
238                 public Task ContinueWith (Action<Task> continuationAction)
239                 {
240                         return ContinueWith (continuationAction, TaskContinuationOptions.None);
241                 }
242                 
243                 public Task ContinueWith (Action<Task> continuationAction, TaskContinuationOptions continuationOptions)
244                 {
245                         return ContinueWith (continuationAction, CancellationToken.None, continuationOptions, TaskScheduler.Current);
246                 }
247                 
248                 public Task ContinueWith (Action<Task> continuationAction, CancellationToken cancellationToken)
249                 {
250                         return ContinueWith (continuationAction, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
251                 }
252                 
253                 public Task ContinueWith (Action<Task> continuationAction, TaskScheduler scheduler)
254                 {
255                         return ContinueWith (continuationAction, CancellationToken.None, TaskContinuationOptions.None, scheduler);
256                 }
257                 
258                 public Task ContinueWith (Action<Task> continuationAction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
259                 {
260                         if (continuationAction == null)
261                                 throw new ArgumentNullException ("continuationAction");
262                         if (scheduler == null)
263                                 throw new ArgumentNullException ("scheduler");
264
265                         return ContinueWith (TaskActionInvoker.Create (continuationAction), cancellationToken, continuationOptions, scheduler);
266                 }
267
268                 internal Task ContinueWith (TaskActionInvoker invoker, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
269                 {
270                         var lazyCancellation = false;
271 #if NET_4_5
272                         lazyCancellation = (continuationOptions & TaskContinuationOptions.LazyCancellation) > 0;
273 #endif
274                         var continuation = new Task (invoker, null, cancellationToken, GetCreationOptions (continuationOptions), null, this, lazyCancellation);
275                         ContinueWithCore (continuation, continuationOptions, scheduler);
276
277                         return continuation;
278                 }
279                 
280                 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction)
281                 {
282                         return ContinueWith<TResult> (continuationFunction, TaskContinuationOptions.None);
283                 }
284                 
285                 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, TaskContinuationOptions continuationOptions)
286                 {
287                         return ContinueWith<TResult> (continuationFunction, CancellationToken.None, continuationOptions, TaskScheduler.Current);
288                 }
289                 
290                 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, CancellationToken cancellationToken)
291                 {
292                         return ContinueWith<TResult> (continuationFunction, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
293                 }
294                 
295                 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, TaskScheduler scheduler)
296                 {
297                         return ContinueWith<TResult> (continuationFunction, CancellationToken.None, TaskContinuationOptions.None, scheduler);
298                 }
299                 
300                 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, CancellationToken cancellationToken,
301                                                             TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
302                 {
303                         if (continuationFunction == null)
304                                 throw new ArgumentNullException ("continuationFunction");
305                         if (scheduler == null)
306                                 throw new ArgumentNullException ("scheduler");
307
308                         return ContinueWith<TResult> (TaskActionInvoker.Create (continuationFunction), cancellationToken, continuationOptions, scheduler);
309                 }
310
311                 internal Task<TResult> ContinueWith<TResult> (TaskActionInvoker invoker, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
312                 {
313                         var lazyCancellation = false;
314 #if NET_4_5
315                         lazyCancellation = (continuationOptions & TaskContinuationOptions.LazyCancellation) > 0;
316 #endif
317                         var continuation = new Task<TResult> (invoker, null, cancellationToken, GetCreationOptions (continuationOptions), parent, this, lazyCancellation);
318                         ContinueWithCore (continuation, continuationOptions, scheduler);
319
320                         return continuation;
321                 }
322         
323                 internal void ContinueWithCore (Task continuation, TaskContinuationOptions options, TaskScheduler scheduler)
324                 {
325                         const TaskContinuationOptions wrongRan = TaskContinuationOptions.NotOnRanToCompletion | TaskContinuationOptions.OnlyOnRanToCompletion;
326                         const TaskContinuationOptions wrongCanceled = TaskContinuationOptions.NotOnCanceled | TaskContinuationOptions.OnlyOnCanceled;
327                         const TaskContinuationOptions wrongFaulted = TaskContinuationOptions.NotOnFaulted | TaskContinuationOptions.OnlyOnFaulted;
328
329                         if (((options & wrongRan) == wrongRan) || ((options & wrongCanceled) == wrongCanceled) || ((options & wrongFaulted) == wrongFaulted))
330                                 throw new ArgumentException ("continuationOptions", "Some options are mutually exclusive");
331
332                         // Already set the scheduler so that user can call Wait and that sort of stuff
333                         continuation.scheduler = scheduler;
334                         continuation.Status = TaskStatus.WaitingForActivation;
335
336                         ContinueWith (new TaskContinuation (continuation, options));
337                 }
338                 
339                 internal bool ContinueWith (IContinuation continuation, bool canExecuteInline = true)
340                 {
341                         if (IsCompleted) {
342                                 if (!canExecuteInline)
343                                         return false;
344
345                                 continuation.Execute ();
346                                 return true;
347                         }
348                         
349                         continuations.Add (continuation);
350                         
351                         // Retry in case completion was achieved but event adding was too late
352                         if (IsCompleted) {
353                                 continuations.Remove (continuation);
354                                 if (!canExecuteInline)
355                                         return false;
356
357                                 continuation.Execute ();
358                         }
359
360                         return true;
361                 }
362
363                 internal void RemoveContinuation (IContinuation continuation)
364                 {
365                         continuations.Remove (continuation);
366                 }
367
368                 static internal TaskCreationOptions GetCreationOptions (TaskContinuationOptions kind)
369                 {
370                         TaskCreationOptions options = TaskCreationOptions.None;
371                         if ((kind & TaskContinuationOptions.AttachedToParent) > 0)
372                                 options |= TaskCreationOptions.AttachedToParent;
373                         if ((kind & TaskContinuationOptions.PreferFairness) > 0)
374                                 options |= TaskCreationOptions.PreferFairness;
375                         if ((kind & TaskContinuationOptions.LongRunning) > 0)
376                                 options |= TaskCreationOptions.LongRunning;
377                         
378                         return options;
379                 }
380                 #endregion
381                 
382                 #region Internal and protected thingies
383                 internal void Schedule ()
384                 {
385                         Status = TaskStatus.WaitingToRun;
386                         scheduler.QueueTask (this);
387                 }
388                 
389                 void ThreadStart ()
390                 {
391                         /* Allow scheduler to break fairness of deque ordering without
392                          * breaking its semantic (the task can be executed twice but the
393                          * second time it will return immediately
394                          */
395                         if (!executing.TryRelaxedSet ())
396                                 return;
397
398                         // Disable CancellationToken direct cancellation
399                         if (cancellationRegistration != null) {
400                                 cancellationRegistration.Value.Dispose ();
401                                 cancellationRegistration = null;
402                         }
403
404                         // If Task are ran inline on the same thread we might trash these values
405                         var saveCurrent = current;
406                         var saveScheduler = TaskScheduler.Current;
407
408                         current = this;
409 #if NET_4_5
410                         TaskScheduler.Current = HasFlag (creationOptions, TaskCreationOptions.HideScheduler) ? TaskScheduler.Default : scheduler;
411 #else
412                         TaskScheduler.Current = scheduler;
413 #endif
414                         
415                         if (!token.IsCancellationRequested) {
416                                 
417                                 status = TaskStatus.Running;
418                                 
419                                 try {
420                                         InnerInvoke ();
421                                 } catch (OperationCanceledException oce) {
422                                         if (token != CancellationToken.None && oce.CancellationToken == token)
423                                                 CancelReal ();
424                                         else
425                                                 HandleGenericException (oce);
426                                 } catch (Exception e) {
427                                         HandleGenericException (e);
428                                 }
429                         } else {
430                                 CancelReal ();
431                         }
432
433                         if (saveCurrent != null)
434                                 current = saveCurrent;
435                         if (saveScheduler != null)
436                                 TaskScheduler.Current = saveScheduler;
437                         Finish ();
438                 }
439
440                 internal bool TrySetCanceled ()
441                 {
442                         if (IsCompleted)
443                                 return false;
444                         
445                         if (!executing.TryRelaxedSet ()) {
446                                 var sw = new SpinWait ();
447                                 while (!IsCompleted)
448                                         sw.SpinOnce ();
449
450                                 return false;
451                         }
452                         
453                         CancelReal ();
454                         return true;
455                 }
456
457                 internal bool TrySetException (AggregateException aggregate, bool cancellation)
458                 {
459                         if (IsCompleted)
460                                 return false;
461                         
462                         if (!executing.TryRelaxedSet ()) {
463                                 var sw = new SpinWait ();
464                                 while (!IsCompleted)
465                                         sw.SpinOnce ();
466
467                                 return false;
468                         }
469
470                         if (cancellation) {
471                                 ExceptionSlot.Exception = aggregate;
472                                 Thread.MemoryBarrier ();
473
474                                 CancelReal ();
475                         } else {
476                                 HandleGenericException (aggregate);
477                         }
478
479                         return true;
480                 }
481
482                 internal bool TrySetExceptionObserved ()
483                 {
484                         if (exSlot != null) {
485                                 exSlot.Observed = true;
486                                 return true;
487                         }
488                         return false;
489                 }
490
491                 internal void Execute ()
492                 {
493                         ThreadStart ();
494                 }
495                 
496                 internal void AddChild ()
497                 {
498                         if (childTasks == null)
499                                 Interlocked.CompareExchange (ref childTasks, new CountdownEvent (1), null);
500                         childTasks.AddCount ();
501                 }
502
503                 internal void ChildCompleted (AggregateException childEx)
504                 {
505                         if (childEx != null) {
506                                 if (ExceptionSlot.ChildExceptions == null)
507                                         Interlocked.CompareExchange (ref ExceptionSlot.ChildExceptions, new ConcurrentQueue<AggregateException> (), null);
508                                 ExceptionSlot.ChildExceptions.Enqueue (childEx);
509                         }
510
511                         if (childTasks.Signal () && status == TaskStatus.WaitingForChildrenToComplete) {
512                                 ProcessChildExceptions ();
513                                 Status = exSlot == null ? TaskStatus.RanToCompletion : TaskStatus.Faulted;
514                                 ProcessCompleteDelegates ();
515                                 if (parent != null &&
516 #if NET_4_5
517                                     !HasFlag (parent.CreationOptions, TaskCreationOptions.DenyChildAttach) &&
518 #endif
519                                         HasFlag (creationOptions, TaskCreationOptions.AttachedToParent))
520                                         parent.ChildCompleted (this.Exception);
521                         }
522                 }
523
524                 void InnerInvoke ()
525                 {
526                         if (IsContinuation) {
527                                 var ancestor = contAncestor;
528                                 contAncestor = null;
529                                 invoker.Invoke (ancestor, state, this);
530                         } else {
531                                 invoker.Invoke (this, state, this);
532                         }
533                 }
534                 
535                 internal void Finish ()
536                 {
537                         // If there was children created and they all finished, we set the countdown
538                         if (childTasks != null) {
539                                 if (childTasks.Signal ())
540                                         ProcessChildExceptions (true);
541                         }
542                         
543                         // Don't override Canceled or Faulted
544                         if (status == TaskStatus.Running) {
545                                 if (childTasks == null || childTasks.IsSet)
546                                         Status = TaskStatus.RanToCompletion;
547                                 else
548                                         Status = TaskStatus.WaitingForChildrenToComplete;
549                         }
550
551                         if (wait_handle != null)
552                                 wait_handle.Set ();
553
554                         // Tell parent that we are finished
555                         if (parent != null && HasFlag (creationOptions, TaskCreationOptions.AttachedToParent) &&
556 #if NET_4_5
557                             !HasFlag (parent.CreationOptions, TaskCreationOptions.DenyChildAttach) &&
558 #endif
559                                 status != TaskStatus.WaitingForChildrenToComplete) {
560                                 parent.ChildCompleted (this.Exception);
561                         }
562
563                         // Completions are already processed when task is canceled or faulted
564                         if (status == TaskStatus.RanToCompletion)
565                                 ProcessCompleteDelegates ();
566
567                         // Reset the current thingies
568                         if (current == this)
569                                 current = null;
570                         if (TaskScheduler.Current == scheduler)
571                                 TaskScheduler.Current = null;
572
573                         if (cancellationRegistration.HasValue)
574                                 cancellationRegistration.Value.Dispose ();
575                 }
576
577                 void ProcessCompleteDelegates ()
578                 {
579                         if (continuations.HasElements) {
580                                 IContinuation continuation;
581                                 while (continuations.TryGetNextCompletion (out continuation))
582                                         continuation.Execute ();
583                         }
584                 }
585
586                 void ProcessChildExceptions (bool isParent = false)
587                 {
588                         if (exSlot == null || exSlot.ChildExceptions == null)
589                                 return;
590
591                         if (ExceptionSlot.Exception == null)
592                                 exSlot.Exception = new AggregateException ();
593
594                         AggregateException childEx;
595                         while (exSlot.ChildExceptions.TryDequeue (out childEx))
596                                 exSlot.Exception.AddChildException (childEx);
597
598                         if (isParent) {
599                                 Status = TaskStatus.Faulted;
600                                 ProcessCompleteDelegates ();                    
601                         }
602                 }
603                 #endregion
604                 
605                 #region Cancel and Wait related method
606                 
607                 internal void CancelReal ()
608                 {
609                         Status = TaskStatus.Canceled;
610
611                         if (wait_handle != null)
612                                 wait_handle.Set ();
613
614                         ProcessCompleteDelegates ();
615                 }
616
617                 void HandleGenericException (Exception e)
618                 {
619                         HandleGenericException (new AggregateException (e));
620                 }
621
622                 void HandleGenericException (AggregateException e)
623                 {
624                         ExceptionSlot.Exception = e;
625                         Thread.MemoryBarrier ();
626                         Status = TaskStatus.Faulted;
627
628                         if (wait_handle != null)
629                                 wait_handle.Set ();
630
631                         ProcessCompleteDelegates ();
632                 }
633
634                 internal bool WaitOnChildren ()
635                 {
636                         if (Status == TaskStatus.WaitingForChildrenToComplete && childTasks != null) {
637                                 childTasks.Wait ();
638                                 return true;
639                         }
640                         return false;
641                 }
642                 
643                 public void Wait ()
644                 {
645                         Wait (Timeout.Infinite, CancellationToken.None);
646                 }
647
648                 public void Wait (CancellationToken cancellationToken)
649                 {
650                         Wait (Timeout.Infinite, cancellationToken);
651                 }
652                 
653                 public bool Wait (TimeSpan timeout)
654                 {
655                         return Wait (CheckTimeout (timeout), CancellationToken.None);
656                 }
657                 
658                 public bool Wait (int millisecondsTimeout)
659                 {
660                         return Wait (millisecondsTimeout, CancellationToken.None);
661                 }
662
663                 public bool Wait (int millisecondsTimeout, CancellationToken cancellationToken)
664                 {
665                         if (millisecondsTimeout < -1)
666                                 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
667
668                         bool result = WaitCore (millisecondsTimeout, cancellationToken, true);
669
670                         if (IsCanceled)
671                                 throw new AggregateException (new TaskCanceledException (this));
672
673                         var exception = Exception;
674                         if (exception != null)
675                                 throw exception;
676
677                         return result;
678                 }
679
680                 internal bool WaitCore (int millisecondsTimeout, CancellationToken cancellationToken, bool runInline)
681                 {
682                         if (IsCompleted)
683                                 return true;
684
685                         // If the task is ready to be run and we were supposed to wait on it indefinitely without cancellation, just run it
686                         if (runInline && Status == TaskStatus.WaitingToRun && millisecondsTimeout == Timeout.Infinite && scheduler != null && !cancellationToken.CanBeCanceled)
687                                 scheduler.RunInline (this, true);
688
689                         bool result = true;
690
691                         if (!IsCompleted) {
692                                 var continuation = new ManualResetContinuation ();
693                                 try {
694                                         ContinueWith (continuation);
695                                         result = continuation.Event.Wait (millisecondsTimeout, cancellationToken);
696                                 } finally {
697                                         if (!result)
698                                                 RemoveContinuation (continuation);
699                                         continuation.Dispose ();
700                                 }
701                         }
702
703                         return result;
704                 }
705                 
706                 public static void WaitAll (params Task[] tasks)
707                 {
708                         WaitAll (tasks, Timeout.Infinite, CancellationToken.None);
709                 }
710
711                 public static void WaitAll (Task[] tasks, CancellationToken cancellationToken)
712                 {
713                         WaitAll (tasks, Timeout.Infinite, cancellationToken);
714                 }
715                 
716                 public static bool WaitAll (Task[] tasks, TimeSpan timeout)
717                 {
718                         return WaitAll (tasks, CheckTimeout (timeout), CancellationToken.None);
719                 }
720                 
721                 public static bool WaitAll (Task[] tasks, int millisecondsTimeout)
722                 {
723                         return WaitAll (tasks, millisecondsTimeout, CancellationToken.None);
724                 }
725                 
726                 public static bool WaitAll (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
727                 {
728                         if (tasks == null)
729                                 throw new ArgumentNullException ("tasks");
730
731                         bool result = true;
732                         foreach (var t in tasks) {
733                                 if (t == null)
734                                         throw new ArgumentException ("tasks", "the tasks argument contains a null element");
735
736                                 result &= t.Status == TaskStatus.RanToCompletion;
737                         }
738
739                         if (!result) {
740                                 var continuation = new CountdownContinuation (tasks.Length);
741                                 try {
742                                         foreach (var t in tasks)
743                                                 t.ContinueWith (continuation);
744
745                                         result = continuation.Event.Wait (millisecondsTimeout, cancellationToken);
746                                 } finally {
747                                         List<Exception> exceptions = null;
748
749                                         foreach (var t in tasks) {
750                                                 if (result) {
751                                                         if (t.Status == TaskStatus.RanToCompletion)
752                                                                 continue;
753                                                         if (exceptions == null)
754                                                                 exceptions = new List<Exception> ();
755                                                         if (t.Exception != null)
756                                                                 exceptions.AddRange (t.Exception.InnerExceptions);
757                                                         else
758                                                                 exceptions.Add (new TaskCanceledException (t));
759                                                 } else {
760                                                         t.RemoveContinuation (continuation);
761                                                 }
762                                         }
763
764                                         continuation.Dispose ();
765
766                                         if (exceptions != null)
767                                                 throw new AggregateException (exceptions);
768                                 }
769                         }
770
771                         return result;
772                 }
773                 
774                 public static int WaitAny (params Task[] tasks)
775                 {
776                         return WaitAny (tasks, Timeout.Infinite, CancellationToken.None);
777                 }
778
779                 public static int WaitAny (Task[] tasks, TimeSpan timeout)
780                 {
781                         return WaitAny (tasks, CheckTimeout (timeout));
782                 }
783                 
784                 public static int WaitAny (Task[] tasks, int millisecondsTimeout)
785                 {
786                         return WaitAny (tasks, millisecondsTimeout, CancellationToken.None);
787                 }
788
789                 public static int WaitAny (Task[] tasks, CancellationToken cancellationToken)
790                 {
791                         return WaitAny (tasks, Timeout.Infinite, cancellationToken);
792                 }
793
794                 public static int WaitAny (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
795                 {
796                         if (tasks == null)
797                                 throw new ArgumentNullException ("tasks");
798                         if (millisecondsTimeout < -1)
799                                 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
800                         CheckForNullTasks (tasks);
801
802                         if (tasks.Length > 0) {
803                                 var continuation = new ManualResetContinuation ();
804                                 bool result = false;
805                                 try {
806                                         for (int i = 0; i < tasks.Length; i++) {
807                                                 var t = tasks[i];
808                                                 if (t.IsCompleted)
809                                                         return i;
810                                                 t.ContinueWith (continuation);
811                                         }
812
813                                         if (!(result = continuation.Event.Wait (millisecondsTimeout, cancellationToken)))
814                                                 return -1;
815                                 } finally {
816                                         if (!result)
817                                                 foreach (var t in tasks)
818                                                         t.RemoveContinuation (continuation);
819                                         continuation.Dispose ();
820                                 }
821                         }
822
823                         int firstFinished = -1;
824                         for (int i = 0; i < tasks.Length; i++) {
825                                 var t = tasks[i];
826                                 if (t.IsCompleted) {
827                                         firstFinished = i;
828                                         break;
829                                 }
830                         }
831
832                         return firstFinished;
833                 }
834
835                 static int CheckTimeout (TimeSpan timeout)
836                 {
837                         try {
838                                 return checked ((int)timeout.TotalMilliseconds);
839                         } catch (System.OverflowException) {
840                                 throw new ArgumentOutOfRangeException ("timeout");
841                         }
842                 }
843
844                 static void CheckForNullTasks (Task[] tasks)
845                 {
846                         foreach (var t in tasks)
847                                 if (t == null)
848                                         throw new ArgumentException ("tasks", "the tasks argument contains a null element");
849                 }
850                 #endregion
851                 
852                 #region Dispose
853                 public void Dispose ()
854                 {
855                         Dispose (true);                 
856                 }
857                 
858                 protected virtual void Dispose (bool disposing)
859                 {
860                         if (!IsCompleted)
861                                 throw new InvalidOperationException ("A task may only be disposed if it is in a completion state");
862
863                         // Set action to null so that the GC can collect the delegate and thus
864                         // any big object references that the user might have captured in a anonymous method
865                         if (disposing) {
866                                 invoker = null;
867                                 state = null;
868                                 if (cancellationRegistration != null)
869                                         cancellationRegistration.Value.Dispose ();
870                                 if (wait_handle != null)
871                                         wait_handle.Dispose ();
872                         }
873                 }
874                 #endregion
875
876 #if NET_4_5
877                 public
878 #else
879                 internal
880 #endif
881                 Task ContinueWith (Action<Task, object> continuationAction, object state, CancellationToken cancellationToken,
882                                                                   TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
883                 {
884                         if (continuationAction == null)
885                                 throw new ArgumentNullException ("continuationAction");
886                         if (scheduler == null)
887                                 throw new ArgumentNullException ("scheduler");
888
889                         Task continuation = new Task (TaskActionInvoker.Create (continuationAction),
890                                                                                   state, cancellationToken,
891                                                                                   GetCreationOptions (continuationOptions),
892                                                       parent,
893                                                       this);
894                         ContinueWithCore (continuation, continuationOptions, scheduler);
895
896                         return continuation;
897                 }
898                 
899 #if NET_4_5
900
901                 public ConfiguredTaskAwaitable ConfigureAwait (bool continueOnCapturedContext)
902                 {
903                         return new ConfiguredTaskAwaitable (this, continueOnCapturedContext);
904                 }
905
906                 public Task ContinueWith (Action<Task, object> continuationAction, object state)
907                 {
908                         return ContinueWith (continuationAction, state, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current);
909                 }
910
911                 public Task ContinueWith (Action<Task, object> continuationAction, object state, CancellationToken cancellationToken)
912                 {
913                         return ContinueWith (continuationAction, state, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
914                 }
915
916                 public Task ContinueWith (Action<Task, object> continuationAction, object state, TaskContinuationOptions continuationOptions)
917                 {
918                         return ContinueWith (continuationAction, state, CancellationToken.None, continuationOptions, TaskScheduler.Current);
919                 }
920
921                 public Task ContinueWith (Action<Task, object> continuationAction, object state, TaskScheduler scheduler)
922                 {
923                         return ContinueWith (continuationAction, state, CancellationToken.None, TaskContinuationOptions.None, scheduler);
924                 }
925
926                 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state)
927                 {
928                         return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current);
929                 }
930
931                 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, TaskContinuationOptions continuationOptions)
932                 {
933                         return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, continuationOptions, TaskScheduler.Current);
934                 }
935
936                 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, CancellationToken cancellationToken)
937                 {
938                         return ContinueWith<TResult> (continuationFunction, state, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
939                 }
940
941                 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, TaskScheduler scheduler)
942                 {
943                         return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, TaskContinuationOptions.None, scheduler);
944                 }
945
946                 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, CancellationToken cancellationToken,
947                                                                                                         TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
948                 {
949                         if (continuationFunction == null)
950                                 throw new ArgumentNullException ("continuationFunction");
951                         if (scheduler == null)
952                                 throw new ArgumentNullException ("scheduler");
953
954                         var t = new Task<TResult> (TaskActionInvoker.Create (continuationFunction),
955                                                    state,
956                                                    cancellationToken,
957                                                    GetCreationOptions (continuationOptions),
958                                                    parent,
959                                                    this);
960
961                         ContinueWithCore (t, continuationOptions, scheduler);
962
963                         return t;
964                 }
965
966                 public static Task Delay (int millisecondsDelay)
967                 {
968                         return Delay (millisecondsDelay, CancellationToken.None);
969                 }
970
971                 public static Task Delay (TimeSpan delay)
972                 {
973                         return Delay (CheckTimeout (delay), CancellationToken.None);
974                 }
975
976                 public static Task Delay (TimeSpan delay, CancellationToken cancellationToken)
977                 {
978                         return Delay (CheckTimeout (delay), cancellationToken);
979                 }
980
981                 public static Task Delay (int millisecondsDelay, CancellationToken cancellationToken)
982                 {
983                         if (millisecondsDelay < -1)
984                                 throw new ArgumentOutOfRangeException ("millisecondsDelay");
985
986                         if (cancellationToken.IsCancellationRequested)
987                                 return TaskConstants.Canceled;
988
989                         var task = new Task (TaskActionInvoker.Empty, null, cancellationToken, TaskCreationOptions.None, null, null);
990                         task.SetupScheduler (TaskScheduler.Default);
991
992                         if (millisecondsDelay != Timeout.Infinite) {
993                                 var timer = new Timer (delegate (object state) {
994                                         var t = (Task) state;
995                                         if (t.Status == TaskStatus.WaitingForActivation) {
996                                                 t.Status = TaskStatus.Running;
997                                                 t.Finish ();
998                                         }
999                                 }, task, millisecondsDelay, -1);
1000
1001                                 task.ContinueWith (new DisposeContinuation (timer));
1002                         }
1003
1004                         return task;
1005                 }
1006
1007                 public static Task<TResult> FromResult<TResult> (TResult result)
1008                 {
1009                         var tcs = new TaskCompletionSource<TResult> ();
1010                         tcs.SetResult (result);
1011                         return tcs.Task;
1012                 }
1013
1014                 public TaskAwaiter GetAwaiter ()
1015                 {
1016                         return new TaskAwaiter (this);
1017                 }
1018
1019                 public static Task Run (Action action)
1020                 {
1021                         return Run (action, CancellationToken.None);
1022                 }
1023
1024                 public static Task Run (Action action, CancellationToken cancellationToken)
1025                 {
1026                         if (cancellationToken.IsCancellationRequested)
1027                                 return TaskConstants.Canceled;
1028
1029                         return Task.Factory.StartNew (action, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
1030                 }
1031
1032                 public static Task Run (Func<Task> function)
1033                 {
1034                         return Run (function, CancellationToken.None);
1035                 }
1036
1037                 public static Task Run (Func<Task> function, CancellationToken cancellationToken)
1038                 {
1039                         if (cancellationToken.IsCancellationRequested)
1040                                 return TaskConstants.Canceled;
1041
1042                         return TaskExtensionsImpl.Unwrap (Task.Factory.StartNew (function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default));
1043                 }
1044
1045                 public static Task<TResult> Run<TResult> (Func<TResult> function)
1046                 {
1047                         return Run (function, CancellationToken.None);
1048                 }
1049
1050                 public static Task<TResult> Run<TResult> (Func<TResult> function, CancellationToken cancellationToken)
1051                 {
1052                         if (cancellationToken.IsCancellationRequested)
1053                                 return TaskConstants<TResult>.Canceled;
1054
1055                         return Task.Factory.StartNew (function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
1056                 }
1057
1058                 public static Task<TResult> Run<TResult> (Func<Task<TResult>> function)
1059                 {
1060                         return Run (function, CancellationToken.None);
1061                 }
1062
1063                 public static Task<TResult> Run<TResult> (Func<Task<TResult>> function, CancellationToken cancellationToken)
1064                 {
1065                         if (cancellationToken.IsCancellationRequested)
1066                                 return TaskConstants<TResult>.Canceled;
1067
1068                         return TaskExtensionsImpl.Unwrap (Task.Factory.StartNew (function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default));
1069                 }
1070
1071                 public static Task WhenAll (params Task[] tasks)
1072                 {
1073                         if (tasks == null)
1074                                 throw new ArgumentNullException ("tasks");
1075
1076                         return WhenAllCore (tasks);
1077                 }
1078
1079                 public static Task WhenAll (IEnumerable<Task> tasks)
1080                 {
1081                         if (tasks == null)
1082                                 throw new ArgumentNullException ("tasks");
1083
1084                         // Call ToList on input enumeration or we end up
1085                         // enumerating it more than once
1086                         return WhenAllCore (new List<Task> (tasks));
1087                 }
1088
1089                 public static Task<TResult[]> WhenAll<TResult> (params Task<TResult>[] tasks)
1090                 {
1091                         if (tasks == null)
1092                                 throw new ArgumentNullException ("tasks");
1093
1094                         return WhenAllCore<TResult> (tasks);
1095                 }
1096
1097                 public static Task<TResult[]> WhenAll<TResult> (IEnumerable<Task<TResult>> tasks)
1098                 {
1099                         if (tasks == null)
1100                                 throw new ArgumentNullException ("tasks");
1101
1102                         // Call ToList on input enumeration or we end up
1103                         // enumerating it more than once
1104                         return WhenAllCore<TResult> (new List<Task<TResult>> (tasks));
1105                 }
1106
1107                 internal static Task<TResult[]> WhenAllCore<TResult> (IList<Task<TResult>> tasks)
1108                 {
1109                         if (tasks.Count == 0)
1110                                 return FromResult(new TResult[0]);
1111
1112                         foreach (var t in tasks) {
1113                                 if (t == null)
1114                                         throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1115                         }
1116
1117                         var task = new Task<TResult[]> (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1118                         task.SetupScheduler (TaskScheduler.Current);
1119
1120                         var continuation = new WhenAllContinuation<TResult> (task, tasks);
1121                         foreach (var t in tasks)
1122                                 t.ContinueWith (continuation);
1123
1124                         return task;
1125                 }
1126
1127                 public static Task<Task> WhenAny (params Task[] tasks)
1128                 {
1129                         if (tasks == null)
1130                                 throw new ArgumentNullException ("tasks");
1131
1132                         return WhenAnyCore (tasks);
1133                 }
1134
1135                 public static Task<Task> WhenAny (IEnumerable<Task> tasks)
1136                 {
1137                         if (tasks == null)
1138                                 throw new ArgumentNullException ("tasks");
1139
1140                         return WhenAnyCore (new List<Task> (tasks));
1141                 }
1142
1143                 public static Task<Task<TResult>> WhenAny<TResult> (params Task<TResult>[] tasks)
1144                 {
1145                         if (tasks == null)
1146                                 throw new ArgumentNullException ("tasks");
1147
1148                         return WhenAnyCore<TResult> (tasks);
1149                 }
1150
1151                 public static Task<Task<TResult>> WhenAny<TResult> (IEnumerable<Task<TResult>> tasks)
1152                 {
1153                         if (tasks == null)
1154                                 throw new ArgumentNullException ("tasks");
1155
1156                         return WhenAnyCore<TResult> (new List<Task<TResult>> (tasks));
1157                 }
1158
1159                 static Task<Task<TResult>> WhenAnyCore<TResult> (IList<Task<TResult>> tasks)
1160                 {
1161                         if (tasks.Count == 0)
1162                                 throw new ArgumentException ("The tasks argument contains no tasks", "tasks");
1163
1164                         int completed_index = -1;
1165                         for (int i = 0; i < tasks.Count; ++i) {
1166                                 var t = tasks[i];
1167                                 if (t == null)
1168                                         throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1169
1170                                 if (t.IsCompleted && completed_index < 0)
1171                                         completed_index = i;
1172                         }
1173
1174                         var task = new Task<Task<TResult>> (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1175
1176                         if (completed_index > 0) {
1177                                 task.TrySetResult (tasks[completed_index]);
1178                                 return task;
1179                         }
1180
1181                         task.SetupScheduler (TaskScheduler.Current);
1182
1183                         var continuation = new WhenAnyContinuation<Task<TResult>> (task, tasks);
1184                         foreach (var t in tasks)
1185                                 t.ContinueWith (continuation);
1186
1187                         return task;
1188                 }
1189
1190                 public static YieldAwaitable Yield ()
1191                 {
1192                         return new YieldAwaitable ();
1193                 }
1194 #endif
1195
1196                 internal static Task WhenAllCore (IList<Task> tasks)
1197                 {
1198                         bool all_completed = true;
1199                         foreach (var t in tasks) {
1200                                 if (t == null)
1201                                         throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1202
1203                                 all_completed &= t.Status == TaskStatus.RanToCompletion;
1204                         }
1205
1206                         if (all_completed)
1207                                 return TaskConstants.Finished;
1208
1209                         var task = new Task (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1210                         task.SetupScheduler (TaskScheduler.Current);
1211
1212                         var continuation = new WhenAllContinuation (task, tasks);
1213                         foreach (var t in tasks)
1214                                 t.ContinueWith (continuation);
1215
1216                         return task;
1217                 }
1218
1219                 internal static Task<Task> WhenAnyCore (IList<Task> tasks)
1220                 {
1221                         if (tasks.Count == 0)
1222                                 throw new ArgumentException ("The tasks argument contains no tasks", "tasks");
1223
1224                         int completed_index = -1;
1225                         for (int i = 0; i < tasks.Count; ++i) {
1226                                 var t = tasks [i];
1227                                 if (t == null)
1228                                         throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1229
1230                                 if (t.IsCompleted && completed_index < 0)
1231                                         completed_index = i;
1232                         }
1233
1234                         var task = new Task<Task> (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1235
1236                         if (completed_index > 0) {
1237                                 task.TrySetResult (tasks[completed_index]);
1238                                 return task;
1239                         }
1240
1241                         task.SetupScheduler (TaskScheduler.Current);
1242
1243                         var continuation = new WhenAnyContinuation<Task> (task, tasks);
1244                         foreach (var t in tasks)
1245                                 t.ContinueWith (continuation);
1246
1247                         return task;
1248                 }
1249                 #region Properties
1250
1251                 internal CancellationToken CancellationToken {
1252                         get {
1253                                 return token;
1254                         }
1255                 }
1256
1257                 public static TaskFactory Factory {
1258                         get {
1259                                 return defaultFactory;
1260                         }
1261                 }
1262                 
1263                 public static int? CurrentId {
1264                         get {
1265                                 Task t = current;
1266                                 return t == null ? (int?)null : t.Id;
1267                         }
1268                 }
1269                 
1270                 public AggregateException Exception {
1271                         get {
1272                                 if (exSlot == null || !IsFaulted)
1273                                         return null;
1274                                 exSlot.Observed = true;
1275                                 return exSlot.Exception;
1276                         }
1277                 }
1278                 
1279                 public bool IsCanceled {
1280                         get {
1281                                 return status == TaskStatus.Canceled;
1282                         }
1283                 }
1284
1285                 public bool IsCompleted {
1286                         get {
1287                                 return status >= TaskStatus.RanToCompletion;
1288                         }
1289                 }
1290                 
1291                 public bool IsFaulted {
1292                         get {
1293                                 return status == TaskStatus.Faulted;
1294                         }
1295                 }
1296
1297                 public TaskCreationOptions CreationOptions {
1298                         get {
1299                                 return creationOptions & MaxTaskCreationOptions;
1300                         }
1301                 }
1302                 
1303                 public TaskStatus Status {
1304                         get {
1305                                 return status;
1306                         }
1307                         internal set {
1308                                 status = value;
1309                                 Thread.MemoryBarrier ();
1310                         }
1311                 }
1312
1313                 internal TaskExceptionSlot ExceptionSlot {
1314                         get {
1315                                 if (exSlot != null)
1316                                         return exSlot;
1317                                 Interlocked.CompareExchange (ref exSlot, new TaskExceptionSlot (this), null);
1318                                 return exSlot;
1319                         }
1320                 }
1321
1322                 public object AsyncState {
1323                         get {
1324                                 return state;
1325                         }
1326                 }
1327                 
1328                 bool IAsyncResult.CompletedSynchronously {
1329                         get {
1330                                 return true;
1331                         }
1332                 }
1333
1334                 WaitHandle IAsyncResult.AsyncWaitHandle {
1335                         get {
1336                                 if (invoker == null)
1337                                         throw new ObjectDisposedException (GetType ().ToString ());
1338
1339                                 if (wait_handle == null)
1340                                         Interlocked.CompareExchange (ref wait_handle, new ManualResetEvent (IsCompleted), null);
1341
1342                                 return wait_handle;
1343                         }
1344                 }
1345                 
1346                 public int Id {
1347                         get {
1348                                 return taskId;
1349                         }
1350                 }
1351
1352                 bool IsContinuation {
1353                         get {
1354                                 return contAncestor != null;
1355                         }
1356                 }
1357
1358                 bool IsPromise {
1359                         get {
1360                                 return invoker == TaskActionInvoker.Promise;
1361                         }
1362                 }
1363
1364                 internal Task ContinuationAncestor {
1365                         get {
1366                                 return contAncestor;
1367                         }
1368                 }
1369                 
1370                 internal string DisplayActionMethod {
1371                         get {
1372                                 Delegate d = invoker.Action;
1373                                 return d == null ? "<none>" : d.Method.ToString ();
1374                         }
1375                 }
1376                 
1377                 #endregion
1378         }
1379 }
1380 #endif