diff --git a/01OS/01OS/clients/base_device.py b/01OS/01OS/clients/base_device.py index 030c00c..42aa60c 100644 --- a/01OS/01OS/clients/base_device.py +++ b/01OS/01OS/clients/base_device.py @@ -29,6 +29,7 @@ from interpreter import interpreter # Just for code execution. Maybe we should l from ..server.utils.kernel import put_kernel_messages_into_queue from ..server.utils.get_system_info import get_system_info from ..server.stt.stt import stt_wav +from process_utils import kill_process_tree from ..server.utils.logs import setup_logging from ..server.utils.logs import logger @@ -217,6 +218,7 @@ class Device: self.toggle_recording(True) elif {keyboard.Key.ctrl, keyboard.KeyCode.from_char('c')} <= self.pressed_keys: logger.info("Ctrl+C pressed. Exiting...") + kill_process_tree() os._exit(0) def on_release(self, key): diff --git a/01OS/poetry.lock b/01OS/poetry.lock index 9e1bc0a..19febbc 100644 --- a/01OS/poetry.lock +++ b/01OS/poetry.lock @@ -8400,4 +8400,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.12" -content-hash = "8bc369fab0a51bfd0538c59c70c239593595fff542b413f9854c8bf5448e7481" +content-hash = "4e7112e334cb1610550bcc44ab5f0a257621d774513c24034d60272b741caf51" diff --git a/01OS/process_utils.py b/01OS/process_utils.py new file mode 100644 index 0000000..adcf028 --- /dev/null +++ b/01OS/process_utils.py @@ -0,0 +1,28 @@ +import os +import psutil +import signal + +def kill_process_tree(): + pid = os.getpid() # Get the current process ID + try: + # Send SIGTERM to the entire process group to ensure all processes are targeted + os.killpg(os.getpgid(pid), signal.SIGKILL) + parent = psutil.Process(pid) + children = parent.children(recursive=True) + for child in children: + print(f"Forcefully terminating child PID {child.pid}") + child.kill() # Forcefully kill the child process immediately + gone, still_alive = psutil.wait_procs(children, timeout=3) + + if still_alive: + for child in still_alive: + print(f"Child PID {child.pid} still alive, attempting another kill") + child.kill() + + print(f"Forcefully terminating parent PID {pid}") + parent.kill() # Forcefully kill the parent process immediately + parent.wait(3) # Wait for the parent process to terminate + except psutil.NoSuchProcess: + print(f"Process {pid} does not exist or is already terminated") + except psutil.AccessDenied: + print(f"Permission denied to terminate some processes") diff --git a/01OS/pyproject.toml b/01OS/pyproject.toml index 2330563..c15eca3 100644 --- a/01OS/pyproject.toml +++ b/01OS/pyproject.toml @@ -26,6 +26,7 @@ ngrok = "^1.0.0" simpleaudio = "^1.0.4" opencv-python = "^4.9.0.80" open-interpreter = {version = "0.2.1rc1", extras = ["os"]} +psutil = "^5.9.8" [build-system] requires = ["poetry-core"] diff --git a/01OS/start.py b/01OS/start.py index 886d332..be75a75 100644 --- a/01OS/start.py +++ b/01OS/start.py @@ -6,6 +6,8 @@ Just starts `start.sh` with all the same command line arguments. Aliased to 01. import os import subprocess import sys +import psutil +from process_utils import kill_process_tree def main(): @@ -18,9 +20,9 @@ def main(): # Prepare the command command = [os.path.join(dir_path, 'start.sh')] + args - # Start start.sh with the command line arguments try: - subprocess.run(command, check=True) + # Start start.sh using psutil for better process management, and to kill all processes + psutil.Popen(command) except KeyboardInterrupt: print("Exiting...") - \ No newline at end of file + kill_process_tree() \ No newline at end of file