Mercurial > repos > melissacline > ucsc_xena_platform
comparison lockfile-0.10.2/lockfile/pidlockfile.py @ 33:7ceb967147c3
start xena with no gui
add library files
author | jingchunzhu <jingchunzhu@gmail.com> |
---|---|
date | Wed, 22 Jul 2015 13:24:44 -0700 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
32:63b1ba1e3424 | 33:7ceb967147c3 |
---|---|
1 # -*- coding: utf-8 -*- | |
2 | |
3 # pidlockfile.py | |
4 # | |
5 # Copyright © 2008–2009 Ben Finney <ben+python@benfinney.id.au> | |
6 # | |
7 # This is free software: you may copy, modify, and/or distribute this work | |
8 # under the terms of the Python Software Foundation License, version 2 or | |
9 # later as published by the Python Software Foundation. | |
10 # No warranty expressed or implied. See the file LICENSE.PSF-2 for details. | |
11 | |
12 """ Lockfile behaviour implemented via Unix PID files. | |
13 """ | |
14 | |
15 from __future__ import absolute_import | |
16 | |
17 import os | |
18 import sys | |
19 import errno | |
20 import time | |
21 | |
22 from . import (LockBase, AlreadyLocked, LockFailed, NotLocked, NotMyLock, | |
23 LockTimeout) | |
24 | |
25 | |
26 class PIDLockFile(LockBase): | |
27 """ Lockfile implemented as a Unix PID file. | |
28 | |
29 The lock file is a normal file named by the attribute `path`. | |
30 A lock's PID file contains a single line of text, containing | |
31 the process ID (PID) of the process that acquired the lock. | |
32 | |
33 >>> lock = PIDLockFile('somefile') | |
34 >>> lock = PIDLockFile('somefile') | |
35 """ | |
36 | |
37 def __init__(self, path, threaded=False, timeout=None): | |
38 # pid lockfiles don't support threaded operation, so always force | |
39 # False as the threaded arg. | |
40 LockBase.__init__(self, path, False, timeout) | |
41 dirname = os.path.dirname(self.lock_file) | |
42 basename = os.path.split(self.path)[-1] | |
43 self.unique_name = self.path | |
44 | |
45 def read_pid(self): | |
46 """ Get the PID from the lock file. | |
47 """ | |
48 return read_pid_from_pidfile(self.path) | |
49 | |
50 def is_locked(self): | |
51 """ Test if the lock is currently held. | |
52 | |
53 The lock is held if the PID file for this lock exists. | |
54 | |
55 """ | |
56 return os.path.exists(self.path) | |
57 | |
58 def i_am_locking(self): | |
59 """ Test if the lock is held by the current process. | |
60 | |
61 Returns ``True`` if the current process ID matches the | |
62 number stored in the PID file. | |
63 """ | |
64 return self.is_locked() and os.getpid() == self.read_pid() | |
65 | |
66 def acquire(self, timeout=None): | |
67 """ Acquire the lock. | |
68 | |
69 Creates the PID file for this lock, or raises an error if | |
70 the lock could not be acquired. | |
71 """ | |
72 | |
73 timeout = timeout is not None and timeout or self.timeout | |
74 end_time = time.time() | |
75 if timeout is not None and timeout > 0: | |
76 end_time += timeout | |
77 | |
78 while True: | |
79 try: | |
80 write_pid_to_pidfile(self.path) | |
81 except OSError as exc: | |
82 if exc.errno == errno.EEXIST: | |
83 # The lock creation failed. Maybe sleep a bit. | |
84 if timeout is not None and time.time() > end_time: | |
85 if timeout > 0: | |
86 raise LockTimeout("Timeout waiting to acquire" | |
87 " lock for %s" % | |
88 self.path) | |
89 else: | |
90 raise AlreadyLocked("%s is already locked" % | |
91 self.path) | |
92 time.sleep(timeout is not None and timeout/10 or 0.1) | |
93 else: | |
94 raise LockFailed("failed to create %s" % self.path) | |
95 else: | |
96 return | |
97 | |
98 def release(self): | |
99 """ Release the lock. | |
100 | |
101 Removes the PID file to release the lock, or raises an | |
102 error if the current process does not hold the lock. | |
103 | |
104 """ | |
105 if not self.is_locked(): | |
106 raise NotLocked("%s is not locked" % self.path) | |
107 if not self.i_am_locking(): | |
108 raise NotMyLock("%s is locked, but not by me" % self.path) | |
109 remove_existing_pidfile(self.path) | |
110 | |
111 def break_lock(self): | |
112 """ Break an existing lock. | |
113 | |
114 Removes the PID file if it already exists, otherwise does | |
115 nothing. | |
116 | |
117 """ | |
118 remove_existing_pidfile(self.path) | |
119 | |
120 def read_pid_from_pidfile(pidfile_path): | |
121 """ Read the PID recorded in the named PID file. | |
122 | |
123 Read and return the numeric PID recorded as text in the named | |
124 PID file. If the PID file cannot be read, or if the content is | |
125 not a valid PID, return ``None``. | |
126 | |
127 """ | |
128 pid = None | |
129 try: | |
130 pidfile = open(pidfile_path, 'r') | |
131 except IOError: | |
132 pass | |
133 else: | |
134 # According to the FHS 2.3 section on PID files in /var/run: | |
135 # | |
136 # The file must consist of the process identifier in | |
137 # ASCII-encoded decimal, followed by a newline character. | |
138 # | |
139 # Programs that read PID files should be somewhat flexible | |
140 # in what they accept; i.e., they should ignore extra | |
141 # whitespace, leading zeroes, absence of the trailing | |
142 # newline, or additional lines in the PID file. | |
143 | |
144 line = pidfile.readline().strip() | |
145 try: | |
146 pid = int(line) | |
147 except ValueError: | |
148 pass | |
149 pidfile.close() | |
150 | |
151 return pid | |
152 | |
153 | |
154 def write_pid_to_pidfile(pidfile_path): | |
155 """ Write the PID in the named PID file. | |
156 | |
157 Get the numeric process ID (“PID”) of the current process | |
158 and write it to the named file as a line of text. | |
159 | |
160 """ | |
161 open_flags = (os.O_CREAT | os.O_EXCL | os.O_WRONLY) | |
162 open_mode = 0o644 | |
163 pidfile_fd = os.open(pidfile_path, open_flags, open_mode) | |
164 pidfile = os.fdopen(pidfile_fd, 'w') | |
165 | |
166 # According to the FHS 2.3 section on PID files in /var/run: | |
167 # | |
168 # The file must consist of the process identifier in | |
169 # ASCII-encoded decimal, followed by a newline character. For | |
170 # example, if crond was process number 25, /var/run/crond.pid | |
171 # would contain three characters: two, five, and newline. | |
172 | |
173 pid = os.getpid() | |
174 line = "%(pid)d\n" % vars() | |
175 pidfile.write(line) | |
176 pidfile.close() | |
177 | |
178 | |
179 def remove_existing_pidfile(pidfile_path): | |
180 """ Remove the named PID file if it exists. | |
181 | |
182 Removing a PID file that doesn't already exist puts us in the | |
183 desired state, so we ignore the condition if the file does not | |
184 exist. | |
185 | |
186 """ | |
187 try: | |
188 os.remove(pidfile_path) | |
189 except OSError as exc: | |
190 if exc.errno == errno.ENOENT: | |
191 pass | |
192 else: | |
193 raise |