Update Wait and WaitAny with event disposal and single execution flow
[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                 static readonly Watch watch = Watch.StartNew ();
56
57                 CountdownEvent childTasks;
58                 
59                 int                 taskId;
60                 TaskCreationOptions taskCreationOptions;
61                 
62                 TaskScheduler       scheduler;
63
64                 ManualResetEventSlim schedWait = new ManualResetEventSlim (false);
65                 
66                 volatile AggregateException  exception;
67                 volatile bool                exceptionObserved;
68                 ConcurrentQueue<AggregateException> childExceptions;
69
70                 TaskStatus          status;
71                 
72                 Action<object> action;
73                 Action         simpleAction;
74                 object         state;
75                 AtomicBooleanValue executing;
76
77                 TaskCompletionQueue<Task> completed;
78                 TaskCompletionQueue<ManualResetEventSlim> registeredEvts;
79                 // If this task is a continuation, this stuff gets filled
80                 CompletionSlot Slot;
81
82                 CancellationToken token;
83                 CancellationTokenRegistration? cancellationRegistration;
84
85                 internal const TaskCreationOptions WorkerTaskNotSupportedOptions = TaskCreationOptions.LongRunning | TaskCreationOptions.PreferFairness;
86
87                 const TaskCreationOptions MaxTaskCreationOptions =
88 #if NET_4_5
89                         TaskCreationOptions.DenyChildAttach | TaskCreationOptions.HideScheduler |
90 #endif
91                         TaskCreationOptions.PreferFairness | TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent;
92
93                 public Task (Action action) : this (action, TaskCreationOptions.None)
94                 {
95                         
96                 }
97                 
98                 public Task (Action action, TaskCreationOptions creationOptions) : this (action, CancellationToken.None, creationOptions)
99                 {
100                         
101                 }
102                 
103                 public Task (Action action, CancellationToken cancellationToken) : this (action, cancellationToken, TaskCreationOptions.None)
104                 {
105                         
106                 }
107                 
108                 public Task (Action action, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
109                         : this (null, null, cancellationToken, creationOptions, current)
110                 {
111                         if (action == null)
112                                 throw new ArgumentNullException ("action");
113                         if (creationOptions > MaxTaskCreationOptions || creationOptions < TaskCreationOptions.None)
114                                 throw new ArgumentOutOfRangeException ("creationOptions");
115                         this.simpleAction = action;
116                 }
117                 
118                 public Task (Action<object> action, object state) : this (action, state, TaskCreationOptions.None)
119                 {       
120                 }
121                 
122                 public Task (Action<object> action, object state, TaskCreationOptions creationOptions)
123                         : this (action, state, CancellationToken.None, creationOptions)
124                 {
125                 }
126                 
127                 public Task (Action<object> action, object state, CancellationToken cancellationToken)
128                         : this (action, state, cancellationToken, TaskCreationOptions.None)
129                 {       
130                 }
131
132                 public Task (Action<object> action, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
133                         : this (action, state, cancellationToken, creationOptions, current)
134                 {
135                         if (action == null)
136                                 throw new ArgumentNullException ("action");
137                         if (creationOptions > MaxTaskCreationOptions || creationOptions < TaskCreationOptions.None)
138                                 throw new ArgumentOutOfRangeException ("creationOptions");
139                 }
140
141                 internal Task (Action<object> action,
142                                object state,
143                                CancellationToken cancellationToken,
144                                TaskCreationOptions creationOptions,
145                                Task parent)
146                 {
147                         this.taskCreationOptions = creationOptions;
148                         this.action              = action;
149                         this.state               = state;
150                         this.taskId              = Interlocked.Increment (ref id);
151                         this.status              = cancellationToken.IsCancellationRequested ? TaskStatus.Canceled : TaskStatus.Created;
152                         this.token               = cancellationToken;
153                         this.parent              = parent;
154
155                         // Process taskCreationOptions
156                         if (CheckTaskOptions (taskCreationOptions, TaskCreationOptions.AttachedToParent) && parent != null)
157                                 parent.AddChild ();
158
159                         if (token.CanBeCanceled)
160                                 cancellationRegistration = token.Register (l => ((Task) l).CancelReal (), this);
161                 }
162
163                 ~Task ()
164                 {
165                         if (exception != null && !exceptionObserved)
166                                 throw exception;
167                 }
168
169                 bool CheckTaskOptions (TaskCreationOptions opt, TaskCreationOptions member)
170                 {
171                         return (opt & member) == member;
172                 }
173
174                 #region Start
175                 public void Start ()
176                 {
177                         Start (TaskScheduler.Current);
178                 }
179                 
180                 public void Start (TaskScheduler scheduler)
181                 {
182                         if (scheduler == null)
183                                 throw new ArgumentNullException ("scheduler");
184
185                         if (status >= TaskStatus.WaitingToRun)
186                                 throw new InvalidOperationException ("The Task is not in a valid state to be started.");
187
188                         if (Slot.Initialized)
189                                 throw new InvalidOperationException ("Start may not be called on a continuation task");
190
191                         SetupScheduler (scheduler);
192                         Schedule ();
193                 }
194
195                 internal void SetupScheduler (TaskScheduler scheduler)
196                 {
197                         this.scheduler = scheduler;
198                         status = TaskStatus.WaitingForActivation;
199                         schedWait.Set ();
200                 }
201                 
202                 public void RunSynchronously ()
203                 {
204                         RunSynchronously (TaskScheduler.Current);
205                 }
206                 
207                 public void RunSynchronously (TaskScheduler scheduler)
208                 {
209                         if (scheduler == null)
210                                 throw new ArgumentNullException ("scheduler");
211
212                         if (Status > TaskStatus.WaitingForActivation)
213                                 throw new InvalidOperationException ("The task is not in a valid state to be started");
214
215                         SetupScheduler (scheduler);
216                         var saveStatus = status;
217                         status = TaskStatus.WaitingToRun;
218
219                         try {
220                                 if (scheduler.RunInline (this))
221                                         return;
222                         } catch (Exception inner) {
223                                 throw new TaskSchedulerException (inner);
224                         }
225
226                         status = saveStatus;
227                         Start (scheduler);
228                         Wait ();
229                 }
230                 #endregion
231                 
232                 #region ContinueWith
233                 public Task ContinueWith (Action<Task> continuationAction)
234                 {
235                         return ContinueWith (continuationAction, TaskContinuationOptions.None);
236                 }
237                 
238                 public Task ContinueWith (Action<Task> continuationAction, TaskContinuationOptions continuationOptions)
239                 {
240                         return ContinueWith (continuationAction, CancellationToken.None, continuationOptions, TaskScheduler.Current);
241                 }
242                 
243                 public Task ContinueWith (Action<Task> continuationAction, CancellationToken cancellationToken)
244                 {
245                         return ContinueWith (continuationAction, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
246                 }
247                 
248                 public Task ContinueWith (Action<Task> continuationAction, TaskScheduler scheduler)
249                 {
250                         return ContinueWith (continuationAction, CancellationToken.None, TaskContinuationOptions.None, scheduler);
251                 }
252                 
253                 public Task ContinueWith (Action<Task> continuationAction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
254                 {
255                         if (continuationAction == null)
256                                 throw new ArgumentNullException ("continuationAction");
257                         if (scheduler == null)
258                                 throw new ArgumentNullException ("scheduler");
259
260                         Task continuation = new Task (l => continuationAction ((Task)l),
261                                                       this,
262                                                       cancellationToken,
263                                                       GetCreationOptions (continuationOptions),
264                                                       this);
265                         ContinueWithCore (continuation, continuationOptions, scheduler);
266
267                         return continuation;
268                 }
269                 
270                 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction)
271                 {
272                         return ContinueWith<TResult> (continuationFunction, TaskContinuationOptions.None);
273                 }
274                 
275                 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, TaskContinuationOptions continuationOptions)
276                 {
277                         return ContinueWith<TResult> (continuationFunction, CancellationToken.None, continuationOptions, TaskScheduler.Current);
278                 }
279                 
280                 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, CancellationToken cancellationToken)
281                 {
282                         return ContinueWith<TResult> (continuationFunction, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
283                 }
284                 
285                 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, TaskScheduler scheduler)
286                 {
287                         return ContinueWith<TResult> (continuationFunction, CancellationToken.None, TaskContinuationOptions.None, scheduler);
288                 }
289                 
290                 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, CancellationToken cancellationToken,
291                                                             TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
292                 {
293                         if (continuationFunction == null)
294                                 throw new ArgumentNullException ("continuationFunction");
295                         if (scheduler == null)
296                                 throw new ArgumentNullException ("scheduler");
297
298                         Task<TResult> t = new Task<TResult> ((o) => continuationFunction ((Task)o),
299                                                              this,
300                                                              cancellationToken,
301                                                              GetCreationOptions (continuationOptions),
302                                                              this);
303                         
304                         ContinueWithCore (t, continuationOptions, scheduler);
305                         
306                         return t;
307                 }
308         
309                 internal void ContinueWithCore (Task continuation, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
310                 {
311                         ContinueWithCore (continuation, continuationOptions, scheduler, null);
312                 }
313                 
314                 internal void ContinueWithCore (Task continuation, TaskContinuationOptions kind,
315                                                 TaskScheduler scheduler, Func<bool> predicate)
316                 {
317                         // Already set the scheduler so that user can call Wait and that sort of stuff
318                         continuation.scheduler = scheduler;
319                         continuation.schedWait.Set ();
320                         continuation.status = TaskStatus.WaitingForActivation;
321                         continuation.Slot = new CompletionSlot (kind, predicate);
322
323                         if (IsCompleted) {
324                                 CompletionExecutor (continuation);
325                                 return;
326                         }
327                         
328                         completed.Add (continuation);
329                         
330                         // Retry in case completion was achieved but event adding was too late
331                         if (IsCompleted)
332                                 CompletionExecutor (continuation);
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
389                 internal void RegisterWaitEvent (ManualResetEventSlim evt)
390                 {
391                         if (IsCompleted) {
392                                 evt.Set ();
393                                 return;
394                         }
395
396                         registeredEvts.Add (evt);
397                         if (IsCompleted)
398                                 evt.Set ();
399                 }
400                 #endregion
401                 
402                 #region Internal and protected thingies
403                 internal void Schedule ()
404                 {
405                         status = TaskStatus.WaitingToRun;
406                         
407                         // If worker is null it means it is a local one, revert to the old behavior
408                         // If TaskScheduler.Current is not being used, the scheduler was explicitly provided, so we must use that
409                         if (scheduler != TaskScheduler.Current || childWorkAdder == null || CheckTaskOptions (taskCreationOptions, TaskCreationOptions.PreferFairness)) {
410                                 scheduler.QueueTask (this);
411                         } else {
412                                 /* Like the semantic of the ABP paper describe it, we add ourselves to the bottom 
413                                  * of our Parent Task's ThreadWorker deque. It's ok to do that since we are in
414                                  * the correct Thread during the creation
415                                  */
416                                 childWorkAdder (this);
417                         }
418                 }
419                 
420                 void ThreadStart ()
421                 {
422                         /* Allow scheduler to break fairness of deque ordering without
423                          * breaking its semantic (the task can be executed twice but the
424                          * second time it will return immediately
425                          */
426                         if (!executing.TryRelaxedSet ())
427                                 return;
428
429                         // Disable CancellationToken direct cancellation
430                         if (cancellationRegistration != null) {
431                                 cancellationRegistration.Value.Dispose ();
432                                 cancellationRegistration = null;
433                         }
434                         current = this;
435                         TaskScheduler.Current = scheduler;
436                         
437                         if (!token.IsCancellationRequested) {
438                                 
439                                 status = TaskStatus.Running;
440                                 
441                                 try {
442                                         InnerInvoke ();
443                                 } catch (OperationCanceledException oce) {
444                                         if (token != CancellationToken.None && oce.CancellationToken == token)
445                                                 CancelReal ();
446                                         else
447                                                 HandleGenericException (oce);
448                                 } catch (Exception e) {
449                                         HandleGenericException (e);
450                                 }
451                         } else {
452                                 CancelReal ();
453                         }
454                         
455                         Finish ();
456                 }
457                 
458                 internal void Execute (Action<Task> childAdder)
459                 {
460                         childWorkAdder = childAdder;
461                         ThreadStart ();
462                 }
463                 
464                 internal void AddChild ()
465                 {
466                         if (childTasks == null)
467                                 Interlocked.CompareExchange (ref childTasks, new CountdownEvent (1), null);
468                         childTasks.AddCount ();
469                 }
470
471                 internal void ChildCompleted (AggregateException childEx)
472                 {
473                         if (childEx != null) {
474                                 if (childExceptions == null)
475                                         Interlocked.CompareExchange (ref childExceptions, new ConcurrentQueue<AggregateException> (), null);
476                                 childExceptions.Enqueue (childEx);
477                         }
478
479                         if (childTasks.Signal () && status == TaskStatus.WaitingForChildrenToComplete) {
480                                 status = TaskStatus.RanToCompletion;
481                                 ProcessChildExceptions ();
482                                 ProcessCompleteDelegates ();
483                         }
484                 }
485
486                 internal virtual void InnerInvoke ()
487                 {
488                         if (action == null && simpleAction != null)
489                                 simpleAction ();
490                         else if (action != null)
491                                 action (state);
492                         // Set action to null so that the GC can collect the delegate and thus
493                         // any big object references that the user might have captured in an anonymous method
494                         action = null;
495                         simpleAction = null;
496                         state = null;
497                 }
498                 
499                 internal void Finish ()
500                 {
501                         // If there was children created and they all finished, we set the countdown
502                         if (childTasks != null)
503                                 childTasks.Signal ();
504                         
505                         // Don't override Canceled or Faulted
506                         if (status == TaskStatus.Running) {
507                                 if (childTasks == null || childTasks.IsSet)
508                                         status = TaskStatus.RanToCompletion;
509                                 else
510                                         status = TaskStatus.WaitingForChildrenToComplete;
511                         }
512                 
513                         if (status != TaskStatus.WaitingForChildrenToComplete)
514                                 ProcessCompleteDelegates ();
515
516                         // Reset the current thingies
517                         current = null;
518                         TaskScheduler.Current = null;
519
520                         if (cancellationRegistration.HasValue)
521                                 cancellationRegistration.Value.Dispose ();
522                         
523                         // Tell parent that we are finished
524                         if (CheckTaskOptions (taskCreationOptions, TaskCreationOptions.AttachedToParent) && parent != null) {
525                                 parent.ChildCompleted (this.Exception);
526                         }
527                 }
528
529                 void CompletionExecutor (Task cont)
530                 {
531                         if (cont.Slot.Predicate != null && !cont.Slot.Predicate ())
532                                 return;
533
534                         if (!cont.Slot.Launched.TryRelaxedSet ())
535                                 return;
536
537                         if (!ContinuationStatusCheck (cont.Slot.Kind)) {
538                                 cont.CancelReal ();
539                                 cont.Dispose ();
540
541                                 return;
542                         }
543                         
544                         if ((cont.Slot.Kind & TaskContinuationOptions.ExecuteSynchronously) != 0)
545                                 cont.RunSynchronously (cont.scheduler);
546                         else
547                                 cont.Schedule ();
548                 }
549
550                 void ProcessCompleteDelegates ()
551                 {
552                         if (completed.HasElements) {
553                                 Task continuation;
554                                 while (completed.TryGetNextCompletion (out continuation))
555                                         CompletionExecutor (continuation);
556                         }
557                         if (registeredEvts.HasElements) {
558                                 ManualResetEventSlim evt;
559                                 while (registeredEvts.TryGetNextCompletion (out evt))
560                                         evt.Set ();
561                         }
562                 }
563
564                 void ProcessChildExceptions ()
565                 {
566                         if (childExceptions == null)
567                                 return;
568
569                         if (exception == null)
570                                 exception = new AggregateException ();
571
572                         AggregateException childEx;
573                         while (childExceptions.TryDequeue (out childEx))
574                                 exception.AddChildException (childEx);
575                 }
576                 #endregion
577                 
578                 #region Cancel and Wait related method
579                 
580                 internal void CancelReal ()
581                 {
582                         status = TaskStatus.Canceled;
583                         ProcessCompleteDelegates ();
584                 }
585
586                 internal void HandleGenericException (Exception e)
587                 {
588                         HandleGenericException (new AggregateException (e));
589                 }
590
591                 internal void HandleGenericException (AggregateException e)
592                 {
593                         exception = e;
594                         Thread.MemoryBarrier ();
595                         status = TaskStatus.Faulted;
596                         if (scheduler != null && scheduler.FireUnobservedEvent (exception).Observed)
597                                 exceptionObserved = true;
598                 }
599                 
600                 public void Wait ()
601                 {
602                         Wait (Timeout.Infinite, CancellationToken.None);
603                 }
604
605                 public void Wait (CancellationToken cancellationToken)
606                 {
607                         Wait (Timeout.Infinite, cancellationToken);
608                 }
609                 
610                 public bool Wait (TimeSpan timeout)
611                 {
612                         return Wait (CheckTimeout (timeout), CancellationToken.None);
613                 }
614                 
615                 public bool Wait (int millisecondsTimeout)
616                 {
617                         return Wait (millisecondsTimeout, CancellationToken.None);
618                 }
619
620                 public bool Wait (int millisecondsTimeout, CancellationToken cancellationToken)
621                 {
622                         if (millisecondsTimeout < -1)
623                                 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
624
625                         bool result = true;
626
627                         if (!IsCompleted) {
628                                 // If the task is ready to be run and we were supposed to wait on it indefinitely, just run it
629                                 if (Status == TaskStatus.WaitingToRun && millisecondsTimeout == -1 && scheduler != null)
630                                         Execute (null);
631
632                                 if (!IsCompleted) {
633                                         // Free heavy ressources used by the event automatically but without removing
634                                         // it from the queue since Set () doesn't trigger ObjectDisposedException
635                                         using (var evt = new ManualResetEventSlim ()) {
636                                                 RegisterWaitEvent (evt);
637                                                 result = evt.Wait (millisecondsTimeout, cancellationToken);
638                                         }
639                                 }
640                         }
641
642                         if (IsCanceled)
643                                 throw new AggregateException (new TaskCanceledException (this));
644
645                         if (exception != null)
646                                 throw exception;
647
648                         return result;
649                 }
650                 
651                 public static void WaitAll (params Task[] tasks)
652                 {
653                         WaitAll (tasks, Timeout.Infinite, CancellationToken.None);
654                 }
655
656                 public static void WaitAll (Task[] tasks, CancellationToken cancellationToken)
657                 {
658                         WaitAll (tasks, Timeout.Infinite, cancellationToken);
659                 }
660                 
661                 public static bool WaitAll (Task[] tasks, TimeSpan timeout)
662                 {
663                         return WaitAll (tasks, CheckTimeout (timeout), CancellationToken.None);
664                 }
665                 
666                 public static bool WaitAll (Task[] tasks, int millisecondsTimeout)
667                 {
668                         return WaitAll (tasks, millisecondsTimeout, CancellationToken.None);
669                 }
670                 
671                 public static bool WaitAll (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
672                 {
673                         if (tasks == null)
674                                 throw new ArgumentNullException ("tasks");
675                         CheckForNullTasks (tasks);
676
677                         bool result = true;
678                         List<Exception> exceptions = null;
679                         long start = watch.ElapsedMilliseconds;
680
681                         foreach (var t in tasks) {
682                                 try {
683                                         result &= t.Wait (millisecondsTimeout, cancellationToken);
684                                 } catch (AggregateException e) {
685                                         if (exceptions == null)
686                                                 exceptions = new List<Exception> ();
687
688                                         exceptions.AddRange (e.InnerExceptions);
689                                 }
690                                 if (!ComputeTimeout (ref millisecondsTimeout, start, watch))
691                                         result = false;
692                                 if (!result)
693                                         break;
694                         }
695
696                         if (exceptions != null)
697                                 throw new AggregateException (exceptions);
698
699                         return result;
700                 }
701                 
702                 public static int WaitAny (params Task[] tasks)
703                 {
704                         return WaitAny (tasks, Timeout.Infinite, CancellationToken.None);
705                 }
706
707                 public static int WaitAny (Task[] tasks, TimeSpan timeout)
708                 {
709                         return WaitAny (tasks, CheckTimeout (timeout));
710                 }
711                 
712                 public static int WaitAny (Task[] tasks, int millisecondsTimeout)
713                 {
714                         return WaitAny (tasks, millisecondsTimeout, CancellationToken.None);
715                 }
716
717                 public static int WaitAny (Task[] tasks, CancellationToken cancellationToken)
718                 {
719                         return WaitAny (tasks, Timeout.Infinite, cancellationToken);
720                 }
721
722                 public static int WaitAny (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
723                 {
724                         if (tasks == null)
725                                 throw new ArgumentNullException ("tasks");
726                         if (millisecondsTimeout < -1)
727                                 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
728                         CheckForNullTasks (tasks);
729
730                         if (tasks.Length > 0) {
731                                 using (var evt = new ManualResetEventSlim ()) {
732                                         for (int i = 0; i < tasks.Length; i++) {
733                                                 var t = tasks[i];
734                                                 if (t.IsCompleted)
735                                                         return i;
736                                                 t.RegisterWaitEvent (evt);
737                                         }
738
739                                         if (!evt.Wait (millisecondsTimeout, cancellationToken))
740                                                 return -1;
741                                 }
742                         }
743
744                         int firstFinished = -1;
745                         for (int i = 0; i < tasks.Length; i++) {
746                                 var t = tasks[i];
747                                 if (t.IsCompleted) {
748                                         firstFinished = i;
749                                         break;
750                                 }
751                         }
752
753                         return firstFinished;
754                 }
755
756                 static int CheckTimeout (TimeSpan timeout)
757                 {
758                         try {
759                                 return checked ((int)timeout.TotalMilliseconds);
760                         } catch (System.OverflowException) {
761                                 throw new ArgumentOutOfRangeException ("timeout");
762                         }
763                 }
764
765                 static bool ComputeTimeout (ref int millisecondsTimeout, long start, Watch watch)
766                 {
767                         if (millisecondsTimeout == -1)
768                                 return true;
769
770                         return (millisecondsTimeout = millisecondsTimeout - (int)(watch.ElapsedMilliseconds - start)) >= 1;
771                 }
772
773                 static void CheckForNullTasks (Task[] tasks)
774                 {
775                         foreach (var t in tasks)
776                                 if (t == null)
777                                         throw new ArgumentNullException ("tasks", "the tasks argument contains a null element");
778                 }
779                 #endregion
780                 
781                 #region Dispose
782                 public void Dispose ()
783                 {
784                         Dispose (true);
785                 }
786                 
787                 protected virtual void Dispose (bool disposing)
788                 {
789                         if (!IsCompleted)
790                                 throw new InvalidOperationException ("A task may only be disposed if it is in a completion state");
791
792                         // Set action to null so that the GC can collect the delegate and thus
793                         // any big object references that the user might have captured in a anonymous method
794                         if (disposing) {
795                                 action = null;
796                                 state = null;
797                                 if (cancellationRegistration != null)
798                                         cancellationRegistration.Value.Dispose ();
799                         }
800                 }
801                 #endregion
802                 
803 #if NET_4_5
804
805                 public ConfiguredTaskAwaitable ConfigureAwait (bool continueOnCapturedContext)
806                 {
807                         return new ConfiguredTaskAwaitable (this, continueOnCapturedContext);
808                 }
809
810                 public Task ContinueWith (Action<Task, object> continuationAction, object state)
811                 {
812                         return ContinueWith (continuationAction, state, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current);
813                 }
814
815                 public Task ContinueWith (Action<Task, object> continuationAction, object state, CancellationToken cancellationToken)
816                 {
817                         return ContinueWith (continuationAction, state, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
818                 }
819
820                 public Task ContinueWith (Action<Task, object> continuationAction, object state, TaskContinuationOptions continuationOptions)
821                 {
822                         return ContinueWith (continuationAction, state, CancellationToken.None, continuationOptions, TaskScheduler.Current);
823                 }
824
825                 public Task ContinueWith (Action<Task, object> continuationAction, object state, TaskScheduler scheduler)
826                 {
827                         return ContinueWith (continuationAction, state, CancellationToken.None, TaskContinuationOptions.None, scheduler);
828                 }
829
830                 public Task ContinueWith (Action<Task, object> continuationAction, object state, CancellationToken cancellationToken,
831                                                                   TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
832                 {
833                         if (continuationAction == null)
834                                 throw new ArgumentNullException ("continuationAction");
835                         if (scheduler == null)
836                                 throw new ArgumentNullException ("scheduler");
837
838                         Task continuation = new Task (l => continuationAction (this, l), state,
839                                                                                   cancellationToken,
840                                                                                   GetCreationOptions (continuationOptions),
841                                                                                   this);
842                         ContinueWithCore (continuation, continuationOptions, scheduler);
843
844                         return continuation;
845                 }
846
847                 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state)
848                 {
849                         return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current);
850                 }
851
852                 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, TaskContinuationOptions continuationOptions)
853                 {
854                         return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, continuationOptions, TaskScheduler.Current);
855                 }
856
857                 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, CancellationToken cancellationToken)
858                 {
859                         return ContinueWith<TResult> (continuationFunction, state, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
860                 }
861
862                 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, TaskScheduler scheduler)
863                 {
864                         return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, TaskContinuationOptions.None, scheduler);
865                 }
866
867                 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, CancellationToken cancellationToken,
868                                                                                                         TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
869                 {
870                         if (continuationFunction == null)
871                                 throw new ArgumentNullException ("continuationFunction");
872                         if (scheduler == null)
873                                 throw new ArgumentNullException ("scheduler");
874
875                         var t = new Task<TResult> (l => continuationFunction (this, l),
876                                                                                                  state,
877                                                                                                  cancellationToken,
878                                                                                                  GetCreationOptions (continuationOptions),
879                                                                                                  this);
880
881                         ContinueWithCore (t, continuationOptions, scheduler);
882
883                         return t;
884                 }
885
886                 public static Task<TResult> FromResult<TResult> (TResult result)
887                 {
888                         var tcs = new TaskCompletionSource<TResult> ();
889                         tcs.SetResult (result);
890                         return tcs.Task;
891                 }
892
893                 public TaskAwaiter GetAwaiter ()
894                 {
895                         return new TaskAwaiter (this);
896                 }
897
898                 public static Task Run (Action action)
899                 {
900                         return Run (action, CancellationToken.None);
901                 }
902
903                 public static Task Run (Action action, CancellationToken cancellationToken)
904                 {
905                         if (cancellationToken.IsCancellationRequested)
906                                 return TaskConstants.Canceled;
907
908                         var t = new Task (action, cancellationToken, TaskCreationOptions.DenyChildAttach);
909                         t.Start ();
910                         return t;
911                 }
912
913                 public static Task Run (Func<Task> function)
914                 {
915                         return Run (function, CancellationToken.None);
916                 }
917
918                 public static Task Run (Func<Task> function, CancellationToken cancellationToken)
919                 {
920                         if (cancellationToken.IsCancellationRequested)
921                                 return TaskConstants.Canceled;
922
923                         var t = new Task<Task> (function, cancellationToken);
924                         t.Start ();
925                         return t;
926                 }
927
928                 public static Task<TResult> Run<TResult> (Func<TResult> function)
929                 {
930                         return Run (function, CancellationToken.None);
931                 }
932
933                 public static Task<TResult> Run<TResult> (Func<TResult> function, CancellationToken cancellationToken)
934                 {
935                         if (cancellationToken.IsCancellationRequested)
936                                 return TaskConstants<TResult>.Canceled;
937
938                         var t = new Task<TResult> (function, cancellationToken, TaskCreationOptions.DenyChildAttach);
939                         t.Start ();
940                         return t;
941                 }
942
943                 public static Task<TResult> Run<TResult> (Func<Task<TResult>> function)
944                 {
945                         return Run (function, CancellationToken.None);
946                 }
947
948                 public static Task<TResult> Run<TResult> (Func<Task<TResult>> function, CancellationToken cancellationToken)
949                 {
950                         if (cancellationToken.IsCancellationRequested)
951                                 return TaskConstants<TResult>.Canceled;
952
953                         var t = Task<Task<TResult>>.Factory.StartNew (function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
954                         return GetTaskResult (t);
955                 }
956
957                 async static Task<TResult> GetTaskResult<TResult> (Task<Task<TResult>> task)
958                 {
959                         var r = await task.ConfigureAwait (false);
960                         return r.Result;
961                 }
962                 
963                 public static YieldAwaitable Yield ()
964                 {
965                         return new YieldAwaitable ();
966                 }
967 #endif
968
969                 #region Properties
970                 public static TaskFactory Factory {
971                         get {
972                                 return defaultFactory;
973                         }
974                 }
975                 
976                 public static int? CurrentId {
977                         get {
978                                 Task t = current;
979                                 return t == null ? (int?)null : t.Id;
980                         }
981                 }
982                 
983                 public AggregateException Exception {
984                         get {
985                                 exceptionObserved = true;
986                                 
987                                 return exception;       
988                         }
989                         internal set {
990                                 exception = value;
991                         }
992                 }
993                 
994                 public bool IsCanceled {
995                         get {
996                                 return status == TaskStatus.Canceled;
997                         }
998                 }
999
1000                 public bool IsCompleted {
1001                         get {
1002                                 return status >= TaskStatus.RanToCompletion;
1003                         }
1004                 }
1005                 
1006                 public bool IsFaulted {
1007                         get {
1008                                 return status == TaskStatus.Faulted;
1009                         }
1010                 }
1011
1012                 public TaskCreationOptions CreationOptions {
1013                         get {
1014                                 return taskCreationOptions;
1015                         }
1016                 }
1017                 
1018                 public TaskStatus Status {
1019                         get {
1020                                 return status;
1021                         }
1022                         internal set {
1023                                 status = value;
1024                         }
1025                 }
1026
1027                 public object AsyncState {
1028                         get {
1029                                 return state;
1030                         }
1031                 }
1032                 
1033                 bool IAsyncResult.CompletedSynchronously {
1034                         get {
1035                                 return true;
1036                         }
1037                 }
1038
1039                 WaitHandle IAsyncResult.AsyncWaitHandle {
1040                         get {
1041                                 return null;
1042                         }
1043                 }
1044                 
1045                 public int Id {
1046                         get {
1047                                 return taskId;
1048                         }
1049                 }
1050
1051                 internal Task Parent {
1052                         get {
1053                                 return parent;
1054                         }
1055                 }
1056                 
1057                 internal string DisplayActionMethod {
1058                         get {
1059                                 Delegate d = simpleAction ?? (Delegate) action;
1060                                 return d == null ? "<none>" : d.Method.ToString ();
1061                         }
1062                 }
1063                 
1064                 #endregion
1065         }
1066 }
1067 #endif