# HG changeset patch # User Edouard Tisserant # Date 1554808083 -7200 # Node ID adfdeaba5a6a0d2fc08cf6a21e878a651cfc5234 # Parent 8fb5c6eddc723baec392be98fe1969044539baee# Parent e172ab28d04e5522220d8168eda9e8583c160ab9 merge diff -r 8fb5c6eddc72 -r adfdeaba5a6a runtime/PLCObject.py --- 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 diff -r 8fb5c6eddc72 -r adfdeaba5a6a runtime/WampClient.py --- 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 diff -r 8fb5c6eddc72 -r adfdeaba5a6a runtime/__init__.py --- 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 + +