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