summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn O. Pearce <sop@google.com>2010-05-11 18:21:33 -0700
committerShawn O. Pearce <sop@google.com>2010-05-11 18:31:47 -0700
commitca8c32cd7ae7c3ae27bb6b649eafbfd54d77f916 (patch)
tree20d74c26df2112515313b0b22c7358427bad8b57
parentf0a9a1a30e60e92cec9bff4cae030478c276da4d (diff)
downloadgit-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.py29
-rw-r--r--git_config.py7
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
17import sys 17import sys
18import subprocess 18import subprocess
19import tempfile 19import tempfile
20from signal import SIGTERM
20from error import GitError 21from error import GitError
21from trace import REPO_TRACE, IsTrace, Trace 22from 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
33def ssh_sock(create=True): 35def 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
56def _add_ssh_client(p):
57 _ssh_clients.append(p)
58
59def _remove_ssh_client(p):
60 try:
61 _ssh_clients.remove(p)
62 except ValueError:
63 pass
64
65def 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
55class _GitCall(object): 75class _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
23from urllib2 import urlopen, HTTPError 23from urllib2 import urlopen, HTTPError
24from error import GitError, UploadError 24from error import GitError, UploadError
25from trace import Trace 25from trace import Trace
26from git_command import GitCommand, ssh_sock 26
27from git_command import GitCommand
28from git_command import ssh_sock
29from git_command import terminate_ssh_clients
27 30
28R_HEADS = 'refs/heads/' 31R_HEADS = 'refs/heads/'
29R_TAGS = 'refs/tags/' 32R_TAGS = 'refs/tags/'
@@ -391,6 +394,8 @@ def _open_ssh(host, port):
391 return True 394 return True
392 395
393def close_ssh(): 396def 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)