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