-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPidFile.py
More file actions
141 lines (125 loc) · 4.38 KB
/
Copy pathPidFile.py
File metadata and controls
141 lines (125 loc) · 4.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
"""Process id file management"""
import os
import atexit
if os.name == 'nt':
try:
import win32api
except ImportError:
try:
import ctypes
win32api = ctypes.windll.kernel32
except (AttributeError, ImportError):
win32api = None
else:
win32api = None
class ProcessRunning(Exception):
"""Error when creating pid file for already running process."""
class PidFile(object):
"""Process id file management."""
def __init__(self, path, create=True):
"""Create a pid file with the given path for the current process."""
self._path = path
self._created = False
self._pid = None
if os.path.exists(path):
try:
self._pid = int(open(path).read())
if self._pid <= 1:
self._pid = None
raise ValueError
except (IOError, ValueError, TypeError):
# Can't open file or read PID from file.
# File is probably invalid or stale, so try to delete it.
print ("%s is invalid or cannot be opened;"
" attempting to remove it." % path)
self.remove(stale=True)
else:
if self.pidRunning(self._pid):
if create:
raise ProcessRunning()
else:
print "%s is stale; removing." % path
self.remove(stale=True)
if create:
self._pid = self.currentPID()
if self._pid is not None:
self.write()
# Delete the pid file when Python exits, so that the pid file
# is removed if the process exits abnormally. If the process
# crashes, though, the pid file will be left behind.
atexit.register(self.remove)
@staticmethod
def pidRunning(pid):
"""Check whether process with given pid is running."""
try:
os.kill(pid, 0)
except OSError, e:
if e.errno == 3: # no such process
return False
except AttributeError:
if win32api:
try:
if not win32api.OpenProcess(1024, False, pid):
return False
except win32api.error, e:
if e.winerror == 87: # wrong parameter (no such process)
return False
return True
@staticmethod
def currentPID():
"""Get the current process id."""
try:
return os.getpid()
except AttributeError:
if win32api:
return win32api.GetCurrentProcessId()
return None
@staticmethod
def killPID(pid, sig=None):
"""Kill the process with the given pid."""
try:
if sig is None:
from signal import SIGTERM
sig = SIGTERM
os.kill(pid, sig)
except (AttributeError, ImportError):
if win32api:
handle = win32api.OpenProcess(1, False, pid)
win32api.TerminateProcess(handle, -1)
win32api.CloseHandle(handle)
def pid(self):
"""Return our process id."""
return self._pid
def running(self):
"""Check whether our process is running."""
return self.pidRunning(self._pid)
def kill(self):
"""Kill our process."""
if self._pid is None:
return
return self.killPID(self._pid)
def __del__(self):
"""Remove pid file together with our instance."""
self.remove()
def remove(self, stale=False):
"""Remove our pid file."""
if not stale:
if not self._created:
# Only remove the file if we created it. Otherwise starting
# a second process will remove the file created by the first.
return
stale = os.path.exists(self._path)
if stale:
try:
os.unlink(self._path)
except (AttributeError, OSError):
pass
self._created = False # remove only once
def write(self):
"""Write our pid file."""
if self._created:
return
pidfile = open(self._path, 'w')
pidfile.write(str(self._pid))
pidfile.close()
self._created = True # write only one