summaryrefslogtreecommitdiff
path: root/python/skytools/fileutil.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/skytools/fileutil.py')
-rw-r--r--python/skytools/fileutil.py67
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
+