mirror of
https://github.com/naruxde/revpipyload.git
synced 2025-11-09 07:28:03 +01:00
Workdirectory prüfen vor dem Wechseln Optimierung -OO entfernt _setuprt(...) um ksoftirqd und ktimersoftd auf höhere Prioritäten zu ziehen Python PLC Programm kann max auf Prio RR 1 laufen
291 lines
8.3 KiB
Python
291 lines
8.3 KiB
Python
# -*- coding: utf-8 -*-
|
|
#
|
|
# RevPiPyLoad
|
|
#
|
|
# Webpage: https://revpimodio.org/revpipyplc/
|
|
# (c) Sven Sager, License: LGPLv3
|
|
#
|
|
"""Main functions of our program."""
|
|
import logging
|
|
import os
|
|
import sys
|
|
from argparse import ArgumentParser
|
|
from subprocess import Popen, PIPE
|
|
|
|
forked = False
|
|
globalconffile = None
|
|
logapp = "revpipyloadapp.log"
|
|
logplc = "revpipyload.log"
|
|
logger = None
|
|
pargs = None
|
|
picontrolreset = "/opt/KUNBUS/piControlReset"
|
|
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
|
|
if os.access(procimg, os.W_OK):
|
|
with open(procimg, "w+b", 0) as f:
|
|
f.write(bytes(4096))
|
|
else:
|
|
if logger is not None:
|
|
logger.error("zeroprocimg can not write to piControl device")
|
|
|
|
|
|
def cleanup():
|
|
"""Clean up program."""
|
|
# NOTE: Pidfile wirklich löschen?
|
|
if pargs is not None and pargs.daemon:
|
|
if os.path.exists("/var/run/revpipyload.pid"):
|
|
os.remove("/var/run/revpipyload.pid")
|
|
|
|
# Logging beenden
|
|
logging.shutdown()
|
|
|
|
# Dateihandler schließen
|
|
if pargs.daemon:
|
|
sys.stdout.close()
|
|
|
|
|
|
def configure():
|
|
"""Initialize general program functions."""
|
|
|
|
# Command arguments
|
|
parser = ArgumentParser(
|
|
description="RevolutionPi Python Loader"
|
|
)
|
|
parser.add_argument(
|
|
"-d", "--daemon", action="store_true", dest="daemon",
|
|
help="Run program as a daemon in background"
|
|
)
|
|
parser.add_argument(
|
|
"-c", "--conffile", dest="conffile",
|
|
default="revpipyload.conf",
|
|
help="Application configuration file"
|
|
)
|
|
parser.add_argument(
|
|
"-f", "--logfile", dest="logfile",
|
|
help="Save log entries to this file"
|
|
)
|
|
parser.add_argument(
|
|
"--procimg", dest="procimg",
|
|
default="/dev/piControl0",
|
|
help="Path to process image"
|
|
)
|
|
parser.add_argument(
|
|
"--pictory", dest="configrsc",
|
|
help="piCtory file to use"
|
|
)
|
|
parser.add_argument(
|
|
"-v", "--verbose", action="count", dest="verbose",
|
|
help="Switch on verbose logging"
|
|
)
|
|
global pargs
|
|
pargs = parser.parse_args()
|
|
|
|
# Prüfen ob als Daemon ausgeführt werden soll
|
|
global forked
|
|
pidfile = "/var/run/revpipyload.pid"
|
|
pid = 0
|
|
if pargs.daemon and not forked:
|
|
# Prüfen ob daemon schon läuft
|
|
if os.path.exists(pidfile):
|
|
raise SystemError(
|
|
"program already running as daemon. check {}".format(pidfile)
|
|
)
|
|
|
|
# Zum daemon machen
|
|
pid = os.fork()
|
|
if pid > 0:
|
|
with open(pidfile, "w") as f:
|
|
f.write(str(pid))
|
|
sys.exit(0)
|
|
else:
|
|
forked = True
|
|
|
|
# piCtory Konfiguration prüfen
|
|
if pargs.configrsc is None:
|
|
lst_rsc = ["/etc/revpi/config.rsc", "/opt/KUNBUS/config.rsc"]
|
|
for rscfile in lst_rsc:
|
|
if os.access(rscfile, os.F_OK | os.R_OK):
|
|
pargs.configrsc = rscfile
|
|
break
|
|
elif not os.access(pargs.configrsc, os.F_OK | os.R_OK):
|
|
pargs.configrsc = None
|
|
if pargs.configrsc is None:
|
|
raise RuntimeError(
|
|
"can not find known pictory configurations at {}"
|
|
"".format(", ".join(lst_rsc))
|
|
)
|
|
|
|
# piControlReset suchen
|
|
global picontrolreset
|
|
if not os.access(picontrolreset, os.F_OK | os.X_OK):
|
|
picontrolreset = "/usr/bin/piTest -x"
|
|
|
|
# rap Katalog an bekannten Stellen prüfen und laden
|
|
global rapcatalog
|
|
lst_rap = [
|
|
"/opt/KUNBUS/pictory/resources/data/rap",
|
|
"/var/www/pictory/resources/data/rap"
|
|
]
|
|
for rapfolder in lst_rap:
|
|
if os.path.isdir(rapfolder):
|
|
rapcatalog = os.listdir(rapfolder)
|
|
|
|
# Pfade absolut umschreiben
|
|
global startdir
|
|
if startdir is None:
|
|
startdir = os.path.abspath(".")
|
|
if pargs.conffile is not None and os.path.dirname(pargs.conffile) == "":
|
|
pargs.conffile = os.path.join(startdir, pargs.conffile)
|
|
if pargs.logfile is not None and os.path.dirname(pargs.logfile) == "":
|
|
pargs.logfile = os.path.join(startdir, pargs.logfile)
|
|
|
|
global logapp
|
|
global logplc
|
|
if pargs.daemon:
|
|
# Ausgage vor Umhängen schließen
|
|
sys.stdout.close()
|
|
|
|
# Ausgaben umhängen in Logfile
|
|
logapp = "/var/log/revpipyloadapp"
|
|
logplc = "/var/log/revpipyload"
|
|
pargs.conffile = "/etc/revpipyload/revpipyload.conf"
|
|
sys.stdout = open(logplc, "a")
|
|
sys.stderr = sys.stdout
|
|
|
|
elif pargs.logfile is not None:
|
|
logplc = pargs.logfile
|
|
|
|
# Initialize configparser globalconfig
|
|
global globalconffile
|
|
globalconffile = pargs.conffile
|
|
|
|
# Program logger
|
|
global logger
|
|
if logger is None:
|
|
logger = logging.getLogger()
|
|
|
|
# Alle handler entfernen
|
|
for lhandler in logger.handlers:
|
|
logger.removeHandler(lhandler)
|
|
|
|
# Neue Handler bauen
|
|
logformat = logging.Formatter(
|
|
"{asctime} [{levelname:8}] {message}",
|
|
datefmt="%Y-%m-%d %H:%M:%S", style="{"
|
|
)
|
|
lhandler = logging.StreamHandler(sys.stdout)
|
|
lhandler.setFormatter(logformat)
|
|
logger.addHandler(lhandler)
|
|
|
|
if pargs.logfile is not None:
|
|
lhandler = logging.FileHandler(filename=pargs.logfile)
|
|
lhandler.setFormatter(logformat)
|
|
logger.addHandler(lhandler)
|
|
|
|
# Loglevel auswerten
|
|
if pargs.verbose is None:
|
|
loglevel = logging.WARNING
|
|
elif pargs.verbose == 1:
|
|
loglevel = logging.INFO
|
|
elif pargs.verbose > 1:
|
|
loglevel = logging.DEBUG
|
|
logger.setLevel(loglevel)
|