From a650ff5c78c56ccf6f8cb0cf202c121eb40c82db Mon Sep 17 00:00:00 2001 From: Martin Regen Date: Fri, 4 Nov 2016 16:04:52 +0100 Subject: [PATCH 1/6] improve autostart of boilers by using the state machine start call --- .../Opc.Ua.Sample/Boiler/BoilerNodeManager.cs | 18 +++++++++++++----- .../Opc.Ua.Sample/Boiler/BoilerState.cs | 2 +- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/SampleApplications/Samples/Opc.Ua.Sample/Boiler/BoilerNodeManager.cs b/SampleApplications/Samples/Opc.Ua.Sample/Boiler/BoilerNodeManager.cs index 7adeefe3e8..c2e3c53a2b 100644 --- a/SampleApplications/Samples/Opc.Ua.Sample/Boiler/BoilerNodeManager.cs +++ b/SampleApplications/Samples/Opc.Ua.Sample/Boiler/BoilerNodeManager.cs @@ -132,8 +132,12 @@ namespace Boiler AddPredefinedNode(context, boiler); - // Autostart boiler simulation - boiler.OnControlSimulation(context, null, 0, Opc.Ua.Methods.ProgramStateMachineType_Start, null, null); + // Autostart boiler simulation state machine + MethodState start = boiler.Simulation.Start; + IList inputArguments = new List(); + IList outputArguments = new List(); + List errors = new List(); + start.Call(context, boiler.NodeId, inputArguments, errors, outputArguments); } @@ -203,15 +207,19 @@ namespace Boiler BoilerState activeNode = new BoilerState(passiveNode.Parent); activeNode.Create(context, passiveNode); - // Autostart boiler simulation - activeNode.OnControlSimulation(context, null, 0, Opc.Ua.Methods.ProgramStateMachineType_Start, null, null); - // replace the node in the parent. if (passiveNode.Parent != null) { passiveNode.Parent.ReplaceChild(context, activeNode); } + // Autostart boiler simulation state machine + MethodState start = activeNode.Simulation.Start; + IList inputArguments = new List(); + IList outputArguments = new List(); + List errors = new List(); + start.Call(context, activeNode.NodeId, inputArguments, errors, outputArguments); + return activeNode; } } diff --git a/SampleApplications/Samples/Opc.Ua.Sample/Boiler/BoilerState.cs b/SampleApplications/Samples/Opc.Ua.Sample/Boiler/BoilerState.cs index 1c7c37fb7e..1afd4dcbf3 100644 --- a/SampleApplications/Samples/Opc.Ua.Sample/Boiler/BoilerState.cs +++ b/SampleApplications/Samples/Opc.Ua.Sample/Boiler/BoilerState.cs @@ -71,7 +71,7 @@ namespace Boiler /// /// Changes the state of the simulation. /// - public ServiceResult OnControlSimulation( + private ServiceResult OnControlSimulation( ISystemContext context, StateMachineState machine, uint transitionId, From d49eca0ae3687f84fe20aed2c95d1b157145bbbe Mon Sep 17 00:00:00 2001 From: Martin Regen Date: Mon, 7 Nov 2016 11:28:27 +0100 Subject: [PATCH 2/6] fix threading issues in console publisher --- .../NetCoreConsolePublisher/AmqpConnection.cs | 61 +++++- .../Opc.Ua.Publisher.Endpoints.xml | 18 +- .../Opc.Ua.Publisher.config.xml | 8 +- .../NetCoreConsolePublisher/Program.cs | 188 ++++++++++-------- 4 files changed, 162 insertions(+), 113 deletions(-) diff --git a/SampleApplications/Samples/NetCoreConsolePublisher/AmqpConnection.cs b/SampleApplications/Samples/NetCoreConsolePublisher/AmqpConnection.cs index a3edd4e6f1..f7923b88ba 100644 --- a/SampleApplications/Samples/NetCoreConsolePublisher/AmqpConnection.cs +++ b/SampleApplications/Samples/NetCoreConsolePublisher/AmqpConnection.cs @@ -75,12 +75,14 @@ namespace Opc.Ua.Publisher private Connection m_connection; private Session m_session; private SenderLink m_link; - private Queue> messages; + private LinkedList> messages; private DateTime m_currentExpiryTime; private Timer m_tokenRenewalTimer; private bool m_closed; private int m_counter; + private object m_sending; + private int m_sendallthreads; #endregion @@ -108,7 +110,13 @@ namespace Opc.Ua.Publisher /// private void Initialize() { - messages = new Queue>(); + m_connection = null; + m_session = null; + m_link = null; + m_closed = true; + m_sending = new object(); + m_sendallthreads = 0; + messages = new LinkedList>(); } #endregion @@ -156,7 +164,7 @@ namespace Opc.Ua.Publisher { lock (messages) { - messages.Enqueue(body); + messages.AddLast(body); } if (IsClosed()) @@ -175,16 +183,40 @@ namespace Opc.Ua.Publisher /// protected void SendAll() { + // make sure only one send all task is active + if (Interlocked.Increment(ref m_sendallthreads) != 1) + { + Interlocked.Decrement(ref m_sendallthreads); + return; + } + try { - lock (messages) + + while (!IsClosed()) { - while (!IsClosed() && messages.Count != 0) + ArraySegment onemessage; + lock (messages) { - bool sent = SendOne(messages.Peek()); - if (sent) + if (messages.Count == 0) { - messages.Dequeue(); + break; + } + onemessage = messages.First.Value; + messages.RemoveFirst(); + } + + bool sent; + lock (m_sending) + { + sent = SendOne(onemessage); + } + + if (!sent) + { + lock (messages) + { + messages.AddFirst(onemessage); } } } @@ -193,6 +225,10 @@ namespace Opc.Ua.Publisher { Close(); } + finally + { + Interlocked.Decrement(ref m_sendallthreads); + } } /// @@ -360,7 +396,10 @@ namespace Opc.Ua.Publisher } // Ensure we have a token - await RenewTokenAsync(GenerateSharedAccessToken()); + lock (m_sending) + { + RenewTokenAsync(GenerateSharedAccessToken()).Wait(); + } // then start the periodic renewal int interval = (int)(TokenLifetime * 0.8); @@ -442,12 +481,12 @@ namespace Opc.Ua.Publisher { try { - lock (messages) + lock (m_sending) { bool result = RenewTokenAsync(GenerateSharedAccessToken()).Wait(60000); if (!result) { - Utils.Trace( "Unexpected timeout error renewing token."); + Utils.Trace("Unexpected timeout error renewing token."); } } } diff --git a/SampleApplications/Samples/NetCoreConsolePublisher/Opc.Ua.Publisher.Endpoints.xml b/SampleApplications/Samples/NetCoreConsolePublisher/Opc.Ua.Publisher.Endpoints.xml index a828504cf2..a73d2d3093 100644 --- a/SampleApplications/Samples/NetCoreConsolePublisher/Opc.Ua.Publisher.Endpoints.xml +++ b/SampleApplications/Samples/NetCoreConsolePublisher/Opc.Ua.Publisher.Endpoints.xml @@ -7,23 +7,7 @@ - opc.tcp://localhost:61210/UA/SampleClient - SignAndEncrypt_3 - http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15 - - - Anonymous_0 - - - http://opcfoundation.org/UA/profiles/transport/wsxmlorbinary - 0 - - true - 0 - - - - opc.tcp://192.168.2.101:51210/UA/SampleServer + opc.tcp://localhost:61410/UA/SampleClient SignAndEncrypt_3 http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15 diff --git a/SampleApplications/Samples/NetCoreConsolePublisher/Opc.Ua.Publisher.config.xml b/SampleApplications/Samples/NetCoreConsolePublisher/Opc.Ua.Publisher.config.xml index 586cead167..06724f0c7e 100644 --- a/SampleApplications/Samples/NetCoreConsolePublisher/Opc.Ua.Publisher.config.xml +++ b/SampleApplications/Samples/NetCoreConsolePublisher/Opc.Ua.Publisher.config.xml @@ -91,6 +91,10 @@ OPC Foundation/CertificateStores/RejectedCertificates + + true + @@ -143,8 +147,8 @@ For example, a URL used for an endpoint which uses the Basic256 security policy would look like this: http://localhost:61211/UA/SampleClient/Basic256 --> - opc.tcp://localhost:61210/UA/SampleClient - https://localhost:61212/UA/SampleClient/ + opc.tcp://localhost:61410/UA/SampleClient + https://localhost:61412/UA/SampleClient/ - opc.tcp://localhost:61410/UA/SampleClient - https://localhost:61412/UA/SampleClient/ + opc.tcp://localhost:61410/UA/Publisher + https://localhost:61412/UA/Publisher/ - opc.tcp://localhost:61210/UA/Publisher - https://localhost:61212/UA/Publisher/ + opc.tcp://localhost:61410/UA/Publisher + https://localhost:61412/UA/Publisher/ - opc.tcp://localhost:61210/UA/Publisher - https://localhost:61212/UA/Publisher/ + opc.tcp://localhost:61410/UA/Publisher + https://localhost:61412/UA/Publisher/