Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/sshpeer.py @ 46701:db8037e38085
sshpeer: add a develwarning if an sshpeer is not closed explicitly
The warning is disabled until the next commit, because fixing it
results in a noisy diff due to indentation changes.
Differential Revision: https://phab.mercurial-scm.org/D9998
author | Valentin Gatien-Baron <valentin.gatienbaron@gmail.com> |
---|---|
date | Mon, 15 Feb 2021 14:40:17 -0500 |
parents | 0738bc25d6ac |
children | a4c19a162615 |
comparison
equal
deleted
inserted
replaced
46700:0509cee38757 | 46701:db8037e38085 |
---|---|
146 | 146 |
147 def flush(self): | 147 def flush(self): |
148 return self._main.flush() | 148 return self._main.flush() |
149 | 149 |
150 | 150 |
151 def _cleanuppipes(ui, pipei, pipeo, pipee): | 151 def _cleanuppipes(ui, pipei, pipeo, pipee, warn): |
152 """Clean up pipes used by an SSH connection.""" | 152 """Clean up pipes used by an SSH connection.""" |
153 if pipeo: | 153 didsomething = False |
154 if pipeo and not pipeo.closed: | |
155 didsomething = True | |
154 pipeo.close() | 156 pipeo.close() |
155 if pipei: | 157 if pipei and not pipei.closed: |
158 didsomething = True | |
156 pipei.close() | 159 pipei.close() |
157 | 160 |
158 if pipee: | 161 if pipee and not pipee.closed: |
162 didsomething = True | |
159 # Try to read from the err descriptor until EOF. | 163 # Try to read from the err descriptor until EOF. |
160 try: | 164 try: |
161 for l in pipee: | 165 for l in pipee: |
162 ui.status(_(b'remote: '), l) | 166 ui.status(_(b'remote: '), l) |
163 except (IOError, ValueError): | 167 except (IOError, ValueError): |
164 pass | 168 pass |
165 | 169 |
166 pipee.close() | 170 pipee.close() |
171 | |
172 if didsomething and warn is not None: | |
173 # Encourage explicit close of sshpeers. Closing via __del__ is | |
174 # not very predictable when exceptions are thrown, which has led | |
175 # to deadlocks due to a peer get gc'ed in a fork | |
176 # We add our own stack trace, because the stacktrace when called | |
177 # from __del__ is useless. | |
178 if False: # enabled in next commit | |
179 ui.develwarn( | |
180 b'missing close on SSH connection created at:\n%s' % warn | |
181 ) | |
167 | 182 |
168 | 183 |
169 def _makeconnection(ui, sshcmd, args, remotecmd, path, sshenv=None): | 184 def _makeconnection(ui, sshcmd, args, remotecmd, path, sshenv=None): |
170 """Create an SSH connection to a server. | 185 """Create an SSH connection to a server. |
171 | 186 |
414 self._pipeo = stdin | 429 self._pipeo = stdin |
415 self._pipei = stdout | 430 self._pipei = stdout |
416 self._pipee = stderr | 431 self._pipee = stderr |
417 self._caps = caps | 432 self._caps = caps |
418 self._autoreadstderr = autoreadstderr | 433 self._autoreadstderr = autoreadstderr |
434 self._initstack = b''.join(util.getstackframes(1)) | |
419 | 435 |
420 # Commands that have a "framed" response where the first line of the | 436 # Commands that have a "framed" response where the first line of the |
421 # response contains the length of that response. | 437 # response contains the length of that response. |
422 _FRAMED_COMMANDS = { | 438 _FRAMED_COMMANDS = { |
423 b'batch', | 439 b'batch', |
454 | 470 |
455 def _abort(self, exception): | 471 def _abort(self, exception): |
456 self._cleanup() | 472 self._cleanup() |
457 raise exception | 473 raise exception |
458 | 474 |
459 def _cleanup(self): | 475 def _cleanup(self, warn=None): |
460 _cleanuppipes(self.ui, self._pipei, self._pipeo, self._pipee) | 476 _cleanuppipes(self.ui, self._pipei, self._pipeo, self._pipee, warn=warn) |
461 | 477 |
462 __del__ = _cleanup | 478 def __del__(self): |
479 self._cleanup(warn=self._initstack) | |
463 | 480 |
464 def _sendrequest(self, cmd, args, framed=False): | 481 def _sendrequest(self, cmd, args, framed=False): |
465 if self.ui.debugflag and self.ui.configbool( | 482 if self.ui.debugflag and self.ui.configbool( |
466 b'devel', b'debug.peer-request' | 483 b'devel', b'debug.peer-request' |
467 ): | 484 ): |
609 testing. | 626 testing. |
610 """ | 627 """ |
611 try: | 628 try: |
612 protoname, caps = _performhandshake(ui, stdin, stdout, stderr) | 629 protoname, caps = _performhandshake(ui, stdin, stdout, stderr) |
613 except Exception: | 630 except Exception: |
614 _cleanuppipes(ui, stdout, stdin, stderr) | 631 _cleanuppipes(ui, stdout, stdin, stderr, warn=None) |
615 raise | 632 raise |
616 | 633 |
617 if protoname == wireprototypes.SSHV1: | 634 if protoname == wireprototypes.SSHV1: |
618 return sshv1peer( | 635 return sshv1peer( |
619 ui, | 636 ui, |
635 stderr, | 652 stderr, |
636 caps, | 653 caps, |
637 autoreadstderr=autoreadstderr, | 654 autoreadstderr=autoreadstderr, |
638 ) | 655 ) |
639 else: | 656 else: |
640 _cleanuppipes(ui, stdout, stdin, stderr) | 657 _cleanuppipes(ui, stdout, stdin, stderr, warn=None) |
641 raise error.RepoError( | 658 raise error.RepoError( |
642 _(b'unknown version of SSH protocol: %s') % protoname | 659 _(b'unknown version of SSH protocol: %s') % protoname |
643 ) | 660 ) |
644 | 661 |
645 | 662 |