Mercurial > pub > ImplabNet
changeset 202:2651cb9a4250 v2
Implemented PollingRunnableComponent
author | cin |
---|---|
date | Tue, 18 Oct 2016 01:03:49 +0300 |
parents | d7cd7a83189a |
children | 4d9830a9bbb8 |
files | Implab/Components/PollingRunnableComponent.cs Implab/Components/RunnableComponent.cs Implab/Implab.csproj |
diffstat | 3 files changed, 101 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Implab/Components/PollingRunnableComponent.cs Tue Oct 18 01:03:49 2016 +0300 @@ -0,0 +1,98 @@ +using System; +using System.Threading; +using Implab.Diagnostics; + +namespace Implab.Components { + public class PollingRunnableComponent : RunnableComponent { + readonly Timer m_timer; + readonly Func<Func<IPromise>, IPromise> m_dispatcher; + readonly TimeSpan m_interval; + + int m_processing; + Promise m_pending; + + protected PollingRunnableComponent(TimeSpan interval, Func<Func<IPromise>, IPromise> dispatcher, bool initialized) : base(initialized) { + m_timer = new Timer(OnInternalTick); + + m_interval = interval; + m_dispatcher = dispatcher; + } + + protected override IPromise OnStart() { + m_timer.Change(TimeSpan.Zero, m_interval); + + return base.OnStart(); + } + + void OnInternalTick(object state) { + if (StartTick()) { + try { + AwaitTick(m_dispatcher != null ? m_dispatcher(OnTick) : OnTick()); + } catch (Exception error) { + HandleTickError(error); + } + } + } + + /// <summary> + /// Starts the tick handler. + /// </summary> + /// <returns>boolean value, true - the new tick handler may be invoked, false - a tick handler is already running or a component isn't running.</returns> + /// <remarks> + /// If the component is stopping no new handlers can be run. Every successful call to this method must be completed with either AwaitTick or HandleTickError handlers. + /// </remarks> + protected virtual bool StartTick() { + if (State == ExecutionState.Running && Interlocked.CompareExchange(ref m_processing, 1, 0) == 0) { + m_pending = new Promise(); + m_pending + .On(() => m_processing = 0, PromiseEventType.All) + .On(null, LogTickError); + return true; + } + return false; + } + + protected virtual void AwaitTick(IPromise tick) { + if (tick == null) { + m_pending.Resolve(); + } else { + tick.On( + m_pending.Resolve, + m_pending.Reject, + m_pending.CancelOperation + ); + m_pending.CancellationRequested(tick.Cancel); + } + } + + protected virtual void HandleTickError(Exception error) { + m_pending.Reject(error); + } + + protected virtual void LogTickError(Exception error) { + } + + protected virtual IPromise OnTick() { + return Promise.SUCCESS; + } + + protected override IPromise OnStop() { + m_timer.Change(-1, -1); + + if (m_pending != null) { + m_pending.Cancel(); + return m_pending.Then(base.OnStop); + } + + return base.OnStop(); + } + + protected override void Dispose(bool disposing, Exception lastError) { + if (disposing) + Safe.Dispose(m_timer); + + base.Dispose(disposing, lastError); + } + } +} +
--- a/Implab/Components/RunnableComponent.cs Mon Oct 17 00:36:36 2016 +0300 +++ b/Implab/Components/RunnableComponent.cs Tue Oct 18 01:03:49 2016 +0300 @@ -210,7 +210,8 @@ public ExecutionState State { get { - return m_stateMachine.State; + lock (m_stateMachine) + return m_stateMachine.State; } }
--- a/Implab/Implab.csproj Mon Oct 17 00:36:36 2016 +0300 +++ b/Implab/Implab.csproj Tue Oct 18 01:03:49 2016 +0300 @@ -194,6 +194,7 @@ <Compile Include="Components\LazyAndWeak.cs" /> <Compile Include="AbstractTask.cs" /> <Compile Include="AbstractTaskT.cs" /> + <Compile Include="Components\PollingRunnableComponent.cs" /> </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <ItemGroup />