Merge pull request #297 from ermshiperete/4959
[mono.git] / mcs / class / corlib / System.Threading.Tasks / TaskFactory.cs
index 4e78b7e3c54f69af908f4b5928dea3a255b33665..5f3dafab164a0dcdd1281799ca8f65659e838259 100644 (file)
 
 #if NET_4_0 || MOBILE
 
-using System;
-using System.Threading;
-
 namespace System.Threading.Tasks
 {
-       
        public class TaskFactory
        {
                readonly TaskScheduler scheduler;
@@ -187,7 +183,15 @@ namespace System.Threading.Tasks
                                                        TaskCreationOptions creationOptions,
                                                        TaskScheduler scheduler)
                {
-                       return StartNew<TResult> ((o) => function (), null, cancellationToken, creationOptions, scheduler);
+                       var t = new Task<TResult> (function, cancellationToken, creationOptions);
+
+                       //
+                       // Don't start cancelled task it would throw an exception
+                       //
+                       if (!t.IsCompleted)
+                               t.Start (scheduler);
+
+                       return t;
                }
                
                public Task<TResult> StartNew<TResult> (Func<object, TResult> function, object state)
@@ -234,24 +238,13 @@ namespace System.Threading.Tasks
                        return ContinueWhenAny (tasks, continuationAction, cancellationToken, continuationOptions, GetScheduler ());
                }
 
-               public Task ContinueWhenAny (Task[] tasks,
-                                            Action<Task> continuationAction,
-                                            CancellationToken cancellationToken,
-                                            TaskContinuationOptions continuationOptions,
-                                            TaskScheduler scheduler)
+               public Task ContinueWhenAny (Task[] tasks, Action<Task> continuationAction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
                {
-                       var ourTasks = (Task[])tasks.Clone ();
-                       AtomicBoolean trigger = new AtomicBoolean ();
-                       var commonContinuation = new TaskCompletionSource<object> ();
-                       Action<Task> continuationFunc = t => commonContinuation.SetResult (null);
-                       
-                       foreach (Task t in ourTasks) {
-                               Task cont = new Task (TaskActionInvoker.Create (continuationAction), null, cancellationToken, creationOptions, t);
-                               t.ContinueWithCore (cont, continuationOptions, scheduler, trigger.TrySet);
-                               cont.ContinueWith (continuationFunc);
-                       }
-                       
-                       return commonContinuation.Task;
+                       CheckContinueArguments (tasks, continuationAction, continuationOptions, scheduler);
+
+                       var cont = Task.WhenAnyCore (tasks).ContinueWith (TaskActionInvoker.CreateSelected (continuationAction), cancellationToken, continuationOptions, scheduler);
+
+                       return cont;
                }
                
                public Task ContinueWhenAny<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
@@ -310,16 +303,11 @@ namespace System.Threading.Tasks
                                                               TaskContinuationOptions continuationOptions,
                                                               TaskScheduler scheduler)
                {
-                       var ourTasks = (Task[])tasks.Clone ();
-                       AtomicBoolean trigger = new AtomicBoolean ();
-                       TaskCompletionSource<TResult> source = new TaskCompletionSource<TResult> ();
+                       CheckContinueArguments (tasks, continuationFunction, continuationOptions, scheduler);
 
-                       foreach (Task t in ourTasks) {
-                               var cont = new Task (TaskActionInvoker.Create (continuationFunction), null, cancellationToken, creationOptions, t);
-                               t.ContinueWithCore (cont, continuationOptions, scheduler, trigger.TrySet);
-                       }
+                       var cont = Task.WhenAnyCore (tasks).ContinueWith<TResult> (TaskActionInvoker.Create (continuationFunction, tasks), cancellationToken, continuationOptions, scheduler);
 
-                       return source.Task;
+                       return cont;
                }
 
                public Task<TResult> ContinueWhenAny<TAntecedentResult, TResult> (Task<TAntecedentResult>[] tasks,
@@ -374,13 +362,10 @@ namespace System.Threading.Tasks
                public Task ContinueWhenAll (Task[] tasks, Action<Task[]> continuationAction, CancellationToken cancellationToken,
                                             TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
                {
-                       var ourTasks = (Task[])tasks.Clone ();
-                       CountdownEvent evt = new CountdownEvent (ourTasks.Length);
-                       Task cont = new Task ((o) => continuationAction ((Task[])o), ourTasks, cancellationToken, creationOptions);
-                       
-                       foreach (Task t in ourTasks)
-                               t.ContinueWithCore (cont, continuationOptions, scheduler, evt.Signal);
-                       
+                       CheckContinueArguments (tasks, continuationAction, continuationOptions, scheduler);
+
+                       var cont = Task.WhenAllCore (tasks).ContinueWith (TaskActionInvoker.Create (continuationAction, tasks), cancellationToken, continuationOptions, scheduler);
+
                        return cont;
                }
                
@@ -432,13 +417,10 @@ namespace System.Threading.Tasks
                                                               CancellationToken cancellationToken,
                                                               TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
                {
-                       var ourTasks = (Task[])tasks.Clone ();
-                       CountdownEvent evt = new CountdownEvent (ourTasks.Length);
-                       Task<TResult> cont = new Task<TResult> ((o) => continuationFunction ((Task[])o), ourTasks, cancellationToken, creationOptions);
-                       
-                       foreach (Task t in ourTasks)
-                               t.ContinueWithCore (cont, continuationOptions, scheduler, evt.Signal);
-                       
+                       CheckContinueArguments (tasks, continuationFunction, continuationOptions, scheduler);
+
+                       var cont = Task.WhenAllCore (tasks).ContinueWith<TResult> (TaskActionInvoker.Create (continuationFunction, tasks), cancellationToken, continuationOptions, scheduler);
+
                        return cont;
                }
                
@@ -640,6 +622,36 @@ namespace System.Threading.Tasks
                {
                        return scheduler ?? TaskScheduler.Current;
                }
+
+               static void CheckContinueArguments (Task[] tasks, object continuationAction, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
+               {
+                       if (tasks == null)
+                               throw new ArgumentNullException ("tasks");
+
+                       if (tasks.Length == 0)
+                               throw new ArgumentException ("The tasks argument contains no tasks", "tasks");
+
+                       foreach (var ta in tasks) {
+                               if (ta == null)
+                                       throw new ArgumentException ("The tasks argument contains a null value", "tasks");
+                       }
+
+                       if (continuationAction == null)
+                               throw new ArgumentNullException ("continuationAction");
+                       if (scheduler == null)
+                               throw new ArgumentNullException ("scheduler");
+
+                       const TaskContinuationOptions notAllowedOptions = 
+                               TaskContinuationOptions.NotOnRanToCompletion  |
+                               TaskContinuationOptions.NotOnFaulted |
+                               TaskContinuationOptions.NotOnCanceled |
+                               TaskContinuationOptions.OnlyOnRanToCompletion |
+                               TaskContinuationOptions.OnlyOnFaulted |
+                               TaskContinuationOptions.OnlyOnCanceled;
+
+                       if ((continuationOptions & notAllowedOptions) != 0)
+                               throw new ArgumentOutOfRangeException ("continuationOptions");
+               }
        }
 }
 #endif