33 It's useful to detect "dead" processes and remove stale locks with |
33 It's useful to detect "dead" processes and remove stale locks with |
34 confidence. Typically it's just hostname. On modern linux, we include an |
34 confidence. Typically it's just hostname. On modern linux, we include an |
35 extra Linux-specific pid namespace identifier. |
35 extra Linux-specific pid namespace identifier. |
36 """ |
36 """ |
37 result = encoding.strtolocal(socket.gethostname()) |
37 result = encoding.strtolocal(socket.gethostname()) |
38 if pycompat.sysplatform.startswith('linux'): |
38 if pycompat.sysplatform.startswith(b'linux'): |
39 try: |
39 try: |
40 result += '/%x' % os.stat('/proc/self/ns/pid').st_ino |
40 result += b'/%x' % os.stat(b'/proc/self/ns/pid').st_ino |
41 except OSError as ex: |
41 except OSError as ex: |
42 if ex.errno not in (errno.ENOENT, errno.EACCES, errno.ENOTDIR): |
42 if ex.errno not in (errno.ENOENT, errno.EACCES, errno.ENOTDIR): |
43 raise |
43 raise |
44 return result |
44 return result |
45 |
45 |
74 raiseinterrupt(num) |
74 raiseinterrupt(num) |
75 |
75 |
76 try: |
76 try: |
77 # save handlers first so they can be restored even if a setup is |
77 # save handlers first so they can be restored even if a setup is |
78 # interrupted between signal.signal() and orighandlers[] =. |
78 # interrupted between signal.signal() and orighandlers[] =. |
79 for name in ['CTRL_C_EVENT', 'SIGINT', 'SIGBREAK', 'SIGHUP', 'SIGTERM']: |
79 for name in [ |
|
80 b'CTRL_C_EVENT', |
|
81 b'SIGINT', |
|
82 b'SIGBREAK', |
|
83 b'SIGHUP', |
|
84 b'SIGTERM', |
|
85 ]: |
80 num = getattr(signal, name, None) |
86 num = getattr(signal, name, None) |
81 if num and num not in orighandlers: |
87 if num and num not in orighandlers: |
82 orighandlers[num] = signal.getsignal(num) |
88 orighandlers[num] = signal.getsignal(num) |
83 try: |
89 try: |
84 for num in orighandlers: |
90 for num in orighandlers: |
112 the held lock while trying to acquires it.""" |
118 the held lock while trying to acquires it.""" |
113 |
119 |
114 def printwarning(printer, locker): |
120 def printwarning(printer, locker): |
115 """issue the usual "waiting on lock" message through any channel""" |
121 """issue the usual "waiting on lock" message through any channel""" |
116 # show more details for new-style locks |
122 # show more details for new-style locks |
117 if ':' in locker: |
123 if b':' in locker: |
118 host, pid = locker.split(":", 1) |
124 host, pid = locker.split(b":", 1) |
119 msg = _( |
125 msg = _( |
120 "waiting for lock on %s held by process %r on host %r\n" |
126 b"waiting for lock on %s held by process %r on host %r\n" |
121 ) % ( |
127 ) % ( |
122 pycompat.bytestr(l.desc), |
128 pycompat.bytestr(l.desc), |
123 pycompat.bytestr(pid), |
129 pycompat.bytestr(pid), |
124 pycompat.bytestr(host), |
130 pycompat.bytestr(host), |
125 ) |
131 ) |
126 else: |
132 else: |
127 msg = _("waiting for lock on %s held by %r\n") % ( |
133 msg = _(b"waiting for lock on %s held by %r\n") % ( |
128 l.desc, |
134 l.desc, |
129 pycompat.bytestr(locker), |
135 pycompat.bytestr(locker), |
130 ) |
136 ) |
131 printer(msg) |
137 printer(msg) |
132 |
138 |
266 if self.held: |
272 if self.held: |
267 self.held += 1 |
273 self.held += 1 |
268 return |
274 return |
269 if lock._host is None: |
275 if lock._host is None: |
270 lock._host = _getlockprefix() |
276 lock._host = _getlockprefix() |
271 lockname = '%s:%d' % (lock._host, self.pid) |
277 lockname = b'%s:%d' % (lock._host, self.pid) |
272 retry = 5 |
278 retry = 5 |
273 while not self.held and retry: |
279 while not self.held and retry: |
274 retry -= 1 |
280 retry -= 1 |
275 try: |
281 try: |
276 with self._maybedelayedinterrupt(): |
282 with self._maybedelayedinterrupt(): |
305 |
311 |
306 if not self.held: |
312 if not self.held: |
307 # use empty locker to mean "busy for frequent lock/unlock |
313 # use empty locker to mean "busy for frequent lock/unlock |
308 # by many processes" |
314 # by many processes" |
309 raise error.LockHeld( |
315 raise error.LockHeld( |
310 errno.EAGAIN, self.vfs.join(self.f), self.desc, "" |
316 errno.EAGAIN, self.vfs.join(self.f), self.desc, b"" |
311 ) |
317 ) |
312 |
318 |
313 def _readlock(self): |
319 def _readlock(self): |
314 """read lock and return its value |
320 """read lock and return its value |
315 |
321 |
339 if procutil.testpid(pid): |
345 if procutil.testpid(pid): |
340 return locker |
346 return locker |
341 # if locker dead, break lock. must do this with another lock |
347 # if locker dead, break lock. must do this with another lock |
342 # held, or can race and break valid lock. |
348 # held, or can race and break valid lock. |
343 try: |
349 try: |
344 l = lock(self.vfs, self.f + '.break', timeout=0) |
350 l = lock(self.vfs, self.f + b'.break', timeout=0) |
345 self.vfs.unlink(self.f) |
351 self.vfs.unlink(self.f) |
346 l.release() |
352 l.release() |
347 except error.LockError: |
353 except error.LockError: |
348 return locker |
354 return locker |
349 |
355 |
369 Communicating this string to the subprocess needs to be done separately |
375 Communicating this string to the subprocess needs to be done separately |
370 -- typically by an environment variable. |
376 -- typically by an environment variable. |
371 """ |
377 """ |
372 if not self.held: |
378 if not self.held: |
373 raise error.LockInheritanceContractViolation( |
379 raise error.LockInheritanceContractViolation( |
374 'inherit can only be called while lock is held' |
380 b'inherit can only be called while lock is held' |
375 ) |
381 ) |
376 if self._inherited: |
382 if self._inherited: |
377 raise error.LockInheritanceContractViolation( |
383 raise error.LockInheritanceContractViolation( |
378 'inherit cannot be called while lock is already inherited' |
384 b'inherit cannot be called while lock is already inherited' |
379 ) |
385 ) |
380 if self._inheritchecker is not None: |
386 if self._inheritchecker is not None: |
381 self._inheritchecker() |
387 self._inheritchecker() |
382 if self.releasefn: |
388 if self.releasefn: |
383 self.releasefn() |
389 self.releasefn() |