Wrap always_inline and noinline attributes in compiler checks and use MSVC equivalent.
[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                 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 = null, 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 = parent == null ? current : 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, false))
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), null, 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
381                         // If Task are ran inline on the same thread we might trash these values
382                         var saveCurrent = current;
383                         var saveScheduler = TaskScheduler.Current;
384
385                         current = this;
386                         TaskScheduler.Current = scheduler;
387                         
388                         if (!token.IsCancellationRequested) {
389                                 
390                                 status = TaskStatus.Running;
391                                 
392                                 try {
393                                         InnerInvoke ();
394                                 } catch (OperationCanceledException oce) {
395                                         if (token != CancellationToken.None && oce.CancellationToken == token)
396                                                 CancelReal ();
397                                         else
398                                                 HandleGenericException (oce);
399                                 } catch (Exception e) {
400                                         HandleGenericException (e);
401                                 }
402                         } else {
403                                 CancelReal ();
404                         }
405
406                         if (saveCurrent != null)
407                                 current = saveCurrent;
408                         if (saveScheduler != null)
409                                 TaskScheduler.Current = saveScheduler;
410                         Finish ();
411                 }
412
413                 internal bool TrySetCanceled ()
414                 {
415                         if (IsCompleted)
416                                 return false;
417                         
418                         if (!executing.TryRelaxedSet ()) {
419                                 var sw = new SpinWait ();
420                                 while (!IsCompleted)
421                                         sw.SpinOnce ();
422
423                                 return false;
424                         }
425                         
426                         CancelReal ();
427                         return true;
428                 }
429
430                 internal bool TrySetException (AggregateException aggregate)
431                 {
432                         if (IsCompleted)
433                                 return false;
434                         
435                         if (!executing.TryRelaxedSet ()) {
436                                 var sw = new SpinWait ();
437                                 while (!IsCompleted)
438                                         sw.SpinOnce ();
439
440                                 return false;
441                         }
442                         
443                         HandleGenericException (aggregate);
444                         return true;
445                 }
446
447                 internal void Execute ()
448                 {
449                         ThreadStart ();
450                 }
451                 
452                 internal void AddChild ()
453                 {
454                         if (childTasks == null)
455                                 Interlocked.CompareExchange (ref childTasks, new CountdownEvent (1), null);
456                         childTasks.AddCount ();
457                 }
458
459                 internal void ChildCompleted (AggregateException childEx)
460                 {
461                         if (childEx != null) {
462                                 if (ExceptionSlot.ChildExceptions == null)
463                                         Interlocked.CompareExchange (ref ExceptionSlot.ChildExceptions, new ConcurrentQueue<AggregateException> (), null);
464                                 ExceptionSlot.ChildExceptions.Enqueue (childEx);
465                         }
466
467                         if (childTasks.Signal () && status == TaskStatus.WaitingForChildrenToComplete) {
468                                 ProcessChildExceptions ();
469                                 Status = exSlot == null ? TaskStatus.RanToCompletion : TaskStatus.Faulted;
470                                 ProcessCompleteDelegates ();
471                                 if (CheckTaskOptions (taskCreationOptions, TaskCreationOptions.AttachedToParent) && parent != null)
472                                         parent.ChildCompleted (this.Exception);
473                         }
474                 }
475
476                 void InnerInvoke ()
477                 {
478                         if (IsContinuation) {
479                                 invoker.Invoke (contAncestor, state, this);
480                         } else {
481                                 invoker.Invoke (this, state, this);
482                         }
483                 }
484                 
485                 internal void Finish ()
486                 {
487                         // If there was children created and they all finished, we set the countdown
488                         if (childTasks != null) {
489                                 if (childTasks.Signal ())
490                                         ProcessChildExceptions (true);
491                         }
492                         
493                         // Don't override Canceled or Faulted
494                         if (status == TaskStatus.Running) {
495                                 if (childTasks == null || childTasks.IsSet)
496                                         Status = TaskStatus.RanToCompletion;
497                                 else
498                                         Status = TaskStatus.WaitingForChildrenToComplete;
499                         }
500
501                         // Completions are already processed when task is canceled or faulted
502                         if (status == TaskStatus.RanToCompletion)
503                                 ProcessCompleteDelegates ();
504
505                         // Reset the current thingies
506                         if (current == this)
507                                 current = null;
508                         if (TaskScheduler.Current == scheduler)
509                                 TaskScheduler.Current = null;
510
511                         if (cancellationRegistration.HasValue)
512                                 cancellationRegistration.Value.Dispose ();
513                         
514                         // Tell parent that we are finished
515                         if (CheckTaskOptions (taskCreationOptions, TaskCreationOptions.AttachedToParent) && parent != null && status != TaskStatus.WaitingForChildrenToComplete) {
516                                 parent.ChildCompleted (this.Exception);
517                         }
518                 }
519
520                 void ProcessCompleteDelegates ()
521                 {
522                         if (continuations.HasElements) {
523                                 IContinuation continuation;
524                                 while (continuations.TryGetNextCompletion (out continuation))
525                                         continuation.Execute ();
526                         }
527                 }
528
529                 void ProcessChildExceptions (bool isParent = false)
530                 {
531                         if (exSlot == null || exSlot.ChildExceptions == null)
532                                 return;
533
534                         if (ExceptionSlot.Exception == null)
535                                 exSlot.Exception = new AggregateException ();
536
537                         AggregateException childEx;
538                         while (exSlot.ChildExceptions.TryDequeue (out childEx))
539                                 exSlot.Exception.AddChildException (childEx);
540
541                         if (isParent) {
542                                 Status = TaskStatus.Faulted;
543                                 ProcessCompleteDelegates ();                    
544                         }
545                 }
546                 #endregion
547                 
548                 #region Cancel and Wait related method
549                 
550                 internal void CancelReal ()
551                 {
552                         Status = TaskStatus.Canceled;
553                         ProcessCompleteDelegates ();
554                 }
555
556                 void HandleGenericException (Exception e)
557                 {
558                         HandleGenericException (new AggregateException (e));
559                 }
560
561                 void HandleGenericException (AggregateException e)
562                 {
563                         ExceptionSlot.Exception = e;
564                         Thread.MemoryBarrier ();
565                         Status = TaskStatus.Faulted;
566                         ProcessCompleteDelegates ();
567                 }
568
569                 internal bool WaitOnChildren ()
570                 {
571                         if (Status == TaskStatus.WaitingForChildrenToComplete && childTasks != null) {
572                                 childTasks.Wait ();
573                                 return true;
574                         }
575                         return false;
576                 }
577                 
578                 public void Wait ()
579                 {
580                         Wait (Timeout.Infinite, CancellationToken.None);
581                 }
582
583                 public void Wait (CancellationToken cancellationToken)
584                 {
585                         Wait (Timeout.Infinite, cancellationToken);
586                 }
587                 
588                 public bool Wait (TimeSpan timeout)
589                 {
590                         return Wait (CheckTimeout (timeout), CancellationToken.None);
591                 }
592                 
593                 public bool Wait (int millisecondsTimeout)
594                 {
595                         return Wait (millisecondsTimeout, CancellationToken.None);
596                 }
597
598                 public bool Wait (int millisecondsTimeout, CancellationToken cancellationToken)
599                 {
600                         if (millisecondsTimeout < -1)
601                                 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
602
603                         bool result = true;
604
605                         if (!IsCompleted) {
606                                 // If the task is ready to be run and we were supposed to wait on it indefinitely without cancellation, just run it
607                                 if (Status == TaskStatus.WaitingToRun && millisecondsTimeout == Timeout.Infinite && scheduler != null && !cancellationToken.CanBeCanceled)
608                                         scheduler.RunInline (this, true);
609
610                                 if (!IsCompleted) {
611                                         var continuation = new ManualResetContinuation ();
612                                         try {
613                                                 ContinueWith (continuation);
614                                                 result = continuation.Event.Wait (millisecondsTimeout, cancellationToken);
615                                         } finally {
616                                                 if (!result)
617                                                         RemoveContinuation (continuation);
618                                                 continuation.Dispose ();
619                                         }
620                                 }
621                         }
622
623                         if (IsCanceled)
624                                 throw new AggregateException (new TaskCanceledException (this));
625
626                         var exception = Exception;
627                         if (exception != null)
628                                 throw exception;
629
630                         if (childTasks != null)
631                                 childTasks.Wait ();
632
633                         return result;
634                 }
635                 
636                 public static void WaitAll (params Task[] tasks)
637                 {
638                         WaitAll (tasks, Timeout.Infinite, CancellationToken.None);
639                 }
640
641                 public static void WaitAll (Task[] tasks, CancellationToken cancellationToken)
642                 {
643                         WaitAll (tasks, Timeout.Infinite, cancellationToken);
644                 }
645                 
646                 public static bool WaitAll (Task[] tasks, TimeSpan timeout)
647                 {
648                         return WaitAll (tasks, CheckTimeout (timeout), CancellationToken.None);
649                 }
650                 
651                 public static bool WaitAll (Task[] tasks, int millisecondsTimeout)
652                 {
653                         return WaitAll (tasks, millisecondsTimeout, CancellationToken.None);
654                 }
655                 
656                 public static bool WaitAll (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
657                 {
658                         if (tasks == null)
659                                 throw new ArgumentNullException ("tasks");
660
661                         bool result = true;
662                         foreach (var t in tasks) {
663                                 if (t == null)
664                                         throw new ArgumentException ("tasks", "the tasks argument contains a null element");
665
666                                 result &= t.Status == TaskStatus.RanToCompletion;
667                         }
668
669                         if (!result) {
670                                 var continuation = new CountdownContinuation (tasks.Length);
671                                 try {
672                                         foreach (var t in tasks)
673                                                 t.ContinueWith (continuation);
674
675                                         result = continuation.Event.Wait (millisecondsTimeout, cancellationToken);
676                                 } finally {
677                                         List<Exception> exceptions = null;
678
679                                         foreach (var t in tasks) {
680                                                 if (result) {
681                                                         if (t.Status == TaskStatus.RanToCompletion)
682                                                                 continue;
683                                                         if (exceptions == null)
684                                                                 exceptions = new List<Exception> ();
685                                                         if (t.Exception != null)
686                                                                 exceptions.AddRange (t.Exception.InnerExceptions);
687                                                         else
688                                                                 exceptions.Add (new TaskCanceledException (t));
689                                                 } else {
690                                                         t.RemoveContinuation (continuation);
691                                                 }
692                                         }
693
694                                         continuation.Dispose ();
695
696                                         if (exceptions != null)
697                                                 throw new AggregateException (exceptions);
698                                 }
699                         }
700
701                         return result;
702                 }
703                 
704                 public static int WaitAny (params Task[] tasks)
705                 {
706                         return WaitAny (tasks, Timeout.Infinite, CancellationToken.None);
707                 }
708
709                 public static int WaitAny (Task[] tasks, TimeSpan timeout)
710                 {
711                         return WaitAny (tasks, CheckTimeout (timeout));
712                 }
713                 
714                 public static int WaitAny (Task[] tasks, int millisecondsTimeout)
715                 {
716                         return WaitAny (tasks, millisecondsTimeout, CancellationToken.None);
717                 }
718
719                 public static int WaitAny (Task[] tasks, CancellationToken cancellationToken)
720                 {
721                         return WaitAny (tasks, Timeout.Infinite, cancellationToken);
722                 }
723
724                 public static int WaitAny (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
725                 {
726                         if (tasks == null)
727                                 throw new ArgumentNullException ("tasks");
728                         if (millisecondsTimeout < -1)
729                                 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
730                         CheckForNullTasks (tasks);
731
732                         if (tasks.Length > 0) {
733                                 var continuation = new ManualResetContinuation ();
734                                 bool result = false;
735                                 try {
736                                         for (int i = 0; i < tasks.Length; i++) {
737                                                 var t = tasks[i];
738                                                 if (t.IsCompleted)
739                                                         return i;
740                                                 t.ContinueWith (continuation);
741                                         }
742
743                                         if (!(result = continuation.Event.Wait (millisecondsTimeout, cancellationToken)))
744                                                 return -1;
745                                 } finally {
746                                         if (!result)
747                                                 foreach (var t in tasks)
748                                                         t.RemoveContinuation (continuation);
749                                         continuation.Dispose ();
750                                 }
751                         }
752
753                         int firstFinished = -1;
754                         for (int i = 0; i < tasks.Length; i++) {
755                                 var t = tasks[i];
756                                 if (t.IsCompleted) {
757                                         firstFinished = i;
758                                         break;
759                                 }
760                         }
761
762                         return firstFinished;
763                 }
764
765                 static int CheckTimeout (TimeSpan timeout)
766                 {
767                         try {
768                                 return checked ((int)timeout.TotalMilliseconds);
769                         } catch (System.OverflowException) {
770                                 throw new ArgumentOutOfRangeException ("timeout");
771                         }
772                 }
773
774                 static void CheckForNullTasks (Task[] tasks)
775                 {
776                         foreach (var t in tasks)
777                                 if (t == null)
778                                         throw new ArgumentException ("tasks", "the tasks argument contains a null element");
779                 }
780                 #endregion
781                 
782                 #region Dispose
783                 public void Dispose ()
784                 {
785                         Dispose (true);
786                 }
787                 
788                 protected virtual void Dispose (bool disposing)
789                 {
790                         if (!IsCompleted)
791                                 throw new InvalidOperationException ("A task may only be disposed if it is in a completion state");
792
793                         // Set action to null so that the GC can collect the delegate and thus
794                         // any big object references that the user might have captured in a anonymous method
795                         if (disposing) {
796                                 invoker = null;
797                                 state = null;
798                                 if (cancellationRegistration != null)
799                                         cancellationRegistration.Value.Dispose ();
800                         }
801                 }
802                 #endregion
803                 
804 #if NET_4_5
805
806                 public ConfiguredTaskAwaitable ConfigureAwait (bool continueOnCapturedContext)
807                 {
808                         return new ConfiguredTaskAwaitable (this, continueOnCapturedContext);
809                 }
810
811                 public Task ContinueWith (Action<Task, object> continuationAction, object state)
812                 {
813                         return ContinueWith (continuationAction, state, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current);
814                 }
815
816                 public Task ContinueWith (Action<Task, object> continuationAction, object state, CancellationToken cancellationToken)
817                 {
818                         return ContinueWith (continuationAction, state, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
819                 }
820
821                 public Task ContinueWith (Action<Task, object> continuationAction, object state, TaskContinuationOptions continuationOptions)
822                 {
823                         return ContinueWith (continuationAction, state, CancellationToken.None, continuationOptions, TaskScheduler.Current);
824                 }
825
826                 public Task ContinueWith (Action<Task, object> continuationAction, object state, TaskScheduler scheduler)
827                 {
828                         return ContinueWith (continuationAction, state, CancellationToken.None, TaskContinuationOptions.None, scheduler);
829                 }
830
831                 public Task ContinueWith (Action<Task, object> continuationAction, object state, CancellationToken cancellationToken,
832                                                                   TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
833                 {
834                         if (continuationAction == null)
835                                 throw new ArgumentNullException ("continuationAction");
836                         if (scheduler == null)
837                                 throw new ArgumentNullException ("scheduler");
838
839                         Task continuation = new Task (TaskActionInvoker.Create (continuationAction),
840                                                                                   state, cancellationToken,
841                                                                                   GetCreationOptions (continuationOptions),
842                                                       parent,
843                                                       this);
844                         ContinueWithCore (continuation, continuationOptions, scheduler);
845
846                         return continuation;
847                 }
848
849                 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state)
850                 {
851                         return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current);
852                 }
853
854                 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, TaskContinuationOptions continuationOptions)
855                 {
856                         return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, continuationOptions, TaskScheduler.Current);
857                 }
858
859                 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, CancellationToken cancellationToken)
860                 {
861                         return ContinueWith<TResult> (continuationFunction, state, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
862                 }
863
864                 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, TaskScheduler scheduler)
865                 {
866                         return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, TaskContinuationOptions.None, scheduler);
867                 }
868
869                 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, CancellationToken cancellationToken,
870                                                                                                         TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
871                 {
872                         if (continuationFunction == null)
873                                 throw new ArgumentNullException ("continuationFunction");
874                         if (scheduler == null)
875                                 throw new ArgumentNullException ("scheduler");
876
877                         var t = new Task<TResult> (TaskActionInvoker.Create (continuationFunction),
878                                                    state,
879                                                    cancellationToken,
880                                                    GetCreationOptions (continuationOptions),
881                                                    parent,
882                                                    this);
883
884                         ContinueWithCore (t, continuationOptions, scheduler);
885
886                         return t;
887                 }
888
889                 public static Task Delay (int millisecondsDelay)
890                 {
891                         return Delay (millisecondsDelay, CancellationToken.None);
892                 }
893
894                 public static Task Delay (TimeSpan delay)
895                 {
896                         return Delay (CheckTimeout (delay), CancellationToken.None);
897                 }
898
899                 public static Task Delay (TimeSpan delay, CancellationToken cancellationToken)
900                 {
901                         return Delay (CheckTimeout (delay), cancellationToken);
902                 }
903
904                 public static Task Delay (int millisecondsDelay, CancellationToken cancellationToken)
905                 {
906                         if (millisecondsDelay < -1)
907                                 throw new ArgumentOutOfRangeException ("millisecondsDelay");
908
909                         var task = new Task (TaskActionInvoker.Delay, millisecondsDelay, cancellationToken, TaskCreationOptions.None, null, TaskConstants.Finished);
910                         task.SetupScheduler (TaskScheduler.Current);
911                         
912                         if (millisecondsDelay != Timeout.Infinite)
913                                 task.scheduler.QueueTask (task);
914
915                         return task;
916                 }
917
918                 public static Task<TResult> FromResult<TResult> (TResult result)
919                 {
920                         var tcs = new TaskCompletionSource<TResult> ();
921                         tcs.SetResult (result);
922                         return tcs.Task;
923                 }
924
925                 public TaskAwaiter GetAwaiter ()
926                 {
927                         return new TaskAwaiter (this);
928                 }
929
930                 public static Task Run (Action action)
931                 {
932                         return Run (action, CancellationToken.None);
933                 }
934
935                 public static Task Run (Action action, CancellationToken cancellationToken)
936                 {
937                         if (cancellationToken.IsCancellationRequested)
938                                 return TaskConstants.Canceled;
939
940                         var t = new Task (action, cancellationToken, TaskCreationOptions.DenyChildAttach);
941                         t.Start ();
942                         return t;
943                 }
944
945                 public static Task Run (Func<Task> function)
946                 {
947                         return Run (function, CancellationToken.None);
948                 }
949
950                 public static Task Run (Func<Task> function, CancellationToken cancellationToken)
951                 {
952                         if (cancellationToken.IsCancellationRequested)
953                                 return TaskConstants.Canceled;
954
955                         var t = new Task<Task> (function, cancellationToken);
956                         t.Start ();
957                         return t;
958                 }
959
960                 public static Task<TResult> Run<TResult> (Func<TResult> function)
961                 {
962                         return Run (function, CancellationToken.None);
963                 }
964
965                 public static Task<TResult> Run<TResult> (Func<TResult> function, CancellationToken cancellationToken)
966                 {
967                         if (cancellationToken.IsCancellationRequested)
968                                 return TaskConstants<TResult>.Canceled;
969
970                         var t = new Task<TResult> (function, cancellationToken, TaskCreationOptions.DenyChildAttach);
971                         t.Start ();
972                         return t;
973                 }
974
975                 public static Task<TResult> Run<TResult> (Func<Task<TResult>> function)
976                 {
977                         return Run (function, CancellationToken.None);
978                 }
979
980                 public static Task<TResult> Run<TResult> (Func<Task<TResult>> function, CancellationToken cancellationToken)
981                 {
982                         if (cancellationToken.IsCancellationRequested)
983                                 return TaskConstants<TResult>.Canceled;
984
985                         var t = Task<Task<TResult>>.Factory.StartNew (function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
986                         return GetTaskResult (t);
987                 }
988
989                 async static Task<TResult> GetTaskResult<TResult> (Task<Task<TResult>> task)
990                 {
991                         var r = await task.ConfigureAwait (false);
992                         return r.Result;
993                 }
994
995                 public static Task WhenAll (params Task[] tasks)
996                 {
997                         if (tasks == null)
998                                 throw new ArgumentNullException ("tasks");
999
1000                         return WhenAllCore (tasks);
1001                 }
1002
1003                 public static Task WhenAll (IEnumerable<Task> tasks)
1004                 {
1005                         if (tasks == null)
1006                                 throw new ArgumentNullException ("tasks");
1007
1008                         // Call ToList on input enumeration or we end up
1009                         // enumerating it more than once
1010                         return WhenAllCore (new List<Task> (tasks));
1011                 }
1012
1013                 public static Task<TResult[]> WhenAll<TResult> (params Task<TResult>[] tasks)
1014                 {
1015                         if (tasks == null)
1016                                 throw new ArgumentNullException ("tasks");
1017
1018                         return WhenAllCore<TResult> (tasks);
1019                 }
1020
1021                 public static Task<TResult[]> WhenAll<TResult> (IEnumerable<Task<TResult>> tasks)
1022                 {
1023                         if (tasks == null)
1024                                 throw new ArgumentNullException ("tasks");
1025
1026                         // Call ToList on input enumeration or we end up
1027                         // enumerating it more than once
1028                         return WhenAllCore<TResult> (new List<Task<TResult>> (tasks));
1029                 }
1030
1031                 internal static Task<TResult[]> WhenAllCore<TResult> (IList<Task<TResult>> tasks)
1032                 {
1033                         foreach (var t in tasks) {
1034                                 if (t == null)
1035                                         throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1036                         }
1037
1038                         var task = new Task<TResult[]> (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1039                         task.SetupScheduler (TaskScheduler.Current);
1040
1041                         var continuation = new WhenAllContinuation<TResult> (task, tasks);
1042                         foreach (var t in tasks)
1043                                 t.ContinueWith (continuation);
1044
1045                         return task;
1046                 }
1047
1048                 public static Task<Task> WhenAny (params Task[] tasks)
1049                 {
1050                         if (tasks == null)
1051                                 throw new ArgumentNullException ("tasks");
1052
1053                         return WhenAnyCore (tasks);
1054                 }
1055
1056                 public static Task<Task> WhenAny (IEnumerable<Task> tasks)
1057                 {
1058                         if (tasks == null)
1059                                 throw new ArgumentNullException ("tasks");
1060
1061                         return WhenAnyCore (new List<Task> (tasks));
1062                 }
1063
1064                 public static Task<Task<TResult>> WhenAny<TResult> (params Task<TResult>[] tasks)
1065                 {
1066                         if (tasks == null)
1067                                 throw new ArgumentNullException ("tasks");
1068
1069                         return WhenAnyCore<TResult> (tasks);
1070                 }
1071
1072                 public static Task<Task<TResult>> WhenAny<TResult> (IEnumerable<Task<TResult>> tasks)
1073                 {
1074                         if (tasks == null)
1075                                 throw new ArgumentNullException ("tasks");
1076
1077                         return WhenAnyCore<TResult> (new List<Task<TResult>> (tasks));
1078                 }
1079
1080                 static Task<Task<TResult>> WhenAnyCore<TResult> (IList<Task<TResult>> tasks)
1081                 {
1082                         if (tasks.Count == 0)
1083                                 throw new ArgumentException ("The tasks argument contains no tasks", "tasks");
1084
1085                         int completed_index = -1;
1086                         for (int i = 0; i < tasks.Count; ++i) {
1087                                 var t = tasks[i];
1088                                 if (t == null)
1089                                         throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1090
1091                                 if (t.IsCompleted && completed_index < 0)
1092                                         completed_index = i;
1093                         }
1094
1095                         var task = new Task<Task<TResult>> (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1096
1097                         if (completed_index > 0) {
1098                                 task.TrySetResult (tasks[completed_index]);
1099                                 return task;
1100                         }
1101
1102                         task.SetupScheduler (TaskScheduler.Current);
1103
1104                         var continuation = new WhenAnyContinuation<Task<TResult>> (task, tasks);
1105                         foreach (var t in tasks)
1106                                 t.ContinueWith (continuation);
1107
1108                         return task;
1109                 }
1110
1111                 public static YieldAwaitable Yield ()
1112                 {
1113                         return new YieldAwaitable ();
1114                 }
1115 #endif
1116
1117                 internal static Task WhenAllCore (IList<Task> tasks)
1118                 {
1119                         bool all_completed = true;
1120                         foreach (var t in tasks) {
1121                                 if (t == null)
1122                                         throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1123
1124                                 all_completed &= t.Status == TaskStatus.RanToCompletion;
1125                         }
1126
1127                         if (all_completed)
1128                                 return TaskConstants.Finished;
1129
1130                         var task = new Task (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1131                         task.SetupScheduler (TaskScheduler.Current);
1132
1133                         var continuation = new WhenAllContinuation (task, tasks);
1134                         foreach (var t in tasks)
1135                                 t.ContinueWith (continuation);
1136
1137                         return task;
1138                 }
1139
1140                 internal static Task<Task> WhenAnyCore (IList<Task> tasks)
1141                 {
1142                         if (tasks.Count == 0)
1143                                 throw new ArgumentException ("The tasks argument contains no tasks", "tasks");
1144
1145                         int completed_index = -1;
1146                         for (int i = 0; i < tasks.Count; ++i) {
1147                                 var t = tasks [i];
1148                                 if (t == null)
1149                                         throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1150
1151                                 if (t.IsCompleted && completed_index < 0)
1152                                         completed_index = i;
1153                         }
1154
1155                         var task = new Task<Task> (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1156
1157                         if (completed_index > 0) {
1158                                 task.TrySetResult (tasks[completed_index]);
1159                                 return task;
1160                         }
1161
1162                         task.SetupScheduler (TaskScheduler.Current);
1163
1164                         var continuation = new WhenAnyContinuation<Task> (task, tasks);
1165                         foreach (var t in tasks)
1166                                 t.ContinueWith (continuation);
1167
1168                         return task;
1169                 }
1170                 #region Properties
1171
1172                 internal CancellationToken CancellationToken {
1173                         get {
1174                                 return token;
1175                         }
1176                 }
1177
1178                 public static TaskFactory Factory {
1179                         get {
1180                                 return defaultFactory;
1181                         }
1182                 }
1183                 
1184                 public static int? CurrentId {
1185                         get {
1186                                 Task t = current;
1187                                 return t == null ? (int?)null : t.Id;
1188                         }
1189                 }
1190                 
1191                 public AggregateException Exception {
1192                         get {
1193                                 if (exSlot == null)
1194                                         return null;
1195                                 exSlot.Observed = true;
1196                                 return exSlot.Exception;
1197                         }
1198                 }
1199                 
1200                 public bool IsCanceled {
1201                         get {
1202                                 return status == TaskStatus.Canceled;
1203                         }
1204                 }
1205
1206                 public bool IsCompleted {
1207                         get {
1208                                 return status >= TaskStatus.RanToCompletion;
1209                         }
1210                 }
1211                 
1212                 public bool IsFaulted {
1213                         get {
1214                                 return status == TaskStatus.Faulted;
1215                         }
1216                 }
1217
1218                 public TaskCreationOptions CreationOptions {
1219                         get {
1220                                 return taskCreationOptions & MaxTaskCreationOptions;
1221                         }
1222                 }
1223                 
1224                 public TaskStatus Status {
1225                         get {
1226                                 return status;
1227                         }
1228                         internal set {
1229                                 status = value;
1230                                 Thread.MemoryBarrier ();
1231                         }
1232                 }
1233
1234                 TaskExceptionSlot ExceptionSlot {
1235                         get {
1236                                 if (exSlot != null)
1237                                         return exSlot;
1238                                 Interlocked.CompareExchange (ref exSlot, new TaskExceptionSlot (this), null);
1239                                 return exSlot;
1240                         }
1241                 }
1242
1243                 public object AsyncState {
1244                         get {
1245                                 return state;
1246                         }
1247                 }
1248                 
1249                 bool IAsyncResult.CompletedSynchronously {
1250                         get {
1251                                 return true;
1252                         }
1253                 }
1254
1255                 WaitHandle IAsyncResult.AsyncWaitHandle {
1256                         get {
1257                                 return null;
1258                         }
1259                 }
1260                 
1261                 public int Id {
1262                         get {
1263                                 return taskId;
1264                         }
1265                 }
1266
1267                 bool IsContinuation {
1268                         get {
1269                                 return contAncestor != null;
1270                         }
1271                 }
1272
1273                 internal Task ContinuationAncestor {
1274                         get {
1275                                 return contAncestor;
1276                         }
1277                 }
1278                 
1279                 internal string DisplayActionMethod {
1280                         get {
1281                                 Delegate d = invoker.Action;
1282                                 return d == null ? "<none>" : d.Method.ToString ();
1283                         }
1284                 }
1285                 
1286                 #endregion
1287         }
1288 }
1289 #endif