diff --git a/Implab.Fx/ControlBoundPromise.cs b/Implab.Fx/ControlBoundPromise.cs --- a/Implab.Fx/ControlBoundPromise.cs +++ b/Implab.Fx/ControlBoundPromise.cs @@ -12,27 +12,12 @@ namespace Implab.Fx { m_target = target; } - protected override void SignalSuccess(Promise.HandlerDescriptor handler) { + protected override void SignalHandler(HandlerDescriptor handler, int signal) { if (m_target.InvokeRequired) - m_target.BeginInvoke(new Action.HandlerDescriptor>(base.SignalSuccess), handler); - else - base.SignalSuccess(handler); - } - - protected override void SignalCancelled(Promise.HandlerDescriptor handler, Exception reason) { - if (m_target.InvokeRequired) - m_target.BeginInvoke(new Action.HandlerDescriptor,Exception>(base.SignalCancelled), handler, reason); + m_target.BeginInvoke(new Action.HandlerDescriptor, int>(base.SignalHandler), handler, signal); else - base.SignalCancelled(handler, reason); + base.SignalHandler(handler, signal); } - - protected override void SignalError(Promise.HandlerDescriptor handler, Exception error) { - if (m_target.InvokeRequired) - m_target.BeginInvoke(new Action.HandlerDescriptor,Exception>(base.SignalError), handler, error); - else - base.SignalError(handler, error); - } - } } diff --git a/Implab/AbstractEvent.cs b/Implab/AbstractEvent.cs --- a/Implab/AbstractEvent.cs +++ b/Implab/AbstractEvent.cs @@ -8,9 +8,9 @@ namespace Implab { const int UNRESOLVED_SATE = 0; const int TRANSITIONAL_STATE = 1; - const int SUCCEEDED_STATE = 2; - const int REJECTED_STATE = 3; - const int CANCELLED_STATE = 4; + protected const int SUCCEEDED_STATE = 2; + protected const int REJECTED_STATE = 3; + protected const int CANCELLED_STATE = 4; const int CANCEL_NOT_REQUESTED = 0; const int CANCEL_REQUESTING = 1; @@ -22,7 +22,8 @@ namespace Implab { Exception m_error; int m_handlersCount; - readonly THandler[] m_handlers = new THandler[RESERVED_HANDLERS_COUNT]; + //readonly THandler[] m_handlers = new THandler[RESERVED_HANDLERS_COUNT]; + THandler[] m_handlers; MTQueue m_extraHandlers; int m_handlerPointer = -1; int m_handlersCommited; @@ -60,7 +61,7 @@ namespace Implab { protected void EndSetResult() { CompleteTransit(SUCCEEDED_STATE); - OnSuccess(); + Signal(); } @@ -78,14 +79,13 @@ namespace Implab { protected void SetError(Exception error) { if (BeginTransit()) { if (error is OperationCanceledException) { + m_error = error.InnerException; CompleteTransit(CANCELLED_STATE); - m_error = error.InnerException; - OnCancelled(); } else { m_error = error is PromiseTransientException ? error.InnerException : error; CompleteTransit(REJECTED_STATE); - OnError(); } + Signal(); } else { WaitTransition(); if (m_state == SUCCEEDED_STATE) @@ -101,22 +101,18 @@ namespace Implab { if (BeginTransit()) { m_error = reason; CompleteTransit(CANCELLED_STATE); - OnCancelled(); + Signal(); } } - protected abstract void SignalSuccess(THandler handler); - - protected abstract void SignalError(THandler handler, Exception error); + protected abstract void SignalHandler(THandler handler, int signal); - protected abstract void SignalCancelled(THandler handler, Exception reason); - - void OnSuccess() { + void Signal() { var hp = m_handlerPointer; var slot = hp +1 ; while (slot < m_handlersCommited) { if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) == hp) { - SignalSuccess(m_handlers[slot]); + SignalHandler(m_handlers[slot], m_state); } hp = m_handlerPointer; slot = hp +1 ; @@ -126,43 +122,7 @@ namespace Implab { if (m_extraHandlers != null) { THandler handler; while (m_extraHandlers.TryDequeue(out handler)) - SignalSuccess(handler); - } - } - - void OnError() { - var hp = m_handlerPointer; - var slot = hp +1 ; - while (slot < m_handlersCommited) { - if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) == hp) { - SignalError(m_handlers[slot],m_error); - } - hp = m_handlerPointer; - slot = hp +1 ; - } - - if (m_extraHandlers != null) { - THandler handler; - while (m_extraHandlers.TryDequeue(out handler)) - SignalError(handler, m_error); - } - } - - void OnCancelled() { - var hp = m_handlerPointer; - var slot = hp +1 ; - while (slot < m_handlersCommited) { - if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) == hp) { - SignalCancelled(m_handlers[slot], m_error); - } - hp = m_handlerPointer; - slot = hp +1 ; - } - - if (m_extraHandlers != null) { - THandler handler; - while (m_extraHandlers.TryDequeue(out handler)) - SignalCancelled(handler, m_error); + SignalHandler(handler, m_state); } } @@ -194,12 +154,15 @@ namespace Implab { if (m_state > 1) { // the promise is in the resolved state, just invoke the handler - InvokeHandler(handler); + SignalHandler(handler, m_state); } else { var slot = Interlocked.Increment(ref m_handlersCount) - 1; if (slot < RESERVED_HANDLERS_COUNT) { + if (slot == 0) + Interlocked.CompareExchange(ref m_handlers, new THandler[RESERVED_HANDLERS_COUNT], null); + m_handlers[slot] = handler; while (slot != Interlocked.CompareExchange(ref m_handlersCommited, slot + 1, slot)) { @@ -212,7 +175,7 @@ namespace Implab { if (slot < m_handlersCommited) { if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) != hp) continue; - InvokeHandler(m_handlers[slot]); + SignalHandler(m_handlers[slot], m_state); } break; } while(true); @@ -233,27 +196,11 @@ namespace Implab { // therefore we need to fetch a handler from the queue and execute it // note that fetched handler may be not the one that we have added // even we can fetch no handlers at all :) - InvokeHandler(handler); + SignalHandler(handler, m_state); } } } - protected void InvokeHandler(THandler handler) { - switch (m_state) { - case SUCCEEDED_STATE: - SignalSuccess(handler); - break; - case CANCELLED_STATE: - SignalCancelled(handler, m_error); - break; - case REJECTED_STATE: - SignalError(handler, m_error); - break; - default: - throw new Exception(String.Format("Invalid promise state {0}", m_state)); - } - } - #endregion #region IPromise implementation diff --git a/Implab/AbstractPromise.cs b/Implab/AbstractPromise.cs --- a/Implab/AbstractPromise.cs +++ b/Implab/AbstractPromise.cs @@ -71,16 +71,20 @@ namespace Implab { #region implemented abstract members of AbstractPromise - protected override void SignalSuccess(HandlerDescriptor handler) { - handler.SignalSuccess(); - } - - protected override void SignalError(HandlerDescriptor handler, Exception error) { - handler.SignalError(error); - } - - protected override void SignalCancelled(HandlerDescriptor handler, Exception reason) { - handler.SignalCancel(reason); + protected override void SignalHandler(HandlerDescriptor handler, int signal) { + switch (signal) { + case SUCCEEDED_STATE: + handler.SignalSuccess(); + break; + case REJECTED_STATE: + handler.SignalError(Error); + break; + case CANCELLED_STATE: + handler.SignalCancel(CancellationReason); + break; + default: + throw new InvalidOperationException(String.Format("Invalid promise signal: {0}", signal)); + } } protected override Signal GetResolveSignal() { diff --git a/Implab/AbstractPromiseT.cs b/Implab/AbstractPromiseT.cs --- a/Implab/AbstractPromiseT.cs +++ b/Implab/AbstractPromiseT.cs @@ -175,16 +175,20 @@ namespace Implab { return signal; } - protected override void SignalSuccess(HandlerDescriptor handler) { - handler.SignalSuccess(m_result); - } - - protected override void SignalError(HandlerDescriptor handler, Exception error) { - handler.SignalError(error); - } - - protected override void SignalCancelled(HandlerDescriptor handler, Exception reason) { - handler.SignalCancel(reason); + protected override void SignalHandler(HandlerDescriptor handler, int signal) { + switch (signal) { + case SUCCEEDED_STATE: + handler.SignalSuccess(m_result); + break; + case REJECTED_STATE: + handler.SignalError(Error); + break; + case CANCELLED_STATE: + handler.SignalCancel(CancellationReason); + break; + default: + throw new InvalidOperationException(String.Format("Invalid promise signal: {0}", signal)); + } } #endregion diff --git a/Implab/Components/ExecutionState.cs b/Implab/Components/ExecutionState.cs --- a/Implab/Components/ExecutionState.cs +++ b/Implab/Components/ExecutionState.cs @@ -1,8 +1,9 @@ namespace Implab.Components { public enum ExecutionState { + Reserved = 0, Uninitialized, - Initial, + Ready, Starting, Running, Stopping, diff --git a/Implab/Components/IFactory.cs b/Implab/Components/IFactory.cs new file mode 100644 --- /dev/null +++ b/Implab/Components/IFactory.cs @@ -0,0 +1,8 @@ +using System; + +namespace Implab.Components { + public interface IFactory { + T Create(); + } +} + diff --git a/Implab/Components/RunnableComponent.cs b/Implab/Components/RunnableComponent.cs new file mode 100644 --- /dev/null +++ b/Implab/Components/RunnableComponent.cs @@ -0,0 +1,141 @@ +using System; +using Implab.Parsing; + +namespace Implab.Components { + public class RunnableComponent : Disposable, IRunnable, IInitializable { + class Automaton : DFAutomaton { + static readonly EDFADefinition _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(EnumAlphabet.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 + } +} + diff --git a/Implab/Implab.csproj b/Implab/Implab.csproj --- a/Implab/Implab.csproj +++ b/Implab/Implab.csproj @@ -182,6 +182,8 @@ + + diff --git a/Implab/JSON/JSONGrammar.cs b/Implab/JSON/JSONGrammar.cs --- a/Implab/JSON/JSONGrammar.cs +++ b/Implab/JSON/JSONGrammar.cs @@ -1,13 +1,9 @@ using Implab.Parsing; -using System; -using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Implab.JSON { - internal class JSONGrammar : Grammar { - public enum TokenType : int { + class JSONGrammar : Grammar { + public enum TokenType { None, BeginObject, EndObject, diff --git a/Implab/JSON/JSONParser.cs b/Implab/JSON/JSONParser.cs --- a/Implab/JSON/JSONParser.cs +++ b/Implab/JSON/JSONParser.cs @@ -1,12 +1,7 @@ -using Implab; -using Implab.Parsing; +using Implab.Parsing; using System; -using System.Collections.Generic; using System.Diagnostics; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Implab.JSON { /// @@ -192,11 +187,10 @@ namespace Implab.JSON { if (m_memberContext == MemberContext.MemberName) { m_context.info.memberName = (string)tokenValue; break; - } else { - m_elementType = JSONElementType.Value; - m_elementValue = tokenValue; - return true; } + m_elementType = JSONElementType.Value; + m_elementValue = tokenValue; + return true; case JsonTokenType.Number: m_elementType = JSONElementType.Value; m_elementValue = tokenValue; diff --git a/Implab/Parsing/AlphabetBase.cs b/Implab/Parsing/AlphabetBase.cs --- a/Implab/Parsing/AlphabetBase.cs +++ b/Implab/Parsing/AlphabetBase.cs @@ -11,7 +11,7 @@ namespace Implab.Parsing { public const int UNCLASSIFIED = 0; int m_nextId = 1; - int[] m_map; + readonly int[] m_map; public int Count { get { return m_nextId; } diff --git a/Implab/Parsing/AltToken.cs b/Implab/Parsing/AltToken.cs --- a/Implab/Parsing/AltToken.cs +++ b/Implab/Parsing/AltToken.cs @@ -1,9 +1,4 @@ -using Implab; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System; namespace Implab.Parsing { public class AltToken: BinaryToken { diff --git a/Implab/Parsing/CDFADefinition.cs b/Implab/Parsing/CDFADefinition.cs --- a/Implab/Parsing/CDFADefinition.cs +++ b/Implab/Parsing/CDFADefinition.cs @@ -7,7 +7,7 @@ using System.Threading.Tasks; namespace Implab.Parsing { public class CDFADefinition : DFADefinitionBase { - Alphabet m_alphabet; + readonly Alphabet m_alphabet; public Alphabet Alphabet { get { return m_alphabet; } diff --git a/Implab/Parsing/CatToken.cs b/Implab/Parsing/CatToken.cs --- a/Implab/Parsing/CatToken.cs +++ b/Implab/Parsing/CatToken.cs @@ -1,9 +1,4 @@ -using Implab; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System; namespace Implab.Parsing { public class CatToken : BinaryToken { diff --git a/Implab/Parsing/DFABuilder.cs b/Implab/Parsing/DFABuilder.cs --- a/Implab/Parsing/DFABuilder.cs +++ b/Implab/Parsing/DFABuilder.cs @@ -166,7 +166,7 @@ namespace Implab.Parsing { int[] GetStateTags(HashSet state) { Debug.Assert(state != null); - return state.Where(pos => m_ends.ContainsKey(pos)).Select(pos => m_ends[pos]).ToArray(); + return state.Where(m_ends.ContainsKey).Select(pos => m_ends[pos]).ToArray(); } int DefineState(IDFADefinition automa, HashSet state) { diff --git a/Implab/Parsing/DFADefinitionBase.cs b/Implab/Parsing/DFADefinitionBase.cs --- a/Implab/Parsing/DFADefinitionBase.cs +++ b/Implab/Parsing/DFADefinitionBase.cs @@ -15,7 +15,7 @@ namespace Implab.Parsing { DFAStateDescriptior[] m_statesArray; - public DFADefinitionBase() { + protected DFADefinitionBase() { m_states = new List(); m_states.Add(new DFAStateDescriptior()); @@ -47,7 +47,7 @@ namespace Implab.Parsing { public int AddState(int[] tag) { var index = m_states.Count; - bool final = tag == null || tag.Length == 0 ? false : true; + bool final = tag != null && tag.Length != 0; m_states.Add(new DFAStateDescriptior { final = final, transitions = new int[AlphabetSize], @@ -139,7 +139,7 @@ namespace Implab.Parsing { // строим карты соотвествия оптимальных состояний с оригинальными - var initialState = optimalStates.Where(x => x.Contains(INITIAL_STATE)).Single(); + var initialState = optimalStates.Single(x => x.Contains(INITIAL_STATE)); // карта получения оптимального состояния по соотвествующему ему простому состоянию int[] reveseOptimalMap = new int[m_states.Count]; @@ -184,10 +184,8 @@ namespace Implab.Parsing { foreach (var term in A) { // ищем все переходы класса по символу term var s2 = reveseOptimalMap[ - optimalMap[s].Select(x => m_states[x].transitions[term]) // все элементарные состояния, куда переходит класс s - .Where(x => x != 0) // только допустимые - .FirstOrDefault() // первое допустимое элементарное состояние, если есть - ]; + optimalMap[s].Select(x => m_states[x].transitions[term]).FirstOrDefault(x => x != 0) // первое допустимое элементарное состояние, если есть + ]; HashSet A2; if (!classes.TryGetValue(s2, out A2)) { diff --git a/Implab/Parsing/DFAutomaton.cs b/Implab/Parsing/DFAutomaton.cs --- a/Implab/Parsing/DFAutomaton.cs +++ b/Implab/Parsing/DFAutomaton.cs @@ -37,7 +37,7 @@ namespace Implab.Parsing { Debug.Assert(states != null); Debug.Assert(current >= 0 && current < states.Length); m_contextStack.Push(m_context); - m_context. states = states; + m_context.states = states; m_context.current = current; m_context.info = info; } @@ -52,5 +52,10 @@ namespace Implab.Parsing { Debug.Assert(input > 0 && input < m_context.states[m_context.current].transitions.Length); m_context.current = m_context.states[m_context.current].transitions[input]; } + + protected bool CanMove(int input) { + Debug.Assert(input > 0 && input < m_context.states[m_context.current].transitions.Length); + return m_context.states[m_context.current].transitions[input] != UNREACHEBLE_STATE; + } } } diff --git a/Implab/Parsing/EDFADefinition.cs b/Implab/Parsing/EDFADefinition.cs --- a/Implab/Parsing/EDFADefinition.cs +++ b/Implab/Parsing/EDFADefinition.cs @@ -1,20 +1,15 @@ using Implab; using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Implab.Parsing { public class EDFADefinition : DFADefinitionBase where T : struct, IConvertible { - EnumAlphabet m_alphabet; + readonly EnumAlphabet m_alphabet; public EnumAlphabet Alphabet { get { return m_alphabet; } } - public EDFADefinition(EnumAlphabet alphabet) - : base() { + public EDFADefinition(EnumAlphabet alphabet) { Safe.ArgumentNotNull(alphabet, "alphabet"); m_alphabet = alphabet; } diff --git a/Implab/Parsing/EnumAlphabet.cs b/Implab/Parsing/EnumAlphabet.cs --- a/Implab/Parsing/EnumAlphabet.cs +++ b/Implab/Parsing/EnumAlphabet.cs @@ -1,11 +1,9 @@ -using Implab; -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Diagnostics.CodeAnalysis; namespace Implab.Parsing { /// @@ -13,10 +11,11 @@ namespace Implab.Parsing { /// /// Тип перечислений public class EnumAlphabet : AlphabetBase where T : struct, IConvertible { + [SuppressMessage("Microsoft.Design", "CA1000:DoNotDeclareStaticMembersOnGenericTypes")] static readonly T[] _symbols; static readonly EnumAlphabet _fullAlphabet; - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1065:DoNotRaiseExceptionsInUnexpectedLocations")] + [SuppressMessage("Microsoft.Design", "CA1065:DoNotRaiseExceptionsInUnexpectedLocations")] static EnumAlphabet() { if (!typeof(T).IsEnum) throw new InvalidOperationException("Invalid generic parameter, enumeration is required"); diff --git a/Implab/SyncContextPromise.cs b/Implab/SyncContextPromise.cs --- a/Implab/SyncContextPromise.cs +++ b/Implab/SyncContextPromise.cs @@ -10,16 +10,8 @@ namespace Implab { m_context = context; } - protected override void SignalSuccess(Promise.HandlerDescriptor handler) { - m_context.Post(x => base.SignalSuccess(handler), null); - } - - protected override void SignalError(Promise.HandlerDescriptor handler, Exception error) { - m_context.Post(x => base.SignalError(handler, error), null); - } - - protected override void SignalCancelled(Promise.HandlerDescriptor handler, Exception reason) { - m_context.Post(x => base.SignalCancelled(handler, reason), null); + protected override void SignalHandler(HandlerDescriptor handler, int signal) { + m_context.Post(x => base.SignalHandler(handler, signal), null); } } } diff --git a/MonoPlay/Program.cs b/MonoPlay/Program.cs --- a/MonoPlay/Program.cs +++ b/MonoPlay/Program.cs @@ -1,12 +1,5 @@ using System; -using Implab.Diagnostics; -using Implab.Parallels; using Implab; -using System.Collections.Generic; -using System.Collections.Concurrent; -using System.Threading; -using Implab.JSON; -using System.IO; using System.Threading.Tasks; namespace MonoPlay { @@ -27,7 +20,10 @@ namespace MonoPlay { } static IPromise DoItem(int x) { - return Promise.FromResult(x + 1); + //return Promise.FromResult(x + 1); + var p = new Promise(); + p.Resolve(x+1); + return p; } static async Task DoWork() {