--- a/runtime/PLCObject.py Sun Apr 07 21:08:07 2019 +0200
+++ b/runtime/PLCObject.py Tue Apr 09 13:08:03 2019 +0200
@@ -23,7 +23,7 @@
from __future__ import absolute_import
-from threading import Thread, Lock, Semaphore, Event
+from threading import Thread, Lock, Event, Condition
import ctypes
import os
import sys
@@ -42,6 +42,7 @@
from runtime.Stunnel import getPSKID
from runtime import PlcStatus
from runtime import MainWorker
+from runtime import default_evaluator
if os.name in ("nt", "ce"):
dlopen = _ctypes.LoadLibrary
@@ -319,13 +320,16 @@
return False
- def PythonRuntimeCall(self, methodname):
+ def PythonRuntimeCall(self, methodname, use_evaluator=True):
"""
Calls init, start, stop or cleanup method provided by
runtime python files, loaded when new PLC uploaded
"""
for method in self.python_runtime_vars.get("_runtime_%s" % methodname, []):
- _res, exp = self.evaluator(method)
+ if use_evaluator:
+ _res, exp = self.evaluator(method)
+ else:
+ _res, exp = default_evaluator(method)
if exp is not None:
self.LogMessage(0, '\n'.join(traceback.format_exception(*exp)))
@@ -379,17 +383,25 @@
self.LogMessage(0, traceback.format_exc())
raise
- self.PythonRuntimeCall("init")
+ self.PythonRuntimeCall("init", use_evaluator=False)
+
+ self.PythonThreadCondLock = Lock()
+ self.PythonThreadCond = Condition(self.PythonThreadCondLock)
+ self.PythonThreadCmd = "Wait"
+ self.PythonThread = Thread(target=self.PythonThreadProc)
+ self.PythonThread.start()
+
# used internaly
def PythonRuntimeCleanup(self):
if self.python_runtime_vars is not None:
- self.PythonRuntimeCall("cleanup")
+ self.PythonThreadCommand("Finish")
+ self.PythonThread.join()
+ self.PythonRuntimeCall("cleanup", use_evaluator=False)
self.python_runtime_vars = None
- def PythonThreadProc(self):
- self.StartSem.release()
+ def PythonThreadLoop(self):
res, cmd, blkid = "None", "None", ctypes.c_void_p()
compile_cache = {}
while True:
@@ -415,6 +427,31 @@
res = "#EXCEPTION : "+str(e)
self.LogMessage(1, ('PyEval@0x%x(Code="%s") Exception "%s"') % (FBID, cmd, str(e)))
+ def PythonThreadProc(self):
+ while True:
+ self.PythonThreadCondLock.acquire()
+ cmd = self.PythonThreadCmd
+ while cmd == "Wait":
+ self.PythonThreadCond.wait()
+ cmd = self.PythonThreadCmd
+ self.PythonThreadCmd = "Wait"
+ self.PythonThreadCondLock.release()
+
+ if cmd == "Activate" :
+ self.PythonRuntimeCall("start")
+
+ self.PythonThreadLoop()
+
+ self.PythonRuntimeCall("stop")
+ else: # "Finish"
+ break
+
+ def PythonThreadCommand(self, cmd):
+ self.PythonThreadCondLock.acquire()
+ self.PythonThreadCmd = cmd
+ self.PythonThreadCond.notify()
+ self.PythonThreadCondLock.release()
+
@RunInMain
def StartPLC(self):
if self.CurrentPLCFilename is not None and self.PLCStatus == PlcStatus.Stopped:
@@ -423,11 +460,7 @@
if res == 0:
self.PLCStatus = PlcStatus.Started
self.StatusChange()
- self.PythonRuntimeCall("start")
- self.StartSem = Semaphore(0)
- self.PythonThread = Thread(target=self.PythonThreadProc)
- self.PythonThread.start()
- self.StartSem.acquire()
+ self.PythonThreadCommand("Activate")
self.LogMessage("PLC started")
else:
self.LogMessage(0, _("Problem starting PLC : error %d" % res))
@@ -439,10 +472,8 @@
if self.PLCStatus == PlcStatus.Started:
self.LogMessage("PLC stopped")
self._stopPLC()
- self.PythonThread.join()
self.PLCStatus = PlcStatus.Stopped
self.StatusChange()
- self.PythonRuntimeCall("stop")
if self.TraceThread is not None:
self.TraceThread.join()
self.TraceThread = None
--- a/runtime/WampClient.py Sun Apr 07 21:08:07 2019 +0200
+++ b/runtime/WampClient.py Tue Apr 09 13:08:03 2019 +0200
@@ -28,7 +28,7 @@
import json
import os
import re
-from builtins import str as text
+from six import text_type as text
from autobahn.twisted import wamp
from autobahn.twisted.websocket import WampWebSocketClientFactory, connectWS
from autobahn.wamp import types, auth
--- a/runtime/__init__.py Sun Apr 07 21:08:07 2019 +0200
+++ b/runtime/__init__.py Tue Apr 09 13:08:03 2019 +0200
@@ -30,3 +30,13 @@
global _PLCObjectSingleton
from runtime.PLCObject import PLCObject # noqa # pylint: disable=wrong-import-position
_PLCObjectSingleton = PLCObject(*args, **kwargs)
+
+
+def default_evaluator(tocall, *args, **kwargs):
+ try:
+ res = (tocall(*args, **kwargs), None)
+ except Exception:
+ res = (None, sys.exc_info())
+ return res
+
+