changeset 259:7d52dc684bbd v3

PollingComponent: implemented correct stopping
author cin
date Fri, 13 Apr 2018 03:57:39 +0300
parents d0876436d95d
children 547a2fc0d93e
files Implab.Test/Implab.Test.csproj Implab.Test/RunnableComponentTests.cs Implab.Test/UnitTest1.cs Implab/Components/PollingComponent.cs Implab/PromiseExtensions.cs Implab/Safe.cs
diffstat 6 files changed, 91 insertions(+), 53 deletions(-) [+]
line wrap: on
line diff
--- a/Implab.Test/Implab.Test.csproj	Fri Apr 13 00:44:57 2018 +0300
+++ b/Implab.Test/Implab.Test.csproj	Fri Apr 13 03:57:39 2018 +0300
@@ -1,16 +1,16 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <TargetFramework>net46</TargetFramework>
-    <FrameworkPathOverride Condition="'$(TargetFramework)'=='net46' and '$(OSTYPE)'=='linux'">/usr/lib/mono/4.5/</FrameworkPathOverride>
+    <TargetFramework>netcoreapp2.1</TargetFramework>
 
     <IsPackable>false</IsPackable>
   </PropertyGroup>
+
   <ItemGroup>
-    <ProjectReference Include="../Implab/Implab.csproj" />
-    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.6.0-preview-20180109-01" />
     <PackageReference Include="xunit" Version="2.3.1" />
     <PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
+    <ProjectReference Include="../Implab/Implab.csproj"/>
     <DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
   </ItemGroup>
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab.Test/RunnableComponentTests.cs	Fri Apr 13 03:57:39 2018 +0300
@@ -0,0 +1,42 @@
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Implab.Components;
+using Xunit;
+
+namespace Implab.Test
+{
+    class TimeLog : PollingComponent {
+        public TimeLog() : base(true) {
+        }
+
+        protected override Task Poll(CancellationToken ct) {
+            Console.WriteLine("Poll");
+            return Task.CompletedTask;
+        }
+    }
+
+    public class UnitTest1
+    {
+        [Fact]
+        public async Task Test1()
+        {
+
+            using(var  tl = new TimeLog()) {
+                tl.StateChanged += (self, args) => Console.WriteLine("{0}", args.State);
+                tl.Delay = 1000;
+                tl.Interval = 500;
+
+                
+                tl.Start(CancellationToken.None);
+                await tl.Completion;
+
+                await Task.Delay(2000);
+
+                tl.Stop(CancellationToken.None);
+                await tl.Completion;
+                await Task.Delay(3000);
+            }
+        }
+    }
+}
--- a/Implab.Test/UnitTest1.cs	Fri Apr 13 00:44:57 2018 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-using System;
-using System.Diagnostics;
-using System.Threading;
-using Implab.Diagnostics;
-using System.Linq;
-using Xunit;
-
-namespace Implab.Test {
-    using System.Threading.Tasks;
-    using static Trace<UnitTest1>;
-    public class UnitTest1 {
-        [Fact]
-        public async Task Test1() {
-            var listener = new SimpleTraceListener(Console.Out);
-            listener.TraceOutputOptions |= TraceOptions.ThreadId;
-
-            var source = TraceSource;
-            source.Switch.Level = SourceLevels.All;
-
-            source.Listeners.Add(listener);
-
-            using (LogicalOperation("Test1")){
-                await Task.Yield();
-                Log(String.Join(", ", Trace.CorrelationManager.LogicalOperationStack.Cast<object>().Select(x => x.ToString())));
-                await AsyncDummy();
-                Log(String.Join(", ", Trace.CorrelationManager.LogicalOperationStack.Cast<object>().Select(x => x.ToString())));
-            }
-        }
-
-        async Task AsyncDummy() {
-            using(LogicalOperation("OuterDummy"))
-            using(LogicalOperation("InnerDummy")) {
-                Log(String.Join(", ", Trace.CorrelationManager.LogicalOperationStack.Cast<object>().Select(x => x.ToString())));
-                await Task.Delay(1);
-                Log(String.Join(", ", Trace.CorrelationManager.LogicalOperationStack.Cast<object>().Select(x => x.ToString())));
-            }
-            Log(String.Join(", ", Trace.CorrelationManager.LogicalOperationStack.Cast<object>().Select(x => x.ToString())));
-        }
-    }
-}
--- a/Implab/Components/PollingComponent.cs	Fri Apr 13 00:44:57 2018 +0300
+++ b/Implab/Components/PollingComponent.cs	Fri Apr 13 03:57:39 2018 +0300
@@ -9,6 +9,9 @@
 
         readonly CancellationTokenSource m_cancellation = new CancellationTokenSource();
 
+        Task m_pending;
+        Task m_poll;
+
         /// <summary>
         /// Poll interval in milliseconds.
         /// </summary>
@@ -41,20 +44,33 @@
         }
 
 
-        //TODO override stop
+        protected override async Task StopInternalAsync(CancellationToken ct) {
+            // component in Stopping state, no new polls will be scheduled
+            m_cancellation.Cancel();
+            try {
+                // await for pending poll
+                await m_poll;
+            } catch (OperationCanceledException e) {
+                // OK
+            }
+        }
         
         protected abstract Task Poll(CancellationToken ct);
 
         void ScheduleNextPoll(int timeout) {
             lock (SynchronizationObject) {
-                if (State == ExecutionState.Running)
+                if (State == ExecutionState.Running) {
+                    m_pending = Safe.CreateTask(m_cancellation.Token);
+                    m_poll = m_pending.Then(() => Poll(m_cancellation.Token));
                     m_timer.Change(timeout, Timeout.Infinite);
+                }
             }
         }
 
-        void OnTimer(object state) {
+        async void OnTimer(object state) {
             try {
-                Poll(m_cancellation.Token);
+                m_pending.Start();
+                await m_poll;
             } catch (Exception e) {
                 UnhandledException.DispatchEvent(this, new UnhandledExceptionEventArgs(e, false));
                 if (FailOnError)
--- a/Implab/PromiseExtensions.cs	Fri Apr 13 00:44:57 2018 +0300
+++ b/Implab/PromiseExtensions.cs	Fri Apr 13 03:57:39 2018 +0300
@@ -211,6 +211,15 @@
             }));
         }
 
+        public static PromiseAwaiter GetAwaiter(this IPromise that) {
+            Safe.ArgumentNotNull(that, nameof(that));
+            return new PromiseAwaiter(that);
+        }
+
+        public static PromiseAwaiter<T> GetAwaiter<T>(this IPromise<T> that) {
+            Safe.ArgumentNotNull(that, nameof(that));
+            return new PromiseAwaiter<T>(that);
+        }
 
     }
 }
--- a/Implab/Safe.cs	Fri Apr 13 00:44:57 2018 +0300
+++ b/Implab/Safe.cs	Fri Apr 13 03:57:39 2018 +0300
@@ -7,6 +7,7 @@
 using System.Collections;
 using System.Runtime.CompilerServices;
 using System.Threading.Tasks;
+using System.Threading;
 
 #if NET_4_5
 using System.Threading.Tasks;
@@ -151,6 +152,21 @@
         public static void NoWait<T>(Task<T> promise) {
         }
 
+        public static void Noop() {
+        }
+
+        public static void Noop(CancellationToken ct) {
+            ct.ThrowIfCancellationRequested();
+        }
+
+        public static Task CreateTask() {
+            return new Task(Noop);
+        }
+
+        public static Task CreateTask(CancellationToken ct) {
+            return new Task(Noop, ct);
+        }
+
         [DebuggerStepThrough]
         public static IPromise<T> Run<T>(Func<IPromise<T>> action) {
             ArgumentNotNull(action, "action");
@@ -162,10 +178,5 @@
             }
         }
 
-#if NET_4_5
-        public static void NoWait(Task t) {
-        }
-#endif
-
     }
 }