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