private void threadSpinCore() { // For Erlang I/O protocol see: // http://erlang.org/doc/apps/stdlib/io_protocol.html var patterns = new ErlPatternMatcher { { "{'$gen_call', {~v::pid(), ~v::ref()}, {call, ~v::atom(), ~v::atom(), ~v::list(), ~v}}".ErlArgs(P, R, M, F, A, G), (_p, _t, b, a) => rpcCall( b.Cast <ErlPid>(P), b.Cast <ErlRef>(R), b.Cast <ErlAtom>(M), b.Cast <ErlAtom>(F), b.Cast <ErlList>(A), b[G]) }, { "{'$gen_cast', {cast, ~v::atom(), ~v::atom(), ~v::list(), ~v}}".ErlArgs(M, F, A, G), (_p, _t, b, a) => rpcCall( ErlPid.Null, ErlRef.Null, b.Cast <ErlAtom>(M), b.Cast <ErlAtom>(F), b.Cast <ErlList>(A), b[G]) }, { "{_, {~v::pid(), ~v::ref()}, _Cmd}".ErlArgs(P, R), (_p, _t, b, a) => ErlTuple.Create(b[P], b[R], ErlTuple.Create(ConstAtoms.Error, ConstAtoms.Unsupported)) }, }; while (m_Active) { Tuple <IErlObject, int> res = Self.ReceiveMatch(patterns, 1500); switch (res.Item2) { case -2: /* timeout */ break; case -1: /* no match */ App.Log.Write(Log.MessageType.Warning, StringConsts.ERL_INVALID_RPC_REQUEST_ERROR, res.Item1.ToString()); break; default: if (res.Item1 == null) { break; } var t = (ErlTuple)res.Item1; var pid = t.Cast <ErlPid>(0); var eref = t.Cast <ErlRef>(1); var reply = t[2]; sendRpcReply(pid, eref, reply); break; } } App.Log.Write( Log.MessageType.Info, StringConsts.ERL_STOPPING_SERVER.Args(Node.NodeName, "RPC")); m_Thread = null; }
private IErlObject ioProcessRequests( ErlPatternMatcher pm, ErlList requests, IErlObject replyAs) { foreach (var r in requests) { IErlObject term = r; if (pm.Match(ref term, replyAs) < 0) { return(term); } } return(s_ReplyPattern.Subst( new ErlVarBind { { RA, replyAs }, { R, (IErlObject)Tuple.Create(ConstAtoms.Error, ConstAtoms.Request) } })); }
public void ErlPatternMatchCollectionTest() { var state = new KVP(); var pm = new ErlPatternMatcher { { 0, "{A::integer(), stop}", (_ctx, p, t, b, _args) => { state = new KVP(p, b); return(t); } }, { "{A::integer(), status}", (p, t, b, _args) => { state = new KVP(p, b); return(t); } }, { 1, "{A::integer(), {status, B::atom()}}", (_ctx, p, t, b, _args) => { state = new KVP(p, b); return(t); } }, { "{A::integer(), {config, B::list()}}", (p, t, b, _args) => { state = new KVP(p, b); return(t); } } }; var term = ErlObject.Parse("{10, stop}"); Assert.AreEqual(1, pm.Match(ref term)); Assert.AreEqual(10, state.Value["A"].ValueAsInt); term = ErlObject.Parse("{11, status}"); Assert.AreEqual(2, pm.Match(ref term)); Assert.AreEqual(11, state.Value["A"].ValueAsInt); term = ErlObject.Parse("{12, {status, ~w}}", new ErlAtom("a")); Assert.AreEqual(3, pm.Match(ref term)); Assert.AreEqual(12, state.Value["A"].ValueAsInt); Assert.AreEqual("a", state.Value["B"].ValueAsString); term = ErlObject.Parse("{13, {config, ~w}}", new ErlList()); Assert.AreEqual(4, pm.Match(ref term)); Assert.AreEqual(13, state.Value["A"].ValueAsInt); Assert.AreEqual(0, (state.Value["B"] as ErlList).Count); term = ErlObject.Parse("{10, exit}"); Assert.AreEqual(-1, pm.Match(ref term)); var pts = pm.PatternsToString; Assert.AreEqual( "[{A::int(),stop},{A::int(),status},{A::int(),{status,B::atom()}},{A::int(),{config,B::list()}}]", pts); }
/// <summary> /// Receive a message and match it against a given pattern /// </summary> /// <param name="pm">Patterns to match the message against</param> /// <param name="timeoutMsec">Timeout in milliseconds</param> /// <returns>Return a tuple containing the received message and index of the /// pattern in the pm instance that was successfully matched. /// On timeout the 2nd element of the tuple is -2 and 1st element of the tuple is null. /// On unsuccessful match the second element of the tuple is -1</returns> public Tuple<IErlObject, int> ReceiveMatch(ErlPatternMatcher pm, int timeoutMsec = -1) { var m = Receive(timeoutMsec); if (m == null) return Tuple.Create<IErlObject, int>(null, -2); int n = pm.Match(ref m); return Tuple.Create(m, n); }
private void start(object obj) { // For Erlang I/O protocol see: // http://erlang.org/doc/apps/stdlib/io_protocol.html var patterns = new ErlPatternMatcher { {"{'$gen_call', {~v::pid(), ~v::ref()}, {call, ~v::atom(), ~v::atom(), ~v::list(), ~v}}".ErlArgs(P,R,M,F,A,G), (_p, _t, b, a) => rpcCall( b.Cast<ErlPid>(P), b.Cast<ErlRef>(R), b.Cast<ErlAtom>(M), b.Cast<ErlAtom>(F), b.Cast<ErlList>(A), b[G]) }, {"{'$gen_cast', {cast, ~v::atom(), ~v::atom(), ~v::list(), ~v}}".ErlArgs(M,F,A,G), (_p, _t, b, a) => rpcCall( ErlPid.Null, ErlRef.Null, b.Cast<ErlAtom>(M), b.Cast<ErlAtom>(F), b.Cast<ErlList>(A), b[G]) }, {"{_, {~v::pid(), ~v::ref()}, _Cmd}".ErlArgs(P,R), (_p, _t, b, a) => ErlTuple.Create(b[P], b[R], ErlTuple.Create(ConstAtoms.Error, ConstAtoms.Unsupported)) }, }; while (m_Active) { Tuple<IErlObject, int> res = Self.ReceiveMatch(patterns, 1500); switch (res.Item2) { case -2: /* timeout */ break; case -1: /* no match */ App.Log.Write(Log.MessageType.Warning, StringConsts.ERL_INVALID_RPC_REQUEST_ERROR, res.Item1.ToString()); break; default: if (res.Item1 == null) break; var t = (ErlTuple)res.Item1; var pid = t.Cast<ErlPid>(0); var eref = t.Cast<ErlRef>(1); var reply = t[2]; sendRpcReply(pid, eref, reply); break; } } App.Log.Write( Log.MessageType.Info, StringConsts.ERL_STOPPING_SERVER.Args(Node.NodeName, "RPC")); m_Thread = null; }
private void threadSpinCore() { // For Erlang I/O protocol see: // http://erlang.org/doc/apps/stdlib/io_protocol.html var patterns = new ErlPatternMatcher { {"{put_chars, ~v::atom(), ~v::string()}".ErlArgs(E, C), (_p, _t, b, a) => ioProcessPutChars( b.Cast<ErlAtom>(E), b.Cast<ErlString>(C), (IErlObject)a[1]) }, {"{put_chars, ~v::atom(), ~v::atom(), ~v::atom(), ~v::list()}".ErlArgs(E,M,F,A), (_p, _t, b, a) => ioProcessPutChars( b.Cast<ErlAtom>(E), b.Cast<ErlAtom>(M), b.Cast<ErlAtom>(F), b.Cast<ErlList>(A), (IErlObject)a[1]) }, {"{put_chars, ~v::string()}".ErlArgs(C), (_p, _t, b, a) => ioProcessPutChars( ConstAtoms.Latin1, b.Cast<ErlString>(C), (IErlObject)a[1]) }, {"{put_chars, ~v::atom(), ~v::atom(), ~v::list()}".ErlArgs(M,F,A), (_p, _t, b, a) => ioProcessPutChars( ConstAtoms.Latin1, b.Cast<ErlAtom>(M), b.Cast<ErlAtom>(F), b.Cast<ErlList>(A), (IErlObject)a[1]) }, {"{get_until, ~v::atom(), ~v, ~v::atom(), ~v::atom(), ~v::list()}".ErlArgs(E,P,M,F,A), (_p, _t, b, a) => ioProcessGetUntil( b.Cast<ErlAtom>(E), b[P], b.Cast<ErlAtom>(M), b.Cast<ErlAtom>(F), b.Cast<ErlList>(A), (IErlObject)a[1]) }, {"{get_chars, ~v::atom(), ~v, ~v::integer()}".ErlArgs(E,P,N), (_p, _t, b, a) => ioProcessGetChars( b.Cast<ErlAtom>(E), b[P], b.Cast<ErlLong>(N), (IErlObject)a[1]) }, {"{get_line, ~v::atom(), ~v}".ErlArgs(E,P), (_p, _t, b, a) => ioProcessGetLine( b.Cast<ErlAtom>(E), b[P], (IErlObject)a[1]) }, {"{get_until, ~v, ~v::atom(), ~v::atom(), ~v::list()}".ErlArgs(P,M,F,A), (_p, _t, b, a) => ioProcessGetUntil( ConstAtoms.Latin1, b[P], b.Cast<ErlAtom>(M), b.Cast<ErlAtom>(F), b.Cast<ErlList>(A), (IErlObject)a[1]) }, {"{get_chars, ~v, ~v::integer()}".ErlArgs(P,N), (_p, _t, b, a) => ioProcessGetChars( ConstAtoms.Latin1, b[P], b.Cast<ErlLong>(N), (IErlObject)a[1]) }, {"{get_line, ~v}".ErlArgs(P), (_p, _t, b, a) => ioProcessGetLine( ConstAtoms.Latin1, b[P], (IErlObject)a[1]) }, {"{requests, ~v::list()}".ErlArgs(R), (_p, _t, b, a) => ioProcessRequests( (ErlPatternMatcher)a[0], b.Cast<ErlList>(R), (IErlObject)a[1]) }, }; while (m_Active) { Tuple<IErlObject, ErlVarBind> res = Node.GroupLeader.ReceiveMatch(s_RequestPattern, 1500); if (res.Item1 == null) // Timeout continue; else if (res.Item2 == null) // No match App.Log.Write(Log.MessageType.Error, StringConsts.ERL_INVALID_IO_REQUEST + res.Item1.ToString(), from: GetType().Name); var from = res.Item2.Cast<ErlPid>(F); var replyAs = res.Item2[RA]; var request = res.Item2.Cast<ErlTuple>(R); var req = (IErlObject)request; if (patterns.Match(ref req, patterns, replyAs) >= 0) { Node.Send(from, req); continue; } var reply = s_ReplyPattern.Subst(new ErlVarBind { { RA, replyAs }, { R, ConstAtoms.Request } }); Debug.Assert(reply != null); Node.Send(from, reply); } App.Log.Write(Log.MessageType.Info, StringConsts.ERL_STOPPING_SERVER.Args(Node.NodeLongName, "I/O")); m_Thread = null; }
private IErlObject ioProcessRequests( ErlPatternMatcher pm, ErlList requests, IErlObject replyAs) { foreach (var r in requests) { IErlObject term = r; if (pm.Match(ref term, replyAs) < 0) return term; } return s_ReplyPattern.Subst( new ErlVarBind{ {RA, replyAs}, {R, (IErlObject)Tuple.Create(ConstAtoms.Error, ConstAtoms.Request) }}); }
private void startIO(object obj) { // For Erlang I/O protocol see: // http://erlang.org/doc/apps/stdlib/io_protocol.html var patterns = new ErlPatternMatcher { { "{put_chars, ~v::atom(), ~v::string()}".ErlArgs(E, C), (_p, _t, b, a) => ioProcessPutChars( b.Cast <ErlAtom>(E), b.Cast <ErlString>(C), (IErlObject)a[1]) }, { "{put_chars, ~v::atom(), ~v::atom(), ~v::atom(), ~v::list()}".ErlArgs(E, M, F, A), (_p, _t, b, a) => ioProcessPutChars( b.Cast <ErlAtom>(E), b.Cast <ErlAtom>(M), b.Cast <ErlAtom>(F), b.Cast <ErlList>(A), (IErlObject)a[1]) }, { "{put_chars, ~v::string()}".ErlArgs(C), (_p, _t, b, a) => ioProcessPutChars( ConstAtoms.Latin1, b.Cast <ErlString>(C), (IErlObject)a[1]) }, { "{put_chars, ~v::atom(), ~v::atom(), ~v::list()}".ErlArgs(M, F, A), (_p, _t, b, a) => ioProcessPutChars( ConstAtoms.Latin1, b.Cast <ErlAtom>(M), b.Cast <ErlAtom>(F), b.Cast <ErlList>(A), (IErlObject)a[1]) }, { "{get_until, ~v::atom(), ~v, ~v::atom(), ~v::atom(), ~v::list()}".ErlArgs(E, P, M, F, A), (_p, _t, b, a) => ioProcessGetUntil( b.Cast <ErlAtom>(E), b[P], b.Cast <ErlAtom>(M), b.Cast <ErlAtom>(F), b.Cast <ErlList>(A), (IErlObject)a[1]) }, { "{get_chars, ~v::atom(), ~v, ~v::integer()}".ErlArgs(E, P, N), (_p, _t, b, a) => ioProcessGetChars( b.Cast <ErlAtom>(E), b[P], b.Cast <ErlLong>(N), (IErlObject)a[1]) }, { "{get_line, ~v::atom(), ~v}".ErlArgs(E, P), (_p, _t, b, a) => ioProcessGetLine( b.Cast <ErlAtom>(E), b[P], (IErlObject)a[1]) }, { "{get_until, ~v, ~v::atom(), ~v::atom(), ~v::list()}".ErlArgs(P, M, F, A), (_p, _t, b, a) => ioProcessGetUntil( ConstAtoms.Latin1, b[P], b.Cast <ErlAtom>(M), b.Cast <ErlAtom>(F), b.Cast <ErlList>(A), (IErlObject)a[1]) }, { "{get_chars, ~v, ~v::integer()}".ErlArgs(P, N), (_p, _t, b, a) => ioProcessGetChars( ConstAtoms.Latin1, b[P], b.Cast <ErlLong>(N), (IErlObject)a[1]) }, { "{get_line, ~v}".ErlArgs(P), (_p, _t, b, a) => ioProcessGetLine( ConstAtoms.Latin1, b[P], (IErlObject)a[1]) }, { "{requests, ~v::list()}".ErlArgs(R), (_p, _t, b, a) => ioProcessRequests( (ErlPatternMatcher)a[0], b.Cast <ErlList>(R), (IErlObject)a[1]) }, }; while (m_Active) { Tuple <IErlObject, ErlVarBind> res = Node.GroupLeader.ReceiveMatch(s_RequestPattern, 1500); if (res.Item1 == null) // Timeout { continue; } else if (res.Item2 == null) // No match { App.Log.Write(Log.MessageType.Error, StringConsts.ERL_INVALID_IO_REQUEST + res.Item1.ToString(), from: GetType().Name); } var from = res.Item2.Cast <ErlPid>(F); var replyAs = res.Item2[RA]; var request = res.Item2.Cast <ErlTuple>(R); var req = (IErlObject)request; if (patterns.Match(ref req, patterns, replyAs) >= 0) { Node.Send(from, req); continue; } var reply = s_ReplyPattern.Subst(new ErlVarBind { { RA, replyAs }, { R, ConstAtoms.Request } }); Debug.Assert(reply != null); Node.Send(from, reply); } App.Log.Write(Log.MessageType.Info, StringConsts.ERL_STOPPING_SERVER.Args(Node.NodeLongName, "I/O")); m_Thread = null; }