/// <summary>
        /// The do spin.
        /// </summary>
        /// <param name="loops">
        /// The loops.
        /// </param>
        /// <param name="iterations">
        /// The iterations.
        /// </param>
        /// <param name="notify">
        /// The notify.
        /// </param>
        /// <param name="token">
        /// The token.
        /// </param>
        public void DoSpin(int loops, int iterations, SpinNotify notify, CancellationToken token)
        {
            for (var i = 0; i < loops; i++)
            {
                WorkflowTrace.Verbose("TaskSpinWaiter loop {0} of {1}", i, loops);

                try
                {
                    if (token.IsCancellationRequested)
                    {
                        WorkflowTrace.Verbose("TaskSpinWaiter Cancel Requested");
                        return;
                    }

                    Task.Run(
                        () =>
                        {
                            WorkflowTrace.Verbose("SpinWait({0})", iterations);
                            Thread.SpinWait(iterations);
                            if (token.IsCancellationRequested)
                            {
                                WorkflowTrace.Verbose("SpinWait - Cancellation is requested");
                            }
                        },
                        token).Wait();
                }
                finally
                {
                    notify.LoopComplete(loops, iterations);
                }
            }

            WorkflowTrace.Verbose("TaskSpinWaiter done with {0} iterations", iterations * loops);
        }
        public void CancelWorkflowApp()
        {
            // Arrange
            TestTrace.Arrange();
            var spinExecuting = new AutoResetEvent(false);
            var completed = new AutoResetEvent(false);
            var notify = new SpinNotify { LoopComplete = (loops, iterations) => spinExecuting.Set() };
            var activity = CreateSequenceWithSpinWaiter(typeof(SpinWaiter));

            WorkflowApplicationCompletedEventArgs completedArgs = null;

            var workflowApplication = new WorkflowApplication(activity)
                {
                    Completed = args =>
                        {
                            completedArgs = args;
                            WorkflowTrace.Verbose(
                                "Completed state: {0} fault {1}", args.CompletionState, args.TerminationException);
                            completed.Set();
                        },
                    Aborted = args => WorkflowTrace.Verbose("Aborted {0}", args.Reason),
                };

            var source = new CancellationTokenSource(Constants.Timeout);

            var tracking = new ListTrackingParticipant();
            workflowApplication.Extensions.Add(tracking);
            workflowApplication.Extensions.Add(notify);
            var activitySource = new ActivityCancellationToken(source.Token);
            workflowApplication.Extensions.Add(activitySource);

            try
            {
                // Act
                TestTrace.Act();

                workflowApplication.Run();

                TestTrace.Write("Waiting for AsyncSpinWaiter to start executing");
                var spinWait = spinExecuting.WaitOne(TimeSpan.FromSeconds(10));

                if (spinWait)
                {
                    source.Token.Register(workflowApplication.Cancel);

                    TestTrace.Write("Cancelling workflow");
                    source.Cancel();

                    // workflow.Cancel();
                }
                else
                {
                    TestTrace.Write("spinWait timeout");
                }

                var isComplete = completed.WaitOne(Constants.Timeout);

                // Assert
                TestTrace.Assert();

                Assert.IsTrue(isComplete);
                Assert.IsNotNull(completedArgs);
                Assert.AreEqual(ActivityInstanceState.Canceled, completedArgs.CompletionState);
            }
            finally
            {
                TestTrace.Finally();
                tracking.Trace();
            }
        }
        public void CancelTaskAsyncActivityViaToken()
        {
            // Arrange
            TestTrace.Arrange();
            var spinExecuting = new ManualResetEvent(false);
            var completedEvent = new ManualResetEvent(false);
            var notify = new SpinNotify { LoopComplete = (loops, iterations) => spinExecuting.Set() };
            var cancellationHandlerClosed = new AutoResetEvent(false);
            var activity = CreateSequenceWithSpinWaiter(typeof(TaskSpinWaiter));

            var tracking = new ListTrackingParticipant();

            var workflow = new WorkflowP1(activity)
            {
                Timeout = Constants.Timeout,
                Extensions =
                        {
                            tracking, 
                            notify
                        }
            };

            workflow.When.Activity.Name("CancellationHandler").Closed +=
                (sender, args) => cancellationHandlerClosed.Set();

            workflow.When.Completed += (sender, args) => completedEvent.Set();

            var source = new CancellationTokenSource(Constants.Timeout);

            try
            {
                // Act
                TestTrace.Act();
                var task = workflow.RunAsync(source.Token);

                TestTrace.Write("Waiting for AsyncSpinWaiter to start executing");
                Assert.IsTrue(spinExecuting.WaitOne(Constants.Timeout));

                TestTrace.Write("Cancelling workflow with token");
                source.Cancel();

                TestTrace.Write("Waiting for workflow to execute cancellation handler");
                Assert.IsTrue(cancellationHandlerClosed.WaitOne(Constants.Timeout));

                TestTrace.Write("Waiting for workflow");

                // Assert
                TestTrace.Assert();
                AssertHelper.Throws<AggregateException>(task.Wait, typeof(TaskCanceledException));
                Assert.IsTrue(
                    tracking.Records.Any(ActivityInstanceState.Closed, "CancellationHandler"),
                    "The cancellation handler was not invoked");
                Assert.IsTrue(task.IsCanceled);
                Assert.IsTrue(task.IsCompleted);
            }
            finally
            {
                TestTrace.Finally();

                workflow.Trace();
            }
        }
        public void CancelWithAsyncActivityWillCancel()
        {
            // Arrange
            TestTrace.Arrange();
            var spinExecuting = new AutoResetEvent(false);
            var notify = new SpinNotify { LoopComplete = (loops, iterations) => spinExecuting.Set() };
            var cancellationHandlerClosed = new AutoResetEvent(false);
            var activity = CreateSequenceWithSpinWaiter(typeof(AsyncSpinWaiter));

            var tracking = new ListTrackingParticipant();

            var workflow = new WorkflowP1(activity)
            {
                Timeout = Constants.Timeout,
                Extensions =
                        {
                            tracking, 
                            notify
                        }
            };

            workflow.When.Activity.Name("CancellationHandler").Closed +=
                (sender, args) => cancellationHandlerClosed.Set();

            var source = new CancellationTokenSource(Constants.Timeout);

            try
            {
                // Act
                TestTrace.Act();
                workflow.Until.Idle.RunAsync(source.Token);

                TestTrace.Write("Waiting for AsyncSpinWaiter to start executing");
                var spinWait = spinExecuting.WaitOne(TimeSpan.FromSeconds(10));

                TestTrace.Write("Cancelling workflow");
                source.Cancel();

                var cancelInvoked = cancellationHandlerClosed.WaitOne(Constants.Timeout);

                // Assert
                TestTrace.Assert();
                Assert.IsTrue(spinWait, "The spinExecuting event was not set");
                Assert.IsTrue(cancelInvoked);
                Assert.IsTrue(
                    tracking.Records.Any(ActivityInstanceState.Closed, "CancellationHandler"),
                    "The cancellation handler was not invoked");
            }
            finally
            {
                TestTrace.Finally();

                workflow.Trace();
            }
        }
        /// <summary>
        /// The execute.
        /// </summary>
        /// <param name="context">
        /// The context. 
        /// </param>
        protected override void Execute(NativeActivityContext context)
        {
            this.notify = context.GetExtension<SpinNotify>();

            for (var i = 0; i < this.Loops; i++)
            {
                WorkflowTrace.Verbose(
                    "NativeSpinWaiter loop {0} of {1}, spinning {2} iterations", i, this.Loops, this.Iterations);

                var token = context.GetExtension<ActivityCancellationToken>();
                token.ThrowIfCancellationRequested();

                if (this.isCancellationRequested)
                {
                    return;
                }

                Thread.SpinWait(this.Iterations);

                this.notify.LoopComplete(this.Loops, this.Iterations);
            }

            WorkflowTrace.Verbose("NativeSpinWaiter done with {0} iterations", this.Iterations * this.Loops);
        }
        /// <summary>
        /// Executes the spin wait
        /// </summary>
        /// <param name="token">
        /// The token. 
        /// </param>
        /// <param name="notify">
        /// The notify. 
        /// </param>
        private void DoSpinWait(ActivityCancellationToken token, SpinNotify notify)
        {
            for (var i = 0; i < this.Loops; i++)
            {
                WorkflowTrace.Verbose(
                    "AsyncSpinWaiter loop {0} of {1}, spinning {2} iterations", i, this.Loops, this.Iterations);

                try
                {
                    // For the token cancel
                    if (token.IsCancellationRequested())
                    {
                        WorkflowTrace.Verbose("Token requests cancel");
                        return;
                    }

                    Thread.SpinWait(this.Iterations);
                }
                finally
                {
                    if (notify != null)
                    {
                        notify.LoopComplete(this.Loops, this.Iterations);
                    }
                }
            }

            WorkflowTrace.Verbose("AsyncSpinWaiter done with {0} iterations", this.Iterations * this.Loops);
        }