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