From e5d284ef362108adea839d118e239c342a06f42d Mon Sep 17 00:00:00 2001 From: Amir Pakdel Date: Sun, 8 Dec 2013 15:55:23 -0500 Subject: [PATCH] Preventing deadlock on subprocess.Popen.poll() According to http://docs.python.org/2/library/subprocess.html#subprocess.Popen.poll Warning: This will deadlock when using stdout=PIPE and/or stderr=PIPE and the child process generates enough output to a pipe such that it blocks waiting for the OS pipe buffer to accept more data. Use communicate() to avoid that. We count consecutive iterations that do not have any output, and only if it reaches a certain threshold, self.communicate() is run. --- salt/utils/nb_popen.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/salt/utils/nb_popen.py b/salt/utils/nb_popen.py index 4c389d6d56..6b325850f5 100644 --- a/salt/utils/nb_popen.py +++ b/salt/utils/nb_popen.py @@ -208,13 +208,25 @@ class NonBlockingPopen(subprocess.Popen): fcntl.fcntl(conn, fcntl.F_SETFL, flags) def poll_and_read_until_finish(self): + silent_iterations = 0 while self.poll() is None: if self.stdout is not None: + silent_iterations = 0 self.recv() if self.stderr is not None: + silent_iterations = 0 self.recv_err() + silent_iterations += 1 + + if silent_iterations > 100: + silent_iterations = 0 + (stdoutdata, stderrdata) = self.communicate() + if stdoutdata: + log.debug(stdoutdata) + if stderrdata: + log.error(stderrdata) time.sleep(0.01) def communicate(self, input=None):