Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(247)

Unified Diff: subprocess2.py

Issue 14798003: Add nag_timer. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: 80 chars Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | tests/subprocess2_test.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: subprocess2.py
diff --git a/subprocess2.py b/subprocess2.py
index 1f9c6c99e365ad8a958acae8511d10d0b99aaaf0..e81798613cf6946789841df1dd4fce44417d9897 100644
--- a/subprocess2.py
+++ b/subprocess2.py
@@ -175,6 +175,7 @@ class Popen(subprocess.Popen):
self.stdin_is_void = False
self.stdout_is_void = False
self.stderr_is_void = False
+ self.cmd_str = tmp_str
if kwargs.get('stdin') is VOID:
kwargs['stdin'] = open(os.devnull, 'r')
@@ -190,6 +191,7 @@ class Popen(subprocess.Popen):
self.start = time.time()
self.timeout = None
+ self.nag_timer = None
self.shell = kwargs.get('shell', None)
# Silence pylint on MacOSX
self.returncode = None
@@ -228,6 +230,8 @@ class Popen(subprocess.Popen):
# because of memory exhaustion.
queue = Queue.Queue()
done = threading.Event()
+ timer = []
+ last_output = [time.time()] * 2
def write_stdin():
try:
@@ -249,10 +253,28 @@ class Popen(subprocess.Popen):
data = pipe.read(1)
if not data:
break
+ last_output[0] = time.time()
queue.put((name, data))
finally:
queue.put(name)
+ def nag_fn():
+ now = time.time()
+ if done.is_set():
+ return
+ if last_output[0] == last_output[1]:
+ logging.warn(' No output for %.0f seconds from command:' % (
+ now - last_output[1]))
+ logging.warn(' %s' % self.cmd_str)
+ # Use 0.1 fudge factor in case:
+ # now ~= last_output[0] + self.nag_timer
+ sleep_time = self.nag_timer + last_output[0] - now - 0.1
+ while sleep_time < 0:
+ sleep_time += self.nag_timer
+ last_output[1] = last_output[0]
+ timer[0] = threading.Timer(sleep_time, nag_fn)
+ timer[0].start()
+
def timeout_fn():
try:
done.wait(self.timeout)
@@ -290,6 +312,10 @@ class Popen(subprocess.Popen):
for t in threads.itervalues():
t.start()
+ if self.nag_timer:
+ timer.append(threading.Timer(self.nag_timer, nag_fn))
+ timer[0].start()
+
timed_out = False
try:
# This thread needs to be optimized for speed.
@@ -313,6 +339,8 @@ class Popen(subprocess.Popen):
finally:
# Stop the threads.
done.set()
+ if timer:
+ timer[0].cancel()
if 'wait' in threads:
# Accelerate things, otherwise it would hang until the child process is
# done.
@@ -324,16 +352,21 @@ class Popen(subprocess.Popen):
if timed_out:
self.returncode = TIMED_OUT
- def communicate(self, input=None, timeout=None): # pylint: disable=W0221,W0622
+ # pylint: disable=W0221,W0622
+ def communicate(self, input=None, timeout=None, nag_timer=None):
"""Adds timeout and callbacks support.
Returns (stdout, stderr) like subprocess.Popen().communicate().
- The process will be killed after |timeout| seconds and returncode set to
TIMED_OUT.
+ - If the subprocess runs for |nag_timer| seconds without producing terminal
+ output, print a warning to stderr.
"""
self.timeout = timeout
- if not self.timeout and not self.stdout_cb and not self.stderr_cb:
+ self.nag_timer = nag_timer
+ if (not self.timeout and not self.nag_timer and
+ not self.stdout_cb and not self.stderr_cb):
return super(Popen, self).communicate(input)
if self.timeout and self.shell:
@@ -360,13 +393,15 @@ class Popen(subprocess.Popen):
return (stdout, stderr)
-def communicate(args, timeout=None, **kwargs):
+def communicate(args, timeout=None, nag_timer=None, **kwargs):
"""Wraps subprocess.Popen().communicate() and add timeout support.
Returns ((stdout, stderr), returncode).
- The process will be killed after |timeout| seconds and returncode set to
TIMED_OUT.
+ - If the subprocess runs for |nag_timer| seconds without producing terminal
+ output, print a warning to stderr.
- Automatically passes stdin content as input so do not specify stdin=PIPE.
"""
stdin = kwargs.pop('stdin', None)
@@ -381,9 +416,9 @@ def communicate(args, timeout=None, **kwargs):
proc = Popen(args, **kwargs)
if stdin:
- return proc.communicate(stdin, timeout), proc.returncode
+ return proc.communicate(stdin, timeout, nag_timer), proc.returncode
else:
- return proc.communicate(None, timeout), proc.returncode
+ return proc.communicate(None, timeout, nag_timer), proc.returncode
def call(args, **kwargs):
« no previous file with comments | « no previous file | tests/subprocess2_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698