@ -459,64 +459,9 @@ class GClientChildren(object):
print >> sys . stderr , ' ' , zombie . pid
print >> sys . stderr , ' ' , zombie . pid
class _KillTimer ( object ) :
""" Timer that kills child process after certain interval since last poke or
creation .
"""
# TODO(tandrii): we really want to make use of subprocess42 here, and not
# re-invent the wheel, but it's too much work :(
def __init__ ( self , timeout , child ) :
self . _timeout = timeout
self . _child = child
self . _cv = threading . Condition ( )
# All items below are protected by condition above.
self . _kill_at = None
self . _working = True
self . _thread = None
# Start the timer immediately.
if self . _timeout :
self . _kill_at = time . time ( ) + self . _timeout
self . _thread = threading . Thread ( name = ' _KillTimer ' , target = self . _work )
self . _thread . daemon = True
self . _thread . start ( )
def poke ( self ) :
if not self . _timeout :
return
with self . _cv :
self . _kill_at = time . time ( ) + self . _timeout
def cancel ( self ) :
with self . _cv :
self . _working = False
self . _cv . notifyAll ( )
def _work ( self ) :
if not self . _timeout :
return
while True :
with self . _cv :
if not self . _working :
return
left = self . _kill_at - time . time ( )
if left > 0 :
self . _cv . wait ( timeout = left )
continue
try :
logging . warn ( ' killing child %s because of no output for %f s ' ,
self . _child , self . _timeout )
self . _child . kill ( )
except OSError :
logging . exception ( ' failed to kill child %s ' , self . _child )
return
def CheckCallAndFilter ( args , stdout = None , filter_fn = None ,
def CheckCallAndFilter ( args , stdout = None , filter_fn = None ,
print_stdout = None , call_filter_on_first_line = False ,
print_stdout = None , call_filter_on_first_line = False ,
retry = False , kill_timeout = None , * * kwargs ) :
retry = False , * * kwargs ) :
""" Runs a command and calls back a filter function if needed.
""" Runs a command and calls back a filter function if needed.
Accepts all subprocess2 . Popen ( ) parameters plus :
Accepts all subprocess2 . Popen ( ) parameters plus :
@ -527,16 +472,10 @@ def CheckCallAndFilter(args, stdout=None, filter_fn=None,
stdout : Can be any bufferable output .
stdout : Can be any bufferable output .
retry : If the process exits non - zero , sleep for a brief interval and try
retry : If the process exits non - zero , sleep for a brief interval and try
again , up to RETRY_MAX times .
again , up to RETRY_MAX times .
kill_timeout : ( float ) if given , number of seconds after which process would
be killed if there is no output . Must not be used with shell = True as
only shell process would be killed , but not processes spawned by
shell .
stderr is always redirected to stdout .
stderr is always redirected to stdout .
"""
"""
assert print_stdout or filter_fn
assert print_stdout or filter_fn
assert not kwargs . get ( ' shell ' , False ) or not kill_timeout , (
' kill_timeout should not be used with shell=True ' )
stdout = stdout or sys . stdout
stdout = stdout or sys . stdout
output = cStringIO . StringIO ( )
output = cStringIO . StringIO ( )
filter_fn = filter_fn or ( lambda x : None )
filter_fn = filter_fn or ( lambda x : None )
@ -558,14 +497,12 @@ def CheckCallAndFilter(args, stdout=None, filter_fn=None,
# normally buffering is done for each line, but if svn requests input, no
# normally buffering is done for each line, but if svn requests input, no
# end-of-line character is output after the prompt and it would not show up.
# end-of-line character is output after the prompt and it would not show up.
try :
try :
timeout_killer = _KillTimer ( kill_timeout , kid )
in_byte = kid . stdout . read ( 1 )
in_byte = kid . stdout . read ( 1 )
if in_byte :
if in_byte :
if call_filter_on_first_line :
if call_filter_on_first_line :
filter_fn ( None )
filter_fn ( None )
in_line = ' '
in_line = ' '
while in_byte :
while in_byte :
timeout_killer . poke ( )
output . write ( in_byte )
output . write ( in_byte )
if print_stdout :
if print_stdout :
stdout . write ( in_byte )
stdout . write ( in_byte )
@ -580,7 +517,6 @@ def CheckCallAndFilter(args, stdout=None, filter_fn=None,
if len ( in_line ) :
if len ( in_line ) :
filter_fn ( in_line )
filter_fn ( in_line )
rv = kid . wait ( )
rv = kid . wait ( )
timeout_killer . cancel ( )
# Don't put this in a 'finally,' since the child may still run if we get
# Don't put this in a 'finally,' since the child may still run if we get
# an exception.
# an exception.