# HG changeset patch # User Edouard Tisserant # Date 1666084180 -7200 # Node ID 7c427418396fc066709e1e17d46a0ac8b8ddf434 # Parent db87744d89008e812225ead78729ea6a5eadf4c1 SVGHMI: prevent browser and watchdog commands to become zombie once finished. diff -r db87744d8900 -r 7c427418396f svghmi/svghmi.py --- a/svghmi/svghmi.py Wed Oct 12 11:59:47 2022 +0200 +++ b/svghmi/svghmi.py Tue Oct 18 11:09:40 2022 +0200 @@ -636,19 +636,29 @@ svghmi_cmds[thing] = ( "Popen(" + repr(shlex.split(given_command.format(**svghmi_options))) + - ")") if given_command else "pass # no command given" + ")") if given_command else "None # no command given" runtimefile_path = os.path.join(buildpath, "runtime_%s_svghmi_.py" % location_str) runtimefile = open(runtimefile_path, 'w') runtimefile.write(""" -# TODO : multiple watchdog (one for each svghmi instance) +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# generated by beremiz/svghmi/svghmi.py + +browser_proc = None + def svghmi_{location}_watchdog_trigger(): - {svghmi_cmds[Watchdog]} + global browser_proc + restart_proc = {svghmi_cmds[Watchdog]} + waitpid_timeout(restart_proc, "SVGHMI watchdog triggered command") + waitpid_timeout(browser_proc, "SVGHMI browser process") + browser_proc = None max_svghmi_sessions = {maxConnections_total} def _runtime_{location}_svghmi_start(): - global svghmi_watchdog, svghmi_servers + global svghmi_watchdog, svghmi_servers, browser_proc srv = svghmi_servers.get("{interface}:{port}", None) if srv is not None: @@ -673,7 +683,7 @@ path_list.append("{path}") - {svghmi_cmds[Start]} + browser_proc = {svghmi_cmds[Start]} if {enable_watchdog}: if svghmi_watchdog is None: @@ -686,7 +696,7 @@ def _runtime_{location}_svghmi_stop(): - global svghmi_watchdog, svghmi_servers + global svghmi_watchdog, svghmi_servers, browser_proc if svghmi_watchdog is not None: svghmi_watchdog.cancel() @@ -702,7 +712,10 @@ svghmi_listener.stopListening() svghmi_servers.pop("{interface}:{port}") - {svghmi_cmds[Stop]} + stop_proc = {svghmi_cmds[Stop]} + waitpid_timeout(stop_proc, "SVGHMI stop command") + waitpid_timeout(browser_proc, "SVGHMI browser process") + browser_proc = None """.format(location=location_str, xhtml=target_fname, diff -r db87744d8900 -r 7c427418396f svghmi/svghmi_server.py --- a/svghmi/svghmi_server.py Wed Oct 12 11:59:47 2022 +0200 +++ b/svghmi/svghmi_server.py Tue Oct 18 11:09:40 2022 +0200 @@ -8,6 +8,7 @@ from __future__ import absolute_import import errno from threading import RLock, Timer +import os, time try: from runtime.spawn_subprocess import Popen @@ -23,6 +24,9 @@ from autobahn.websocket.protocol import WebSocketProtocol from autobahn.twisted.resource import WebSocketResource +from runtime.loglevels import LogLevelsDict +from runtime import GetPLCObjectSingleton + max_svghmi_sessions = None svghmi_watchdog = None @@ -299,3 +303,21 @@ render_HEAD = render_GET +def waitpid_timeout(proc, helpstr="", timeout = 3): + if proc is None: + return + def waitpid_timeout_loop(pid=proc.pid, timeout = timeout): + try: + while os.waitpid(pid,os.WNOHANG) == (0,0): + time.sleep(1) + timeout = timeout - 1 + if not timeout: + GetPLCObjectSingleton().LogMessage( + LogLevelsDict["WARNING"], + "Timeout waiting for {} PID: {}".format(helpstr, str(pid))) + break + except OSError: + # workaround exception "OSError: [Errno 10] No child processes" + pass + Thread(target=waitpid_timeout_loop, name="Zombie hunter").start() +