async Task <StepExecutionState> IProgressStepOperation.Run(CancellationToken cancellationToken, IProgressStepExecutionEvents progressCallback) { if (this.ExecutionState != StepExecutionState.NotStarted) { throw new InvalidOperationException(ProgressResources.StepOperationWasAlreadyExecuted); } if (this.Cancellable && cancellationToken.IsCancellationRequested) { return(this.ExecutionState = StepExecutionState.Cancelled); } VsTaskRunContext context = GetContext(this.Execution); StepExecutionState stepState = await VsThreadingHelper.RunTask <StepExecutionState>(this.controller, context, () => { DoStatefulExecution(progressCallback, cancellationToken); return(this.ExecutionState); }, cancellationToken); return(stepState); }
/// <summary> /// Executes the operation in the supplied <see cref="VsTaskRunContext"/> /// </summary> /// <param name="serviceProvider">An instance of <see cref="IServiceProvider"/>. Required.</param> /// <param name="context">The <see cref="VsTaskRunContext"/> in which to run the operation</param> /// <param name="op">The operation to run</param> /// <param name="token">Cancellation token</param> /// <returns>An await-able object</returns> internal static async TPL.Task RunTask(IServiceProvider serviceProvider, VsTaskRunContext context, Action op, CancellationToken token) { await RunTask <object>(serviceProvider, context, () => { op(); return(null); }, token); }
public VsTask(SingleThreadedTaskSchedulerService owner, VsTaskRunContext context, Func <object> action) { owner.Should().NotBeNull(); context.Should().NotBeNull(); action.Should().NotBeNull(); this.owner = owner; this.context = context; this.action = action; }
public VsTask(SingleThreadedTaskSchedulerService owner, VsTaskRunContext context, Func <object> action) { Assert.IsNotNull(owner); Assert.IsNotNull(context); Assert.IsNotNull(action); this.owner = owner; this.context = context; this.action = action; }
/// <summary> /// Executes a non-cancellable operation in the specified <see cref="VsTaskRunContext"/> and doesn't wait until it is completed /// </summary> /// <param name="serviceProvider">An instance of <see cref="IServiceProvider"/>. Required.</param> /// <param name="context">The <see cref="VsTaskRunContext"/> in which to run the operation</param> /// <param name="op">The operation to run</param> internal static void BeginTask(IServiceProvider serviceProvider, VsTaskRunContext context, Action op) { Debug.Assert(serviceProvider != null, "IServiceProvider is required"); Debug.Assert(op != null, "Action is required"); IVsTaskSchedulerService taskService = serviceProvider.GetService(typeof(SVsTaskSchedulerService)) as IVsTaskSchedulerService; IVsTaskBody body = VsTaskLibraryHelper.CreateTaskBody(op); IVsTask task = VsTaskLibraryHelper.CreateTask(taskService, context, VsTaskCreationOptions.NotCancelable, body, null); task.Start(); }
/// <summary> /// Runs the specified action in the specified <see cref="VsTaskRunContext"/>. /// If context is the same as the current context, in terms of UI/non-UI thread, it will execute the operation directly instead of switching context. /// </summary> /// <param name="serviceProvider">An instance of <see cref="IServiceProvider"/>. Required.</param> /// <param name="context">The <see cref="VsTaskRunContext"/> in which to run the operation</param> /// <param name="op">The operation to run</param> internal static void RunInline(IServiceProvider serviceProvider, VsTaskRunContext context, Action op) { Debug.Assert(serviceProvider != null); Debug.Assert(op != null); RunInline <object>(serviceProvider, context, () => { op(); return(null); }, null); }
/// <summary> /// Test helper to run test code in a pseudo-UI context that will let the platform code to behave nicely /// </summary> /// <param name="action">The action to run</param> public void RunInUIContext(Action action) { VsTaskRunContext prev = this.currentContext; this.SetCurrentThreadContextAs(VsTaskRunContext.UIThreadNormalPriority); try { action(); } finally { this.SetCurrentThreadContextAs(prev); } }
/// <summary> /// Creates a <see cref="IVsTask"/> in the specified <see cref="VsTaskRunContext"/> /// </summary> /// <param name="serviceProvider">An instance of <see cref="IServiceProvider"/>. Required.</param> /// <param name="context">The <see cref="VsTaskRunContext"/> in which to run the operation</param> /// <param name="op">The operation to run</param> /// <param name="token">Option cancellation token <see cref="CancellationToken"/></param> /// <returns>An await-able object that returns a result</returns> private static IVsTask CreateTask <T>(IServiceProvider serviceProvider, VsTaskRunContext context, Func <T> op, CancellationToken token) { Debug.Assert(serviceProvider != null, "IServiceProvider is required"); Debug.Assert(op != null, "op is required"); IVsTaskSchedulerService taskService = serviceProvider.GetService(typeof(SVsTaskSchedulerService)) as IVsTaskSchedulerService; IVsTaskBody body = VsTaskLibraryHelper.CreateTaskBody(() => (object)op()); IVsTask task = VsTaskLibraryHelper.CreateTask(taskService, context, body); if (token != CancellationToken.None) { task.ApplyCancellationToken(token); } return(task); }
/// <summary> /// Simulates the current thread as the specified context when <see cref="ThreadHelper.CheckAccess"/> is used /// </summary> /// <param name="context">The context to set</param> private void SetCurrentThreadContextAs(VsTaskRunContext context) { if (context == VsTaskRunContext.CurrentContext) { // Don't need to change a thing return; } MethodInfo setUIThread = typeof(ThreadHelper).GetMethod("SetUIThread", BindingFlags.Static | BindingFlags.NonPublic); setUIThread.Should().NotBeNull("Cannot find ThreadHelper.SetUIThread"); bool isUiThread = context == VsTaskRunContext.UIThreadBackgroundPriority || context == VsTaskRunContext.UIThreadIdlePriority || context == VsTaskRunContext.UIThreadNormalPriority || context == VsTaskRunContext.UIThreadSend; try { if (isUiThread) { // The single thread scheduler will using the current thread as if it was the UI thread setUIThread.Invoke(null, new object[0]); } else { // The single thread scheduler doesn't really uses other threads, so to simulate that: set the UI thread // to be a thread on the thread pool (and the current thread will be the background one) using (ManualResetEventSlim signal = new ManualResetEventSlim(false)) { ThreadPool.QueueUserWorkItem(new WaitCallback( (s) => { setUIThread.Invoke(null, new object[0]); signal.Set(); })); signal.Wait(); } } } finally { this.currentContext = context; } isUiThread.Should().Be(ThreadHelper.CheckAccess(), "SetUIThread patching code failed"); }
public void Start() { VsTaskRunContext previous = this.owner.currentContext; try { this.owner.SetCurrentThreadContextAs(this.context); this.result = this.action(); } catch { this.IsFaulted = true; throw; } finally { this.IsCompleted = true; this.owner.SetCurrentThreadContextAs(previous); } }
private static T RunInContext <T>(IServiceProvider serviceProvider, VsTaskRunContext context, Func <T> op, T faultedResult) { bool executeOperationDirectly = context == VsTaskRunContext.CurrentContext || ThreadHelper.CheckAccess() == VsTaskLibraryHelper.IsUIThreadContext(context); if (executeOperationDirectly) { return(op()); } else { T result = faultedResult; Exception fault = null; IVsTask task = CreateTask <T>(serviceProvider, context, () => { try { return(result = op()); } catch (Exception ex) { fault = ex; throw; // VS doesn't bubble up the exception } }, CancellationToken.None); task.Start(); task.Wait(); Debug.Assert(!task.IsFaulted, "Not expecting any faults"); if (fault != null) { throw new Exception(string.Empty, fault); } return(result); } }
/// <summary> /// Schedules a delegate for background execution on the UI thread without inheriting any claim to the UI thread from its caller. /// </summary> /// <param name="joinableTaskFactory">The factory to use for creating the task.</param> /// <param name="asyncMethod">The async delegate to invoke on the UI thread sometime in the future.</param> /// <param name="priority">The priority to use when switching to the UI thread or resuming after a yielding await.</param> /// <returns>The <see cref="JoinableTask"/> that represents the on-idle operation.</returns> public static JoinableTask StartOnIdle(this JoinableTaskFactory joinableTaskFactory, Func <Task> asyncMethod, VsTaskRunContext priority = VsTaskRunContext.UIThreadBackgroundPriority) { Requires.NotNull(joinableTaskFactory, nameof(joinableTaskFactory)); Requires.NotNull(asyncMethod, nameof(asyncMethod)); // Avoid inheriting any context from any ambient JoinableTask that is scheduling this work. using (joinableTaskFactory.Context.SuppressRelevance()) { return(joinableTaskFactory.RunAsync( priority, async() => { // We always yield, so as to not inline execution of the delegate if the caller is already on the UI thread. await Task.Yield(); // In case the caller wasn't on the UI thread, switch to it. It no-ops if we're already there. await joinableTaskFactory.SwitchToMainThreadAsync(); await asyncMethod(); })); } }
/// <summary> /// Schedules a delegate for background execution on the UI thread without inheriting any claim to the UI thread from its caller. /// </summary> /// <remarks> /// StartOnIdle is a included in later versions of the SDK, but this shim is to add support to VS 14+ /// </remarks> public static JoinableTask StartOnIdleShim(this JoinableTaskFactory joinableTaskFactory, Action action, VsTaskRunContext priority = VsTaskRunContext.UIThreadBackgroundPriority) { using (joinableTaskFactory.Context.SuppressRelevance()) { return(joinableTaskFactory.RunAsync(priority, async delegate { await System.Threading.Tasks.Task.Yield(); await joinableTaskFactory.SwitchToMainThreadAsync(); action(); })); } }
/// <summary> /// Runs the specified function in the specified <see cref="VsTaskRunContext"/>. /// If context is the same as the current context, in terms of UI/non-UI thread, it will execute the operation directly instead of switching context. /// </summary> /// <param name="serviceProvider">An instance of <see cref="IServiceProvider"/>. Required.</param> /// <param name="context">The <see cref="VsTaskRunContext"/> in which to run the operation</param> /// <param name="op">The operation to run</param> /// <param name="faultedResult">The result to return in case of a fault</param> /// <returns>The result of the operation</returns> internal static T RunInline <T>(IServiceProvider serviceProvider, VsTaskRunContext context, Func <T> op, T faultedResult) { return(RunInContext(serviceProvider, context, op, faultedResult)); }
/// <summary> /// Executes the operation in the supplied <see cref="VsTaskRunContext"/> /// </summary> /// <param name="serviceProvider">An instance of <see cref="IServiceProvider"/>. Required.</param> /// <param name="context">The <see cref="VsTaskRunContext"/> in which to run the operation</param> /// <param name="op">The operation to run</param> /// <returns>An await-able object</returns> internal static async TPL.Task RunTask(IServiceProvider serviceProvider, VsTaskRunContext context, Action op) { await RunTask(serviceProvider, context, op, CancellationToken.None); }
public VsTask(SingleThreadedTaskSchedulerService owner, VsTaskRunContext context, Func<object> action) { Assert.IsNotNull(owner); Assert.IsNotNull(context); Assert.IsNotNull(action); this.owner = owner; this.context = context; this.action = action; }
/// <summary> /// Simulates the current thread as the specified context when <see cref="ThreadHelper.CheckAccess"/> is used /// </summary> /// <param name="context">The context to set</param> private void SetCurrentThreadContextAs(VsTaskRunContext context) { if (context == VsTaskRunContext.CurrentContext) { // Don't need to change a thing return; } MethodInfo setUIThread = typeof(ThreadHelper).GetMethod("SetUIThread", BindingFlags.Static | BindingFlags.NonPublic); Assert.IsNotNull(setUIThread, "Cannot find ThreadHelper.SetUIThread"); bool isUiThread = context == VsTaskRunContext.UIThreadBackgroundPriority || context == VsTaskRunContext.UIThreadIdlePriority || context == VsTaskRunContext.UIThreadNormalPriority || context == VsTaskRunContext.UIThreadSend; try { if (isUiThread) { // The single thread scheduler will using the current thread as if it was the UI thread setUIThread.Invoke(null, new object[0]); } else { // The single thread scheduler doesn't really uses other threads, so to simulate that: set the UI thread // to be a thread on the thread pool (and the current thread will be the background one) using (ManualResetEventSlim signal = new ManualResetEventSlim(false)) { ThreadPool.QueueUserWorkItem(new WaitCallback( (s) => { setUIThread.Invoke(null, new object[0]); signal.Set(); })); signal.Wait(); } } } finally { this.currentContext = context; } Assert.AreEqual(isUiThread, ThreadHelper.CheckAccess(), "SetUIThread patching code failed"); }
/// <summary> /// Executes the cancellable operation in the supplied <see cref="VsTaskRunContext"/>. The result of the operation is of the generic method argument T. /// </summary> /// <param name="serviceProvider">An instance of <see cref="IServiceProvider"/>. Required.</param> /// <param name="context">The <see cref="VsTaskRunContext"/> in which to run the operation</param> /// <param name="op">The operation to run</param> /// <param name="token">Option cancellation token <see cref="CancellationToken"/></param> /// <returns>An await-able object that returns a result</returns> internal static async TPL.Task <T> RunTask <T>(IServiceProvider serviceProvider, VsTaskRunContext context, Func <T> op, CancellationToken token) { IVsTask task = CreateTask <T>(serviceProvider, context, op, token); task.Start(); await task.GetAwaiter(); Debug.Assert(!task.IsFaulted, "Not expecting to be faulted and reach this far"); return((T)task.GetResult()); }