diff options
Diffstat (limited to 'python/skytools/fileutil.py')
-rw-r--r-- | python/skytools/fileutil.py | 67 |
1 files changed, 66 insertions, 1 deletions
diff --git a/python/skytools/fileutil.py b/python/skytools/fileutil.py index fd657fd4..c6fcefdd 100644 --- a/python/skytools/fileutil.py +++ b/python/skytools/fileutil.py @@ -2,7 +2,7 @@ import os -__all__ = ['write_atomic'] +__all__ = ['write_atomic', 'signal_pidfile'] def write_atomic(fn, data, bakext=None, mode='b'): """Write file with rename.""" @@ -35,3 +35,68 @@ def write_atomic(fn, data, bakext=None, mode='b'): # atomically replace file os.rename(fn2, fn) +def signal_pidfile(pidfile, sig): + """Send a signal to process whose ID is located in pidfile. + + Read only first line of pidfile to support multiline + pidfiles like postmaster.pid. + + Returns True is successful, False if pidfile does not exist + or process itself is dead. Any other errors will passed + as exceptions.""" + + ln = '' + try: + f = open(pidfile, 'r') + ln = f.readline().strip() + f.close() + pid = int(ln) + if sig == 0 and sys.platform == 'win32': + return win32_detect_pid(pid) + os.kill(pid, sig) + return True + except IOError, ex: + if ex.errno != errno.ENOENT: + raise + except OSError, ex: + if ex.errno != errno.ESRCH: + raise + except ValueError, ex: + # this leaves slight race when someone is just creating the file, + # but more common case is old empty file. + if not ln: + return False + raise ValueError('Corrupt pidfile: %s' % pidfile) + return False + +def win32_detect_pid(pid): + """Process detection for win32.""" + + # avoid pywin32 dependecy, use ctypes instead + import ctypes + + # win32 constants + PROCESS_QUERY_INFORMATION = 1024 + STILL_ACTIVE = 259 + ERROR_INVALID_PARAMETER = 87 + ERROR_ACCESS_DENIED = 5 + + # Load kernel32.dll + k = ctypes.windll.kernel32 + OpenProcess = k.OpenProcess + OpenProcess.restype = ctypes.c_void_p + + # query pid exit code + h = OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid) + if h == None: + err = k.GetLastError() + if err == ERROR_INVALID_PARAMETER: + return False + if err == ERROR_ACCESS_DENIED: + return True + raise OSError(errno.EFAULT, "Unknown win32error: " + str(err)) + code = ctypes.c_int() + k.GetExitCodeProcess(h, ctypes.byref(code)) + k.CloseHandle(h) + return code.value == STILL_ACTIVE + |