<div class="gmail_quote">2012/9/27 Tim Watson <span dir="ltr"><<a href="mailto:watson.timothy@gmail.com" target="_blank">watson.timothy@gmail.com</a>></span><br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div style="word-wrap:break-word"><div><div>Hi Erik,</div><div class="im"><div><br></div><div>On 27 Sep 2012, at 03:20, Erik Søe Sørensen wrote:</div><blockquote type="cite"><p>It is the responsibility of the port program to shut down when stdin reaches EOF.<br>
This behaviour/expectation confused me too at some point, but it probably has its merits: not all software is designed for "let it crash", so simply killing the port program might be too crude in some circumstances.</p>
</blockquote></div>Well that's fine, but it should be documented a bit more clearly IMHO.</div></div></blockquote><div> </div><div>It's not in the API docs for open_port(), but in the section in the manual which definesports (<a href="http://www.erlang.org/doc/reference_manual/ports.html#id84207">http://www.erlang.org/doc/reference_manual/ports.html#id84207</a>) it does say<br>
<p style="margin-left:40px">The external program resides in another OS process. By default,
it should read from standard input (file descriptor 0) and write
to standard output (file descriptor 1). <i>The external program
should terminate when the port is closed.</i></p> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div> Also the port program, in this instance, is another beam emulator, so it's clearly *not* going to behave that way!</div>
</div></blockquote><div>Why not? - see below.<br> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div> Currently the connected process for the port has 3 shutdown modes:</div>
<div><br></div><div>1. rpc:call(Node, custom_app, stop, [])</div><div>2. close_port(Port)</div><div>3. open_port({spawn, "kill -9 " ++ OsPid, Opts)</div></div></blockquote><div><br>You could add<br>4. Ensure that the node runs a reading loop which detects EOF - e.g. using file:read_line(standard_io) or file:read(standard_io, SomeBlockSize).<br>
<br>Example for detecting EOF:<br>erl -noshell -eval 'F=fun(G)->X=file:read_line(standard_io), io:format("~p\n", [X]), X==eof orelse G(G) end, F(F), init:stop().'<br><br>You can even do exactly this in practise: put the loop code on the command line.<br>
<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div><br></div><div>Item 3 is the least preferable as it is not portable (relies on 'kill' being a shell built-in, etc) and requires that the os process id is known. It sounds like (2) is not a workable solution unless the external program is hand written to deal with 'stdin reaches EOF'. This is less than ideal, as it means that open_port/2 is not much use for spawning (and monitoring thereafter) arbitrary programs unless you're willing to live with the fact that you're not able to shut them down by closing the port. </div>
</div></blockquote></div><br>No, the port mechanism was apparently not meant for arbitrary slave programs. However, a little wrapping can often get you far, as Jesper demonstrated earlier.<br>