public void SignalAndWaitSynchronousBlockDoesNotHang() { SynchronizationContext.SetSynchronizationContext(SingleThreadedSynchronizationContext.New()); var evt = new AsyncCountdownEvent(1); Assert.True(evt.SignalAndWaitAsync().Wait(AsyncDelay), "Hang"); }
/// <summary> /// Runs an asynchronous task synchronously, using just the current thread to execute continuations. /// </summary> internal static void Run(Func <Task> func) { if (func == null) { throw new ArgumentNullException(nameof(func)); } var prevCtx = SynchronizationContext.Current; try { var syncCtx = SingleThreadedSynchronizationContext.New(); SynchronizationContext.SetSynchronizationContext(syncCtx); var t = func(); if (t == null) { throw new InvalidOperationException(); } var frame = SingleThreadedSynchronizationContext.NewFrame(); t.ContinueWith(_ => { frame.Continue = false; }, TaskScheduler.Default); SingleThreadedSynchronizationContext.PushFrame(syncCtx, frame); t.GetAwaiter().GetResult(); } finally { SynchronizationContext.SetSynchronizationContext(prevCtx); } }
public void WithCancellationNoncancelableNoDeadlockFromSyncContext() { var dispatcher = SingleThreadedSynchronizationContext.New(); SynchronizationContext.SetSynchronizationContext(dispatcher); WithCancellationSyncBlockOnNoncancelableToken(); }
public void SynchronizationContextCaptured() { var syncContext = SingleThreadedSynchronizationContext.New(); SynchronizationContext.SetSynchronizationContext(syncContext); Exception callbackError = null; var callback = new Action <GenericParameterHelper>( p => { try { Assert.Same(syncContext, SynchronizationContext.Current); } catch (Exception e) { callbackError = e; } }); var progress = new ProgressWithCompletion <GenericParameterHelper>(callback); IProgress <GenericParameterHelper> reporter = progress; Task.Run(delegate { reporter.Report(new GenericParameterHelper(1)); }); if (callbackError != null) { throw callbackError; } }
public void WithCancellationNoDeadlockFromSyncContext_Completed() { var dispatcher = SingleThreadedSynchronizationContext.New(); SynchronizationContext.SetSynchronizationContext(dispatcher); WithCancellationSyncBlock(simulateCancellation: false); }
public void ConfigureAwaitRunInlineOfT_NoExtraThreadSwitching(NamedSyncContexts invokeOn, NamedSyncContexts completeOn) { // Set up various SynchronizationContexts that we may invoke or complete the async method with. var aSyncContext = SingleThreadedSynchronizationContext.New(); var bSyncContext = SingleThreadedSynchronizationContext.New(); var invokeOnSyncContext = invokeOn == NamedSyncContexts.None ? null : invokeOn == NamedSyncContexts.A ? aSyncContext : invokeOn == NamedSyncContexts.B ? bSyncContext : throw new ArgumentOutOfRangeException(nameof(invokeOn)); var completeOnSyncContext = completeOn == NamedSyncContexts.None ? null : completeOn == NamedSyncContexts.A ? aSyncContext : completeOn == NamedSyncContexts.B ? bSyncContext : throw new ArgumentOutOfRangeException(nameof(completeOn)); // Set up a single-threaded SynchronizationContext that we'll invoke the async method within. SynchronizationContext.SetSynchronizationContext(invokeOnSyncContext); var unblockAsyncMethod = new TaskCompletionSource <bool>(); var asyncTask = AwaitThenGetThreadAsync(unblockAsyncMethod.Task); SynchronizationContext.SetSynchronizationContext(completeOnSyncContext); unblockAsyncMethod.SetResult(true); // Confirm that setting the intermediate task allowed the async method to complete immediately, using our thread to do it. Assert.True(asyncTask.IsCompleted); Assert.Equal(Environment.CurrentManagedThreadId, asyncTask.Result); async Task <int> AwaitThenGetThreadAsync(Task <bool> antecedent) { bool result = await antecedent.ConfigureAwaitRunInline(); Assert.True(result); return(Environment.CurrentManagedThreadId); } }
public void WithCancellationNoncancelableNoDeadlockFromSyncContextWithinJTFRun() { var dispatcher = SingleThreadedSynchronizationContext.New(); SynchronizationContext.SetSynchronizationContext(dispatcher); var jtc = new JoinableTaskContext(); jtc.Factory.Run(delegate { WithCancellationSyncBlockOnNoncancelableToken(); return(TplExtensions.CompletedTask); }); }
public void WithCancellationNoncancelableNoDeadlockFromSyncContext() { var dispatcher = SingleThreadedSynchronizationContext.New(); SynchronizationContext.SetSynchronizationContext(dispatcher); var tcs = new TaskCompletionSource <object>(); Task.Run(async delegate { await Task.Delay(AsyncDelay); tcs.SetResult(null); }); ((Task)tcs.Task).WithCancellation(CancellationToken.None).Wait(TestTimeout); }
protected JoinableTaskTestBase(ITestOutputHelper logger) : base(logger) { this.dispatcherContext = SingleThreadedSynchronizationContext.New(); SynchronizationContext.SetSynchronizationContext(this.dispatcherContext); this.context = this.CreateJoinableTaskContext(); this.joinableCollection = this.context.CreateCollection(); this.asyncPump = this.context.CreateFactory(this.joinableCollection); this.originalThread = Thread.CurrentThread; this.testFrame = SingleThreadedSynchronizationContext.NewFrame(); // Suppress the assert dialog that appears and causes test runs to hang. Trace.Listeners.OfType <DefaultTraceListener>().Single().AssertUiEnabled = false; }
protected void ExecuteOnDispatcher(Func <Task> action) { Action worker = delegate { var frame = SingleThreadedSynchronizationContext.NewFrame(); Exception failure = null; SynchronizationContext.Current.Post( async _ => { try { await action(); } catch (Exception ex) { failure = ex; } finally { frame.Continue = false; } }, null); SingleThreadedSynchronizationContext.PushFrame(SynchronizationContext.Current, frame); if (failure != null) { ExceptionDispatchInfo.Capture(failure).Throw(); } }; if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA && SingleThreadedSynchronizationContext.IsSingleThreadedSyncContext(SynchronizationContext.Current)) { worker(); } else { this.ExecuteOnSTA(() => { if (!SingleThreadedSynchronizationContext.IsSingleThreadedSyncContext(SynchronizationContext.Current)) { SynchronizationContext.SetSynchronizationContext(SingleThreadedSynchronizationContext.New()); } worker(); }); } }
public void WithCancellationNoDeadlockFromSyncContext() { var dispatcher = SingleThreadedSynchronizationContext.New(); SynchronizationContext.SetSynchronizationContext(dispatcher); var tcs = new TaskCompletionSource <object>(); var cts = new CancellationTokenSource(AsyncDelay / 4); try { ((Task)tcs.Task).WithCancellation(cts.Token).Wait(TestTimeout); Assert.True(false, "Expected OperationCanceledException not thrown."); } catch (AggregateException ex) { ex.Handle(x => x is OperationCanceledException); } }
public void ValueFactoryRequiresMainThreadHeldByOtherSync(bool passJtfToLazyCtor) { var ctxt = SingleThreadedSynchronizationContext.New(); SynchronizationContext.SetSynchronizationContext(ctxt); var context = new JoinableTaskContext(); var asyncPump = context.Factory; var originalThread = Thread.CurrentThread; var evt = new AsyncManualResetEvent(); var lazy = new AsyncLazy <object>( async delegate { // It is important that no await appear before this JTF.Run call, since // we're testing that the value factory is not invoked while the AsyncLazy // holds a private lock that would deadlock when called from another thread. asyncPump.Run(async delegate { await asyncPump.SwitchToMainThreadAsync(this.TimeoutToken); }); await Task.Yield(); return(new object()); }, passJtfToLazyCtor ? asyncPump : null); // mix it up to exercise all the code paths in the ctor. var backgroundRequest = Task.Run(async delegate { return(await lazy.GetValueAsync()); }); Thread.Sleep(AsyncDelay); // Give the background thread time to call GetValueAsync(), but it doesn't yield (when the test was written). var foregroundRequest = lazy.GetValueAsync(); var frame = SingleThreadedSynchronizationContext.NewFrame(); var combinedTask = Task.WhenAll(foregroundRequest, backgroundRequest); combinedTask.WithTimeout(UnexpectedTimeout).ContinueWith(_ => frame.Continue = false, TaskScheduler.Default); SingleThreadedSynchronizationContext.PushFrame(ctxt, frame); // Ensure that the test didn't simply timeout, and that the individual tasks did not throw. Assert.True(foregroundRequest.IsCompleted); Assert.True(backgroundRequest.IsCompleted); Assert.Same(foregroundRequest.GetAwaiter().GetResult(), backgroundRequest.GetAwaiter().GetResult()); }
public void ValueFactoryRequiresMainThreadHeldByOtherInJTFRun() { var ctxt = SingleThreadedSynchronizationContext.New(); SynchronizationContext.SetSynchronizationContext(ctxt); var context = new JoinableTaskContext(); var asyncPump = context.Factory; var originalThread = Thread.CurrentThread; var evt = new AsyncManualResetEvent(); var lazy = new AsyncLazy <object>( async delegate { // It is important that no await appear before this JTF.Run call, since // we're testing that the value factory is not invoked while the AsyncLazy // holds a private lock that would deadlock when called from another thread. asyncPump.Run(async delegate { await asyncPump.SwitchToMainThreadAsync(this.TimeoutToken); }); await Task.Yield(); return(new object()); }, asyncPump); var backgroundRequest = Task.Run(async delegate { return(await lazy.GetValueAsync()); }); Thread.Sleep(AsyncDelay); // Give the background thread time to call GetValueAsync(), but it doesn't yield (when the test was written). asyncPump.Run(async delegate { var foregroundValue = await lazy.GetValueAsync(this.TimeoutToken); var backgroundValue = await backgroundRequest; Assert.Same(foregroundValue, backgroundValue); }); }
public void AsyncLazy_CompletesOnThreadWithValueFactory(NamedSyncContexts invokeOn, NamedSyncContexts completeOn) { // Set up various SynchronizationContexts that we may invoke or complete the async method with. var aSyncContext = SingleThreadedSynchronizationContext.New(); var bSyncContext = SingleThreadedSynchronizationContext.New(); var invokeOnSyncContext = invokeOn == NamedSyncContexts.None ? null : invokeOn == NamedSyncContexts.A ? aSyncContext : invokeOn == NamedSyncContexts.B ? bSyncContext : throw new ArgumentOutOfRangeException(nameof(invokeOn)); var completeOnSyncContext = completeOn == NamedSyncContexts.None ? null : completeOn == NamedSyncContexts.A ? aSyncContext : completeOn == NamedSyncContexts.B ? bSyncContext : throw new ArgumentOutOfRangeException(nameof(completeOn)); // Set up a single-threaded SynchronizationContext that we'll invoke the async method within. SynchronizationContext.SetSynchronizationContext(invokeOnSyncContext); var unblockAsyncMethod = new TaskCompletionSource <bool>(); var getValueTask = new AsyncLazy <int>(async delegate { await unblockAsyncMethod.Task.ConfigureAwaitRunInline(); return(Environment.CurrentManagedThreadId); }).GetValueAsync(); var verificationTask = getValueTask.ContinueWith( lazyValue => Environment.CurrentManagedThreadId, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); SynchronizationContext.SetSynchronizationContext(completeOnSyncContext); unblockAsyncMethod.SetResult(true); // Confirm that setting the intermediate task allowed the async method to complete immediately, using our thread to do it. Assert.True(verificationTask.IsCompleted); Assert.Equal(Environment.CurrentManagedThreadId, verificationTask.Result); }
private JoinableTaskContext InitializeJTCAndSC() { SynchronizationContext.SetSynchronizationContext(SingleThreadedSynchronizationContext.New()); return(new JoinableTaskContext()); }
protected void ExecuteOnDispatcher(Func <Task> action, bool staRequired = true) { Action worker = delegate { var frame = SingleThreadedSynchronizationContext.NewFrame(); Exception failure = null; SynchronizationContext.Current.Post( async _ => { try { await action(); } catch (Exception ex) { failure = ex; } finally { frame.Continue = false; } }, null); SingleThreadedSynchronizationContext.PushFrame(SynchronizationContext.Current, frame); if (failure != null) { ExceptionDispatchInfo.Capture(failure).Throw(); } }; #if DESKTOP || NETCOREAPP2_0 if ((!staRequired || Thread.CurrentThread.GetApartmentState() == ApartmentState.STA) && SingleThreadedSynchronizationContext.IsSingleThreadedSyncContext(SynchronizationContext.Current)) { worker(); } else { this.ExecuteOnSTA(() => { if (!SingleThreadedSynchronizationContext.IsSingleThreadedSyncContext(SynchronizationContext.Current)) { SynchronizationContext.SetSynchronizationContext(SingleThreadedSynchronizationContext.New()); } worker(); }); } #else if (SingleThreadedSynchronizationContext.IsSingleThreadedSyncContext(SynchronizationContext.Current)) { worker(); } else { Task.Run(delegate { SynchronizationContext.SetSynchronizationContext(SingleThreadedSynchronizationContext.New()); worker(); }).GetAwaiter().GetResult(); } #endif }