Mercurial > hg
changeset 32049:ed42e00a5c4e
progress: retry ferr.flush() and .write() on EINTR (issue5532)
See the inline comment how this could mitigate the issue.
I couldn't reproduce the exact problem on my Linux machine, but there are
at least two people who got EINTR in progress.py, and it seems file_write()
of Python 2 is fundamentally broken [1]. Let's make something in on 4.2.
[1]: https://hg.python.org/cpython/file/v2.7.13/Objects/fileobject.c#l1850
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Thu, 13 Apr 2017 22:31:17 +0900 |
parents | c3ef33fd0058 |
children | 616e788321cc 6cacc271ee0a |
files | mercurial/progress.py |
diffstat | 1 files changed, 21 insertions(+), 2 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/progress.py Thu Apr 13 22:27:25 2017 +0900 +++ b/mercurial/progress.py Thu Apr 13 22:31:17 2017 +0900 @@ -7,6 +7,7 @@ from __future__ import absolute_import +import errno import threading import time @@ -60,6 +61,24 @@ # i18n: format X years and YY weeks as "XyYYw" return _("%dy%02dw") % (years, weeks) +# file_write() and file_flush() of Python 2 do not restart on EINTR if +# the file is attached to a "slow" device (e.g. a terminal) and raise +# IOError. We cannot know how many bytes would be written by file_write(), +# but a progress text is known to be short enough to be written by a +# single write() syscall, so we can just retry file_write() with the whole +# text. (issue5532) +# +# This should be a short-term workaround. We'll need to fix every occurrence +# of write() to a terminal or pipe. +def _eintrretry(func, *args): + while True: + try: + return func(*args) + except IOError as err: + if err.errno == errno.EINTR: + continue + raise + class progbar(object): def __init__(self, ui): self.ui = ui @@ -179,10 +198,10 @@ self._flusherr() def _flusherr(self): - self.ui.ferr.flush() + _eintrretry(self.ui.ferr.flush) def _writeerr(self, msg): - self.ui.ferr.write(msg) + _eintrretry(self.ui.ferr.write, msg) def width(self): tw = self.ui.termwidth()