def get_processes(self): process = Process(self.rootpid) num_children = 0 num_watched_children = 0 terminated_children = 0 passed_terminal_procs = False processes = defaultdict(list) for child in self.iter_children(process): # Exclude terminal processes if self.terminal: if child.name == "run_in_term.sh": passed_terminal_procs = True if not passed_terminal_procs: continue num_children += 1 if child.pid in self.old_pids: processes['external'].append(str(child)) continue if (child.name and child.name in self.exclude_processes and child.name not in self.include_processes): processes['excluded'].append(str(child)) continue num_watched_children += 1 processes['monitored'].append(str(child)) if child.state == 'Z': terminated_children += 1 for child in self.monitored_processes['monitored']: if child not in processes['monitored']: num_children += 1 num_watched_children += 1 return processes, num_children, num_watched_children, terminated_children
def is_running(): pid = system.get_pid("Steam.exe$") if pid: # If process is defunct, don't consider it as running process = Process(pid) return process.state != "Z" return False
def refresh_process_status(self): """Return status of a process""" old_children, self.children = self.children, [] old_ignored_children, self.ignored_children = self.ignored_children, [] for child in self.iter_children(Process(os.getpid())): if child.state == 'Z': # should never happen anymore... logger.debug("Unexpected zombie process %s", child) try: os.wait3(os.WNOHANG) except ChildProcessError: pass continue if (child.name and child.name in self.exclude_processes and child.name not in self.include_processes): self.ignored_children.append(child) else: self.children.append(child) self._log_changes('ignored', old_ignored_children, self.ignored_children) self._log_changes('monitored', old_children, self.children) return len(self.children) > 0
def winekill(prefix, arch='win32', wine_path=None, env=None, initial_pids=None): """Kill processes in Wine prefix.""" initial_pids = initial_pids or [] for pid in initial_pids: logger.debug(Process(pid)) if not wine_path: wine_path = wine().get_executable() wine_root = os.path.dirname(wine_path) if not env: env = {'WINEARCH': arch, 'WINEPREFIX': prefix} command = [os.path.join(wine_root, "wineserver"), "-k"] logger.debug("Killing all wine processes: %s" % command) logger.debug("\tWine prefix: %s", prefix) logger.debug("\tWine arch: %s", arch) logger.debug("\tInitial pids: %s", initial_pids) system.execute(command, env=env, quiet=True) logger.debug("Waiting for wine processes to terminate") # Wineserver needs time to terminate processes num_cycles = 0 while True: num_cycles += 1 running_processes = [ pid for pid in initial_pids if os.path.exists("/proc/%s" % pid) ] logger.debug("running_processes: %s, cycles: %s", running_processes, num_cycles) for pid in running_processes: logger.debug(Process(pid)) if not running_processes: logger.debug("Done in %s cycles", num_cycles) break if num_cycles > 300: logger.warning("Some wine processes are still running: %s", ', '.join(running_processes)) break time.sleep(0.1)
def watch_children(self): """Poke at the running process(es).""" if not self.game_process: logger.error('No game process available') return False process = Process(self.rootpid) num_children = 0 num_watched_children = 0 terminated_children = 0 passed_terminal_procs = False for child in self.iter_children(process): # Exclude terminal processes if self.terminal: if child.name == "run_in_term.sh": passed_terminal_procs = True if not passed_terminal_procs: continue num_children += 1 if child.name in EXCLUDED_PROCESSES: logger.debug("Excluding %s from process monitor" % child.name) continue num_watched_children += 1 logger.debug("{}\t{}\t{}".format(child.pid, child.state, child.name)) if child.state == 'Z': terminated_children += 1 if num_watched_children > 0 and not self.monitoring_started: self.monitoring_started = True if self.runner and hasattr(self.runner, 'watch_game_process'): if not self.runner.watch_game_process(): self.is_running = False return False if num_watched_children == 0: time_since_start = time.time() - self.startup_time if self.monitoring_started or time_since_start > WARMUP_TIME: self.cycles_without_children += 1 max_cycles_reached = (self.cycles_without_children >= self.max_cycles_without_children) if num_children == 0 or max_cycles_reached: if max_cycles_reached: logger.debug( 'Maximum number of cycles without children reached') self.is_running = False self.stop() if num_children == 0: logger.debug("No children left in thread") self.game_process.communicate() else: logger.debug('Some processes are still active (%d)', num_children) self.return_code = self.game_process.returncode return False if terminated_children and terminated_children == num_watched_children: logger.debug("All children terminated") self.game_process.wait() return True
def killall(self): """Kill every remaining child process""" killed_processes = [] for process in self.iter_children(Process(self.rootpid), topdown=False): killed_processes.append(str(process)) process.kill() if killed_processes: logger.debug("Killed processes: %s", ', '.join(killed_processes))
def stop(self, killall=False): for thread in self.attached_threads: thread.stop() if hasattr(self, 'stop_func'): self.stop_func() if not killall: return for process in self.iter_children(Process(self.rootpid), topdown=False): process.kill()
def iter_children(self, process, topdown=True, first=True): if self.runner.name.startswith('wine') and first: pids = self.runner.get_pids() for pid in pids: wineprocess = Process(pid) if wineprocess.name not in self.runner.core_processes: process.children.append(wineprocess) for child in process.children: if topdown: yield child subs = self.iter_children(child, topdown=topdown, first=False) for sub in subs: yield sub if not topdown: yield child
def iter_children(self, process, topdown=True, first=True): if self.runner and self.runner.name.startswith('wine') and first: if 'WINE' in self.env: # Track the correct version of wine for winetricks wine_version = self.env['WINE'] else: wine_version = None pids = self.runner.get_pids(wine_version) for pid in pids: wineprocess = Process(pid) if wineprocess.name not in self.runner.core_processes: process.children.append(wineprocess) for child in process.children: if topdown: yield child subs = self.iter_children(child, topdown=topdown, first=False) for sub in subs: yield sub if not topdown: yield child
def watch_children(self): """pokes at the running process""" process = Process(self.rootpid) num_children = 0 num_watched_children = 0 terminated_children = 0 for child in self.iter_children(process): num_children += 1 if child.name in ('steamwebhelper', 'steam', 'sh', 'tee', 'bash'): continue num_watched_children += 1 print "{}\t{}\t{}".format(child.pid, child.state, child.name) if child.state == 'Z': terminated_children += 1 if terminated_children and terminated_children == num_watched_children: self.game_process.wait() if num_watched_children == 0: self.cycles_without_children += 1 if num_children == 0 or self.cycles_without_children >= 3: self.is_running = False return False return True
def watch_children(self): """Poke at the running process(es).""" if not self.game_process: logger.error('No game process available') return False process = Process(self.rootpid) num_children = 0 num_watched_children = 0 terminated_children = 0 passed_terminal_procs = False processes = defaultdict(list) for child in self.iter_children(process): # Exclude terminal processes if self.terminal: if child.name == "run_in_term.sh": passed_terminal_procs = True if not passed_terminal_procs: continue num_children += 1 if child.pid in self.old_pids: processes['external'].append(str(child)) continue if child.name in EXCLUDED_PROCESSES and child.name not in self.include_processes: processes['excluded'].append(str(child)) continue num_watched_children += 1 processes['monitored'].append(str(child)) if child.state == 'Z': terminated_children += 1 logger.debug("Processes: " + " | ".join([ "{}: {}".format(key, ', '.join(processes[key])) for key in processes if processes[key] ])) if num_watched_children > 0 and not self.monitoring_started: self.monitoring_started = True if self.runner and hasattr(self.runner, 'watch_game_process'): if not self.runner.watch_game_process(): self.is_running = False return False if num_watched_children == 0: time_since_start = time.time() - self.startup_time if self.monitoring_started or time_since_start > WARMUP_TIME: self.cycles_without_children += 1 max_cycles_reached = (self.cycles_without_children >= MAX_CYCLES_WITHOUT_CHILDREN) if num_children == 0 or max_cycles_reached: if max_cycles_reached: logger.debug( 'Maximum number of cycles without children reached') self.is_running = False self.stop() if num_children == 0: logger.debug("No children left in thread") self.game_process.communicate() else: logger.debug('Some processes are still active (%d)', num_children) self.return_code = self.game_process.returncode if self.stdout_monitor: GLib.source_remove(self.stdout_monitor) return False if terminated_children and terminated_children == num_watched_children: logger.debug("All children terminated") self.game_process.wait() if self.stdout_monitor: GLib.source_remove(self.stdout_monitor) self.is_running = False return False return True
def killall(self): for process in self.iter_children(Process(self.rootpid), topdown=False): logger.debug("Killing process %s", process) process.kill()
def iterate_all_processes(self): return Process(os.getpid()).iter_children()
def iterate_children(): """Iterates through all children process of the lutris client. This is not accurate since not all processes are started by lutris but are started by Systemd instead. """ return Process(os.getpid()).iter_children()