Merge pull request #3528 from BrzVlad/fix-sgen-check-before-collections
[mono.git] / mcs / class / corlib / Test / System.Runtime.CompilerServices / TaskAwaiterTest.cs
index 5237e377e38c80d9a73ce149db5dde8934bdc428..c9d7aca855bc8a1fa9eb64ccd193d34715fd6e38 100644 (file)
@@ -26,7 +26,6 @@
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
-#if NET_4_5
 
 using System;
 using System.Threading;
@@ -35,6 +34,7 @@ using NUnit.Framework;
 using System.Runtime.CompilerServices;
 using System.Collections.Generic;
 using System.Collections;
+using System.Collections.Concurrent;
 
 namespace MonoTests.System.Runtime.CompilerServices
 {
@@ -72,6 +72,11 @@ namespace MonoTests.System.Runtime.CompilerServices
                                Interlocked.Increment (ref ic);
                                return false;
                        }
+
+                       public override string ToString ()
+                       {
+                               return "Scheduler-" + name;
+                       }
                }
 
                class SingleThreadSynchronizationContext : SynchronizationContext
@@ -101,6 +106,43 @@ namespace MonoTests.System.Runtime.CompilerServices
                        }
                }
 
+               class NestedSynchronizationContext : SynchronizationContext
+               {
+                       Thread thread;
+                       readonly ConcurrentQueue<Tuple<SendOrPostCallback, object, ExecutionContext>> workQueue = new ConcurrentQueue<Tuple<SendOrPostCallback, object, ExecutionContext>> ();
+                       readonly AutoResetEvent workReady = new AutoResetEvent (false);
+
+                       public NestedSynchronizationContext ()
+                       {
+                               thread = new Thread (WorkerThreadProc) { IsBackground = true };
+                               thread.Start ();
+                       }
+
+                       public override void Post (SendOrPostCallback d, object state)
+                       {
+                               var context = ExecutionContext.Capture ();
+                               workQueue.Enqueue (Tuple.Create (d, state, context));
+                               workReady.Set ();
+                       }
+
+                       void WorkerThreadProc ()
+                       {
+                               if (!workReady.WaitOne (10000))
+                                       return;
+
+                               Tuple<SendOrPostCallback, object, ExecutionContext> work;
+
+                               while (workQueue.TryDequeue (out work)) {
+                                       ExecutionContext.Run (work.Item3, _ => {
+                                               var oldSyncContext = SynchronizationContext.Current;
+                                               SynchronizationContext.SetSynchronizationContext (this);
+                                               work.Item1 (_);
+                                               SynchronizationContext.SetSynchronizationContext (oldSyncContext);
+                                       }, work.Item2); 
+                               }
+                       }
+               }
+
                string progress;
                SynchronizationContext sc;
                ManualResetEvent mre;
@@ -205,6 +247,7 @@ namespace MonoTests.System.Runtime.CompilerServices
                        return res.Result;
                }
 
+#if !MOBILE_STATIC
                [Test]
                public void FinishedTaskOnCompleted ()
                {
@@ -229,6 +272,8 @@ namespace MonoTests.System.Runtime.CompilerServices
                        Assert.AreEqual (Thread.CurrentThread.IsBackground, mres2.WaitOne (2000), "#2");;
                }
 
+#endif
+
                [Test]
                public void CompletionOnSameCustomSynchronizationContext ()
                {
@@ -320,7 +365,33 @@ namespace MonoTests.System.Runtime.CompilerServices
 
                        SynchronizationContext.SetSynchronizationContext (null);
                }
+
+               [Test]
+               public void NestedLeakingSynchronizationContext ()
+               {
+                       var sc = SynchronizationContext.Current;
+                       if (sc == null)
+                               Assert.IsTrue (NestedLeakingSynchronizationContext_MainAsync (sc).Wait (5000), "#1");
+                       else
+                               Assert.Ignore ("NestedSynchronizationContext may never complete on custom context");
+               }
+
+               static async Task NestedLeakingSynchronizationContext_MainAsync (SynchronizationContext sc)
+               {
+                       Assert.AreSame (sc, SynchronizationContext.Current, "#1");
+                       await NestedLeakingSynchronizationContext_DoWorkAsync ();
+                       Assert.AreSame (sc, SynchronizationContext.Current, "#2");
+               }
+
+               static async Task NestedLeakingSynchronizationContext_DoWorkAsync ()
+               {
+                       var sc = new NestedSynchronizationContext ();
+                       SynchronizationContext.SetSynchronizationContext (sc);
+
+                       Assert.AreSame (sc, SynchronizationContext.Current);
+                       await Task.Yield ();
+                       Assert.AreSame (sc, SynchronizationContext.Current);
+               }
        }
 }
 
-#endif