X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2Fcorlib%2FTest%2FSystem.Runtime.CompilerServices%2FTaskAwaiterTest.cs;h=57b1d2c27642c1dafc45d854a7ccf92f086f1cee;hb=69f207ee9e4f440e66e98bf5f685807f6527c39d;hp=a403d5287e2d6af53add6c41d825a641bea42ae6;hpb=96edd46e16619fe64e26ea017330c22bf893f0dd;p=mono.git diff --git a/mcs/class/corlib/Test/System.Runtime.CompilerServices/TaskAwaiterTest.cs b/mcs/class/corlib/Test/System.Runtime.CompilerServices/TaskAwaiterTest.cs index a403d5287e2..57b1d2c2764 100644 --- a/mcs/class/corlib/Test/System.Runtime.CompilerServices/TaskAwaiterTest.cs +++ b/mcs/class/corlib/Test/System.Runtime.CompilerServices/TaskAwaiterTest.cs @@ -35,6 +35,7 @@ using NUnit.Framework; using System.Runtime.CompilerServices; using System.Collections.Generic; using System.Collections; +using System.Collections.Concurrent; namespace MonoTests.System.Runtime.CompilerServices { @@ -44,14 +45,15 @@ namespace MonoTests.System.Runtime.CompilerServices class Scheduler : TaskScheduler { string name; + int ic, qc; public Scheduler (string name) { this.name = name; } - public int InlineCalls { get; set; } - public int QueueCalls { get; set; } + public int InlineCalls { get { return ic; } } + public int QueueCalls { get { return qc; } } protected override IEnumerable GetScheduledTasks () { @@ -60,7 +62,7 @@ namespace MonoTests.System.Runtime.CompilerServices protected override void QueueTask (Task task) { - ++QueueCalls; + Interlocked.Increment (ref qc); ThreadPool.QueueUserWorkItem (o => { TryExecuteTask (task); }); @@ -68,9 +70,14 @@ namespace MonoTests.System.Runtime.CompilerServices protected override bool TryExecuteTaskInline (Task task, bool taskWasPreviouslyQueued) { - ++InlineCalls; + Interlocked.Increment (ref ic); return false; } + + public override string ToString () + { + return "Scheduler-" + name; + } } class SingleThreadSynchronizationContext : SynchronizationContext @@ -100,8 +107,46 @@ namespace MonoTests.System.Runtime.CompilerServices } } + class NestedSynchronizationContext : SynchronizationContext + { + Thread thread; + readonly ConcurrentQueue> workQueue = new ConcurrentQueue> (); + 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 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; [SetUp] public void Setup () @@ -176,7 +221,7 @@ namespace MonoTests.System.Runtime.CompilerServices Assert.IsTrue (t.Wait (3000), "#0"); Assert.AreEqual (0, t.Result, "#1"); Assert.AreEqual (0, b.InlineCalls, "#2b"); - Assert.AreEqual (2, a.QueueCalls, "#3a"); + Assert.IsTrue (a.QueueCalls == 1 || a.QueueCalls == 2, "#3a"); Assert.AreEqual (1, b.QueueCalls, "#3b"); } @@ -203,6 +248,7 @@ namespace MonoTests.System.Runtime.CompilerServices return res.Result; } +#if !MOBILE_STATIC [Test] public void FinishedTaskOnCompleted () { @@ -227,6 +273,8 @@ namespace MonoTests.System.Runtime.CompilerServices Assert.AreEqual (Thread.CurrentThread.IsBackground, mres2.WaitOne (2000), "#2");; } +#endif + [Test] public void CompletionOnSameCustomSynchronizationContext () { @@ -270,12 +318,15 @@ namespace MonoTests.System.Runtime.CompilerServices [Test] public void CompletionOnDifferentCustomSynchronizationContext () { + mre = new ManualResetEvent (false); progress = ""; var syncContext = new SingleThreadSynchronizationContext (); SynchronizationContext.SetSynchronizationContext (syncContext); syncContext.Post (delegate { - Go2 (syncContext); + Task t = new Task (delegate() { }); + Go2 (syncContext, t); + t.Start (); }, null); // Custom message loop @@ -286,26 +337,62 @@ namespace MonoTests.System.Runtime.CompilerServices Thread.Sleep (0); } - Assert.AreEqual ("132", progress); + Assert.AreEqual ("13xa2", progress); } - async void Go2 (SynchronizationContext ctx) + async void Go2 (SynchronizationContext ctx, Task t) { - await Wait2 (ctx); + await Wait2 (ctx, t); - progress += "2"; + progress += "a"; + + if (mre.WaitOne (5000)) + progress += "2"; + else + progress += "b"; } - async Task Wait2 (SynchronizationContext ctx) + async Task Wait2 (SynchronizationContext ctx, Task t) { - await Task.Delay (10); // Force block suspend/return + await t; // Force block suspend/return - ctx.Post (l => progress += "3", null); + ctx.Post (l => { + progress += "3"; + mre.Set (); + progress += "x"; + }, null); progress += "1"; 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); + } } }