Fixes Task.WaitAny with further fixes to Task.Wait
[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 //
7 // Copyright (c) 2008 Jérémie "Garuma" Laval
8 // Copyright 2011 Xamarin Inc (http://www.xamarin.com).
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining a copy
11 // of this software and associated documentation files (the "Software"), to deal
12 // in the Software without restriction, including without limitation the rights
13 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 // copies of the Software, and to permit persons to whom the Software is
15 // furnished to do so, subject to the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be included in
18 // all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 // THE SOFTWARE.
27 //
28 //
29
30 #if NET_4_0 || MOBILE
31
32 using System;
33 using System.Threading;
34 using System.Collections.Concurrent;
35 using System.Collections.Generic;
36 using System.Runtime.CompilerServices;
37
38 namespace System.Threading.Tasks
39 {
40         [System.Diagnostics.DebuggerDisplay ("Id = {Id}, Status = {Status}")]
41         [System.Diagnostics.DebuggerTypeProxy (typeof (TaskDebuggerView))]
42         public class Task : IDisposable, IAsyncResult
43         {
44                 // With this attribute each thread has its own value so that it's correct for our Schedule code
45                 // and for Parent property.
46                 [System.ThreadStatic]
47                 static Task         current;
48                 [System.ThreadStatic]
49                 static Action<Task> childWorkAdder;
50                 
51                 Task parent;
52                 
53                 static int          id = -1;
54                 static readonly TaskFactory defaultFactory = new TaskFactory ();
55                 
56                 CountdownEvent childTasks;
57                 
58                 int                 taskId;
59                 TaskCreationOptions taskCreationOptions;
60                 
61                 TaskScheduler       scheduler;
62
63                 ManualResetEventSlim schedWait = new ManualResetEventSlim (false);
64                 
65                 volatile AggregateException  exception;
66                 volatile bool                exceptionObserved;
67                 ConcurrentQueue<AggregateException> childExceptions;
68
69                 TaskStatus          status;
70                 
71                 Action<object> action;
72                 Action         simpleAction;
73                 object         state;
74                 AtomicBooleanValue executing;
75
76                 TaskCompletionQueue completed;
77                 // If this task is a continuation, this stuff gets filled
78                 CompletionSlot Slot;
79
80                 CancellationToken token;
81                 CancellationTokenRegistration? cancelation_registration;
82
83                 internal const TaskCreationOptions WorkerTaskNotSupportedOptions = TaskCreationOptions.LongRunning | TaskCreationOptions.PreferFairness;
84
85                 const TaskCreationOptions MaxTaskCreationOptions =
86 #if NET_4_5
87                         TaskCreationOptions.DenyChildAttach | TaskCreationOptions.HideScheduler |
88 #endif
89                         TaskCreationOptions.PreferFairness | TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent;
90
91                 public Task (Action action) : this (action, TaskCreationOptions.None)
92                 {
93                         
94                 }
95                 
96                 public Task (Action action, TaskCreationOptions creationOptions) : this (action, CancellationToken.None, creationOptions)
97                 {
98                         
99                 }
100                 
101                 public Task (Action action, CancellationToken cancellationToken) : this (action, cancellationToken, TaskCreationOptions.None)
102                 {
103                         
104                 }
105                 
106                 public Task (Action action, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
107                         : this (null, 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                         this.simpleAction = action;
114                 }
115                 
116                 public Task (Action<object> action, object state) : 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 (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 (Action<object> action,
140                                object state,
141                                CancellationToken cancellationToken,
142                                TaskCreationOptions creationOptions,
143                                Task parent)
144                 {
145                         this.taskCreationOptions = creationOptions;
146                         this.action              = action;
147                         this.state               = state;
148                         this.taskId              = Interlocked.Increment (ref id);
149                         this.status              = cancellationToken.IsCancellationRequested ? TaskStatus.Canceled : TaskStatus.Created;
150                         this.token               = cancellationToken;
151                         this.parent              = parent;
152
153                         // Process taskCreationOptions
154                         if (CheckTaskOptions (taskCreationOptions, TaskCreationOptions.AttachedToParent) && parent != null)
155                                 parent.AddChild ();
156
157                         if (token.CanBeCanceled) {
158                                 cancelation_registration = token.Register (l => ((Task) l).CancelReal (), this);
159                         }
160                 }
161
162                 ~Task ()
163                 {
164                         if (exception != null && !exceptionObserved)
165                                 throw exception;
166                 }
167
168                 bool CheckTaskOptions (TaskCreationOptions opt, TaskCreationOptions member)
169                 {
170                         return (opt & member) == member;
171                 }
172
173                 #region Start
174                 public void Start ()
175                 {
176                         Start (TaskScheduler.Current);
177                 }
178                 
179                 public void Start (TaskScheduler scheduler)
180                 {
181                         if (scheduler == null)
182                                 throw new ArgumentNullException ("scheduler");
183
184                         if (status >= TaskStatus.WaitingToRun)
185                                 throw new InvalidOperationException ("The Task is not in a valid state to be started.");
186
187                         if (Slot.Initialized)
188                                 throw new InvalidOperationException ("Start may not be called on a continuation task");
189
190                         SetupScheduler (scheduler);
191                         Schedule ();
192                 }
193
194                 internal void SetupScheduler (TaskScheduler scheduler)
195                 {
196                         this.scheduler = scheduler;
197                         status = TaskStatus.WaitingForActivation;
198                         schedWait.Set ();
199                 }
200                 
201                 public void RunSynchronously ()
202                 {
203                         RunSynchronously (TaskScheduler.Current);
204                 }
205                 
206                 public void RunSynchronously (TaskScheduler scheduler)
207                 {
208                         if (scheduler == null)
209                                 throw new ArgumentNullException ("scheduler");
210
211                         if (Status > TaskStatus.WaitingForActivation)
212                                 throw new InvalidOperationException ("The task is not in a valid state to be started");
213
214                         SetupScheduler (scheduler);
215                         var saveStatus = status;
216                         status = TaskStatus.WaitingToRun;
217
218                         try {
219                                 if (scheduler.RunInline (this))
220                                         return;
221                         } catch (Exception inner) {
222                                 throw new TaskSchedulerException (inner);
223                         }
224
225                         status = saveStatus;
226                         Start (scheduler);
227                         Wait ();
228                 }
229                 #endregion
230                 
231                 #region ContinueWith
232                 public Task ContinueWith (Action<Task> continuationAction)
233                 {
234                         return ContinueWith (continuationAction, TaskContinuationOptions.None);
235                 }
236                 
237                 public Task ContinueWith (Action<Task> continuationAction, TaskContinuationOptions continuationOptions)
238                 {
239                         return ContinueWith (continuationAction, CancellationToken.None, continuationOptions, TaskScheduler.Current);
240                 }
241                 
242                 public Task ContinueWith (Action<Task> continuationAction, CancellationToken cancellationToken)
243                 {
244                         return ContinueWith (continuationAction, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
245                 }
246                 
247                 public Task ContinueWith (Action<Task> continuationAction, TaskScheduler scheduler)
248                 {
249                         return ContinueWith (continuationAction, CancellationToken.None, TaskContinuationOptions.None, scheduler);
250                 }
251                 
252                 public Task ContinueWith (Action<Task> continuationAction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
253                 {
254                         if (continuationAction == null)
255                                 throw new ArgumentNullException ("continuationAction");
256                         if (scheduler == null)
257                                 throw new ArgumentNullException ("scheduler");
258
259                         Task continuation = new Task (l => continuationAction ((Task)l),
260                                                       this,
261                                                       cancellationToken,
262                                                       GetCreationOptions (continuationOptions),
263                                                       this);
264                         ContinueWithCore (continuation, continuationOptions, scheduler);
265
266                         return continuation;
267                 }
268                 
269                 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction)
270                 {
271                         return ContinueWith<TResult> (continuationFunction, TaskContinuationOptions.None);
272                 }
273                 
274                 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, TaskContinuationOptions continuationOptions)
275                 {
276                         return ContinueWith<TResult> (continuationFunction, CancellationToken.None, continuationOptions, TaskScheduler.Current);
277                 }
278                 
279                 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, CancellationToken cancellationToken)
280                 {
281                         return ContinueWith<TResult> (continuationFunction, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
282                 }
283                 
284                 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, TaskScheduler scheduler)
285                 {
286                         return ContinueWith<TResult> (continuationFunction, CancellationToken.None, TaskContinuationOptions.None, scheduler);
287                 }
288                 
289                 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, CancellationToken cancellationToken,
290                                                             TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
291                 {
292                         if (continuationFunction == null)
293                                 throw new ArgumentNullException ("continuationFunction");
294                         if (scheduler == null)
295                                 throw new ArgumentNullException ("scheduler");
296
297                         Task<TResult> t = new Task<TResult> ((o) => continuationFunction ((Task)o),
298                                                              this,
299                                                              cancellationToken,
300                                                              GetCreationOptions (continuationOptions),
301                                                              this);
302                         
303                         ContinueWithCore (t, continuationOptions, scheduler);
304                         
305                         return t;
306                 }
307         
308                 internal void ContinueWithCore (Task continuation, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
309                 {
310                         ContinueWithCore (continuation, continuationOptions, scheduler, null);
311                 }
312                 
313                 internal void ContinueWithCore (Task continuation, TaskContinuationOptions kind,
314                                                 TaskScheduler scheduler, Func<bool> predicate)
315                 {
316                         // Already set the scheduler so that user can call Wait and that sort of stuff
317                         continuation.scheduler = scheduler;
318                         continuation.schedWait.Set ();
319                         continuation.status = TaskStatus.WaitingForActivation;
320                         continuation.Slot = new CompletionSlot (kind, predicate);
321
322                         if (IsCompleted) {
323                                 CompletionTaskExecutor (continuation);
324                                 return;
325                         }
326                         
327                         completed.Add (continuation);
328                         
329                         // Retry in case completion was achieved but event adding was too late
330                         if (IsCompleted)
331                                 CompletionTaskExecutor (continuation);
332                 }
333
334                 
335                 bool ContinuationStatusCheck (TaskContinuationOptions kind)
336                 {
337                         if (kind == TaskContinuationOptions.None)
338                                 return true;
339                         
340                         int kindCode = (int)kind;
341                         
342                         if (kindCode >= ((int)TaskContinuationOptions.NotOnRanToCompletion)) {
343                                 // Remove other options
344                                 kind &= ~(TaskContinuationOptions.PreferFairness
345                                           | TaskContinuationOptions.LongRunning
346                                           | TaskContinuationOptions.AttachedToParent
347                                           | TaskContinuationOptions.ExecuteSynchronously);
348
349                                 if (status == TaskStatus.Canceled) {
350                                         if (kind == TaskContinuationOptions.NotOnCanceled)
351                                                 return false;
352                                         if (kind == TaskContinuationOptions.OnlyOnFaulted)
353                                                 return false;
354                                         if (kind == TaskContinuationOptions.OnlyOnRanToCompletion)
355                                                 return false;
356                                 } else if (status == TaskStatus.Faulted) {
357                                         if (kind == TaskContinuationOptions.NotOnFaulted)
358                                                 return false;
359                                         if (kind == TaskContinuationOptions.OnlyOnCanceled)
360                                                 return false;
361                                         if (kind == TaskContinuationOptions.OnlyOnRanToCompletion)
362                                                 return false;
363                                 } else if (status == TaskStatus.RanToCompletion) {
364                                         if (kind == TaskContinuationOptions.NotOnRanToCompletion)
365                                                 return false;
366                                         if (kind == TaskContinuationOptions.OnlyOnFaulted)
367                                                 return false;
368                                         if (kind == TaskContinuationOptions.OnlyOnCanceled)
369                                                 return false;
370                                 }
371                         }
372                         
373                         return true;
374                 }
375                         
376                 static internal TaskCreationOptions GetCreationOptions (TaskContinuationOptions kind)
377                 {
378                         TaskCreationOptions options = TaskCreationOptions.None;
379                         if ((kind & TaskContinuationOptions.AttachedToParent) > 0)
380                                 options |= TaskCreationOptions.AttachedToParent;
381                         if ((kind & TaskContinuationOptions.PreferFairness) > 0)
382                                 options |= TaskCreationOptions.PreferFairness;
383                         if ((kind & TaskContinuationOptions.LongRunning) > 0)
384                                 options |= TaskCreationOptions.LongRunning;
385                         
386                         return options;
387                 }
388                 #endregion
389                 
390                 #region Internal and protected thingies
391                 internal void Schedule ()
392                 {
393                         status = TaskStatus.WaitingToRun;
394                         
395                         // If worker is null it means it is a local one, revert to the old behavior
396                         // If TaskScheduler.Current is not being used, the scheduler was explicitly provided, so we must use that
397                         if (scheduler != TaskScheduler.Current || childWorkAdder == null || CheckTaskOptions (taskCreationOptions, TaskCreationOptions.PreferFairness)) {
398                                 scheduler.QueueTask (this);
399                         } else {
400                                 /* Like the semantic of the ABP paper describe it, we add ourselves to the bottom 
401                                  * of our Parent Task's ThreadWorker deque. It's ok to do that since we are in
402                                  * the correct Thread during the creation
403                                  */
404                                 childWorkAdder (this);
405                         }
406                 }
407                 
408                 void ThreadStart ()
409                 {
410                         /* Allow scheduler to break fairness of deque ordering without
411                          * breaking its semantic (the task can be executed twice but the
412                          * second time it will return immediately
413                          */
414                         if (!executing.TryRelaxedSet ())
415                                 return;
416
417                         current = this;
418                         TaskScheduler.Current = scheduler;
419                         
420                         if (!token.IsCancellationRequested) {
421                                 
422                                 status = TaskStatus.Running;
423                                 
424                                 try {
425                                         InnerInvoke ();
426                                 } catch (OperationCanceledException oce) {
427                                         if (token != CancellationToken.None && oce.CancellationToken == token)
428                                                 CancelReal ();
429                                         else
430                                                 HandleGenericException (oce);
431                                 } catch (Exception e) {
432                                         HandleGenericException (e);
433                                 }
434                         } else {
435                                 CancelReal ();
436                         }
437                         
438                         Finish ();
439                 }
440                 
441                 internal void Execute (Action<Task> childAdder)
442                 {
443                         childWorkAdder = childAdder;
444                         ThreadStart ();
445                 }
446                 
447                 internal void AddChild ()
448                 {
449                         if (childTasks == null)
450                                 Interlocked.CompareExchange (ref childTasks, new CountdownEvent (1), null);
451                         childTasks.AddCount ();
452                 }
453
454                 internal void ChildCompleted (AggregateException childEx)
455                 {
456                         if (childEx != null) {
457                                 if (childExceptions == null)
458                                         Interlocked.CompareExchange (ref childExceptions, new ConcurrentQueue<AggregateException> (), null);
459                                 childExceptions.Enqueue (childEx);
460                         }
461
462                         if (childTasks.Signal () && status == TaskStatus.WaitingForChildrenToComplete) {
463                                 status = TaskStatus.RanToCompletion;
464                                 ProcessChildExceptions ();
465                                 ProcessCompleteDelegates ();
466                         }
467                 }
468
469                 internal virtual void InnerInvoke ()
470                 {
471                         if (action == null && simpleAction != null)
472                                 simpleAction ();
473                         else if (action != null)
474                                 action (state);
475                         // Set action to null so that the GC can collect the delegate and thus
476                         // any big object references that the user might have captured in an anonymous method
477                         action = null;
478                         simpleAction = null;
479                         state = null;
480                 }
481                 
482                 internal void Finish ()
483                 {
484                         // If there was children created and they all finished, we set the countdown
485                         if (childTasks != null)
486                                 childTasks.Signal ();
487                         
488                         // Don't override Canceled or Faulted
489                         if (status == TaskStatus.Running) {
490                                 if (childTasks == null || childTasks.IsSet)
491                                         status = TaskStatus.RanToCompletion;
492                                 else
493                                         status = TaskStatus.WaitingForChildrenToComplete;
494                         }
495                 
496                         if (status != TaskStatus.WaitingForChildrenToComplete)
497                                 ProcessCompleteDelegates ();
498
499                         // Reset the current thingies
500                         current = null;
501                         TaskScheduler.Current = null;
502
503                         if (cancelation_registration.HasValue)
504                                 cancelation_registration.Value.Dispose ();
505                         
506                         // Tell parent that we are finished
507                         if (CheckTaskOptions (taskCreationOptions, TaskCreationOptions.AttachedToParent) && parent != null) {
508                                 parent.ChildCompleted (this.Exception);
509                         }
510                 }
511
512                 void ProcessCompleteDelegates ()
513                 {
514                         if (!completed.HasElements)
515                                 return;
516
517                         object value;
518                         while (completed.TryGetNext (out value)) {
519                                 var t = value as Task;
520                                 if (t != null) {
521                                         CompletionTaskExecutor (t);
522                                         continue;
523                                 }
524
525                                 var mre = value as ManualResetEventSlim;
526                                 if (mre != null) {
527                                         mre.Set ();
528                                         continue;
529                                 }
530
531                                 throw new NotImplementedException ("Unknown completition type " + t.GetType ());
532                         }
533                 }
534
535                 void CompletionTaskExecutor (Task cont)
536                 {
537                         if (cont.Slot.Predicate != null && !cont.Slot.Predicate ())
538                                 return;
539
540                         if (!cont.Slot.Launched.TryRelaxedSet ())
541                                 return;
542
543                         if (!ContinuationStatusCheck (cont.Slot.Kind)) {
544                                 cont.CancelReal ();
545                                 cont.Dispose ();
546
547                                 return;
548                         }
549                         
550                         if ((cont.Slot.Kind & TaskContinuationOptions.ExecuteSynchronously) != 0)
551                                 cont.RunSynchronously (cont.scheduler);
552                         else
553                                 cont.Schedule ();
554                 }
555
556                 void ProcessChildExceptions ()
557                 {
558                         if (childExceptions == null)
559                                 return;
560
561                         if (exception == null)
562                                 exception = new AggregateException ();
563
564                         AggregateException childEx;
565                         while (childExceptions.TryDequeue (out childEx))
566                                 exception.AddChildException (childEx);
567                 }
568                 #endregion
569                 
570                 #region Cancel and Wait related method
571                 
572                 internal void CancelReal ()
573                 {
574                         status = TaskStatus.Canceled;
575                         ProcessCompleteDelegates ();
576                 }
577
578                 internal void HandleGenericException (Exception e)
579                 {
580                         HandleGenericException (new AggregateException (e));
581                 }
582
583                 internal void HandleGenericException (AggregateException e)
584                 {
585                         exception = e;
586                         Thread.MemoryBarrier ();
587                         status = TaskStatus.Faulted;
588                         if (scheduler != null && scheduler.FireUnobservedEvent (exception).Observed)
589                                 exceptionObserved = true;
590                 }
591                 
592                 public void Wait ()
593                 {
594                         Wait (Timeout.Infinite, CancellationToken.None);
595                 }
596
597                 public void Wait (CancellationToken cancellationToken)
598                 {
599                         Wait (Timeout.Infinite, cancellationToken);
600                 }
601                 
602                 public bool Wait (TimeSpan timeout)
603                 {
604                         return Wait (CheckTimeout (timeout), CancellationToken.None);
605                 }
606                 
607                 public bool Wait (int millisecondsTimeout)
608                 {
609                         return Wait (millisecondsTimeout, CancellationToken.None);
610                 }
611
612                 public bool Wait (int millisecondsTimeout, CancellationToken cancellationToken)
613                 {
614                         if (millisecondsTimeout < -1)
615                                 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
616
617                         bool result = IsCompleted;
618                         if (!result) {
619                                 CancellationTokenRegistration? registration = null;
620                                 var completed_event =  new ManualResetEventSlim (false);
621
622                                 try {
623                                         if (cancellationToken.CanBeCanceled) {
624                                                 registration = cancellationToken.Register (completed_event.Set);
625                                         }
626
627                                         completed.Add (completed_event);
628
629                                         // Task could complete while we were setting things up
630                                         if (IsCompleted) {
631                                                 // Don't bother removing completed_event, GC can handle it
632                                                 result = true;
633                                         } else {
634                                                 result = completed_event.Wait (millisecondsTimeout);
635                                         }
636                                 } finally {
637                                         if (registration.HasValue)
638                                                 registration.Value.Dispose ();
639
640                                         // Try to remove completition event when timeout expired
641                                         if (!result)
642                                                 completed.TryRemove (completed_event);
643
644                                         completed_event.Dispose ();
645                                 }
646                         }
647
648                         if (IsCanceled)
649                                 throw new AggregateException (new TaskCanceledException (this));
650
651                         if (exception != null)
652                                 throw exception;
653
654                         return result;
655                 }
656                 
657                 public static void WaitAll (params Task[] tasks)
658                 {
659                         WaitAll (tasks, Timeout.Infinite, CancellationToken.None);
660                 }
661
662                 public static void WaitAll (Task[] tasks, CancellationToken cancellationToken)
663                 {
664                         WaitAll (tasks, Timeout.Infinite, cancellationToken);
665                 }
666                 
667                 public static bool WaitAll (Task[] tasks, TimeSpan timeout)
668                 {
669                         return WaitAll (tasks, CheckTimeout (timeout), CancellationToken.None);
670                 }
671                 
672                 public static bool WaitAll (Task[] tasks, int millisecondsTimeout)
673                 {
674                         return WaitAll (tasks, millisecondsTimeout, CancellationToken.None);
675                 }
676                 
677                 public static bool WaitAll (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
678                 {
679                         if (tasks == null)
680                                 throw new ArgumentNullException ("tasks");
681
682                         if (millisecondsTimeout < -1)
683                                 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
684                         
685                         bool result = true;
686                         bool simple_run = millisecondsTimeout == Timeout.Infinite || tasks.Length == 1;
687                         List<Exception> exceptions = null;
688
689                         foreach (var t in tasks) {
690                                 if (t == null)
691                                         throw new ArgumentNullException ("tasks", "the tasks argument contains a null element");
692
693                                 if (simple_run) {
694                                         try {
695                                                 result &= t.Wait (millisecondsTimeout, cancellationToken);
696                                         } catch (AggregateException e) {
697                                                 if (exceptions == null)
698                                                         exceptions = new List<Exception> ();
699
700                                                 exceptions.AddRange (e.InnerExceptions);
701                                         }
702                                 }
703                         }
704
705                         // FIXME: Wrong implementation, millisecondsTimeout is total time not time per task
706                         if (!simple_run) {
707                                 foreach (var t in tasks) {
708                                         try {
709                                                 result &= t.Wait (millisecondsTimeout, cancellationToken);
710                                         } catch (AggregateException e) {
711                                                 if (exceptions == null)
712                                                         exceptions = new List<Exception> ();
713
714                                                 exceptions.AddRange (e.InnerExceptions);
715                                         }
716                                 }
717                         }
718
719                         if (exceptions != null)
720                                 throw new AggregateException (exceptions);
721
722                         return result;
723                 }
724                 
725                 public static int WaitAny (params Task[] tasks)
726                 {
727                         return WaitAny (tasks, Timeout.Infinite, CancellationToken.None);
728                 }
729
730                 public static int WaitAny (Task[] tasks, TimeSpan timeout)
731                 {
732                         return WaitAny (tasks, CheckTimeout (timeout));
733                 }
734                 
735                 public static int WaitAny (Task[] tasks, int millisecondsTimeout)
736                 {
737                         return WaitAny (tasks, millisecondsTimeout, CancellationToken.None);
738                 }
739
740                 public static int WaitAny (Task[] tasks, CancellationToken cancellationToken)
741                 {
742                         return WaitAny (tasks, Timeout.Infinite, cancellationToken);
743                 }
744
745                 public static int WaitAny (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
746                 {
747                         if (tasks == null)
748                                 throw new ArgumentNullException ("tasks");
749
750                         int first_finished = -1;
751                         for (int i = 0; i < tasks.Length; ++i) {
752                                 var t = tasks [i];
753
754                                 if (t == null)
755                                         throw new ArgumentNullException ("tasks", "the tasks argument contains a null element");
756
757                                 if (first_finished < 0 && t.IsCompleted)
758                                         first_finished = i;
759                         }
760
761                         if (first_finished >= 0 || tasks.Length == 0)
762                                 return first_finished;
763
764                         using (var completed_event = new ManualResetEventSlim (false)) {
765
766                                 foreach (var t in tasks) {
767                                         t.completed.Add (completed_event);
768                                 }
769
770                                 completed_event.Wait (millisecondsTimeout, cancellationToken);
771
772                                 for (int i = 0; i < tasks.Length; ++i) {
773                                         var t = tasks[i];
774                                         if (first_finished < 0 && t.IsCompleted)
775                                                 first_finished = i;
776
777                                         t.completed.TryRemove (completed_event);
778                                 }
779                         }
780
781                         return first_finished;
782                 }
783
784                 static int CheckTimeout (TimeSpan timeout)
785                 {
786                         try {
787                                 return checked ((int)timeout.TotalMilliseconds);
788                         } catch (System.OverflowException) {
789                                 throw new ArgumentOutOfRangeException ("timeout");
790                         }
791                 }
792
793                 static int ComputeTimeout (int millisecondsTimeout, Watch watch)
794                 {
795                         return millisecondsTimeout == -1 ? -1 : (int)Math.Max (watch.ElapsedMilliseconds - millisecondsTimeout, 1);
796                 }
797
798                 #endregion
799                 
800                 #region Dispose
801                 public void Dispose ()
802                 {
803                         Dispose (true);
804                 }
805                 
806                 protected virtual void Dispose (bool disposing)
807                 {
808                         if (!IsCompleted)
809                                 throw new InvalidOperationException ("A task may only be disposed if it is in a completion state");
810
811                         // Set action to null so that the GC can collect the delegate and thus
812                         // any big object references that the user might have captured in a anonymous method
813                         if (disposing) {
814                                 action = null;
815                                 state = null;
816                         }
817                 }
818                 #endregion
819                 
820 #if NET_4_5
821
822                 public ConfiguredTaskAwaitable ConfigureAwait (bool continueOnCapturedContext)
823                 {
824                         return new ConfiguredTaskAwaitable (this, continueOnCapturedContext);
825                 }
826
827                 public Task ContinueWith (Action<Task, object> continuationAction, object state)
828                 {
829                         return ContinueWith (continuationAction, state, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current);
830                 }
831
832                 public Task ContinueWith (Action<Task, object> continuationAction, object state, CancellationToken cancellationToken)
833                 {
834                         return ContinueWith (continuationAction, state, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
835                 }
836
837                 public Task ContinueWith (Action<Task, object> continuationAction, object state, TaskContinuationOptions continuationOptions)
838                 {
839                         return ContinueWith (continuationAction, state, CancellationToken.None, continuationOptions, TaskScheduler.Current);
840                 }
841
842                 public Task ContinueWith (Action<Task, object> continuationAction, object state, TaskScheduler scheduler)
843                 {
844                         return ContinueWith (continuationAction, state, CancellationToken.None, TaskContinuationOptions.None, scheduler);
845                 }
846
847                 public Task ContinueWith (Action<Task, object> continuationAction, object state, CancellationToken cancellationToken,
848                                                                   TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
849                 {
850                         if (continuationAction == null)
851                                 throw new ArgumentNullException ("continuationAction");
852                         if (scheduler == null)
853                                 throw new ArgumentNullException ("scheduler");
854
855                         Task continuation = new Task (l => continuationAction (this, l), state,
856                                                                                   cancellationToken,
857                                                                                   GetCreationOptions (continuationOptions),
858                                                                                   this);
859                         ContinueWithCore (continuation, continuationOptions, scheduler);
860
861                         return continuation;
862                 }
863
864                 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state)
865                 {
866                         return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current);
867                 }
868
869                 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, TaskContinuationOptions continuationOptions)
870                 {
871                         return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, continuationOptions, TaskScheduler.Current);
872                 }
873
874                 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, CancellationToken cancellationToken)
875                 {
876                         return ContinueWith<TResult> (continuationFunction, state, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
877                 }
878
879                 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, TaskScheduler scheduler)
880                 {
881                         return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, TaskContinuationOptions.None, scheduler);
882                 }
883
884                 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, CancellationToken cancellationToken,
885                                                                                                         TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
886                 {
887                         if (continuationFunction == null)
888                                 throw new ArgumentNullException ("continuationFunction");
889                         if (scheduler == null)
890                                 throw new ArgumentNullException ("scheduler");
891
892                         var t = new Task<TResult> (l => continuationFunction (this, l),
893                                                                                                  state,
894                                                                                                  cancellationToken,
895                                                                                                  GetCreationOptions (continuationOptions),
896                                                                                                  this);
897
898                         ContinueWithCore (t, continuationOptions, scheduler);
899
900                         return t;
901                 }
902
903                 public static Task<TResult> FromResult<TResult> (TResult result)
904                 {
905                         var tcs = new TaskCompletionSource<TResult> ();
906                         tcs.SetResult (result);
907                         return tcs.Task;
908                 }
909
910                 public TaskAwaiter GetAwaiter ()
911                 {
912                         return new TaskAwaiter (this);
913                 }
914
915                 public static Task Run (Action action)
916                 {
917                         return Run (action, CancellationToken.None);
918                 }
919
920                 public static Task Run (Action action, CancellationToken cancellationToken)
921                 {
922                         if (cancellationToken.IsCancellationRequested)
923                                 return TaskConstants.Canceled;
924
925                         var t = new Task (action, cancellationToken, TaskCreationOptions.DenyChildAttach);
926                         t.Start ();
927                         return t;
928                 }
929
930                 public static Task Run (Func<Task> function)
931                 {
932                         return Run (function, CancellationToken.None);
933                 }
934
935                 public static Task Run (Func<Task> function, CancellationToken cancellationToken)
936                 {
937                         if (cancellationToken.IsCancellationRequested)
938                                 return TaskConstants.Canceled;
939
940                         var t = new Task<Task> (function, cancellationToken);
941                         t.Start ();
942                         return t;
943                 }
944
945                 public static Task<TResult> Run<TResult> (Func<TResult> function)
946                 {
947                         return Run (function, CancellationToken.None);
948                 }
949
950                 public static Task<TResult> Run<TResult> (Func<TResult> function, CancellationToken cancellationToken)
951                 {
952                         if (cancellationToken.IsCancellationRequested)
953                                 return TaskConstants<TResult>.Canceled;
954
955                         var t = new Task<TResult> (function, cancellationToken, TaskCreationOptions.DenyChildAttach);
956                         t.Start ();
957                         return t;
958                 }
959
960                 public static Task<TResult> Run<TResult> (Func<Task<TResult>> function)
961                 {
962                         return Run (function, CancellationToken.None);
963                 }
964
965                 public static Task<TResult> Run<TResult> (Func<Task<TResult>> function, CancellationToken cancellationToken)
966                 {
967                         if (cancellationToken.IsCancellationRequested)
968                                 return TaskConstants<TResult>.Canceled;
969
970                         var t = Task<Task<TResult>>.Factory.StartNew (function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
971                         return GetTaskResult (t);
972                 }
973
974                 async static Task<TResult> GetTaskResult<TResult> (Task<Task<TResult>> task)
975                 {
976                         var r = await task.ConfigureAwait (false);
977                         return r.Result;
978                 }
979                 
980                 public static YieldAwaitable Yield ()
981                 {
982                         return new YieldAwaitable ();
983                 }
984 #endif
985
986                 #region Properties
987                 public static TaskFactory Factory {
988                         get {
989                                 return defaultFactory;
990                         }
991                 }
992                 
993                 public static int? CurrentId {
994                         get {
995                                 Task t = current;
996                                 return t == null ? (int?)null : t.Id;
997                         }
998                 }
999                 
1000                 public AggregateException Exception {
1001                         get {
1002                                 exceptionObserved = true;
1003                                 
1004                                 return exception;       
1005                         }
1006                         internal set {
1007                                 exception = value;
1008                         }
1009                 }
1010                 
1011                 public bool IsCanceled {
1012                         get {
1013                                 return status == TaskStatus.Canceled;
1014                         }
1015                 }
1016
1017                 public bool IsCompleted {
1018                         get {
1019                                 return status == TaskStatus.RanToCompletion ||
1020                                         status == TaskStatus.Canceled || status == TaskStatus.Faulted;
1021                         }
1022                 }
1023                 
1024                 public bool IsFaulted {
1025                         get {
1026                                 return status == TaskStatus.Faulted;
1027                         }
1028                 }
1029
1030                 public TaskCreationOptions CreationOptions {
1031                         get {
1032                                 return taskCreationOptions;
1033                         }
1034                 }
1035                 
1036                 public TaskStatus Status {
1037                         get {
1038                                 return status;
1039                         }
1040                         internal set {
1041                                 status = value;
1042                         }
1043                 }
1044
1045                 public object AsyncState {
1046                         get {
1047                                 return state;
1048                         }
1049                 }
1050                 
1051                 bool IAsyncResult.CompletedSynchronously {
1052                         get {
1053                                 return true;
1054                         }
1055                 }
1056
1057                 WaitHandle IAsyncResult.AsyncWaitHandle {
1058                         get {
1059                                 return null;
1060                         }
1061                 }
1062                 
1063                 public int Id {
1064                         get {
1065                                 return taskId;
1066                         }
1067                 }
1068
1069                 internal Task Parent {
1070                         get {
1071                                 return parent;
1072                         }
1073                 }
1074                 
1075                 internal string DisplayActionMethod {
1076                         get {
1077                                 Delegate d = simpleAction ?? (Delegate) action;
1078                                 return d == null ? "<none>" : d.Method.ToString ();
1079                         }
1080                 }
1081                 
1082                 #endregion
1083         }
1084 }
1085 #endif