Example #1
0
        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);
 }
Example #3
0
 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;
 }
Example #4
0
 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);
        }
Example #7
0
        /// <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);
        }
Example #9
0
        /// <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");
        }
Example #10
0
            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();
                }));
            }
        }
Example #13
0
 /// <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());
        }