| 41 | # is gone, and the only way to check it through OS is to let the worker have a process handle |
| 42 | # of the manager and ask if the process status has changed. |
| 43 | class ManagerWatchdog(object): |
| 44 | def __init__(self): |
| 45 | self.manager_pid = os.getppid() |
| 46 | |
| 47 | # mypy cannot detect this code is windows only |
| 48 | self.kernel32 = ctypes.WinDLL("kernel32", use_last_error=True) # type: ignore[attr-defined] |
| 49 | self.kernel32.OpenProcess.argtypes = (DWORD, BOOL, DWORD) |
| 50 | self.kernel32.OpenProcess.restype = HANDLE |
| 51 | self.kernel32.WaitForSingleObject.argtypes = (HANDLE, DWORD) |
| 52 | self.kernel32.WaitForSingleObject.restype = DWORD |
| 53 | |
| 54 | # Value obtained from https://msdn.microsoft.com/en-us/library/ms684880.aspx |
| 55 | SYNCHRONIZE = 0x00100000 |
| 56 | self.manager_handle = self.kernel32.OpenProcess( |
| 57 | SYNCHRONIZE, 0, self.manager_pid |
| 58 | ) |
| 59 | |
| 60 | if not self.manager_handle: |
| 61 | raise ctypes.WinError(ctypes.get_last_error()) # type: ignore[attr-defined] |
| 62 | |
| 63 | self.manager_dead = False |
| 64 | |
| 65 | def is_alive(self): |
| 66 | if not self.manager_dead: |
| 67 | # Value obtained from https://msdn.microsoft.com/en-us/library/windows/desktop/ms687032.aspx |
| 68 | self.manager_dead = ( |
| 69 | self.kernel32.WaitForSingleObject(self.manager_handle, 0) == 0 |
| 70 | ) |
| 71 | return not self.manager_dead |
| 72 | |
| 73 | |
| 74 | else: |