diff --git a/data/etc/revpipyload/revpipyload.conf b/data/etc/revpipyload/revpipyload.conf index 8bc228d..723167f 100644 --- a/data/etc/revpipyload/revpipyload.conf +++ b/data/etc/revpipyload/revpipyload.conf @@ -8,7 +8,7 @@ plcuid = 1000 plcgid = 1000 plcslave = 0 pythonversion = 3 -rtlevel = 1 +rtlevel = 0 xmlrpc = 0 zeroonerror = 0 zeroonexit = 0 diff --git a/doc/proginit.html b/doc/proginit.html index 507669a..ecfaf75 100644 --- a/doc/proginit.html +++ b/doc/proginit.html @@ -23,6 +23,9 @@ Classes Functions + + + @@ -34,6 +37,24 @@ Functions
_setuprtKonfiguriert Programm fuer den RT-Scheduler.
_zeroprocimg Setzt Prozessabbild auf NULL.


+ +

_setuprt

+_setuprt(pid, evt_exit) +

+Konfiguriert Programm fuer den RT-Scheduler. +

+
pid
+
+PID, der angehoben werden soll +
+
+
Returns:
+
+None +
+
+
Up
+

_zeroprocimg

_zeroprocimg() diff --git a/eric-revpipyload.api b/eric-revpipyload.api index c8d612f..4b6b3ee 100644 --- a/eric-revpipyload.api +++ b/eric-revpipyload.api @@ -24,6 +24,7 @@ procimgserver.ProcimgServer.start?4() procimgserver.ProcimgServer.stop?4() procimgserver.ProcimgServer.values?4() procimgserver.ProcimgServer?1(xmlserver, aclmode) +proginit._setuprt?5(pid, evt_exit) proginit._zeroprocimg?5() proginit.cleanup?4() proginit.configure?4() diff --git a/revpipyload.e4p b/revpipyload.e4p index 2c1556f..ae748b5 100644 --- a/revpipyload.e4p +++ b/revpipyload.e4p @@ -1,7 +1,7 @@ - + en_US @@ -9,7 +9,7 @@ Python3 Console Dieser Loader wird über das Init-System geladen und führt das angegebene Pythonprogramm aus. Es ist für den RevolutionPi gedacht um automatisch das SPS-Programm zu starten. - 0.4.3 + 0.4.6 Sven Sager akira@narux.de diff --git a/revpipyload/plcsystem.py b/revpipyload/plcsystem.py index d2a0037..eb8b867 100644 --- a/revpipyload/plcsystem.py +++ b/revpipyload/plcsystem.py @@ -11,6 +11,7 @@ import proginit import shlex import subprocess from logsystem import PipeLogwriter +from proginit import _setuprt from sys import stdout as sysstdout from threading import Event, Thread from time import sleep, asctime @@ -41,7 +42,7 @@ class RevPiPlc(Thread): self.exitcode = None self.gid = 65534 self.uid = 65534 - self.rtlevel = 1 + self.rtlevel = 0 self.zeroonerror = False self.zeroonexit = False @@ -104,8 +105,16 @@ class RevPiPlc(Thread): """Fuehrt PLC-Programm aus und ueberwacht es.""" proginit.logger.debug("enter RevPiPlc.run()") + # LogWriter starten und Logausgaben schreiben + if self._plw is not None: + self._plw.logline("-" * 55) + self._plw.logline("plc: {} started: {}".format( + os.path.basename(self._program), asctime() + )) + self._plw.start() + # Befehlstliste aufbauen - lst_proc = shlex.split("/usr/bin/env {} -OO -u {} {}".format( + lst_proc = shlex.split("/usr/bin/env {} -u {} {}".format( "python2" if self._pversion == 2 else "python3", self._program, self._arguments @@ -115,29 +124,13 @@ class RevPiPlc(Thread): proginit.logger.info("start plc program {}".format(self._program)) self._procplc = self._spopen(lst_proc) - # RealTime Scheduler nutzen - if self.rtlevel > 0 and self._procplc.poll() is None: - proginit.logger.info( - "set scheduler profile of pid {}".format(self._procplc.pid) - ) - ec = os.system("/usr/bin/env chrt -p {} {}".format( - 20 if self.rtlevel == 2 else 1, - self._procplc.pid - )) - if ec != 0: - proginit.logger.error( - "could not set scheduler profile of pid {}" - "".format(self._procplc.pid) - ) - - # LogWriter starten und Logausgaben schreiben - if self._plw is not None: - self._plw.logline("-" * 55) - self._plw.logline("plc: {} started: {}".format( - os.path.basename(self._program), asctime() - )) - self._plw.start() + # RealTime Scheduler nutzen nach 5 Sekunden Programmvorlauf + if self.rtlevel > 0 \ + and not self._evt_exit.wait(5) \ + and self._procplc.poll() is None: + _setuprt(self._procplc.pid, self._evt_exit) + # Überwachung starten while not self._evt_exit.is_set(): # Auswerten @@ -179,7 +172,7 @@ class RevPiPlc(Thread): else: break - self._evt_exit.wait(1) + self._evt_exit.wait(0.5) if self._plw is not None: self._plw.logline("-" * 55) diff --git a/revpipyload/proginit.py b/revpipyload/proginit.py index 0110be3..fe0b69e 100644 --- a/revpipyload/proginit.py +++ b/revpipyload/proginit.py @@ -10,6 +10,7 @@ import logging import os import sys from argparse import ArgumentParser +from subprocess import Popen, PIPE forked = False globalconffile = None @@ -22,6 +23,99 @@ rapcatalog = None startdir = None +def _setuprt(pid, evt_exit): + """Konfiguriert Programm fuer den RT-Scheduler. + @param pid PID, der angehoben werden soll + @return None""" + if logger is not None: + logger.debug("enter _setuprt()") + + dict_change = { + "ksoftirqd/0,ksoftirqd/1,ksoftirqd/2,ksoftirqd/3": 10, + "ktimersoftd/0,ktimersoftd/1,ktimersoftd/2,ktimersoftd/3": 20 + } + + for ps_change in dict_change: + # pid und prio ermitteln + kpidps = Popen([ + "/bin/ps", "-o", "pid=,rtprio=", "-C", ps_change + ], bufsize=1, stdout=PIPE) + + # Timeout nachbilden da in Python 3.2 nicht vorhanden + count = 10 + while kpidps.poll() is None: + count -= 1 + if count == 0: + kpidps.kill() + if logger is not None: + logger.error( + "ps timeout to get rt prio info - no rt active" + ) + return None + + evt_exit.wait(0.5) + if evt_exit.is_set(): + return None + + try: + kpiddat = kpidps.communicate()[0] + lst_kpids = kpiddat.split() + except: + kpidps.kill() + if logger is not None: + logger.error( + "can not get pid and prio - no rt active" + ) + return None + + while len(lst_kpids) > 0: + # Elemente paarweise übernehmen + kpid = lst_kpids.pop(0) + kprio = lst_kpids.pop(0) + + # Daten prüfen + if not kpid.isdigit(): + if logger is not None: + logger.error( + "pid={} and prio={} are not valid - no rt active" + "".format(kpid, kprio) + ) + return None + kpid = int(kpid) + + # RTPrio ermitteln + if kprio.isdigit(): + kprio = int(kprio) + else: + kprio = 0 + + if kprio < 10: + # Profile anpassen + ec = os.system("/usr/bin/env chrt -fp {} {}".format( + dict_change[ps_change], kpid + )) + if ec != 0: + if logger is not None: + logger.error( + "could not adjust scheduler - no rt active" + ) + return None + + # SCHED_RR für pid setzen + if logger is not None: + logger.info("set scheduler profile of pid {}".format(pid)) + + ec = os.system("/usr/bin/env chrt -p 1 {}".format(pid)) + if ec != 0 and logger is not None: + logger.error( + "could not set scheduler profile of pid {}" + "".format(pid) + ) + + if logger is not None: + logger.debug("leave _setuprt()") + + def _zeroprocimg(): """Setzt Prozessabbild auf NULL.""" procimg = "/dev/piControl0" if pargs is None else pargs.procimg diff --git a/revpipyload/revpipyload.py b/revpipyload/revpipyload.py index 8703150..d7ae316 100755 --- a/revpipyload/revpipyload.py +++ b/revpipyload/revpipyload.py @@ -49,7 +49,7 @@ from time import asctime from xmlrpc.client import Binary from xmlrpc.server import SimpleXMLRPCServer -pyloadversion = "0.4.5" +pyloadversion = "0.4.6" class RevPiPyLoad(): @@ -124,7 +124,7 @@ class RevPiPyLoad(): self.pythonver = \ int(self.globalconfig["DEFAULT"].get("pythonversion", 3)) self.rtlevel = \ - int(self.globalconfig["DEFAULT"].get("rtlevel", 1)) + int(self.globalconfig["DEFAULT"].get("rtlevel", 0)) self.xmlrpc = \ int(self.globalconfig["DEFAULT"].get("xmlrpc", 0)) self.zeroonerror = \ @@ -133,6 +133,10 @@ class RevPiPyLoad(): int(self.globalconfig["DEFAULT"].get("zeroonexit", 1)) # Workdirectory wechseln + if not os.access(self.plcworkdir, os.R_OK | os.W_OK | os.X_OK): + raise ValueError( + "can not access plcworkdir '{}'".format(self.plcworkdir) + ) os.chdir(self.plcworkdir) # PLC Thread konfigurieren @@ -569,7 +573,7 @@ class RevPiPyLoad(): "plcarguments": ".*", "plcslave": "[01]", "pythonversion": "[23]", - "rtlevel": "[0-2]", + "rtlevel": "[0-1]", "xmlrpc": "[0-3]", "zeroonerror": "[01]", "zeroonexit": "[01]" diff --git a/setup.py b/setup.py index 37cae22..536fe7e 100644 --- a/setup.py +++ b/setup.py @@ -27,7 +27,7 @@ setup( license="LGPLv3", name="revpipyload", - version="0.4.5", + version="0.4.6", scripts=["data/revpipyload"],