diff options
author | Marko Kreen | 2012-06-15 13:36:32 +0000 |
---|---|---|
committer | Marko Kreen | 2012-06-15 13:36:32 +0000 |
commit | d4886026435ddbc94ac94326fb7d0fcf4f35155f (patch) | |
tree | 322f8c937fedd29f2a490bd8cfd2148f6ef47a1d | |
parent | c51a6dc989a9882cb91bbfe2927cd3cedb2d506a (diff) |
Move signal_pidfile to 'fileutil' module
-rw-r--r-- | python/skytools/__init__.py | 2 | ||||
-rw-r--r-- | python/skytools/fileutil.py | 67 | ||||
-rw-r--r-- | python/skytools/scripting.py | 76 |
3 files changed, 70 insertions, 75 deletions
diff --git a/python/skytools/__init__.py b/python/skytools/__init__.py index 4f6d1bde..84ed00de 100644 --- a/python/skytools/__init__.py +++ b/python/skytools/__init__.py @@ -30,6 +30,7 @@ _symbols = { 'T_TABLE': 'skytools.dbstruct:T_TABLE', 'T_TRIGGER': 'skytools.dbstruct:T_TRIGGER', # skytools.fileutil + 'signal_pidfile': 'skytools.fileutil:signal_pidfile', 'write_atomic': 'skytools.fileutil:write_atomic', # skytools.gzlog 'gzip_append': 'skytools.gzlog:gzip_append', @@ -83,7 +84,6 @@ _symbols = { 'BaseScript': 'skytools.scripting:BaseScript', 'daemonize': 'skytools.scripting:daemonize', 'DBScript': 'skytools.scripting:DBScript', - 'signal_pidfile': 'skytools.scripting:signal_pidfile', 'UsageError': 'skytools.scripting:UsageError', # skytools.skylog 'getLogger': 'skytools.skylog:getLogger', 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 + diff --git a/python/skytools/scripting.py b/python/skytools/scripting.py index 6e6716e9..c7791dbc 100644 --- a/python/skytools/scripting.py +++ b/python/skytools/scripting.py @@ -17,82 +17,12 @@ except ImportError: __pychecker__ = 'no-badexcept' -__all__ = ['BaseScript', 'signal_pidfile', 'UsageError', 'daemonize', - 'DBScript'] +__all__ = ['BaseScript', 'UsageError', 'daemonize', 'DBScript'] class UsageError(Exception): """User induced error.""" # -# utils -# - -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 - -# # daemon mode # @@ -127,7 +57,7 @@ def run_single_process(runnable, daemon, pidfile): # check if another process is running if pidfile and os.path.isfile(pidfile): - if signal_pidfile(pidfile, 0): + if skytools.signal_pidfile(pidfile, 0): print("Pidfile exists, another process running?") sys.exit(1) else: @@ -468,7 +398,7 @@ class BaseScript(object): if not self.pidfile: self.log.warning("No pidfile in config, nothing to do") elif os.path.isfile(self.pidfile): - alive = signal_pidfile(self.pidfile, sig) + alive = skytools.signal_pidfile(self.pidfile, sig) if not alive: self.log.warning("pidfile exists, but process not running") else: |