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
+    }
+}
+