<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE TIP SYSTEM "http://www.tcl.tk/cgi-bin/tct/tip/tipxml.dtd">
<!-- Converted at Sun Feb 12 12:09:04 GMT 2012 -->
<!-- TIP AutoGenerator - written by Donal K. Fellows -->

<TIP number='332'>
<header><title>Half-Close for Bidirectional Channels</title><author address="mailto:alexandre.ferrieux@gmail.com">Alexandre Ferrieux</author><status type='project' state='final' tclversion="8.6" vote='after'>$Revision: 1.6 $</status><history></history><created day='25' month='sep' year='2008' /><keyword>Tcl channel close socket shutdown</keyword><obsoletes tip='301'/></header>
<abstract>This TIP proposes to extend the <emph style="bold">close</emph>/<emph style="bold">chan close</emph> commands to let them perform an unidirectional &quot;half-close&quot; on bidirectional channels.</abstract>
<body><section title="Background">
<para>Bidirectional channels (sockets and command pipelines) allow Tcl to make an efficient use of a &quot;filter process&quot;, by exchanging data back and forth over an abstract &quot;single&quot; channel.</para>
<para>However, this single channel abstraction comes with a too coarse-grained <emph style="bold">close</emph> primitive. Indeed, it closes both directions simultaneously, while it is often desirable to close &quot;gracefully&quot; the half-connection <emph style="italic">to</emph> the filter process, leaving the return path open. The effect of such a half-close is that the filter receives a bona fide EOF alone, without a nearly simultaneous SIGPIPE on its write end if it happens to be writing at that time. Moreover, if the filter is itself comprised of a pipeline of processes, some of which doing buffered I/O, then this graceful EOF may be the only way of flushing the chain and receiving back precious data.</para>
<para>This technique is supported by all modern OSes: for pipes there are actually two separate file descriptors/handles, and it suffices to close() the write side; for sockets, a single fd is used, but a specific syscall, shutdown(), brings back the ability to half-close. Hence it is fairly natural for a universal &quot;OS glove&quot; like Tcl to expose this universal feature.</para>
</section>
<section title="Proposed Change">
<para>This TIP proposes to extend the <emph style="bold">close</emph> and twin brother <emph style="bold">chan close</emph> commands to take an optional extra &quot;direction&quot; argument, indicating a half-close on the substream going in that direction:</para>
<quote><emph style="bold">close</emph> <emph style="italic">channel</emph> ?<emph style="bold">read</emph>|<emph style="bold">write</emph>?</quote>
<para>When the extra direction argument (which may be abbreviated) is given, first the OS-level half-close is performed: this means a shutdown() on a socket, and a close() of one end of a pipe for a command pipeline. Then, the Tcl-level channel data structure is either kept or freed depending on whether the other direction is still open:</para>
<verbatim><vline encoding='base64'>CXNldCBmIFtvcGVuIHxjb21tYW5kIHIrXQ==</vline><vline encoding='base64'>CS4uLg==</vline><vline encoding='base64'>CWNsb3NlICRmIHcgOyMgJGYgc3RpbGwgZXhpc3Rz</vline><vline encoding='base64'>CS4uLg==</vline><vline encoding='base64'>CWNsb3NlICRmIHIgOyMgbm93ICRmIGlzIGdvbmU=</vline></verbatim>
<para>Also, a single-argument <emph style="bold">close</emph> on an already half-closed bi-channel is defined to just &quot;finish the job&quot;, which allows to write blind cleanup procedures easily:</para>
<verbatim><vline encoding='base64'>CWlmIHtbY2F0Y2ggew==</vline><vline encoding='base64'>CSAgc2V0IGYgW29wZW4gfGNvbW1hbmQgcitd</vline><vline encoding='base64'>CSAgLi4u</vline><vline encoding='base64'>CSAgY2xvc2UgJGYgdw==</vline><vline encoding='base64'>CSAgLi4u</vline><vline encoding='base64'>CX0gZXJyXX0gew==</vline><vline encoding='base64'>CSAgLi4u</vline><vline encoding='base64'>CSAgY2xvc2UgJGYgOyMgY2xvc2Ugd2hhdCdzIGxlZnQ=</vline><vline encoding='base64'>CX0=</vline></verbatim>
<para>In the case of a command pipeline, the child-reaping duty falls upon the shoulders of the last close or half-close, so that an error condition at this stage (like &quot;Child exited abnormally&quot;) doesn&apos;t leak system resources.</para>
<para>Last, a half-close on an already closed half raises an error:</para>
<verbatim><vline encoding='base64'>CXNldCBbb3BlbiB8Y29tbWFuZCByK10=</vline><vline encoding='base64'>CWNsb3NlICRmIHc=</vline><vline encoding='base64'>CWNsb3NlICRmIHc=</vline><vline encoding='base64'>CT09PiBjaGFubmVsICJmaWxlMyIgd2Fzbid0IG9wZW5lZCBmb3Igd3JpdGluZw==</vline></verbatim>
<para>And the same applies to wrong-sided unidirectional channels:</para>
<verbatim><vline encoding='base64'>CXNldCBbb3BlbiBmaWxlbmFtZSByXQ==</vline><vline encoding='base64'>CWNsb3NlICRmIHc=</vline><vline encoding='base64'>CT09PiBjaGFubmVsICJmaWxlMyIgd2Fzbid0IG9wZW5lZCBmb3Igd3JpdGluZw==</vline></verbatim>
</section>
<section title="Rationale">
<para>The concept has gone full circle. From an initial half-close proposal very close to the current one, an ambitious <emph style="bold">chan split</emph> generalization was born in the surrounding enthusiasm, and specified in <tipref type="text" tip="301"/>. Then, <tipref type="text" tip="304"/>&apos;s <emph style="bold">chan pipe</emph> was accepted, which addressed most of the &quot;splitting&quot; demand (asymmetric fconfigures on both ends of a command pipeline can be done by redirecting to a standalone pipe). Moreover, in hindsight it appears that the implementation of <tipref type="text" tip="301"/> had very long-ranging effects on various channel implementations, which are more numerous today than before (TLS, reflection API).</para>
<para>As a consequence, <tipref type="text" tip="301"/> is being withdrawn, and the current TIP goes back to its initial, lower profile: just provide the half-close.</para>
</section>
<section title="C Interface">
<para>Luckily, the polymorphic channel API in Tcl has been fitted with a half-close function for nearly 10 years (!): the Tcl_ChannelType structure has had a <emph style="italic">close2proc</emph> member since 1998 in order to avoid deadlocks when closing a command pipeline. As a consequence, the implementation of half-close can be done with a constant channel ABI, avoiding any compatibility issue for extensions.</para>
<para>Still, the <emph style="italic">close2proc</emph> member does not have public status. To promote symmetry between the script-level and public C APIs, this TIP proposes to add an entry in the main stub table with the following signature:</para>
<quote>int <emph style="bold">Tcl_CloseEx</emph>(Tcl_Interp *<emph style="italic">interp</emph>, Tcl_Channel <emph style="italic">chan</emph>, int <emph style="italic">flags</emph>)</quote>
<para>The behavior being defined as mirrorring the script-level semantics described bove, where <emph style="italic">flags</emph> is either 0 (meaning bidirectional close) or one of TCL_CLOSE_READ and TCL_CLOSE_WRITE (meaning half-close).</para>
</section>
<section title="Reference Implementation">
<para>See Patch 219159 [<url ref="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=219159&amp;group_id=10894&amp;atid=310894"/>].</para>
<para>After a discussion with Andreas Kupries, the plan is to half-close-enable only raw (unstacked) channels for the time being, raising an explicit error when trying a half-close on a non-bottom channel. This leaves time to carefully design the necessary API extension of the generic stacking and reflection layers, while preparing a fully compatible change (error cases becoming valid).</para>
<para>On the channel-type-dependent side, only sockets and pipelines will be half-close-enabled for now: these are assumed to represent the most pressing demand.</para>
</section>
<section title="Copyright">
<para>This document has been placed in the public domain.</para>
</section>
</body></TIP>

