diff -r 2e38b5ec4753 -r d9175daf6522 runtime/PLCObject.py --- a/runtime/PLCObject.py Thu Aug 16 11:22:40 2018 +0200 +++ b/runtime/PLCObject.py Tue Aug 21 16:11:02 2018 +0200 @@ -23,7 +23,6 @@ from __future__ import absolute_import -import thread from threading import Thread, Lock, Semaphore, Event, Condition import ctypes import os @@ -31,10 +30,10 @@ import traceback from time import time import _ctypes # pylint: disable=wrong-import-order -import Pyro.core as pyro from runtime.typemapping import TypeTranslator from runtime.loglevels import LogLevelsDefault, LogLevelsCount +from runtime import MainWorker if os.name in ("nt", "ce"): dlopen = _ctypes.LoadLibrary @@ -61,107 +60,6 @@ sys.stdout.flush() -class job(object): - """ - job to be executed by a worker - """ - def __init__(self, call, *args, **kwargs): - self.job = (call, args, kwargs) - self.result = None - self.success = False - self.exc_info = None - - def do(self): - """ - do the job by executing the call, and deal with exceptions - """ - try: - call, args, kwargs = self.job - self.result = call(*args, **kwargs) - self.success = True - except Exception: - self.success = False - self.exc_info = sys.exc_info() - - -class worker(object): - """ - serialize main thread load/unload of PLC shared objects - """ - def __init__(self): - # Only one job at a time - self._finish = False - self._threadID = None - self.mutex = Lock() - self.todo = Condition(self.mutex) - self.done = Condition(self.mutex) - self.free = Condition(self.mutex) - self.job = None - - def runloop(self, *args, **kwargs): - """ - meant to be called by worker thread (blocking) - """ - self._threadID = thread.get_ident() - if args or kwargs: - job(*args, **kwargs).do() - # result is ignored - self.mutex.acquire() - while not self._finish: - self.todo.wait() - if self.job is not None: - self.job.do() - self.done.notify() - else: - self.free.notify() - self.mutex.release() - - def call(self, *args, **kwargs): - """ - creates a job, execute it in worker thread, and deliver result. - if job execution raise exception, re-raise same exception - meant to be called by non-worker threads, but this is accepted. - blocking until job done - """ - - _job = job(*args, **kwargs) - - if self._threadID == thread.get_ident() or self._threadID is None: - # if caller is worker thread execute immediately - _job.do() - else: - # otherwise notify and wait for completion - self.mutex.acquire() - - while self.job is not None: - self.free.wait() - - self.job = _job - self.todo.notify() - self.done.wait() - _job = self.job - self.job = None - self.mutex.release() - - if _job.success: - return _job.result - else: - raise _job.exc_info[0], _job.exc_info[1], _job.exc_info[2] - - def quit(self): - """ - unblocks main thread, and terminate execution of runloop() - """ - # mark queue - self._finish = True - self.mutex.acquire() - self.job = None - self.todo.notify() - self.mutex.release() - - -MainWorker = worker() - def RunInMain(func): def func_wrapper(*args, **kwargs): @@ -169,22 +67,19 @@ return func_wrapper -class PLCObject(pyro.ObjBase): - def __init__(self, server): - pyro.ObjBase.__init__(self) - self.evaluator = server.evaluator - self.argv = [server.workdir] + server.argv # force argv[0] to be "path" to exec... - self.workingdir = server.workdir +class PLCObject(object): + def __init__(self, WorkingDir, argv, statuschange, evaluator, pyruntimevars): + self.workingdir = WorkingDir + # FIXME : is argv of any use nowadays ? + self.argv = [WorkingDir] + argv # force argv[0] to be "path" to exec... + self.statuschange = statuschange + self.evaluator = evaluator + self.pyruntimevars = pyruntimevars self.PLCStatus = "Empty" self.PLClibraryHandle = None self.PLClibraryLock = Lock() - self.DummyIteratorLock = None # Creates fake C funcs proxies self._InitPLCStubCalls() - self.daemon = server.daemon - self.statuschange = server.statuschange - self.hmi_frame = None - self.pyruntimevars = server.pyruntimevars self._loading_error = None self.python_runtime_vars = None self.TraceThread = None @@ -192,7 +87,7 @@ self.Traces = [] # First task of worker -> no @RunInMain - def AutoLoad(self): + def AutoLoad(self, autostart): # Get the last transfered PLC try: self.CurrentPLCFilename = open( @@ -200,10 +95,15 @@ "r").read().strip() + lib_ext if self.LoadPLC(): self.PLCStatus = "Stopped" + if autostart: + self.StartPLC() + return except Exception: self.PLCStatus = "Empty" self.CurrentPLCFilename = None + self.StatusChange() + def StatusChange(self): if self.statuschange is not None: for callee in self.statuschange: