Mercurial > pub > ImplabNet
diff Implab/Components/RunnableComponent.cs @ 156:97fbbf816844 v2
Promises: SignalXXX methods merged into SignalHandler method.
Components: RunnableComponent In progress
author | cin |
---|---|
date | Mon, 15 Feb 2016 04:22:15 +0300 |
parents | |
children | 948c015a9011 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Implab/Components/RunnableComponent.cs Mon Feb 15 04:22:15 2016 +0300 @@ -0,0 +1,141 @@ +using System; +using Implab.Parsing; + +namespace Implab.Components { + public class RunnableComponent : Disposable, IRunnable, IInitializable { + class Automaton : DFAutomaton<ExecutionState> { + static readonly EDFADefinition<ExecutionState> _dfa; + + static Automaton() { + + var token = Token + .New(ExecutionState.Uninitialized).Optional() // we can skip uninitialized state + .Cat( + Token.New(ExecutionState.Ready) // uninitialized -> initial + .Cat( + Token.New(ExecutionState.Starting) // initial -> starting + .Cat( + Token.New(ExecutionState.Running) // running -> {stopping -> stopped | failed } + .Cat( + Token.New(ExecutionState.Stopping) // running -> stopping + .Cat( + Token.New(ExecutionState.Stopped) // stopping -> stopped + .Or(Token.New(ExecutionState.Failed)) // stopping -> failed + ) + .Or(Token.New(ExecutionState.Failed)) // running -> failed + ) + .Or(Token.New(ExecutionState.Failed)) // starting -> failed + ).EClosure() + ) + .Or(Token.New(ExecutionState.Failed)) // uninitialized->failed + .Cat(Token.New(ExecutionState.Disposed).Tag(0)) // ... -> disposed + ); + + var builder = new DFABuilder(); + token.Accept(builder); + + var _dfa = new EDFADefinition<ExecutionState>(EnumAlphabet<ExecutionState>.FullAlphabet); + builder.BuildDFA(_dfa); // don't optimize dfa to avoid remapping of the alphabet + + } + + public Automaton() : base(_dfa.States, INITIAL_STATE, ExecutionState.Reserved) { + } + + public void MoveTo(ExecutionState state) { + + if (!CanMove((int)state)) + throw new InvalidOperationException(String.Format("Illegal state transition from {0} to {1}", Current, state)); + Move((int)state); + m_context.info = state; + } + + public ExecutionState Current { + get { + return (ExecutionState)m_context.info; + } + } + } + + readonly Automaton m_automaton = new Automaton(); + IPromise m_pending; + Exception m_lastError; + + protected RunnableComponent(bool initialized) { + if (initialized) + m_automaton.MoveTo(ExecutionState.Ready); + else + m_automaton.MoveTo(ExecutionState.Uninitialized); + } + + #region IInitializable implementation + + public void Init() { + + } + + #endregion + + #region IRunnable implementation + + public IPromise Start() { + return Safe.InvokePromise(() => { + Promise promise; + lock (m_automaton) { + if (m_automaton.Current == ExecutionState.Starting) + return m_pending; + m_automaton.MoveTo(ExecutionState.Starting); + m_pending = promise = new Promise(); + } + + var start = Safe.InvokePromise(OnStart); + promise.On(null, null, start.Cancel); + start.On(promise.Resolve, promise.Reject, promise.CancelOperation); + + return promise.Then(() => { + lock(m_automaton) { + m_automaton.MoveTo(ExecutionState.Running); + m_pending = null; + } + + Run(); + }, err => { + if (BeginTransition(RUNNING_REQUIRE)) { + m_lastError = err; + CompleteTransition(FAILED_STATE); + throw new PromiseTransientException(err); + } + throw new OperationCanceledException(); + }, reason => { + throw new OperationCanceledException("The operation was cancelled", reason); + }); + }); + } + + protected virtual IPromise OnStart() { + return Promise.SUCCESS; + } + + protected virtual void Run() { + } + + public IPromise Stop() { + throw new NotImplementedException(); + } + + public ExecutionState State { + get { + throw new NotImplementedException(); + } + } + + public Exception LastError { + get { + throw new NotImplementedException(); + } + } + + #endregion + } +} +