Implement TaskFactory.FromAsync
authorJérémie Laval <jeremie.laval@gmail.com>
Tue, 15 Feb 2011 13:25:25 +0000 (13:25 +0000)
committerJérémie Laval <jeremie.laval@gmail.com>
Tue, 15 Feb 2011 13:26:02 +0000 (13:26 +0000)
mcs/class/corlib/System.Threading.Tasks/TaskFactory.cs
mcs/class/corlib/Test/System.Threading.Tasks/TaskFactoryTest.cs

index ea86b4e3f39adcf0d2b604dbb0b80f57cd31401c..f5fca34c0c3ea0ca8756db9135f13aabab2903d0 100644 (file)
@@ -430,173 +430,197 @@ namespace System.Threading.Tasks
                #endregion
                
                #region FromAsync
-               // For these methods to work we first have to convert the ThreadPool to use Tasks as it
-               // is doing in 4.0, then all that is remaining is to identify the Task on which is 
-               // run the async operation (probably with some additional state in a IAsyncResult subclass)
-               // and call its ContinueWith method accordingly
-               
-               const string errorMsg = "Mono's thread pool doesn't support this operation yet";
-               
-               [MonoLimitation(errorMsg)]
                public Task FromAsync (IAsyncResult asyncResult, Action<IAsyncResult> endMethod)
                {
-                       return FromAsync (asyncResult, endMethod, creationOptions);
+                       return FromAsync (asyncResult, endMethod, creationOptions, scheduler);
                }
                
-               [MonoLimitation(errorMsg)]
                public Task FromAsync (IAsyncResult asyncResult, Action<IAsyncResult> endMethod,
                                       TaskCreationOptions creationOptions)
                {
-                       return FromAsync (asyncResult, endMethod, creationOptions);
+                       return FromAsync (asyncResult, endMethod, creationOptions, scheduler);
                }
                
-               [MonoLimitation(errorMsg)]
                public Task FromAsync (IAsyncResult asyncResult, Action<IAsyncResult> endMethod,
                                       TaskCreationOptions creationOptions, TaskScheduler scheduler)
                {
-                       throw new NotSupportedException (errorMsg);
+                       return FromAsync<object> (asyncResult, (ar) => { endMethod (ar); return null; }, creationOptions, scheduler);
                }
                
-               [MonoLimitation(errorMsg)]
                public Task<TResult> FromAsync<TResult> (IAsyncResult asyncResult, Func<IAsyncResult, TResult> endMethod)
                {
-                       return FromAsync<TResult> (asyncResult, endMethod, creationOptions);
+                       return FromAsync<TResult> (asyncResult, endMethod, creationOptions, scheduler);
                }
                
-               [MonoLimitation(errorMsg)]
                public Task<TResult> FromAsync<TResult> (IAsyncResult asyncResult, Func<IAsyncResult, TResult> endMethod,
                                                         TaskCreationOptions creationOptions)
                {
-                       return FromAsync<TResult> (asyncResult, endMethod, creationOptions);
+                       return FromAsync<TResult> (asyncResult, endMethod, creationOptions, scheduler);
                }
                
-               [MonoLimitation(errorMsg)]
                public Task<TResult> FromAsync<TResult> (IAsyncResult asyncResult, Func<IAsyncResult, TResult> endMethod,
                                                         TaskCreationOptions creationOptions, TaskScheduler scheduler)
                {
-                       throw new NotSupportedException (errorMsg);
+                       var completionSource = new TaskCompletionSource<TResult> ();
+
+                       ThreadPool.RegisterWaitForSingleObject (asyncResult.AsyncWaitHandle,
+                                                               (o, b) => {
+                                                                       try {
+                                                                               completionSource.SetResult (endMethod (asyncResult));
+                                                                       } catch (Exception e) {
+                                                                               completionSource.SetException (e);
+                                                                       }
+                                                               },
+                                                               null,
+                                                               -1,
+                                                               true);
+
+                       return completionSource.Task;
                }
                
-               
-               [MonoLimitation(errorMsg)]
-               public Task FromAsync (Func<AsyncCallback, Object, IAsyncResult> beginMethod, Action<IAsyncResult> endMethod,
+               public Task FromAsync (Func<AsyncCallback, Object, IAsyncResult> beginMethod,
+                                      Action<IAsyncResult> endMethod,
                                       object state)
                {
-                       return FromAsync<object> ((a, c, o) => beginMethod (c, o), endMethod, state, creationOptions);
+                       return FromAsync (beginMethod, endMethod, state, creationOptions);
                }
                
-               [MonoLimitation(errorMsg)]
-               public Task FromAsync (Func<AsyncCallback, Object, IAsyncResult> beginMethod, Action<IAsyncResult> endMethod,
+               public Task FromAsync (Func<AsyncCallback, Object, IAsyncResult> beginMethod,
+                                      Action<IAsyncResult> endMethod,
                                       object state, TaskCreationOptions creationOptions)
                {
-                       return FromAsync<object> ((a, c, o) => beginMethod (c, o), endMethod, state, creationOptions);
+                       return FromAsync (beginMethod, (ar) => { endMethod (ar); return (object)null; }, state, creationOptions);
                }
                
-               [MonoLimitation(errorMsg)]
                public Task FromAsync<TArg1> (Func<TArg1, AsyncCallback, Object, IAsyncResult> beginMethod, Action<IAsyncResult> endMethod,
                                              TArg1 arg1, object state)
                {
-                       throw new NotSupportedException (errorMsg);
+                       return FromAsync (beginMethod, endMethod, arg1, state, creationOptions);
                }
                
-               [MonoLimitation(errorMsg)]
                public Task FromAsync<TArg1> (Func<TArg1, AsyncCallback, Object, IAsyncResult> beginMethod, Action<IAsyncResult> endMethod,
                                              TArg1 arg1, object state, TaskCreationOptions creationOptions)
                {
-                       throw new NotSupportedException (errorMsg);
+                       return FromAsync (beginMethod, (ar) => { endMethod (ar); return (object)null; }, arg1, state, creationOptions);
                }
                
-               [MonoLimitation(errorMsg)]
-               public Task FromAsync<TArg1, TArg2> (Func<TArg1, TArg2, AsyncCallback, Object, IAsyncResult> beginMethod, Action<IAsyncResult> endMethod,
+               public Task FromAsync<TArg1, TArg2> (Func<TArg1, TArg2, AsyncCallback, Object, IAsyncResult> beginMethod,
+                                                    Action<IAsyncResult> endMethod,
                                                     TArg1 arg1, TArg2 arg2, object state)
                {
-                       throw new NotSupportedException (errorMsg);
+                       return FromAsync (beginMethod, endMethod, arg1, arg2, state, creationOptions);
                }
                
-               [MonoLimitation(errorMsg)]
-               public Task FromAsync<TArg1, TArg2> (Func<TArg1, TArg2, AsyncCallback, Object, IAsyncResult> beginMethod, Action<IAsyncResult> endMethod,
+               public Task FromAsync<TArg1, TArg2> (Func<TArg1, TArg2, AsyncCallback, Object, IAsyncResult> beginMethod,
+                                                    Action<IAsyncResult> endMethod,
                                                     TArg1 arg1, TArg2 arg2, object state, TaskCreationOptions creationOptions)
                {
-                       throw new NotSupportedException (errorMsg);
+                       return FromAsync (beginMethod, (ar) => { endMethod (ar); return (object)null; }, arg1, arg2, state, creationOptions);
                }
                
-               [MonoLimitation(errorMsg)]
                public Task FromAsync<TArg1, TArg2, TArg3> (Func<TArg1, TArg2, TArg3, AsyncCallback, Object, IAsyncResult> beginMethod, Action<IAsyncResult> endMethod,
                                                            TArg1 arg1, TArg2 arg2, TArg3 arg3, object state)
                {
-                       throw new NotSupportedException (errorMsg);
+                       return FromAsync (beginMethod, endMethod, arg1, arg2, arg3, state, creationOptions);
                }
                
-               [MonoLimitation(errorMsg)]
                public Task FromAsync<TArg1, TArg2, TArg3> (Func<TArg1, TArg2, TArg3, AsyncCallback, Object, IAsyncResult> beginMethod, Action<IAsyncResult> endMethod,
                                                            TArg1 arg1, TArg2 arg2, TArg3 arg3, object state, TaskCreationOptions creationOptions)
                {
-                       throw new NotSupportedException (errorMsg);
+                       return FromAsync (beginMethod, (ar) => { endMethod (ar); return (object)null; }, arg1, arg2, arg3, state, creationOptions);
                }               
                
-               [MonoLimitation(errorMsg)]
                public Task<TResult> FromAsync<TResult> (Func<AsyncCallback, Object, IAsyncResult> beginMethod,
                                                         Func<IAsyncResult, TResult> endMethod,
                                                         object state)
                {
-                       throw new NotSupportedException (errorMsg);
+                       return FromAsync (beginMethod, endMethod, state, creationOptions);
                }
                
-               [MonoLimitation(errorMsg)]
                public Task<TResult> FromAsync<TResult> (Func<AsyncCallback, Object, IAsyncResult> beginMethod,
                                                         Func<IAsyncResult, TResult> endMethod,
-                                      object state, TaskCreationOptions creationOptions)
-               {
-                       throw new NotSupportedException (errorMsg);
+                                                        object state, TaskCreationOptions creationOptions)
+               {
+                       var completionSource = new TaskCompletionSource<TResult> (creationOptions);
+                       beginMethod ((ar) => {
+                               try {
+                                       completionSource.SetResult (endMethod (ar));
+                               } catch (Exception e) {
+                                       completionSource.SetException (e);
+                               }
+                       }, state);
+
+                       return completionSource.Task;
                }
                
-               [MonoLimitation(errorMsg)]
                public Task<TResult> FromAsync<TArg1, TResult> (Func<TArg1, AsyncCallback, Object, IAsyncResult> beginMethod,
                                                                Func<IAsyncResult, TResult> endMethod,
                                                                TArg1 arg1, object state)
                {
-                       throw new NotSupportedException (errorMsg);
+                       return FromAsync (beginMethod, endMethod, arg1, state, creationOptions);
                }
                
-               [MonoLimitation(errorMsg)]
                public Task<TResult> FromAsync<TArg1, TResult> (Func<TArg1, AsyncCallback, Object, IAsyncResult> beginMethod,
-                                                            Func<IAsyncResult, TResult> endMethod,
-                                                            TArg1 arg1, object state, TaskCreationOptions creationOptions)
-               {
-                       throw new NotSupportedException (errorMsg);
+                                                               Func<IAsyncResult, TResult> endMethod,
+                                                               TArg1 arg1, object state, TaskCreationOptions creationOptions)
+               {
+                       var completionSource = new TaskCompletionSource<TResult> (creationOptions);
+                       beginMethod (arg1, (ar) => {
+                               try {
+                                       completionSource.SetResult (endMethod (ar));
+                               } catch (Exception e) {
+                                       completionSource.SetException (e);
+                               }
+                       }, state);
+
+                       return completionSource.Task;
                }
-               
-               [MonoLimitation(errorMsg)]
+
                public Task<TResult> FromAsync<TArg1, TArg2, TResult> (Func<TArg1, TArg2, AsyncCallback, Object, IAsyncResult> beginMethod,
                                                                       Func<IAsyncResult, TResult> endMethod,
                                                                       TArg1 arg1, TArg2 arg2, object state)
                {
-                       throw new NotSupportedException (errorMsg);
+                       return FromAsync (beginMethod, endMethod, arg1, arg2, state, creationOptions);
                }
                
-               [MonoLimitation(errorMsg)]
                public Task<TResult> FromAsync<TArg1, TArg2, TResult> (Func<TArg1, TArg2, AsyncCallback, Object, IAsyncResult> beginMethod,
                                                                       Func<IAsyncResult, TResult> endMethod,
                                                                       TArg1 arg1, TArg2 arg2, object state, TaskCreationOptions creationOptions)
                {
-                       throw new NotSupportedException (errorMsg);
+                       var completionSource = new TaskCompletionSource<TResult> (creationOptions);
+                       beginMethod (arg1, arg2, (ar) => {
+                               try {
+                                       completionSource.SetResult (endMethod (ar));
+                               } catch (Exception e) {
+                                       completionSource.SetException (e);
+                               }
+                       }, state);
+
+                       return completionSource.Task;
                }
                
-               [MonoLimitation(errorMsg)]
                public Task<TResult> FromAsync<TArg1, TArg2, TArg3, TResult> (Func<TArg1, TArg2, TArg3, AsyncCallback, Object, IAsyncResult> beginMethod,
                                                                              Func<IAsyncResult, TResult> endMethod,
                                                                              TArg1 arg1, TArg2 arg2, TArg3 arg3, object state)
                {
-                       throw new NotSupportedException (errorMsg);
+                       return FromAsync (beginMethod, endMethod, arg1, arg2, arg3, state, creationOptions);
                }
                
-               [MonoLimitation(errorMsg)]
                public Task<TResult> FromAsync<TArg1, TArg2, TArg3, TResult> (Func<TArg1, TArg2, TArg3, AsyncCallback, Object, IAsyncResult> beginMethod,
                                                                              Func<IAsyncResult, TResult> endMethod,
                                                                              TArg1 arg1, TArg2 arg2, TArg3 arg3, object state,
                                                                              TaskCreationOptions creationOptions)
                {
-                       throw new NotSupportedException (errorMsg);
+                       var completionSource = new TaskCompletionSource<TResult> (creationOptions);
+                       beginMethod (arg1, arg2, arg3, (ar) => {
+                               try {
+                                       completionSource.SetResult (endMethod (ar));
+                               } catch (Exception e) {
+                                       completionSource.SetException (e);
+                               }
+                       }, state);
+
+                       return completionSource.Task;
                }
                #endregion
                
index 12928aaf2e8faa0e8d12c23c4c9baad52b1a4871..cb3cc10fe6a02c4e576c4764bb8edcd7c2f4fe31 100644 (file)
@@ -80,10 +80,10 @@ namespace MonoTests.System.Threading.Tasks
                {
                        bool r = false, result = false, finished = false;
                        
-                       Task[] tasks = new Task[3];
+                       Task[] tasks = new Task[2];
                        tasks[0] = new Task (() => { Thread.Sleep (300); r = true; });
                        tasks[1] = new Task (() => { SpinWait sw; while (!finished) sw.SpinOnce (); });
-                       tasks[2] = new Task (() => { SpinWait sw; while (!finished) sw.SpinOnce (); });
+                       //tasks[2] = new Task (() => { SpinWait sw; while (!finished) sw.SpinOnce (); });
                        
                        Task cont = factory.ContinueWhenAny (tasks, (t) => { if (r) result = t == tasks[0]; finished = true; });
                        
@@ -96,6 +96,62 @@ namespace MonoTests.System.Threading.Tasks
                        Assert.IsTrue (result, "#2");
                        Assert.IsTrue (finished, "#3");
                }
+
+               [Test]
+               public void FromAsyncWithBeginTest ()
+               {
+                       bool result = false;
+                       bool continuationTest = false;
+
+                       Func<int, int> func = (i) => { result = true; return i + 3; };
+                       Task<int> task = factory.FromAsync<int, int> (func.BeginInvoke, func.EndInvoke, 1, null);
+                       var cont = task.ContinueWith (_ => continuationTest = true, TaskContinuationOptions.ExecuteSynchronously);
+                       task.Wait ();
+                       cont.Wait ();
+
+                       Assert.IsTrue (result);
+                       Assert.IsTrue (continuationTest);
+                       Assert.AreEqual (4, task.Result);
+               }
+
+               [Test]
+               public void FromAsyncWithDirectAsyncResultTest ()
+               {
+                       bool result = false;
+                       bool continuationTest = false;
+
+                       Func<int, int> func = (i) => { result = true; return i + 3; };
+                       Task<int> task = factory.FromAsync<int> (func.BeginInvoke (1, delegate {}, null), func.EndInvoke);
+                       var cont = task.ContinueWith (_ => continuationTest = true, TaskContinuationOptions.ExecuteSynchronously);
+                       task.Wait ();
+                       cont.Wait ();
+
+                       Assert.IsTrue (result);
+                       Assert.IsTrue (continuationTest);
+                       Assert.AreEqual (4, task.Result);
+               }
+
+               [Test]
+               public void FromAsyncWithBeginAndExceptionTest ()
+               {
+                       bool result = false;
+                       bool continuationTest = false;
+
+                       Func<int, int> func = (i) => { result = true; throw new ApplicationException ("bleh"); return i + 3; };
+                       Task<int> task = factory.FromAsync<int, int> (func.BeginInvoke, func.EndInvoke, 1, null);
+                       var cont = task.ContinueWith (_ => continuationTest = true, TaskContinuationOptions.ExecuteSynchronously);
+                       try {
+                               task.Wait ();
+                       } catch {}
+                       cont.Wait ();
+
+                       Assert.IsTrue (result);
+                       Assert.IsTrue (continuationTest);
+                       Assert.IsNotNull (task.Exception);
+                       var agg = task.Exception;
+                       Assert.AreEqual (1, agg.InnerExceptions.Count);
+                       Assert.IsInstanceOfType (typeof (ApplicationException), agg.InnerExceptions[0]);
+               }
        }
 }
 #endif