]> git.proxmox.com Git - mirror_edk2.git/blame - AppPkg/Applications/Python/Python-2.7.2/Demo/pdist/cvslock.py
EmbeddedPkg: Extend NvVarStoreFormattedLib LIBRARY_CLASS
[mirror_edk2.git] / AppPkg / Applications / Python / Python-2.7.2 / Demo / pdist / cvslock.py
CommitLineData
4710c53d 1"""CVS locking algorithm.\r
2\r
3CVS locking strategy\r
4====================\r
5\r
6As reverse engineered from the CVS 1.3 sources (file lock.c):\r
7\r
8- Locking is done on a per repository basis (but a process can hold\r
9write locks for multiple directories); all lock files are placed in\r
10the repository and have names beginning with "#cvs.".\r
11\r
12- Before even attempting to lock, a file "#cvs.tfl.<pid>" is created\r
13(and removed again), to test that we can write the repository. [The\r
14algorithm can still be fooled (1) if the repository's mode is changed\r
15while attempting to lock; (2) if this file exists and is writable but\r
16the directory is not.]\r
17\r
18- While creating the actual read/write lock files (which may exist for\r
19a long time), a "meta-lock" is held. The meta-lock is a directory\r
20named "#cvs.lock" in the repository. The meta-lock is also held while\r
21a write lock is held.\r
22\r
23- To set a read lock:\r
24\r
25 - acquire the meta-lock\r
26 - create the file "#cvs.rfl.<pid>"\r
27 - release the meta-lock\r
28\r
29- To set a write lock:\r
30\r
31 - acquire the meta-lock\r
32 - check that there are no files called "#cvs.rfl.*"\r
33 - if there are, release the meta-lock, sleep, try again\r
34 - create the file "#cvs.wfl.<pid>"\r
35\r
36- To release a write lock:\r
37\r
38 - remove the file "#cvs.wfl.<pid>"\r
39 - rmdir the meta-lock\r
40\r
41- To release a read lock:\r
42\r
43 - remove the file "#cvs.rfl.<pid>"\r
44\r
45\r
46Additional notes\r
47----------------\r
48\r
49- A process should read-lock at most one repository at a time.\r
50\r
51- A process may write-lock as many repositories as it wishes (to avoid\r
52deadlocks, I presume it should always lock them top-down in the\r
53directory hierarchy).\r
54\r
55- A process should make sure it removes all its lock files and\r
56directories when it crashes.\r
57\r
58- Limitation: one user id should not be committing files into the same\r
59repository at the same time.\r
60\r
61\r
62Turn this into Python code\r
63--------------------------\r
64\r
65rl = ReadLock(repository, waittime)\r
66\r
67wl = WriteLock(repository, waittime)\r
68\r
69list = MultipleWriteLock([repository1, repository2, ...], waittime)\r
70\r
71"""\r
72\r
73\r
74import os\r
75import time\r
76import stat\r
77import pwd\r
78\r
79\r
80# Default wait time\r
81DELAY = 10\r
82\r
83\r
84# XXX This should be the same on all Unix versions\r
85EEXIST = 17\r
86\r
87\r
88# Files used for locking (must match cvs.h in the CVS sources)\r
89CVSLCK = "#cvs.lck"\r
90CVSRFL = "#cvs.rfl."\r
91CVSWFL = "#cvs.wfl."\r
92\r
93\r
94class Error:\r
95\r
96 def __init__(self, msg):\r
97 self.msg = msg\r
98\r
99 def __repr__(self):\r
100 return repr(self.msg)\r
101\r
102 def __str__(self):\r
103 return str(self.msg)\r
104\r
105\r
106class Locked(Error):\r
107 pass\r
108\r
109\r
110class Lock:\r
111\r
112 def __init__(self, repository = ".", delay = DELAY):\r
113 self.repository = repository\r
114 self.delay = delay\r
115 self.lockdir = None\r
116 self.lockfile = None\r
117 pid = repr(os.getpid())\r
118 self.cvslck = self.join(CVSLCK)\r
119 self.cvsrfl = self.join(CVSRFL + pid)\r
120 self.cvswfl = self.join(CVSWFL + pid)\r
121\r
122 def __del__(self):\r
123 print "__del__"\r
124 self.unlock()\r
125\r
126 def setlockdir(self):\r
127 while 1:\r
128 try:\r
129 self.lockdir = self.cvslck\r
130 os.mkdir(self.cvslck, 0777)\r
131 return\r
132 except os.error, msg:\r
133 self.lockdir = None\r
134 if msg[0] == EEXIST:\r
135 try:\r
136 st = os.stat(self.cvslck)\r
137 except os.error:\r
138 continue\r
139 self.sleep(st)\r
140 continue\r
141 raise Error("failed to lock %s: %s" % (\r
142 self.repository, msg))\r
143\r
144 def unlock(self):\r
145 self.unlockfile()\r
146 self.unlockdir()\r
147\r
148 def unlockfile(self):\r
149 if self.lockfile:\r
150 print "unlink", self.lockfile\r
151 try:\r
152 os.unlink(self.lockfile)\r
153 except os.error:\r
154 pass\r
155 self.lockfile = None\r
156\r
157 def unlockdir(self):\r
158 if self.lockdir:\r
159 print "rmdir", self.lockdir\r
160 try:\r
161 os.rmdir(self.lockdir)\r
162 except os.error:\r
163 pass\r
164 self.lockdir = None\r
165\r
166 def sleep(self, st):\r
167 sleep(st, self.repository, self.delay)\r
168\r
169 def join(self, name):\r
170 return os.path.join(self.repository, name)\r
171\r
172\r
173def sleep(st, repository, delay):\r
174 if delay <= 0:\r
175 raise Locked(st)\r
176 uid = st[stat.ST_UID]\r
177 try:\r
178 pwent = pwd.getpwuid(uid)\r
179 user = pwent[0]\r
180 except KeyError:\r
181 user = "uid %d" % uid\r
182 print "[%s]" % time.ctime(time.time())[11:19],\r
183 print "Waiting for %s's lock in" % user, repository\r
184 time.sleep(delay)\r
185\r
186\r
187class ReadLock(Lock):\r
188\r
189 def __init__(self, repository, delay = DELAY):\r
190 Lock.__init__(self, repository, delay)\r
191 ok = 0\r
192 try:\r
193 self.setlockdir()\r
194 self.lockfile = self.cvsrfl\r
195 fp = open(self.lockfile, 'w')\r
196 fp.close()\r
197 ok = 1\r
198 finally:\r
199 if not ok:\r
200 self.unlockfile()\r
201 self.unlockdir()\r
202\r
203\r
204class WriteLock(Lock):\r
205\r
206 def __init__(self, repository, delay = DELAY):\r
207 Lock.__init__(self, repository, delay)\r
208 self.setlockdir()\r
209 while 1:\r
210 uid = self.readers_exist()\r
211 if not uid:\r
212 break\r
213 self.unlockdir()\r
214 self.sleep(uid)\r
215 self.lockfile = self.cvswfl\r
216 fp = open(self.lockfile, 'w')\r
217 fp.close()\r
218\r
219 def readers_exist(self):\r
220 n = len(CVSRFL)\r
221 for name in os.listdir(self.repository):\r
222 if name[:n] == CVSRFL:\r
223 try:\r
224 st = os.stat(self.join(name))\r
225 except os.error:\r
226 continue\r
227 return st\r
228 return None\r
229\r
230\r
231def MultipleWriteLock(repositories, delay = DELAY):\r
232 while 1:\r
233 locks = []\r
234 for r in repositories:\r
235 try:\r
236 locks.append(WriteLock(r, 0))\r
237 except Locked, instance:\r
238 del locks\r
239 break\r
240 else:\r
241 break\r
242 sleep(instance.msg, r, delay)\r
243 return list\r
244\r
245\r
246def test():\r
247 import sys\r
248 if sys.argv[1:]:\r
249 repository = sys.argv[1]\r
250 else:\r
251 repository = "."\r
252 rl = None\r
253 wl = None\r
254 try:\r
255 print "attempting write lock ..."\r
256 wl = WriteLock(repository)\r
257 print "got it."\r
258 wl.unlock()\r
259 print "attempting read lock ..."\r
260 rl = ReadLock(repository)\r
261 print "got it."\r
262 rl.unlock()\r
263 finally:\r
264 print [1]\r
265 sys.exc_traceback = None\r
266 print [2]\r
267 if rl:\r
268 rl.unlock()\r
269 print [3]\r
270 if wl:\r
271 wl.unlock()\r
272 print [4]\r
273 rl = None\r
274 print [5]\r
275 wl = None\r
276 print [6]\r
277\r
278\r
279if __name__ == '__main__':\r
280 test()\r