Under what condition does a Python subprocess get a SIGPIPE?
<p>I am reading the the Python documentation on the Popen class in the subprocess module section and I came across the following code:</p>

<pre><code>p1 = Popen(["dmesg"], stdout=PIPE)
p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
p1.stdout.close()  # Allow p1 to receive a SIGPIPE if p2 exits.
output = p2.communicate()[0]
</code></pre>

<p>The <a href="https://docs.python.org/2/library/subprocess.html#replacing-shell-pipeline" rel="nofollow">documentation</a> also states that </p>

<blockquote>
  <p>"The p1.stdout.close() call after starting the p2 is important in order for p1 to receive a SIGPIPE if p2 exits before p1.</p>
</blockquote>

<p>Why must the p1.stdout be closed before we can receive a SIGPIPE and how does p1 knows that p2 exits before p1 if we already closed it? </p>

<p><code>SIGPIPE</code> is a signal that would be sent if <code>dmesg</code> tried to write to a closed pipe. Here, <code>dmesg</code> ends up with <em>two</em> targets to write to, your Python process and the <code>grep</code> process.</p>

<p>That's because <code>subprocess</code> clones file handles (using the <a href="https://docs.python.org/2/library/os.html#os.dup2" rel="nofollow"><code>os.dup2()</code> function</a>). Configuring <code>p2</code> to use <code>p1.stdout</code> triggers a <code>os.dup2()</code> call that asks the OS to duplicate the pipe filehandle; the duplicate is used to connect <code>dmesg</code> to <code>grep</code>.</p>

<p>With two open file handles for <code>dmesg</code> stdout, <code>dmesg</code> is never given a <code>SIGPIPE</code> signal if only <em>one</em> of them closes early, so <code>grep</code> closing would never be detected. <code>dmesg</code> would needlessly continue to produce output.</p>

<p>So by closing <code>p1.stdout</code> immediately, you ensure that the only remaining filehandle reading from <code>dmesg</code> stdout is the <code>grep</code> process, and if that process were to exit, <code>dmesg</code> receives a <code>SIGPIPE</code>.</p>

python pipe subprocess