Create Task continuation with less intermediate delegates
authorMarek Safar <marek.safar@gmail.com>
Fri, 21 Oct 2011 08:59:40 +0000 (09:59 +0100)
committerMarek Safar <marek.safar@gmail.com>
Fri, 21 Oct 2011 09:00:53 +0000 (10:00 +0100)
mcs/class/corlib/System.Threading.Tasks/Task.cs
mcs/class/corlib/System.Threading.Tasks/TaskActionInvoker.cs [new file with mode: 0644]
mcs/class/corlib/System.Threading.Tasks/TaskFactory.cs
mcs/class/corlib/System.Threading.Tasks/TaskFactory_T.cs
mcs/class/corlib/System.Threading.Tasks/Task_T.cs
mcs/class/corlib/Test/System.Threading.Tasks/TaskTest.cs
mcs/class/corlib/corlib.dll.sources

index 47203b417d8f4d3e8a5eda7605972c0787b462fe..d11b7c072b88b7345b0b2da08f6490b3663229bb 100644 (file)
@@ -66,9 +66,8 @@ namespace System.Threading.Tasks
                ConcurrentQueue<AggregateException> childExceptions;
 
                TaskStatus          status;
-               
-               Action<object> action;
-               Action         simpleAction;
+
+               TaskActionInvoker invoker;
                object         state;
                AtomicBooleanValue executing;
 
@@ -88,32 +87,35 @@ namespace System.Threading.Tasks
 #endif
                        TaskCreationOptions.PreferFairness | TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent;
 
-               public Task (Action action) : this (action, TaskCreationOptions.None)
+               public Task (Action action)
+                       : this (action, TaskCreationOptions.None)
                {
                        
                }
                
-               public Task (Action action, TaskCreationOptions creationOptions) : this (action, CancellationToken.None, creationOptions)
+               public Task (Action action, TaskCreationOptions creationOptions)
+                       : this (action, CancellationToken.None, creationOptions)
                {
                        
                }
                
-               public Task (Action action, CancellationToken cancellationToken) : this (action, cancellationToken, TaskCreationOptions.None)
+               public Task (Action action, CancellationToken cancellationToken)
+                       : this (action, cancellationToken, TaskCreationOptions.None)
                {
                        
                }
                
                public Task (Action action, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
-                       : this (null, null, cancellationToken, creationOptions, current)
+                       : this (TaskActionInvoker.Create (action), null, cancellationToken, creationOptions, current)
                {
                        if (action == null)
                                throw new ArgumentNullException ("action");
                        if (creationOptions > MaxTaskCreationOptions || creationOptions < TaskCreationOptions.None)
                                throw new ArgumentOutOfRangeException ("creationOptions");
-                       this.simpleAction = action;
                }
                
-               public Task (Action<object> action, object state) : this (action, state, TaskCreationOptions.None)
+               public Task (Action<object> action, object state)
+                       : this (action, state, TaskCreationOptions.None)
                {       
                }
                
@@ -128,7 +130,7 @@ namespace System.Threading.Tasks
                }
 
                public Task (Action<object> action, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
-                       : this (action, state, cancellationToken, creationOptions, current)
+                       : this (TaskActionInvoker.Create (action), state, cancellationToken, creationOptions, current)
                {
                        if (action == null)
                                throw new ArgumentNullException ("action");
@@ -136,14 +138,11 @@ namespace System.Threading.Tasks
                                throw new ArgumentOutOfRangeException ("creationOptions");
                }
 
-               internal Task (Action<object> action,
-                              object state,
-                              CancellationToken cancellationToken,
-                              TaskCreationOptions creationOptions,
-                              Task parent)
+               internal Task (TaskActionInvoker invoker, object state, CancellationToken cancellationToken,
+                              TaskCreationOptions creationOptions, Task parent)
                {
+                       this.invoker = invoker;
                        this.taskCreationOptions = creationOptions;
-                       this.action              = action;
                        this.state               = state;
                        this.taskId              = Interlocked.Increment (ref id);
                        this.status              = cancellationToken.IsCancellationRequested ? TaskStatus.Canceled : TaskStatus.Created;
@@ -183,7 +182,7 @@ namespace System.Threading.Tasks
                        if (status >= TaskStatus.WaitingToRun)
                                throw new InvalidOperationException ("The Task is not in a valid state to be started.");
 
-                       if (Slot.Initialized)
+                       if (IsContinuation)
                                throw new InvalidOperationException ("Start may not be called on a continuation task");
 
                        SetupScheduler (scheduler);
@@ -254,8 +253,8 @@ namespace System.Threading.Tasks
                        if (scheduler == null)
                                throw new ArgumentNullException ("scheduler");
 
-                       Task continuation = new Task (l => continuationAction ((Task)l),
-                                                     this,
+                       Task continuation = new Task (TaskActionInvoker.Create (continuationAction),
+                                                     null,
                                                      cancellationToken,
                                                      GetCreationOptions (continuationOptions),
                                                      this);
@@ -292,8 +291,8 @@ namespace System.Threading.Tasks
                        if (scheduler == null)
                                throw new ArgumentNullException ("scheduler");
 
-                       Task<TResult> t = new Task<TResult> ((o) => continuationFunction ((Task)o),
-                                                            this,
+                       var t = new Task<TResult> (TaskActionInvoker.Create (continuationFunction),
+                                                            null,
                                                             cancellationToken,
                                                             GetCreationOptions (continuationOptions),
                                                             this);
@@ -501,17 +500,13 @@ namespace System.Threading.Tasks
                        }
                }
 
-               internal virtual void InnerInvoke ()
+               void InnerInvoke ()
                {
-                       if (action == null && simpleAction != null)
-                               simpleAction ();
-                       else if (action != null)
-                               action (state);
-                       // Set action to null so that the GC can collect the delegate and thus
-                       // any big object references that the user might have captured in an anonymous method
-                       action = null;
-                       simpleAction = null;
-                       state = null;
+                       if (IsContinuation) {
+                               invoker.Invoke (parent, state, this);
+                       } else {
+                               invoker.Invoke (this, state, this);
+                       }
                }
                
                internal void Finish ()
@@ -833,7 +828,7 @@ namespace System.Threading.Tasks
                        // Set action to null so that the GC can collect the delegate and thus
                        // any big object references that the user might have captured in a anonymous method
                        if (disposing) {
-                               action = null;
+                               invoker = null;
                                state = null;
                                if (cancellationRegistration != null)
                                        cancellationRegistration.Value.Dispose ();
@@ -876,8 +871,8 @@ namespace System.Threading.Tasks
                        if (scheduler == null)
                                throw new ArgumentNullException ("scheduler");
 
-                       Task continuation = new Task (l => continuationAction (this, l), state,
-                                                                                 cancellationToken,
+                       Task continuation = new Task (TaskActionInvoker.Create (continuationAction),
+                                                                                 state, cancellationToken,
                                                                                  GetCreationOptions (continuationOptions),
                                                                                  this);
                        ContinueWithCore (continuation, continuationOptions, scheduler);
@@ -913,7 +908,7 @@ namespace System.Threading.Tasks
                        if (scheduler == null)
                                throw new ArgumentNullException ("scheduler");
 
-                       var t = new Task<TResult> (l => continuationFunction (this, l),
+                       var t = new Task<TResult> (TaskActionInvoker.Create (continuationFunction),
                                                                                                 state,
                                                                                                 cancellationToken,
                                                                                                 GetCreationOptions (continuationOptions),
@@ -1090,6 +1085,12 @@ namespace System.Threading.Tasks
                        }
                }
 
+               bool IsContinuation {
+                       get {
+                               return Slot.Initialized;
+                       }
+               }
+
                internal Task Parent {
                        get {
                                return parent;
@@ -1098,7 +1099,7 @@ namespace System.Threading.Tasks
                
                internal string DisplayActionMethod {
                        get {
-                               Delegate d = simpleAction ?? (Delegate) action;
+                               Delegate d = invoker.Action;
                                return d == null ? "<none>" : d.Method.ToString ();
                        }
                }
diff --git a/mcs/class/corlib/System.Threading.Tasks/TaskActionInvoker.cs b/mcs/class/corlib/System.Threading.Tasks/TaskActionInvoker.cs
new file mode 100644 (file)
index 0000000..144780a
--- /dev/null
@@ -0,0 +1,351 @@
+//
+// TaskActionInvoker.cs
+//
+// Authors:
+//    Marek Safar  <marek.safar@gmail.com>
+//
+// Copyright 2011 Xamarin Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+//
+
+#if NET_4_0 || MOBILE
+
+namespace System.Threading.Tasks
+{
+       abstract class TaskActionInvoker
+       {
+               sealed class ActionInvoke : TaskActionInvoker
+               {
+                       readonly Action action;
+
+                       public ActionInvoke (Action action)
+                       {
+                               this.action = action;
+                       }
+
+                       public override Delegate Action {
+                               get {
+                                       return action;
+                               }
+                       }
+
+                       public override void Invoke (Task owner, object state, Task context)
+                       {
+                               action ();
+                       }
+               }
+
+               sealed class ActionObjectInvoke : TaskActionInvoker
+               {
+                       readonly Action<object> action;
+
+                       public ActionObjectInvoke (Action<object> action)
+                       {
+                               this.action = action;
+                       }
+
+                       public override Delegate Action {
+                               get {
+                                       return action;
+                               }
+                       }
+
+                       public override void Invoke (Task owner, object state, Task context)
+                       {
+                               action (state);
+                       }
+               }
+
+               sealed class ActionTaskInvoke : TaskActionInvoker
+               {
+                       readonly Action<Task> action;
+
+                       public ActionTaskInvoke (Action<Task> action)
+                       {
+                               this.action = action;
+                       }
+
+                       public override Delegate Action {
+                               get {
+                                       return action;
+                               }
+                       }
+
+                       public override void Invoke (Task owner, object state, Task context)
+                       {
+                               action (owner);
+                       }
+               }
+
+               sealed class ActionTaskObjectInvoke : TaskActionInvoker
+               {
+                       readonly Action<Task, object> action;
+
+                       public ActionTaskObjectInvoke (Action<Task, object> action)
+                       {
+                               this.action = action;
+                       }
+
+                       public override Delegate Action {
+                               get {
+                                       return action;
+                               }
+                       }
+
+                       public override void Invoke (Task owner, object state, Task context)
+                       {
+                               action (owner, state);
+                       }
+               }
+
+               sealed class ActionTaskObjectInvoke<TResult> : TaskActionInvoker
+               {
+                       readonly Action<Task<TResult>, object> action;
+
+                       public ActionTaskObjectInvoke (Action<Task<TResult>, object> action)
+                       {
+                               this.action = action;
+                       }
+
+                       public override Delegate Action {
+                               get {
+                                       return action;
+                               }
+                       }
+
+                       public override void Invoke (Task owner, object state, Task context)
+                       {
+                               action ((Task<TResult>) owner, state);
+                       }
+               }
+
+               sealed class ActionTaskInvoke<TResult> : TaskActionInvoker
+               {
+                       readonly Action<Task<TResult>> action;
+
+                       public ActionTaskInvoke (Action<Task<TResult>> action)
+                       {
+                               this.action = action;
+                       }
+
+                       public override Delegate Action {
+                               get {
+                                       return action;
+                               }
+                       }
+
+                       public override void Invoke (Task owner, object state, Task context)
+                       {
+                               action ((Task<TResult>) owner);
+                       }
+               }
+
+               sealed class FuncInvoke<TResult> : TaskActionInvoker
+               {
+                       readonly Func<TResult> action;
+
+                       public FuncInvoke (Func<TResult> action)
+                       {
+                               this.action = action;
+                       }
+
+                       public override Delegate Action {
+                               get {
+                                       return action;
+                               }
+                       }
+
+                       public override void Invoke (Task owner, object state, Task context)
+                       {
+                               ((Task<TResult>) context).Result = action ();
+                       }
+               }
+
+               sealed class FuncTaskInvoke<TResult> : TaskActionInvoker
+               {
+                       readonly Func<Task, TResult> action;
+
+                       public FuncTaskInvoke (Func<Task, TResult> action)
+                       {
+                               this.action = action;
+                       }
+
+                       public override Delegate Action {
+                               get {
+                                       return action;
+                               }
+                       }
+
+                       public override void Invoke (Task owner, object state, Task context)
+                       {
+                               ((Task<TResult>) context).Result = action (owner);
+                       }
+               }
+
+               sealed class FuncTaskInvoke<TResult, TNewResult> : TaskActionInvoker
+               {
+                       readonly Func<Task<TResult>, TNewResult> action;
+
+                       public FuncTaskInvoke (Func<Task<TResult>, TNewResult> action)
+                       {
+                               this.action = action;
+                       }
+
+                       public override Delegate Action {
+                               get {
+                                       return action;
+                               }
+                       }
+
+                       public override void Invoke (Task owner, object state, Task context)
+                       {
+                               ((Task<TNewResult>) context).Result = action ((Task<TResult>) owner);
+                       }
+               }
+
+               sealed class FuncObjectInvoke<TResult> : TaskActionInvoker
+               {
+                       readonly Func<object, TResult> action;
+
+                       public FuncObjectInvoke (Func<object, TResult> action)
+                       {
+                               this.action = action;
+                       }
+
+                       public override Delegate Action {
+                               get {
+                                       return action;
+                               }
+                       }
+
+                       public override void Invoke (Task owner, object state, Task context)
+                       {
+                               ((Task<TResult>) context).Result = action (state);
+                       }
+               }
+
+               sealed class FuncTaskObjectInvoke<TResult> : TaskActionInvoker
+               {
+                       readonly Func<Task, object, TResult> action;
+
+                       public FuncTaskObjectInvoke (Func<Task, object, TResult> action)
+                       {
+                               this.action = action;
+                       }
+
+                       public override Delegate Action {
+                               get {
+                                       return action;
+                               }
+                       }
+
+                       public override void Invoke (Task owner, object state, Task context)
+                       {
+                               ((Task<TResult>) context).Result = action (owner, state);
+                       }
+               }
+
+               sealed class FuncTaskObjectInvoke<TResult, TNewResult> : TaskActionInvoker
+               {
+                       readonly Func<Task<TResult>, object, TNewResult> action;
+
+                       public FuncTaskObjectInvoke (Func<Task<TResult>, object, TNewResult> action)
+                       {
+                               this.action = action;
+                       }
+
+                       public override Delegate Action {
+                               get {
+                                       return action;
+                               }
+                       }
+
+                       public override void Invoke (Task owner, object state, Task context)
+                       {
+                               ((Task<TNewResult>) context).Result = action ((Task<TResult>) owner, state);
+                       }
+               }
+
+               public static TaskActionInvoker Create (Action action)
+               {
+                       return new ActionInvoke (action);
+               }
+
+               public static TaskActionInvoker Create (Action<object> action)
+               {
+                       return new ActionObjectInvoke (action);
+               }
+
+               public static TaskActionInvoker Create (Action<Task> action)
+               {
+                       return new ActionTaskInvoke (action);
+               }
+
+               public static TaskActionInvoker Create (Action<Task, object> action)
+               {
+                       return new ActionTaskObjectInvoke (action);
+               }
+
+               public static TaskActionInvoker Create<TResult> (Action<Task<TResult>> action)
+               {
+                       return new ActionTaskInvoke<TResult> (action);
+               }
+
+               public static TaskActionInvoker Create<TResult> (Action<Task<TResult>, object> action)
+               {
+                       return new ActionTaskObjectInvoke<TResult> (action);
+               }
+
+               public static TaskActionInvoker Create<TResult> (Func<TResult> action)
+               {
+                       return new FuncInvoke<TResult> (action);
+               }
+
+               public static TaskActionInvoker Create<TResult> (Func<object, TResult> action)
+               {
+                       return new FuncObjectInvoke<TResult> (action);
+               }
+
+               public static TaskActionInvoker Create<TResult> (Func<Task, TResult> action)
+               {
+                       return new FuncTaskInvoke<TResult> (action);
+               }
+
+               public static TaskActionInvoker Create<TResult> (Func<Task, object, TResult> action)
+               {
+                       return new FuncTaskObjectInvoke<TResult> (action);
+               }
+
+               public static TaskActionInvoker Create<TResult, TNewResult> (Func<Task<TResult>, TNewResult> action)
+               {
+                       return new FuncTaskInvoke<TResult, TNewResult> (action);
+               }
+
+               public static TaskActionInvoker Create<TResult, TNewResult> (Func<Task<TResult>, object, TNewResult> action)
+               {
+                       return new FuncTaskObjectInvoke<TResult, TNewResult> (action);
+               }
+
+               public abstract Delegate Action { get; }
+               public abstract void Invoke (Task owner, object state, Task context);
+       }
+}
+#endif
index 0f0391e0b3878972dcb1119042a6b7f716a08ccd..4e78b7e3c54f69af908f4b5928dea3a255b33665 100644 (file)
@@ -246,7 +246,7 @@ namespace System.Threading.Tasks
                        Action<Task> continuationFunc = t => commonContinuation.SetResult (null);
                        
                        foreach (Task t in ourTasks) {
-                               Task cont = new Task ((o) => continuationAction ((Task)o), t, cancellationToken, creationOptions, t);
+                               Task cont = new Task (TaskActionInvoker.Create (continuationAction), null, cancellationToken, creationOptions, t);
                                t.ContinueWithCore (cont, continuationOptions, scheduler, trigger.TrySet);
                                cont.ContinueWith (continuationFunc);
                        }
@@ -315,7 +315,7 @@ namespace System.Threading.Tasks
                        TaskCompletionSource<TResult> source = new TaskCompletionSource<TResult> ();
 
                        foreach (Task t in ourTasks) {
-                               Task cont = new Task ((o) => source.SetResult (continuationFunction ((Task)o)), t, cancellationToken, creationOptions, t);
+                               var cont = new Task (TaskActionInvoker.Create (continuationFunction), null, cancellationToken, creationOptions, t);
                                t.ContinueWithCore (cont, continuationOptions, scheduler, trigger.TrySet);
                        }
 
index 8c8f1dc0244e6624e55c077db3352411365626e5..af9ff6fe122088829f7118fee3053873b78197d3 100644 (file)
@@ -28,9 +28,6 @@
 
 #if NET_4_0 || MOBILE
 
-using System;
-using System.Threading;
-
 namespace System.Threading.Tasks
 {
        public class TaskFactory<TResult>
index 67dcb25c816d4a9cee329aa614571819a6d19416..2fafdcabe4224d52c71a2961077f4f2e7166c1f6 100644 (file)
@@ -28,7 +28,7 @@
 //
 
 #if NET_4_0 || MOBILE
-using System;
+
 using System.Runtime.CompilerServices;
 
 namespace System.Threading.Tasks
@@ -38,12 +38,8 @@ namespace System.Threading.Tasks
        public class Task<TResult> : Task
        {
                static readonly TaskFactory<TResult> factory = new TaskFactory<TResult> ();
-               static readonly Action<object> emptyAction = delegate (object o) {};
 
                TResult value;
-               Func<object, TResult> function;
-               Func<TResult> simpleFunction;
-               object state;
                
                [System.Diagnostics.DebuggerBrowsable (System.Diagnostics.DebuggerBrowsableState.Never)]
                public TResult Result {
@@ -76,7 +72,8 @@ namespace System.Threading.Tasks
                        }
                }
                
-               public Task (Func<TResult> function) : this (function, TaskCreationOptions.None)
+               public Task (Func<TResult> function)
+                       : this (function, TaskCreationOptions.None)
                {
                        
                }
@@ -94,16 +91,14 @@ namespace System.Threading.Tasks
                }
                
                public Task (Func<TResult> function, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
-                       : base (emptyAction, null, cancellationToken, creationOptions)
+                       : base (TaskActionInvoker.Create (function), null, cancellationToken, creationOptions, null)
                {
                        if (function == null)
                                throw new ArgumentNullException ("function");
-
-                       this.simpleFunction = function;
-                       this.state = null;
                }
                
-               public Task (Func<object, TResult> function, object state) : this (function, state, TaskCreationOptions.None)
+               public Task (Func<object, TResult> function, object state)
+                       : this (function, state, TaskCreationOptions.None)
                {
                        
                }
@@ -121,38 +116,17 @@ namespace System.Threading.Tasks
                }
 
                public Task (Func<object, TResult> function, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
-                       : base (emptyAction, state, cancellationToken, creationOptions)
+                       : base (TaskActionInvoker.Create (function), state, cancellationToken, creationOptions, null)
                {
                        if (function == null)
                                throw new ArgumentNullException ("function");
-
-                       this.function = function;
-                       this.state = state;
                }
 
-               internal Task (Func<object, TResult> function,
-                              object state,
-                              CancellationToken cancellationToken,
-                              TaskCreationOptions creationOptions,
-                              Task parent)
-                       : base (emptyAction, state, cancellationToken, creationOptions, parent)
+               internal Task (TaskActionInvoker invoker, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions, Task parent)
+                       : base (invoker, state, cancellationToken, creationOptions, parent)
                {
-                       this.function = function;
-                       this.state = state;
                }
-               
-               internal override void InnerInvoke ()
-               {
-                       if (function != null)
-                               value = function (state);
-                       else if (simpleFunction != null)
-                               value = simpleFunction ();
-                       
-                       function = null;
-                       simpleFunction = null;
-                       state = null;
-               }
-               
+
                public Task ContinueWith (Action<Task<TResult>> continuationAction)
                {
                        return ContinueWith (continuationAction, TaskContinuationOptions.None);
@@ -181,8 +155,8 @@ namespace System.Threading.Tasks
                        if (scheduler == null)
                                throw new ArgumentNullException ("scheduler");
 
-                       Task t = new Task (l => continuationAction ((Task<TResult>)l),
-                                          this,
+                       Task t = new Task (TaskActionInvoker.Create (continuationAction),
+                                          null,
                                           cancellationToken,
                                           GetCreationOptions (continuationOptions),
                                           this);
@@ -221,8 +195,8 @@ namespace System.Threading.Tasks
                        if (scheduler == null)
                                throw new ArgumentNullException ("scheduler");
 
-                       Task<TNewResult> t = new Task<TNewResult> ((o) => continuationFunction ((Task<TResult>)o),
-                                                                  this,
+                       var t = new Task<TNewResult> (TaskActionInvoker.Create (continuationFunction),
+                                                                  null,
                                                                   cancellationToken,
                                                                   GetCreationOptions (continuationOptions),
                                                                   this);
@@ -261,7 +235,7 @@ namespace System.Threading.Tasks
                        if (scheduler == null)
                                throw new ArgumentNullException ("scheduler");
 
-                       var t = new Task (l => continuationAction (this, l),
+                       var t = new Task (TaskActionInvoker.Create (continuationAction),
                                                           state,
                                                           cancellationToken,
                                                           GetCreationOptions (continuationOptions),
@@ -302,7 +276,7 @@ namespace System.Threading.Tasks
                        if (scheduler == null)
                                throw new ArgumentNullException ("scheduler");
 
-                       var t = new Task<TNewResult> (l => continuationFunction (this, l),
+                       var t = new Task<TNewResult> (TaskActionInvoker.Create (continuationFunction),
                                                           state,
                                                           cancellationToken,
                                                           GetCreationOptions (continuationOptions),
index 40885e1d8fb791ca700bd5b2f62bf5b28ce08d68..913c979af27cd39267f853d74cf9973485c7bd50 100644 (file)
@@ -724,6 +724,61 @@ namespace MonoTests.System.Threading.Tasks
                        }
                }
 
+               [Test]
+               public void ContinueWith_StateValue ()
+               {
+                       var t = Task.Factory.StartNew (l => {
+                               Assert.AreEqual (1, l, "a-1");
+                       }, 1);
+
+                       var c = t.ContinueWith ((a, b) => {
+                               Assert.AreEqual (t, a, "c-1");
+                               Assert.AreEqual (2, b, "c-2");
+                       }, 2);
+
+                       var d = t.ContinueWith ((a, b) => {
+                               Assert.AreEqual (t, a, "d-1");
+                               Assert.AreEqual (3, b, "d-2");
+                               return 77;
+                       }, 3);
+
+                       Assert.IsTrue (d.Wait (1000), "#1");
+
+                       Assert.AreEqual (1, t.AsyncState, "#2");
+                       Assert.AreEqual (2, c.AsyncState, "#3");
+                       Assert.AreEqual (3, d.AsyncState, "#4");
+               }
+
+               [Test]
+               public void ContinueWith_StateValueGeneric ()
+               {
+                       var t = Task<int>.Factory.StartNew (l => {
+                               Assert.AreEqual (1, l, "a-1");
+                               return 80;
+                       }, 1);
+
+                       var c = t.ContinueWith ((a, b) => {
+                               Assert.AreEqual (t, a, "c-1");
+                               Assert.AreEqual (2, b, "c-2");
+                               return "c";
+                       }, 2);
+
+                       var d = t.ContinueWith ((a, b) => {
+                               Assert.AreEqual (t, a, "d-1");
+                               Assert.AreEqual (3, b, "d-2");
+                               return 'd';
+                       }, 3);
+
+                       Assert.IsTrue (d.Wait (1000), "#1");
+
+                       Assert.AreEqual (1, t.AsyncState, "#2");
+                       Assert.AreEqual (80, t.Result, "#2r");
+                       Assert.AreEqual (2, c.AsyncState, "#3");
+                       Assert.AreEqual ("c", c.Result, "#3r");
+                       Assert.AreEqual (3, d.AsyncState, "#4");
+                       Assert.AreEqual ('d', d.Result, "#3r");
+               }
+
                [Test]
                public void FromResult ()
                {
index c50371f39cada143b1b57fad433b70a22c5d8b17..49f30add87a33deaa08402820dfae13f63e44141 100644 (file)
@@ -1559,6 +1559,7 @@ System.Threading.Tasks/TaskCompletionQueue.cs
 System.Threading.Tasks/IEventSlot.cs
 System.Threading.Tasks/EventSlots.cs
 System.Threading.Tasks/CompletionSlot.cs
+System.Threading.Tasks/TaskActionInvoker.cs
 System.Threading.Tasks/TaskDebuggerView.cs
 System.Threading.Tasks/TaskCompletionSource.cs
 System.Threading.Tasks/TaskSchedulerException.cs