chg: suppress OSError in _restoreio() and add some logging (
issue6330)
According to
issue6330, running chg on heavy loaded systems can lead to
following error:
```
Traceback (most recent call last):
File "path-to-hg/mercurial/commandserver.py", line 650, in _acceptnewconnection
self._runworker(conn)
File "path-to-hg/mercurial/commandserver.py", line 701, in _runworker
prereposetups=[self._reposetup],
File "path-to-hg/mercurial/commandserver.py", line 470, in _serverequest
sv.cleanup()
File "path-to-hg/mercurial/chgserver.py", line 381, in cleanup
self._restoreio()
File "path-to-hg/mercurial/chgserver.py", line 444, in _restoreio
os.dup2(fd, fp.fileno())
OSError: [Errno 16] Device or resource busy
```
[man dup2] indicates that, on Linux, EBUSY comes from a race condition
between open() and dup2().
However it's not clear why open() race occurred for newfd=stdin/out/err.
We suppress the OSError in _restoreio() since the forked worker process will
finish anyway and add some logging.
Thanks to Mitchell Plamann for a detailed bug description and Yuya Nishihara for
suggesting the fix.
--- a/mercurial/chgserver.py Thu Jul 02 19:54:44 2020 +0200
+++ b/mercurial/chgserver.py Fri Jul 03 13:45:59 2020 +0530
@@ -442,7 +442,20 @@
if newfp is not fp:
newfp.close()
# restore original fd: fp is open again
- os.dup2(fd, fp.fileno())
+ try:
+ os.dup2(fd, fp.fileno())
+ except OSError as err:
+ # According to issue6330, running chg on heavy loaded systems
+ # can lead to EBUSY. [man dup2] indicates that, on Linux,
+ # EBUSY comes from a race condition between open() and dup2().
+ # However it's not clear why open() race occurred for
+ # newfd=stdin/out/err.
+ self.ui.log(
+ b'chgserver',
+ b'got %s while duplicating %s\n',
+ stringutil.forcebytestr(err),
+ fn,
+ )
os.close(fd)
setattr(self, cn, ch)
setattr(ui, fn, fp)