RunnableComponent.cs
141 lines
| 4.9 KiB
| text/x-csharp
|
CSharpLexer
cin
|
r156 | 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 | ||||
} | ||||
} | ||||