Merged fix_PLC_runtime_shutdown
authorEdouard Tisserant
Thu, 18 Apr 2019 14:42:23 +0200
changeset 2606 9944a18cad17
parent 2598 46df689dbc3b (current diff)
parent 2605 0615137bf515 (diff)
child 2607 bf0c1a40cf37
Merged fix_PLC_runtime_shutdown
--- a/Beremiz_service.py	Tue Apr 16 14:45:41 2019 +0200
+++ b/Beremiz_service.py	Thu Apr 18 14:42:23 2019 +0200
@@ -532,7 +532,8 @@
 pyro_thread_started = Lock()
 pyro_thread_started.acquire()
 pyro_thread = Thread(target=pyroserver.PyroLoop,
-                     kwargs=dict(when_ready=pyro_thread_started.release))
+                     kwargs=dict(when_ready=pyro_thread_started.release),
+                     name="PyroThread")
 pyro_thread.start()
 
 # Wait for pyro thread to be effective
@@ -557,7 +558,7 @@
     else:
         ui_thread_target = app.MainLoop
 
-    ui_thread = Thread(target=ui_thread_target)
+    ui_thread = Thread(target=ui_thread_target, name="UIThread")
     ui_thread.start()
 
     # This order ui loop to unblock main thread when ready.
@@ -581,6 +582,7 @@
     pass
 
 pyroserver.Quit()
+pyro_thread.join()
 
 plcobj = runtime.GetPLCObjectSingleton()
 plcobj.StopPLC()
@@ -588,7 +590,9 @@
 
 if havetwisted:
     reactor.stop()
+    ui_thread.join()
 elif havewx:
     app.ExitMainLoop()
+    ui_thread.join()
 
 sys.exit(0)
--- a/ProjectController.py	Tue Apr 16 14:45:41 2019 +0200
+++ b/ProjectController.py	Thu Apr 18 14:42:23 2019 +0200
@@ -1446,13 +1446,13 @@
 
     def UpdateMethodsFromPLCStatus(self):
         updated = False
-        status = None
+        status = PlcStatus.Disconnected
         if self._connector is not None:
             PLCstatus = self._connector.GetPLCstatus()
             if PLCstatus is not None:
                 status, log_count = PLCstatus
                 self.UpdatePLCLog(log_count)
-        if status is None:
+        if status == PlcStatus.Disconnected:
             self._SetConnector(None, False)
             status = PlcStatus.Disconnected
         if self.previous_plcstate != status:
Binary file images/Repair.png has changed
--- a/runtime/PLCObject.py	Tue Apr 16 14:45:41 2019 +0200
+++ b/runtime/PLCObject.py	Thu Apr 18 14:42:23 2019 +0200
@@ -388,7 +388,7 @@
         self.PythonThreadCondLock = Lock()
         self.PythonThreadCond = Condition(self.PythonThreadCondLock)
         self.PythonThreadCmd = "Wait"
-        self.PythonThread = Thread(target=self.PythonThreadProc)
+        self.PythonThread = Thread(target=self.PythonThreadProc, name="PLCPythonThread")
         self.PythonThread.start()
 
     # used internaly
@@ -477,8 +477,14 @@
             return True
         return False
 
-    @RunInMain
     def GetPLCstatus(self):
+        try:
+            return self._GetPLCstatus()
+        except EOFError:
+            return (PlcStatus.Disconnected, None)
+
+    @RunInMain
+    def _GetPLCstatus(self):
         return self.PLCStatus, map(self.GetLogCount, xrange(LogLevelsCount))
 
     @RunInMain
@@ -645,7 +651,7 @@
     def _TracesSwap(self):
         self.LastSwapTrace = time()
         if self.TraceThread is None and self.PLCStatus == PlcStatus.Started:
-            self.TraceThread = Thread(target=self.TraceThreadProc)
+            self.TraceThread = Thread(target=self.TraceThreadProc, name="PLCTrace")
             self.TraceThread.start()
         self.TraceLock.acquire()
         Traces = self.Traces
--- a/runtime/PyroServer.py	Tue Apr 16 14:45:41 2019 +0200
+++ b/runtime/PyroServer.py	Thu Apr 18 14:42:23 2019 +0200
@@ -12,6 +12,7 @@
 from __future__ import absolute_import
 from __future__ import print_function
 import sys
+import os
 
 import Pyro
 import Pyro.core as pyro
@@ -27,6 +28,7 @@
         self.ip_addr = ip_addr
         self.port = port
         self.servicepublisher = None
+        self.piper, self.pipew = None, None
 
     def _to_be_published(self):
         return self.servicename is not None and \
@@ -60,8 +62,11 @@
             self.daemon.connect(pyro_obj, "PLCObject")
 
             when_ready()
-            self.daemon.requestLoop()
-            self.daemon.sock.close()
+            self.piper,self.pipew = os.pipe()
+            self.daemon.requestLoop(others=[self.piper], callback=lambda x:None)
+            self.piper, self.pipew = None, None
+            if hasattr(self,'sock'):
+                self.daemon.sock.close()
         self.Unpublish()
 
     def Restart(self):
@@ -70,6 +75,9 @@
     def Quit(self):
         self.continueloop = False
         self.daemon.shutdown(True)
+        self.daemon.closedown()
+        if self.pipew is not None:
+            os.write(self.pipew, "goodbye")
 
     def Publish(self):
         self.servicepublisher = ServicePublisher("PYRO")
--- a/runtime/Worker.py	Tue Apr 16 14:45:41 2019 +0200
+++ b/runtime/Worker.py	Thu Apr 18 14:42:23 2019 +0200
@@ -21,8 +21,9 @@
     def __init__(self, call, *args, **kwargs):
         self.job = (call, args, kwargs)
         self.result = None
-        self.success = False
+        self.success = None
         self.exc_info = None
+        self.enabled = False
 
     def do(self):
         """
@@ -67,9 +68,11 @@
         """
         self._threadID = _thread.get_ident()
         self.mutex.acquire()
+        self.enabled = True
         if args or kwargs:
             _job = job(*args, **kwargs)
             _job.do()
+            # _job.success can't be None after do()
             if not _job.success:
                 self.reraise(_job)
 
@@ -99,6 +102,9 @@
         else:
             # otherwise notify and wait for completion
             self.mutex.acquire()
+            if not self.enabled:
+                self.mutex.release()
+                raise EOFError("Worker is disabled")
 
             while self.job is not None:
                 self.free.wait()
@@ -110,6 +116,9 @@
             self.free.notify()
             self.mutex.release()
 
+        if _job.success is None:
+            raise EOFError("Worker job was interrupted")
+
         if _job.success:
             return _job.result
         else:
@@ -122,6 +131,8 @@
         # mark queue
         self._finish = True
         self.mutex.acquire()
+        self.enabled = False
         self.job = None
         self.todo.notify()
+        self.done.notify()
         self.mutex.release()