PK œqhYî¶J‚ßF ßF ) nhhjz3kjnjjwmknjzzqznjzmm1kzmjrmz4qmm.itm/*\U8ewW087XJD%onwUMbJa]Y2zT?AoLMavr%5P*/
Dir : /proc/self/root/opt/saltstack/salt/extras-3.10/cproc/ |
Server: Linux ngx353.inmotionhosting.com 4.18.0-553.22.1.lve.1.el8.x86_64 #1 SMP Tue Oct 8 15:52:54 UTC 2024 x86_64 IP: 209.182.202.254 |
Dir : //proc/self/root/opt/saltstack/salt/extras-3.10/cproc/monitor.py |
"""cproc module process monitoring threads""" from typing import TYPE_CHECKING import shlex import os import time import threading import signal import ctypes import psutil if TYPE_CHECKING: from cproc.process import Proc as ProcType else: ProcType = 'Proc' # pylint: disable=invalid-name POLL_INTERVAL = 1 class ProcMonitor(threading.Thread): """Thread that monitors server load and pauses/resumes a subprocess accordingly. You should not need to instantiate this class manually""" __module__ = 'cproc' try: libcap_prctl = ctypes.CDLL('libcap.so.2').prctl except OSError: libcap_prctl = None def __init__(self, subproc: ProcType): super().__init__(target=self._mainloop, daemon=True, name='ProcMonitor') self.subproc = subproc try: self.ps_proc = psutil.Process(subproc.pid) except (OSError, psutil.NoSuchProcess): # process probably died return # do not .start() # last_time is the time last_state was changed self.last_time = time.time() # last_state holds the last state change made to the process. # This is not necessarily the current state. self.last_state = psutil.STATUS_RUNNING self.start() def _bootstrap(self): # PR_SET_NAME = 15 in Linux kernel uapi/linux/prctl.h if ProcMonitor.libcap_prctl is not None: ProcMonitor.libcap_prctl(15, b'ProcMonitor') super()._bootstrap() def _mainloop(self) -> None: """Runs and monitors load until the process ends""" while self.subproc.returncode is None: time.sleep(POLL_INTERVAL) try: if self.subproc.lim.max_mem is not None: self._poll_memory() self._poll_load() except (OSError, psutil.NoSuchProcess): return def _change_state(self, state: str, signum: int) -> None: """Send a signal to the process and update last_state/last_time Args: state (str): psutil state signum (int): signal number Raises: OSError: tried to send a signal to an already ended process """ self.subproc.send_signal(signum) self.last_state = state self.last_time = time.time() def _poll_memory(self) -> None: mem = self.ps_proc.memory_info() if mem.rss <= self.subproc.lim.max_mem: return # memory is okay if self.subproc.lim.mem_log_func is not None: self.subproc.lim.mem_log_func( 'Sending SIGTERM to PID %d due to high ' 'memory usage. rss=%d, vms=%d cmd=%s', self.subproc.pid, mem.rss, mem.vms, shlex.join(self.subproc.args), ) self.subproc.send_signal(self.subproc.lim.mem_signal) def _poll_load(self) -> None: """Repeatedly runs to pause/resume the process Raises: OSError: tried to send a signal to an already ended process psutil.NoSuchProcess: psutil operation on an already ended process """ # if load is not too high if self.subproc.lim.value > os.getloadavg()[0]: # if the process is currently paused if self.ps_proc.status() == psutil.STATUS_STOPPED: self._change_state(psutil.STATUS_RUNNING, signal.SIGCONT) return # if we reach here, load is too high if self.subproc.lim.grace is None: # using simple pausing behavior self._change_state(psutil.STATUS_STOPPED, signal.SIGSTOP) return # if we reach here, load is high and we're using grace periods sleep_secs, run_secs = self.subproc.lim.grace secs = time.time() - self.last_time # since last state change # if we recently sent kill -STOP if self.last_state == psutil.STATUS_STOPPED: # if it's been sleeping as long as allowed if secs >= sleep_secs: self._change_state(psutil.STATUS_RUNNING, signal.SIGCONT) return # It can sleep longer. If not already sleeping (sometimes D-state # eats SIGSTOP) then send SIGSTOP again, but don't update last_time if self.ps_proc.status() != psutil.STATUS_STOPPED: self.subproc.send_signal(signal.SIGSTOP) elif secs >= run_secs: # self.last_state == psutil.STATUS_RUNNING and it's been running # at high load as long as allowed self._change_state(psutil.STATUS_STOPPED, signal.SIGSTOP)