[corlib] Protect against multiple invocation of FromAsync result code. Fix #7965.
authorJeremie Laval <jeremie.laval@gmail.com>
Fri, 16 Nov 2012 11:32:24 +0000 (11:32 +0000)
committerJeremie Laval <jeremie.laval@gmail.com>
Fri, 16 Nov 2012 11:36:41 +0000 (11:36 +0000)
For some weird reason, it seems the end callback can be called multiple times by some async result.

mcs/class/corlib/System.Threading.Tasks/TaskFactory_T.cs

index 0c4ba2a09263a74e61af5ef1db8b4d973f6d10f7..0ac088c9058160dc52cc14bbc0d73ca6d066ea2c 100644 (file)
@@ -339,14 +339,13 @@ namespace System.Threading.Tasks
                                throw new ArgumentOutOfRangeException ("creationOptions");
 
                        var tcs = new TaskCompletionSource<TResult> (state, creationOptions);
-                       var alreadyInvoked = false;
+                       var alreadyInvoked = new AtomicBoolean ();
                        var iar = beginMethod (l => {
-                               alreadyInvoked = true;
-                               InnerInvoke (tcs, endMethod, l);
+                               if (alreadyInvoked.TryRelaxedSet ())
+                                       InnerInvoke (tcs, endMethod, l);
                        }, state);
-                       if (iar != null && !alreadyInvoked && iar.CompletedSynchronously) {
+                       if (iar != null && iar.CompletedSynchronously && alreadyInvoked.TryRelaxedSet ())
                                InnerInvoke (tcs, endMethod, iar);
-                       }
 
                        return tcs.Task;
                }
@@ -377,14 +376,13 @@ namespace System.Threading.Tasks
                                throw new ArgumentOutOfRangeException ("creationOptions");
 
                        var tcs = new TaskCompletionSource<TResult> (state, creationOptions);
-                       var alreadyInvoked = false;
+                       var alreadyInvoked = new AtomicBoolean ();
                        var iar = beginMethod (arg1, l => {
-                               alreadyInvoked = true;
-                               InnerInvoke (tcs, endMethod, l);
+                               if (alreadyInvoked.TryRelaxedSet ())
+                                       InnerInvoke (tcs, endMethod, l);
                        }, state);
-                       if (iar != null && !alreadyInvoked && iar.CompletedSynchronously) {
+                       if (iar != null && iar.CompletedSynchronously && alreadyInvoked.TryRelaxedSet ())
                                InnerInvoke (tcs, endMethod, iar);
-                       }
 
                        return tcs.Task;
                }
@@ -414,14 +412,13 @@ namespace System.Threading.Tasks
                                throw new ArgumentOutOfRangeException ("creationOptions");
 
                        var tcs = new TaskCompletionSource<TResult> (state, creationOptions);
-                       var alreadyInvoked = false;
+                       var alreadyInvoked = new AtomicBoolean ();
                        var iar = beginMethod (arg1, arg2, l => {
-                               alreadyInvoked = true;
-                               InnerInvoke (tcs, endMethod, l);
+                               if (alreadyInvoked.TryRelaxedSet ())
+                                       InnerInvoke (tcs, endMethod, l);
                        }, state);
-                       if (iar != null && !alreadyInvoked && iar.CompletedSynchronously) {
+                       if (iar != null && iar.CompletedSynchronously && alreadyInvoked.TryRelaxedSet ())
                                InnerInvoke (tcs, endMethod, iar);
-                       }
 
                        return tcs.Task;
                }
@@ -452,14 +449,13 @@ namespace System.Threading.Tasks
                                throw new ArgumentOutOfRangeException ("creationOptions");
 
                        var tcs = new TaskCompletionSource<TResult> (state, creationOptions);
-                       bool alreadyInvoked = false;
+                       var alreadyInvoked = new AtomicBoolean ();
                        var iar = beginMethod (arg1, arg2, arg3, l => {
-                               alreadyInvoked = true;
-                               InnerInvoke (tcs, endMethod, l);
+                               if (alreadyInvoked.TryRelaxedSet ())
+                                       InnerInvoke (tcs, endMethod, l);
                        }, state);
-                       if (iar != null && !alreadyInvoked && iar.CompletedSynchronously) {
+                       if (iar != null && iar.CompletedSynchronously && alreadyInvoked.TryRelaxedSet ())
                                InnerInvoke (tcs, endMethod, iar);
-                       }
 
                        return tcs.Task;
                }