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