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