"""Single-instance lock for up/stop.""" from __future__ import annotations import os import sys from types import TracebackType from gpu_rent.errors import GpuRentError from gpu_rent.paths import lock_path def _pid_alive(pid: int) -> bool: if pid <= 0: return False if sys.platform == "win32": import ctypes handle = ctypes.windll.kernel32.OpenProcess(0x100000, False, pid) if handle: ctypes.windll.kernel32.CloseHandle(handle) return True return False try: os.kill(pid, 0) return True except OSError: return False class SessionLock: def __enter__(self) -> SessionLock: path = lock_path() path.parent.mkdir(parents=True, exist_ok=True) if path.is_file(): try: old = int(path.read_text(encoding="utf-8").strip() or "0") except ValueError: old = 0 if _pid_alive(old) and old != os.getpid(): raise GpuRentError( f"gpu-rent уже работает (pid {old}, {path}). Дождись окончания up/stop." ) path.write_text(str(os.getpid()), encoding="utf-8") self._path = path self._pid = os.getpid() return self def __exit__( self, exc_type: type[BaseException] | None, exc: BaseException | None, tb: TracebackType | None, ) -> None: try: if self._path.is_file() and self._path.read_text(encoding="utf-8").strip() == str(self._pid): self._path.unlink() except OSError: pass