Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/chgserver.py @ 45185:a17454a189d1 stable
chgserver: discard buffered output before restoring fds (issue6207)
On Python 3, flush() appears not discarding buffered data on EPIPE, and
the buffered data will be carried over to the restored stdout.
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Mon, 20 Jul 2020 20:31:24 +0900 |
parents | 3862de62d5cf |
children | d2e1dcd4490d |
comparison
equal
deleted
inserted
replaced
45184:3781e9f74b27 | 45185:a17454a189d1 |
---|---|
432 fp = getattr(ui, fn) | 432 fp = getattr(ui, fn) |
433 fd = os.dup(fp.fileno()) | 433 fd = os.dup(fp.fileno()) |
434 self._oldios.append((ch, fp, fd)) | 434 self._oldios.append((ch, fp, fd)) |
435 | 435 |
436 def _restoreio(self): | 436 def _restoreio(self): |
437 if not self._oldios: | |
438 return | |
439 nullfd = os.open(os.devnull, os.O_WRONLY) | |
437 ui = self.ui | 440 ui = self.ui |
438 for (ch, fp, fd), (cn, fn, _mode) in zip(self._oldios, _iochannels): | 441 for (ch, fp, fd), (cn, fn, mode) in zip(self._oldios, _iochannels): |
439 newfp = getattr(ui, fn) | 442 newfp = getattr(ui, fn) |
440 # close newfp while it's associated with client; otherwise it | 443 # close newfp while it's associated with client; otherwise it |
441 # would be closed when newfp is deleted | 444 # would be closed when newfp is deleted |
442 if newfp is not fp: | 445 if newfp is not fp: |
443 newfp.close() | 446 newfp.close() |
444 # restore original fd: fp is open again | 447 # restore original fd: fp is open again |
445 try: | 448 try: |
449 if newfp is fp and 'w' in mode: | |
450 # Discard buffered data which couldn't be flushed because | |
451 # of EPIPE. The data should belong to the current session | |
452 # and should never persist. | |
453 os.dup2(nullfd, fp.fileno()) | |
454 fp.flush() | |
446 os.dup2(fd, fp.fileno()) | 455 os.dup2(fd, fp.fileno()) |
447 except OSError as err: | 456 except OSError as err: |
448 # According to issue6330, running chg on heavy loaded systems | 457 # According to issue6330, running chg on heavy loaded systems |
449 # can lead to EBUSY. [man dup2] indicates that, on Linux, | 458 # can lead to EBUSY. [man dup2] indicates that, on Linux, |
450 # EBUSY comes from a race condition between open() and dup2(). | 459 # EBUSY comes from a race condition between open() and dup2(). |
457 fn, | 466 fn, |
458 ) | 467 ) |
459 os.close(fd) | 468 os.close(fd) |
460 setattr(self, cn, ch) | 469 setattr(self, cn, ch) |
461 setattr(ui, fn, fp) | 470 setattr(ui, fn, fp) |
471 os.close(nullfd) | |
462 del self._oldios[:] | 472 del self._oldios[:] |
463 | 473 |
464 def validate(self): | 474 def validate(self): |
465 """Reload the config and check if the server is up to date | 475 """Reload the config and check if the server is up to date |
466 | 476 |