diff options
author | Shawn O. Pearce <sop@google.com> | 2010-05-11 18:21:33 -0700 |
---|---|---|
committer | Shawn O. Pearce <sop@google.com> | 2010-05-11 18:31:47 -0700 |
commit | ca8c32cd7ae7c3ae27bb6b649eafbfd54d77f916 (patch) | |
tree | 20d74c26df2112515313b0b22c7358427bad8b57 | |
parent | f0a9a1a30e60e92cec9bff4cae030478c276da4d (diff) | |
download | git-repo-ca8c32cd7ae7c3ae27bb6b649eafbfd54d77f916.tar.gz |
sync: kill git fetch process before SSH control master processv1.6.9.6
If the SSH control master process is killed while an active git
fetch is using its network socket, the underlying SSH client may
not realize the connection was broken. This can lead to both the
client and the server waiting indefinitely for network messages
which will never be sent.
Work around the problem by keeping track of any processes that use
the tunnels we establish. If we are about to kill any of the SSH
control masters that we started, ensure the clients using them are
successfully killed first.
Change-Id: Ida6c124dcb0c6a26bf7dd69cba2fbdc2ecd5b2fc
Signed-off-by: Shawn O. Pearce <sop@google.com>
-rw-r--r-- | git_command.py | 29 | ||||
-rw-r--r-- | git_config.py | 7 |
2 files changed, 34 insertions, 2 deletions
diff --git a/git_command.py b/git_command.py index 3309f378..4ad908f6 100644 --- a/git_command.py +++ b/git_command.py | |||
@@ -17,6 +17,7 @@ import os | |||
17 | import sys | 17 | import sys |
18 | import subprocess | 18 | import subprocess |
19 | import tempfile | 19 | import tempfile |
20 | from signal import SIGTERM | ||
20 | from error import GitError | 21 | from error import GitError |
21 | from trace import REPO_TRACE, IsTrace, Trace | 22 | from trace import REPO_TRACE, IsTrace, Trace |
22 | 23 | ||
@@ -29,6 +30,7 @@ LAST_CWD = None | |||
29 | 30 | ||
30 | _ssh_proxy_path = None | 31 | _ssh_proxy_path = None |
31 | _ssh_sock_path = None | 32 | _ssh_sock_path = None |
33 | _ssh_clients = [] | ||
32 | 34 | ||
33 | def ssh_sock(create=True): | 35 | def ssh_sock(create=True): |
34 | global _ssh_sock_path | 36 | global _ssh_sock_path |
@@ -51,6 +53,24 @@ def _ssh_proxy(): | |||
51 | 'git_ssh') | 53 | 'git_ssh') |
52 | return _ssh_proxy_path | 54 | return _ssh_proxy_path |
53 | 55 | ||
56 | def _add_ssh_client(p): | ||
57 | _ssh_clients.append(p) | ||
58 | |||
59 | def _remove_ssh_client(p): | ||
60 | try: | ||
61 | _ssh_clients.remove(p) | ||
62 | except ValueError: | ||
63 | pass | ||
64 | |||
65 | def terminate_ssh_clients(): | ||
66 | global _ssh_clients | ||
67 | for p in _ssh_clients: | ||
68 | try: | ||
69 | os.kill(p.pid, SIGTERM) | ||
70 | p.wait() | ||
71 | except OSError: | ||
72 | pass | ||
73 | _ssh_clients = [] | ||
54 | 74 | ||
55 | class _GitCall(object): | 75 | class _GitCall(object): |
56 | def version(self): | 76 | def version(self): |
@@ -188,6 +208,9 @@ class GitCommand(object): | |||
188 | except Exception, e: | 208 | except Exception, e: |
189 | raise GitError('%s: %s' % (command[1], e)) | 209 | raise GitError('%s: %s' % (command[1], e)) |
190 | 210 | ||
211 | if ssh_proxy: | ||
212 | _add_ssh_client(p) | ||
213 | |||
191 | self.process = p | 214 | self.process = p |
192 | self.stdin = p.stdin | 215 | self.stdin = p.stdin |
193 | 216 | ||
@@ -210,4 +233,8 @@ class GitCommand(object): | |||
210 | else: | 233 | else: |
211 | p.stderr = None | 234 | p.stderr = None |
212 | 235 | ||
213 | return self.process.wait() | 236 | try: |
237 | rc = p.wait() | ||
238 | finally: | ||
239 | _remove_ssh_client(p) | ||
240 | return rc | ||
diff --git a/git_config.py b/git_config.py index a7c82107..75936d40 100644 --- a/git_config.py +++ b/git_config.py | |||
@@ -23,7 +23,10 @@ from signal import SIGTERM | |||
23 | from urllib2 import urlopen, HTTPError | 23 | from urllib2 import urlopen, HTTPError |
24 | from error import GitError, UploadError | 24 | from error import GitError, UploadError |
25 | from trace import Trace | 25 | from trace import Trace |
26 | from git_command import GitCommand, ssh_sock | 26 | |
27 | from git_command import GitCommand | ||
28 | from git_command import ssh_sock | ||
29 | from git_command import terminate_ssh_clients | ||
27 | 30 | ||
28 | R_HEADS = 'refs/heads/' | 31 | R_HEADS = 'refs/heads/' |
29 | R_TAGS = 'refs/tags/' | 32 | R_TAGS = 'refs/tags/' |
@@ -391,6 +394,8 @@ def _open_ssh(host, port): | |||
391 | return True | 394 | return True |
392 | 395 | ||
393 | def close_ssh(): | 396 | def close_ssh(): |
397 | terminate_ssh_clients() | ||
398 | |||
394 | for key,p in _ssh_cache.iteritems(): | 399 | for key,p in _ssh_cache.iteritems(): |
395 | try: | 400 | try: |
396 | os.kill(p.pid, SIGTERM) | 401 | os.kill(p.pid, SIGTERM) |