From 65d6fd2acf286afe7945b0e3e0b2cd4169a80125 Mon Sep 17 00:00:00 2001 From: deathaxe Date: Tue, 3 Sep 2019 21:12:00 +0200 Subject: [PATCH] Fix parent process being killed on Windows when checking if it's alive (#445) --- pyls/_utils.py | 56 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/pyls/_utils.py b/pyls/_utils.py index 6e9bfbdf..1ce2195a 100644 --- a/pyls/_utils.py +++ b/pyls/_utils.py @@ -147,19 +147,49 @@ def clip_column(column, lines, line_number): return min(column, max_column) -def is_process_alive(pid): - """ Check whether the process with the given pid is still alive. +if os.name == 'nt': + import ctypes - Args: - pid (int): process ID + kernel32 = ctypes.windll.kernel32 + PROCESS_QUERY_INFROMATION = 0x1000 - Returns: - bool: False if the process is not alive or don't have permission to check, True otherwise. - """ - try: - os.kill(pid, 0) - except OSError: - # no such process or process is already dead + def is_process_alive(pid): + """Check whether the process with the given pid is still alive. + + Running `os.kill()` on Windows always exits the process, so it can't be used to check for an alive process. + see: https://docs.python.org/3/library/os.html?highlight=os%20kill#os.kill + + Hence ctypes is used to check for the process directly via windows API avoiding any other 3rd-party dependency. + + Args: + pid (int): process ID + + Returns: + bool: False if the process is not alive or don't have permission to check, True otherwise. + """ + process = kernel32.OpenProcess(PROCESS_QUERY_INFROMATION, 0, pid) + if process != 0: + kernel32.CloseHandle(process) + return True return False - else: - return True + +else: + import errno + + def is_process_alive(pid): + """Check whether the process with the given pid is still alive. + + Args: + pid (int): process ID + + Returns: + bool: False if the process is not alive or don't have permission to check, True otherwise. + """ + if pid < 0: + return False + try: + os.kill(pid, 0) + except OSError as e: + return e.errno == errno.EPERM + else: + return True