emacs.d/clones/lisp/docs.racket-lang.org/reference/customport.html

370 lines
279 KiB
HTML
Raw Normal View History

2022-08-24 19:36:32 +02:00
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"/><meta name="viewport" content="width=device-width, initial-scale=0.8"/><title>13.1.9&nbsp;Custom Ports</title><link rel="stylesheet" type="text/css" href="../scribble.css" title="default"/><link rel="stylesheet" type="text/css" href="extras.css" title="default"/><link rel="stylesheet" type="text/css" href="../racket.css" title="default"/><link rel="stylesheet" type="text/css" href="../manual-style.css" title="default"/><link rel="stylesheet" type="text/css" href="../manual-racket.css" title="default"/><link rel="stylesheet" type="text/css" href="../manual-racket.css" title="default"/><link rel="stylesheet" type="text/css" href="../doc-site.css" title="default"/><script type="text/javascript" src="../scribble-common.js"></script><script type="text/javascript" src="../manual-racket.js"></script><script type="text/javascript" src="../manual-racket.js"></script><script type="text/javascript" src="../doc-site.js"></script><script type="text/javascript" src="../local-redirect/local-redirect.js"></script><script type="text/javascript" src="../local-redirect/local-user-redirect.js"></script><!--[if IE 6]><style type="text/css">.SIEHidden { overflow: hidden; }</style><![endif]--></head><body id="doc-racket-lang-org"><div class="tocset"><div class="tocview"><div class="tocviewlist tocviewlisttopspace"><div class="tocviewtitle"><table cellspacing="0" cellpadding="0"><tr><td style="width: 1em;"><a href="javascript:void(0);" title="Expand/Collapse" class="tocviewtoggle" onclick="TocviewToggle(this,&quot;tocview_0&quot;);">&#9658;</a></td><td></td><td><a href="index.html" class="tocviewlink" data-pltdoc="x">The Racket Reference</a></td></tr></table></div><div class="tocviewsublisttop" style="display: none;" id="tocview_0"><table cellspacing="0" cellpadding="0"><tr><td align="right">1&nbsp;</td><td><a href="model.html" class="tocviewlink" data-pltdoc="x">Language Model</a></td></tr><tr><td align="right">2&nbsp;</td><td><a href="notation.html" class="tocviewlink" data-pltdoc="x">Notation for Documentation</a></td></tr><tr><td align="right">3&nbsp;</td><td><a href="syntax.html" class="tocviewlink" data-pltdoc="x">Syntactic Forms</a></td></tr><tr><td align="right">4&nbsp;</td><td><a href="data.html" class="tocviewlink" data-pltdoc="x">Datatypes</a></td></tr><tr><td align="right">5&nbsp;</td><td><a href="structures.html" class="tocviewlink" data-pltdoc="x">Structures</a></td></tr><tr><td align="right">6&nbsp;</td><td><a href="mzlib_class.html" class="tocviewlink" data-pltdoc="x">Classes and Objects</a></td></tr><tr><td align="right">7&nbsp;</td><td><a href="mzlib_unit.html" class="tocviewlink" data-pltdoc="x">Units</a></td></tr><tr><td align="right">8&nbsp;</td><td><a href="contracts.html" class="tocviewlink" data-pltdoc="x">Contracts</a></td></tr><tr><td align="right">9&nbsp;</td><td><a href="match.html" class="tocviewlink" data-pltdoc="x">Pattern Matching</a></td></tr><tr><td align="right">10&nbsp;</td><td><a href="control.html" class="tocviewlink" data-pltdoc="x">Control Flow</a></td></tr><tr><td align="right">11&nbsp;</td><td><a href="concurrency.html" class="tocviewlink" data-pltdoc="x">Concurrency and Parallelism</a></td></tr><tr><td align="right">12&nbsp;</td><td><a href="Macros.html" class="tocviewlink" data-pltdoc="x">Macros</a></td></tr><tr><td align="right">13&nbsp;</td><td><a href="input-and-output.html" class="tocviewselflink" data-pltdoc="x">Input and Output</a></td></tr><tr><td align="right">14&nbsp;</td><td><a href="security.html" class="tocviewlink" data-pltdoc="x">Reflection and Security</a></td></tr><tr><td align="right">15&nbsp;</td><td><a href="os.html" class="tocviewlink" data-pltdoc="x">Operating System</a></td></tr><tr><td align="right">16&nbsp;</td><td><a href="memory.html" class="tocviewlink" data-pltdoc="x">Memory Management</a></td></tr><tr><td align="right">17&nbsp;</td><td><a href="unsafe.html" class="tocviewlink" data-pltdoc="x">Unsafe Operations</a></td></tr><tr><td align="right">18&nbsp;</td><td><a href="running.html" class="to
create <a name="(tech._custom._port)"></a><span style="font-style: italic">custom ports</span> with arbitrary control procedures (much like
implementing a device driver). Custom ports are mainly useful to
obtain fine control over the action of committing bytes as read or
written.</p><p><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" cellpadding="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>procedure</p></div></div><table cellspacing="0" cellpadding="0" class="prototype RForeground"><tr><td valign="top"><span class="RktPn">(</span><a name="(def._((quote._~23~25kernel)._make-input-port))"></a><span title="Provided from: racket/base, racket | Package: base"><span class="RktSym"><a href="customport.html#%28def._%28%28quote._~23~25kernel%29._make-input-port%29%29" class="RktValDef RktValLink" data-pltdoc="x">make-input-port</a></span></span></td><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="RktVar">name</span></td><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="hspace">&nbsp;</span></td></tr><tr><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="RktVar">read-in</span></td><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="hspace">&nbsp;</span></td></tr><tr><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="RktVar">peek</span></td><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="hspace">&nbsp;</span></td></tr><tr><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="RktVar">close</span></td><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="hspace">&nbsp;</span></td></tr><tr><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="hspace">&nbsp;</span><span class="RktOpt">[</span></td><td valign="top"><span class="RktVar">get-progress-evt</span></td><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="hspace">&nbsp;</span></td></tr><tr><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="RktVar">commit</span></td><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="hspace">&nbsp;</span></td></tr><tr><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="RktVar">get-location</span></td><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="hspace">&nbsp;</span></td></tr><tr><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="RktVar">count-lines!</span></td><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="hspace">&nbsp;</span></td></tr><tr><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="hspace">&nbsp;</span></td><td valign="top"><span class="RktVar">init-position</span></td><td valign="top"
<span class="RktVar">close</span> procedure has no side effects, then the port need not
be explicitly closed. See also <span class="RktSym"><a href="port-lib.html#%28def._%28%28lib._racket%2Fport..rkt%29._make-input-port%2Fread-to-peek%29%29" class="RktValLink" data-pltdoc="x">make-input-port/read-to-peek</a></span>.</div></p><p>The arguments implement the port as follows:</p><ul><li><p><span class="RktVar">name</span> &#8212;<wbr></wbr> the name for the input port.</p></li><li><p><div class="SIntrapara"><span class="RktVar">read-in</span> &#8212;<wbr></wbr> either an input port, in which case reads
are redirected to the given port, or a procedure that takes a single
argument:
a mutable byte string to receive read bytes. The procedure&rsquo;s
result is one of the following:
</div><div class="SIntrapara"><ul><li><p>the number of bytes read, as an exact, non-negative integer;</p></li><li><p><span class="RktSym"><a href="port-ops.html#%28def._%28%28quote._~23~25kernel%29._eof%29%29" class="RktValLink" data-pltdoc="x">eof</a></span>;</p></li><li><p>a procedure of arity four (representing a &ldquo;special&rdquo;
result, as discussed <a href="customport.html#%28elem._special%29" data-pltdoc="x">further below</a>),
but a procedure result is allowed only
when <span class="RktVar">peek</span> is not <span class="RktVal">#f</span>;</p></li><li><p>a <a href="pipeports.html#%28tech._pipe%29" data-pltdoc="x">pipe</a> input port that supplies bytes to be
used as long as the pipe has content (see
<span class="RktSym"><a href="pipeports.html#%28def._%28%28quote._~23~25kernel%29._pipe-content-length%29%29" class="RktValLink" data-pltdoc="x">pipe-content-length</a></span>) or until <span class="RktVar">read-in</span> or
<span class="RktVar">peek</span> is called again; or</p></li><li><p>a <a href="sync.html#%28tech._synchronizable._event%29" class="techoutside" data-pltdoc="x"><span class="techinside">synchronizable event</span></a> (see <a href="sync.html" data-pltdoc="x">Events</a>) other
than a pipe input port or procedure of arity four; the event
becomes ready when the read is complete (roughly): the event&rsquo;s
value can be one of the above four results or another event like
itself; in the last case, a reading process loops with
<span class="RktSym"><a href="sync.html#%28def._%28%28quote._~23~25kernel%29._sync%29%29" class="RktValLink" data-pltdoc="x">sync</a></span> until it gets a non-event result.</p></li></ul></div></p><p>The <span class="RktVar">read-in</span> procedure must not block indefinitely. If no
bytes are immediately available for reading, the <span class="RktVar">read-in</span>
must return <span class="RktVal">0</span> or an event, and preferably an event (to
avoid busy waits). The <span class="RktVar">read-in</span> should not return
<span class="RktVal">0</span> (or an event whose value is <span class="RktVal">0</span>) when data is
available in the port, otherwise polling the port will behave
incorrectly. An event result from an event can also break polling.</p><p>If the result of a <span class="RktVar">read-in</span> call is not one of the above
values, the <span class="RktSym"><a href="exns.html#%28def._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._exn~3afail~3acontract%29%29" class="RktValLink" data-pltdoc="x">exn:fail:contract</a></span> exception is raised. If a returned integer is
larger than the supplied byte string&rsquo;s length, the
<span class="RktSym"><a href="exns.html#%28def._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._exn~3afail~3acontract%29%29" class="RktValLink" data-pltdoc="x">exn:fail:contract</a></span> exception is raised. If <span class="RktVar">peek</span> is <span class="RktVal">#f</span> and
a procedure for a <a href="customport.html#%28elem._special%29" data-pltdoc="x">special</a> result is returned,
the <span class="RktSym"><a href="exns.html#%28def._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._exn~3afail~3acontract%29%29" class="RktValLink" data-pltdoc="x">exn:fail:contract</a></span> exception is raised.</p><p>The <span class="RktVar">read-in</span> procedure can report an error by raising an
exception, but only if no bytes are read. Similarly, no bytes
should be read if <span class="RktSym"><a href="port-ops.html#%28def._%28%28quote._~23~25kernel%29._eof%29%29" class="RktValLink" data-pltdoc="x">eof</a></span>, an event, or a procedure is
returned. In other words, no bytes should be lost due to spurious
exceptions or non-byte data.</p><p>A port&rsquo;s reading procedure may be called in multiple threads
simultaneously (if the port is accessible in multiple threads),
and the port is responsible for its own internal
synchronization. Note that improper implementation of such
synchronization mechanisms might cause a non-blocking read
procedure to block indefinitely.</p><p>If the result is a pipe input port, then previous
<span class="RktVar">get-progress-evt</span> calls whose event is not yet ready must
have been the pipe input port itself. Furthermore,
<span class="RktVar">get-progress-evt</span> must continue to return the pipe as long
as it contains data, or until the <span class="RktVar">read-in</span> or
<span class="RktSym">peek-in</span> procedure is called again (instead of using the
pipe, for whatever reason). If <span class="RktVar">read-in</span> or
<span class="RktSym">peek-in</span> is called, any previously associated pipe (as
returned by a previous call) is disassociated from the
port and is not in use by any other thread as a result of the
previous association.</p><p>If <span class="RktVar">peek</span>, <span class="RktVar">get-progress-evt</span>, and
<span class="RktVar">commit</span> are all provided and
non-<span class="RktVal">#f</span>, then the following is an acceptable implementation
of <span class="RktVar">read-in</span>:</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktPn">(</span><span class="RktSym"><a href="lambda.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._lambda%29%29" class="RktStxLink" data-pltdoc="x">lambda</a></span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">bstr</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym"><a href="let.html#%28form._%28%28lib._racket%2Fprivate%2Fletstx-scheme..rkt%29._let%2A%29%29" class="RktStxLink" data-pltdoc="x">let*</a></span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">progress-evt</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktVar">get-progress-evt</span><span class="RktPn">)</span><span class="RktPn">]</span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">[</span><span class="RktSym">v</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktVar">peek</span><span class="hspace">&nbsp;</span><span class="RktSym">bstr</span><span class="hspace">&nbsp;</span><span class="RktVal">0</span><span class="hspace">&nbsp;</span><span class="RktSym">progress-evt</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym"><a href="if.html#%28form._%28%28lib._racket%2Fprivate%2Fletstx-scheme..rkt%29._cond%29%29" class="RktStxLink" data-pltdoc="x">cond</a></span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym"><a href="sync.html#%28def._%28%28quote._~23~25kernel%29._sync%2Ftimeout%29%29" class="RktValLink" data-pltdoc="x">sync/timeout</a></span><span class="hspace">&nbsp;</span><span class="RktVal">0</span><span class="hspace">&nbsp;</span><span class="RktSym">progress-evt</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span><span class="RktVal">0</span><span class="RktPn">]</span><span class="hspace">&nbsp;</span><span class="RktCmt">;</span><span class="RktCmt">&nbsp;</span><span class="RktCmt">try again</span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym"><a href="sync.html#%28def._%28%28quote._~23~25kernel%29._evt~3f%29%29" class="RktValLink" data-pltdoc="x">evt?</a></span><span class="hspace">&nbsp;</span><span class="RktSym">v</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym"><a href="sync.html#%28def._%28%28quote._~23~25kernel%29._wrap-evt%29%29" class="RktValLink" data-pltdoc="x">wrap-evt</a></span><span class="hspace">&nbsp;</span><span class="RktSym">v</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym"><a href="lambda.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._lambda%29%29" class="RktStxLink" data-pltdoc="x">lambda</a></span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">x</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span><span class="RktVal">0</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="hspace">&nbsp;</span><span class="RktCmt">;</span><span class="RktCmt">&nbsp;</span><span class="RktCmt">sync, try again</span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym"><a href="if.html#%28form._%28%28lib._racket%2Fprivate%2Fletstx-scheme..rkt%29._and%29%29" class="RktStxLink" data-pltdoc="x">and</a></span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><sp
<span class="RktVar">get-progress-evt</span>, and <span class="RktVar">commit</span>
procedures, however, and even an implementor who does supply
them may provide a different <span class="RktVar">read-in</span>
that uses a fast path for non-blocking reads.</p><p>In an input port is provided for <span class="RktVar">read-in</span>, then an input port
must also be provided for <span class="RktVar">peek</span>.</p></li><li><p><span class="RktVar">peek</span> &#8212;<wbr></wbr> either <span class="RktVal">#f</span>, an input port (in which
case peeks are redirected to the given port), or a procedure
that takes three arguments:</p><ul><li><p>a mutable byte string to receive peeked bytes;</p></li><li><p>a non-negative number of bytes (or
<a href="customport.html#%28elem._special%29" data-pltdoc="x">specials</a>) to skip before peeking; and</p></li><li><p>either <span class="RktVal">#f</span> or a progress event produced by
<span class="RktVar">get-progress-evt</span>.</p></li></ul><p>The results and conventions for <span class="RktVar">peek</span> are mostly the same
as for <span class="RktVar">read-in</span>. The main difference is in the handling of
the progress event, if it is not <span class="RktVal">#f</span>. If the given
progress event becomes ready, the <span class="RktVar">peek</span> must abort any
skip attempts and not peek any values. In particular,
<span class="RktVar">peek</span> must not peek any values if the progress event is
initially ready. If the port has been closed, the progress event
should be ready, in which case <span class="RktVar">peek</span> should complete
(instead of failing because the port is closed).</p><p>Unlike <span class="RktVar">read-in</span>, <span class="RktVar">peek</span> should produce
<span class="RktVal">#f</span> (or an event whose value is <span class="RktVal">#f</span>) if no bytes
were peeked because the progress event became ready. Like
<span class="RktVar">read-in</span>, a <span class="RktVal">0</span> result indicates that another
attempt is likely to succeed, so <span class="RktVal">0</span> is inappropriate when
the progress event is ready. Also like <span class="RktVar">read-in</span>,
<span class="RktVar">peek</span> must not block indefinitely.</p><p>The skip count provided to <span class="RktVar">peek</span> is a number of bytes (or
<a href="customport.html#%28elem._special%29" data-pltdoc="x">specials</a>) that must remain present in the
port&#8212;<wbr></wbr>in addition to the peek results&#8212;<wbr></wbr>when the peek results are
reported. If the skip count requests reading data that is past an eof,
it should not, and instead produce <span class="RktSym"><a href="port-ops.html#%28def._%28%28quote._~23~25kernel%29._eof%29%29" class="RktValLink" data-pltdoc="x">eof</a></span> (until the eof is
consumed).</p><p>If a progress event is supplied, then the peek is
effectively canceled when another process reads data before the
given number can be skipped. If a progress event is not supplied
and data is read, then the peek must effectively restart with the
original skip count.</p><p>The system does not check that multiple peeks return consistent
results, or that peeking and reading produce consistent results,
although they must.</p><p>If <span class="RktVar">peek</span> is <span class="RktVal">#f</span>, then peeking for the port is
implemented automatically in terms of reads, but with several
limitations. First, the automatic implementation is not
thread-safe. Second, the automatic implementation cannot handle
<a href="customport.html#%28elem._special%29" data-pltdoc="x">special</a> results (non-byte and non-eof), so
<span class="RktVar">read-in</span> cannot return a procedure for a
<a href="customport.html#%28elem._special%29" data-pltdoc="x">special</a> when <span class="RktVar">peek</span> is
<span class="RktVal">#f</span>. Finally, the automatic peek implementation is
incompatible with progress events, so if <span class="RktVar">peek</span> is
<span class="RktVal">#f</span>, then <span class="RktVar">get-progress-evt</span> and <span class="RktVar">commit</span> must
be <span class="RktVal">#f</span>. See also <span class="RktSym"><a href="port-lib.html#%28def._%28%28lib._racket%2Fport..rkt%29._make-input-port%2Fread-to-peek%29%29" class="RktValLink" data-pltdoc="x">make-input-port/read-to-peek</a></span>,
which implements peeking in terms of <span class="RktVar">read-in</span> without
these constraints.</p><p>In an input port is provided for <span class="RktVar">peek</span>, then an input port
must also be provided for <span class="RktVar">read-in</span>.</p></li><li><p><span class="RktVar">close</span> &#8212;<wbr></wbr> a procedure of zero arguments that is
called to close the port. The port is not considered closed until
the closing procedure returns. The port&rsquo;s procedures will never be
used again via the port after it is closed. However, the closing
procedure can be called simultaneously in multiple threads (if the
port is accessible in multiple threads), and it may be called
during a call to the other procedures in another thread; in the
latter case, any outstanding reads and peeks should be terminated
with an error.</p></li><li><p><span class="RktVar">get-progress-evt</span> &#8212;<wbr></wbr> either <span class="RktVal">#f</span> (the
default), or a procedure that takes no arguments and returns an
event. The event must become ready only after data is next read
from the port or the port is closed. If the port is already closed,
the event must be ready. After the event becomes
ready, it must remain so. See the description of <span class="RktVar">read-in</span>
for information about the allowed results of this function when
<span class="RktVar">read-in</span> returns a pipe input port. See also
<span class="RktSym"><a href="semaphore.html#%28def._%28%28quote._~23~25kernel%29._semaphore-peek-evt%29%29" class="RktValLink" data-pltdoc="x">semaphore-peek-evt</a></span>, which is sometimes useful for
implementing <span class="RktVar">get-progress-evt</span>.</p><p>If <span class="RktVar">get-progress-evt</span> is <span class="RktVal">#f</span>, then
<span class="RktSym"><a href="Byte_and_String_Input.html#%28def._%28%28quote._~23~25kernel%29._port-provides-progress-evts~3f%29%29" class="RktValLink" data-pltdoc="x">port-provides-progress-evts?</a></span> applied to the port will
produce <span class="RktVal">#f</span>, and the port will not be a valid argument to
<span class="RktSym"><a href="Byte_and_String_Input.html#%28def._%28%28quote._~23~25kernel%29._port-progress-evt%29%29" class="RktValLink" data-pltdoc="x">port-progress-evt</a></span>.</p><p>The result event will not be exposed directly by
<span class="RktSym"><a href="Byte_and_String_Input.html#%28def._%28%28quote._~23~25kernel%29._port-progress-evt%29%29" class="RktValLink" data-pltdoc="x">port-progress-evt</a></span>. Instead, it will be wrapped in an
event for which <span class="RktSym"><a href="Byte_and_String_Input.html#%28def._%28%28quote._~23~25kernel%29._progress-evt~3f%29%29" class="RktValLink" data-pltdoc="x">progress-evt?</a></span> returns true.</p></li><li><p><span class="RktVar">commit</span> &#8212;<wbr></wbr> either <span class="RktVal">#f</span> (the
default), or a procedure that takes three arguments:</p><ul><li><p>an exact, positive integer <span style="font-style: italic">k</span><span style="vertical-align: sub; font-size: 80%"><span style="font-style: italic">r</span></span><span style="font-style: italic"></span>;</p></li><li><p>a progress event produced by <span class="RktVar">get-progress-evt</span>;</p></li><li><p>an event, <span class="RktVar">done</span>, that is either a channel-put
event, channel, semaphore, semaphore-peek event, always
event, or never event.</p></li></ul><p>A <span style="font-style: italic">commit</span> corresponds to removing data from the stream
that was previously peeked, but only if no other process removed
data first. (The removed data does not need to be reported,
because it has been peeked already.) More precisely, assuming
that <span style="font-style: italic">k</span><span style="vertical-align: sub; font-size: 80%"><span style="font-style: italic">p</span></span><span style="font-style: italic"></span> bytes, <a href="customport.html#%28elem._special%29" data-pltdoc="x">specials</a>, and
mid-stream <span class="RktSym"><a href="port-ops.html#%28def._%28%28quote._~23~25kernel%29._eof%29%29" class="RktValLink" data-pltdoc="x">eof</a></span>s have been previously peeked or skipped
at the start of the port&rsquo;s stream, <span class="RktVar">commit</span> must satisfy
the following constraints:</p><ul><li><p>It must return only when the commit is complete or when the
given progress event becomes ready.</p></li><li><p>It must commit only if <span style="font-style: italic">k</span><span style="vertical-align: sub; font-size: 80%"><span style="font-style: italic">p</span></span><span style="font-style: italic"></span> is positive.</p></li><li><p>If it commits, then it must do so with either <span style="font-style: italic">k</span><span style="vertical-align: sub; font-size: 80%"><span style="font-style: italic">r</span></span><span style="font-style: italic"></span> items
or <span style="font-style: italic">k</span><span style="vertical-align: sub; font-size: 80%"><span style="font-style: italic">p</span></span><span style="font-style: italic"></span> items, whichever is smaller, and only if <span style="font-style: italic">k</span><span style="vertical-align: sub; font-size: 80%"><span style="font-style: italic">p</span></span><span style="font-style: italic"></span> is
positive.</p></li><li><p>It must never choose <span class="RktVar">done</span> in a synchronization
after the given progress event is ready, or after <span class="RktVar">done</span>
has been synchronized once.</p></li><li><p>It must not treat any data as read from the port unless
<span class="RktVar">done</span> is chosen in a synchronization.</p></li><li><p>It must not block indefinitely if <span class="RktVar">done</span> is ready;
it must return soon after the read completes or soon after the
given progress event is ready, whichever is first.</p></li><li><p>It can report an error by raising an exception, but only if
no data has been committed. In other words, no data should be lost due to
an exception, including a break exception.</p></li><li><p>It must return a true value if data has been committed,
<span class="RktVal">#f</span> otherwise. When it returns a value, the given
progress event must be ready (perhaps because data has just been
committed).</p></li><li><p>It should return a byte string as a true result when line
counting is enabled and <span class="RktVar">get-location</span> is <span class="RktVal">#f</span> (so
that line counting is implemented the default way); the result
byte string represents the data that was committed for the
purposes of character and line counting. If any other true result
is returned when a byte string is expected, it is treated like a
byte string where each byte corresponds to a non-newline
character.</p></li><li><p>It must raise an exception if no data (including
<span class="RktSym"><a href="port-ops.html#%28def._%28%28quote._~23~25kernel%29._eof%29%29" class="RktValLink" data-pltdoc="x">eof</a></span>) has been peeked from the beginning of the port&rsquo;s
stream, or if it would have to block indefinitely to wait for the
given progress event to become ready.</p></li></ul><p>A call to <span class="RktVar">commit</span> is <span class="RktSym"><a href="breakhandler.html#%28form._%28%28lib._racket%2Fprivate%2Fmore-scheme..rkt%29._parameterize-break%29%29" class="RktStxLink" data-pltdoc="x">parameterize-break</a></span>ed to
disable breaks.</p></li><li><p><span class="RktVar">get-location</span> &#8212;<wbr></wbr> either <span class="RktVal">#f</span> (the
default), or a procedure that takes no arguments and returns three
values: the line number for the next item in the port&rsquo;s stream (a
positive number or <span class="RktVal">#f</span>), the column number for the next
item in the port&rsquo;s stream (a non-negative number or <span class="RktVal">#f</span>),
and the position for the next item in the port&rsquo;s stream (a
positive number or <span class="RktVal">#f</span>). See also <a href="linecol.html" data-pltdoc="x">Counting Positions, Lines, and Columns</a>.</p><p>This procedure is called to implement <span class="RktSym"><a href="linecol.html#%28def._%28%28quote._~23~25kernel%29._port-next-location%29%29" class="RktValLink" data-pltdoc="x">port-next-location</a></span>,
but only if line counting is enabled for the port via
<span class="RktSym"><a href="linecol.html#%28def._%28%28quote._~23~25kernel%29._port-count-lines%21%29%29" class="RktValLink" data-pltdoc="x">port-count-lines!</a></span> (in which case <span class="RktVar">count-lines!</span> is
called). The <span class="RktSym"><a href="Reading.html#%28def._%28%28quote._~23~25kernel%29._read%29%29" class="RktValLink" data-pltdoc="x">read</a></span> and <span class="RktSym"><a href="Reading.html#%28def._%28%28quote._~23~25kernel%29._read-syntax%29%29" class="RktValLink" data-pltdoc="x">read-syntax</a></span> procedures
assume that reading a non-whitespace character increments the
column and position by one.</p></li><li><p><span class="RktVar">count-lines!</span> &#8212;<wbr></wbr> a procedure of no arguments
that is called if and when line counting is enabled for the port.
The default procedure is <span class="RktSym"><a href="void.html#%28def._%28%28quote._~23~25kernel%29._void%29%29" class="RktValLink" data-pltdoc="x">void</a></span>.</p></li><li><p><span class="RktVar">init-position</span> &#8212;<wbr></wbr> normally an exact, positive integer
that determines the position of the port&rsquo;s first item, which is
used by <span class="RktSym"><a href="port-buffers.html#%28def._%28%28quote._~23~25kernel%29._file-position%29%29" class="RktValLink" data-pltdoc="x">file-position</a></span> or when line counting is
<span style="font-style: italic">not</span> enabled for the port. The default is <span class="RktVal">1</span>. If
<span class="RktVar">init-position</span> is <span class="RktVal">#f</span>, the port is treated as
having an unknown position. If <span class="RktVar">init-position</span> is a port,
then the given port&rsquo;s position is always used for the new port&rsquo;s
position. If <span class="RktVar">init-position</span> is a procedure, it is called
as needed to obtain the port&rsquo;s position.</p></li><li><p><span class="RktVar">buffer-mode</span> &#8212;<wbr></wbr> either <span class="RktVal">#f</span> (the default) or a
procedure that accepts zero or one arguments. If
<span class="RktVar">buffer-mode</span> is <span class="RktVal">#f</span>, then the resulting port does
not support a buffer-mode setting. Otherwise, the procedure is
called with one symbol argument (<span class="RktVal">'</span><span class="RktVal">block</span> or
<span class="RktVal">'</span><span class="RktVal">none</span>) to set the buffer mode, and it is called with zero
arguments to get the current buffer mode. In the latter case, the
result must be <span class="RktVal">'</span><span class="RktVal">block</span>, <span class="RktVal">'</span><span class="RktVal">none</span>, or <span class="RktVal">#f</span>
(unknown). See <a href="port-buffers.html" data-pltdoc="x">Port Buffers and Positions</a> for more information on
buffer modes.</p></li></ul><p><a name="(elem._special)"></a><span style="font-weight: bold">&ldquo;Special&rdquo; results:</span> When
<span class="RktVar">read-in</span> or <span class="RktVar">peek</span> (or an event produced by one of
these) returns a procedure, the procedure is used to obtain a
non-byte result. (This non-byte result is <span style="font-style: italic">not</span> intended to
return a character or <span class="RktSym"><a href="port-ops.html#%28def._%28%28quote._~23~25kernel%29._eof%29%29" class="RktValLink" data-pltdoc="x">eof</a></span>; in particular, <span class="RktSym"><a href="Byte_and_String_Input.html#%28def._%28%28quote._~23~25kernel%29._read-char%29%29" class="RktValLink" data-pltdoc="x">read-char</a></span>
raises an exception if it encounters a special-result procedure, even
if the procedure produces a byte.) A special-result procedure must
accept four arguments that represent a source location. The first
argument is <span class="RktVal">#f</span> when the special read is triggered by <span class="RktSym"><a href="Reading.html#%28def._%28%28quote._~23~25kernel%29._read%29%29" class="RktValLink" data-pltdoc="x">read</a></span>
or <span class="RktSym"><a href="Reading.html#%28def._%28%28quote._~23~25kernel%29._read%2Frecursive%29%29" class="RktValLink" data-pltdoc="x">read/recursive</a></span>.</p><p>The special-value procedure can return an arbitrary value, and it
will be called zero or one times (not necessarily before further
reads or peeks from the port). See <a href="reader-procs.html" data-pltdoc="x">Reader-Extension Procedures</a> for
more details on the procedure&rsquo;s result.</p><p>If <span class="RktVar">read-in</span> or <span class="RktVar">peek</span> returns a special
procedure when called by any reading procedure other than
<span class="RktSym"><a href="Reading.html#%28def._%28%28quote._~23~25kernel%29._read%29%29" class="RktValLink" data-pltdoc="x">read</a></span>, <span class="RktSym"><a href="Reading.html#%28def._%28%28quote._~23~25kernel%29._read-syntax%29%29" class="RktValLink" data-pltdoc="x">read-syntax</a></span>, <span class="RktSym"><a href="Byte_and_String_Input.html#%28def._%28%28quote._~23~25kernel%29._read-char-or-special%29%29" class="RktValLink" data-pltdoc="x">read-char-or-special</a></span>,
<span class="RktSym"><a href="Byte_and_String_Input.html#%28def._%28%28quote._~23~25kernel%29._peek-char-or-special%29%29" class="RktValLink" data-pltdoc="x">peek-char-or-special</a></span>, <span class="RktSym"><a href="Byte_and_String_Input.html#%28def._%28%28quote._~23~25kernel%29._read-byte-or-special%29%29" class="RktValLink" data-pltdoc="x">read-byte-or-special</a></span>, or
<span class="RktSym"><a href="Byte_and_String_Input.html#%28def._%28%28quote._~23~25kernel%29._peek-byte-or-special%29%29" class="RktValLink" data-pltdoc="x">peek-byte-or-special</a></span>, then the <span class="RktSym"><a href="exns.html#%28def._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._exn~3afail~3acontract%29%29" class="RktValLink" data-pltdoc="x">exn:fail:contract</a></span> exception is raised.</p><p><div class="SIntrapara">Examples:</div><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktCmt">;</span><span class="RktCmt">&nbsp;</span><span class="RktCmt">A port with no input...</span></td></tr><tr><td><span class="RktCmt">;</span><span class="RktCmt">&nbsp;</span><span class="RktCmt">Easy: </span><span class="RktPn">(</span><span class="RktSym"><a href="stringport.html#%28def._%28%28quote._~23~25kernel%29._open-input-bytes%29%29" class="RktValLink" data-pltdoc="x">open-input-bytes</a></span><span class="stt"> </span><span class="RktVal">#""</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktCmt">;</span><span class="RktCmt">&nbsp;</span><span class="RktCmt">Hard:</span></td></tr><tr><td><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">&gt; </span><span class="RktPn">(</span><span class="RktSym"><a href="define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span><span class="hspace">&nbsp;</span><span class="RktSym">/dev/null-in</span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="hspace">&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym"><a href="customport.html#%28def._%28%28quote._~23~25kernel%29._make-input-port%29%29" class="RktValLink" data-pltdoc="x">make-input-port</a></span><span class="hspace">&nbsp;</span><span class="RktVal">'</span><span class="RktVal">null</span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym"><a href="lambda.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._lambda%29%29" class="RktStxLink" data-pltdoc="x">lambda</a></span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">s</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span><span class="RktSym"><a href="port-ops.html#%28def._%28%28quote._~23~25kernel%29._eof%29%29" class="RktValLink" data-pltdoc="x">eof</a></span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym"><a href="lambda.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._lambda%29%29" class="RktStxLink" data-pltdoc="x">lambda</a></span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">skip</span><span class="hspace">&nbsp;</span><span class="RktSym">s</span><span class="hspace">&nbsp;</span><span class="RktSym">progress-evt</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span><span class="RktSym"><a href="port-ops.html#%28def._%28%28quote._~23~25kernel%29._eof%29%29" class="RktValLink" data-pltdoc="x">eof</a></span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktSym"><a href="void.html#%28def._%28%28quote._~23~25kernel%29._void%29%29" class="RktValLink" data-pltdoc="x">void</a></span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">(</span><span c
writing. If <span class="RktVar">close</span> procedure has no side effects, then
the port need not be explicitly closed. The port can buffer data
within its <span class="RktVar">write-out</span> and <span class="RktVar">write-out-special</span>
procedures.</div></p><ul><li><p><span class="RktVar">name</span> &#8212;<wbr></wbr> the name for the output port.</p></li><li><p><span class="RktVar">evt</span> &#8212;<wbr></wbr> a synchronization event (see <a href="sync.html" data-pltdoc="x">Events</a>;
e.g., a semaphore or another port). The event is used in place of
the output port when the port is supplied to synchronization
procedures like <span class="RktSym"><a href="sync.html#%28def._%28%28quote._~23~25kernel%29._sync%29%29" class="RktValLink" data-pltdoc="x">sync</a></span>. Thus, the event should be
unblocked when the port is ready for writing at least one byte
without blocking, or ready to make progress in flushing an
internal buffer without blocking. The event must not unblock
unless the port is ready for writing; otherwise, the guarantees of
<span class="RktSym"><a href="sync.html#%28def._%28%28quote._~23~25kernel%29._sync%29%29" class="RktValLink" data-pltdoc="x">sync</a></span> will be broken for the output port. Use
<span class="RktSym"><a href="sync.html#%28def._%28%28quote._~23~25kernel%29._always-evt%29%29" class="RktValLink" data-pltdoc="x">always-evt</a></span> if writes to the port always succeed without
blocking.</p></li><li><p><span class="RktVar">write-out</span> &#8212;<wbr></wbr> either an output port, which indicates that
writes should be redirected to the given port, or a procedure
of five arguments:</p><ul><li><p>an immutable byte string containing bytes to write;</p></li><li><p>a non-negative exact integer for a starting offset
(inclusive) into the byte string;</p></li><li><p>a non-negative exact integer for an ending offset
(exclusive) into the byte string;</p></li><li><p>a boolean; <span class="RktVal">#f</span> indicates that the port is allowed
to keep the written bytes in a buffer, and that it is
allowed to block indefinitely; <span class="RktVal">#t</span> indicates that the
write should not block, and that the port should attempt to flush
its buffer and completely write new bytes instead of
buffering them;</p></li><li><p>a boolean; <span class="RktVal">#t</span> indicates that if the port blocks
for a write, then it should enable breaks while blocking (e.g.,
using <span class="RktSym"><a href="sync.html#%28def._%28%28quote._~23~25kernel%29._sync%2Fenable-break%29%29" class="RktValLink" data-pltdoc="x">sync/enable-break</a></span>); this argument is always
<span class="RktVal">#f</span> if the fourth argument is <span class="RktVal">#t</span>.</p></li></ul><p>The procedure returns one of the following:</p><ul><li><p>a non-negative exact integer representing the number of
bytes written or buffered;</p></li><li><p><span class="RktVal">#f</span> if no bytes could be written, perhaps because
the internal buffer could not be completely flushed;</p></li><li><p>a <a href="pipeports.html#%28tech._pipe%29" data-pltdoc="x">pipe</a> output port (when buffering is allowed
and not when flushing) for buffering bytes as long as the pipe is
not full and until <span class="RktVar">write-out</span> or
<span class="RktVar">write-out-special</span> is called; or</p></li><li><p>a synchronizable event (see <a href="sync.html" data-pltdoc="x">Events</a>) other than a
pipe output port that acts like the result of
<span class="RktSym"><a href="Byte_and_String_Output.html#%28def._%28%28quote._~23~25kernel%29._write-bytes-avail-evt%29%29" class="RktValLink" data-pltdoc="x">write-bytes-avail-evt</a></span> to complete the write.</p></li></ul><p>Since <span class="RktVar">write-out</span> can produce an event, an acceptable
implementation of <span class="RktVar">write-out</span> is to pass its first three
arguments to the port&rsquo;s <span class="RktVar">get-write-evt</span>. Some port
implementors, however, may choose not to provide
<span class="RktVar">get-write-evt</span> (perhaps because writes cannot be
made atomic), or may implement <span class="RktVar">write-out</span> to
enable a fast path for non-blocking writes or to
enable buffering.</p><p>From a user&rsquo;s perspective, the difference between buffered and
completely written data is (1) buffered data can be lost in the
future due to a failed write, and (2) <span class="RktSym"><a href="port-buffers.html#%28def._%28%28quote._~23~25kernel%29._flush-output%29%29" class="RktValLink" data-pltdoc="x">flush-output</a></span> forces
all buffered data to be completely written. Under no circumstances
is buffering required.</p><p>If the start and end indices are the same, then the fourth
argument to <span class="RktVar">write-out</span> will be <span class="RktVal">#f</span>, and the write
request is actually a flush request for the port&rsquo;s buffer (if
any), and the result should be <span class="RktVal">0</span> for a successful flush
(or if there is no buffer).</p><p>The result should never be <span class="RktVal">0</span> if the start and end indices
are different, otherwise the <span class="RktSym"><a href="exns.html#%28def._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._exn~3afail~3acontract%29%29" class="RktValLink" data-pltdoc="x">exn:fail:contract</a></span> exception is raised.
Similarly, the <span class="RktSym"><a href="exns.html#%28def._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._exn~3afail~3acontract%29%29" class="RktValLink" data-pltdoc="x">exn:fail:contract</a></span> exception is raised if <span class="RktVar">write-out</span>
returns a pipe output port when buffering is disallowed or when it
is called for flushing. If a returned integer is larger than the
supplied byte-string range, the <span class="RktSym"><a href="exns.html#%28def._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._exn~3afail~3acontract%29%29" class="RktValLink" data-pltdoc="x">exn:fail:contract</a></span> exception is raised.</p><p>The <span class="RktVal">#f</span> result should be avoided, unless the next write
attempt is likely to work. Otherwise, if data cannot be written,
return an event instead.</p><p>An event returned by <span class="RktVar">write-out</span> can return <span class="RktVal">#f</span> or
another event like itself, in contrast to events produced by
<span class="RktSym"><a href="Byte_and_String_Output.html#%28def._%28%28quote._~23~25kernel%29._write-bytes-avail-evt%29%29" class="RktValLink" data-pltdoc="x">write-bytes-avail-evt</a></span> or <span class="RktVar">get-write-evt</span>.
A writing process loops with <span class="RktSym"><a href="sync.html#%28def._%28%28quote._~23~25kernel%29._sync%29%29" class="RktValLink" data-pltdoc="x">sync</a></span> until it obtains a
non-event result.</p><p>The <span class="RktVar">write-out</span> procedure is always called with breaks
disabled, independent of whether breaks were enabled when the write
was requested by a client of the port. If breaks were enabled for
a blocking operation, then the fifth argument to <span class="RktVar">write-out</span>
will be <span class="RktVal">#t</span>, which indicates that <span class="RktVar">write-out</span> should
re-enable breaks while blocking.</p><p>If the writing procedure raises an exception, due to write
or commit operations, it must not have committed any bytes
(though it may have committed previously buffered bytes).</p><p>A port&rsquo;s writing procedure may be called in multiple threads
simultaneously (if the port is accessible in multiple
threads). The port is responsible for its own internal
synchronization. Note that improper implementation of such
synchronization mechanisms might cause a non-blocking write
procedure to block.</p></li><li><p><span class="RktVar">close</span> &#8212;<wbr></wbr> a procedure of zero arguments that is
called to close the port. The port is not considered closed until
the closing procedure returns. The port&rsquo;s procedures will never be
used again via the port after it is closed. However, the closing
procedure can be called simultaneously in multiple threads (if the
port is accessible in multiple threads), and it may be called
during a call to the other procedures in another thread; in the
latter case, any outstanding writes or flushes should be
terminated immediately with an error.</p></li><li><p><span class="RktVar">write-out-special</span> &#8212;<wbr></wbr> either <span class="RktVal">#f</span> (the
default), an output port (which indicates that
special writes should be redirected to the given port),
or a procedure to handle <span class="RktSym"><a href="Byte_and_String_Output.html#%28def._%28%28quote._~23~25kernel%29._write-special%29%29" class="RktValLink" data-pltdoc="x">write-special</a></span> calls
for the port. If <span class="RktVal">#f</span>, then the port does not support
special output, and <span class="RktSym"><a href="Byte_and_String_Output.html#%28def._%28%28quote._~23~25kernel%29._port-writes-special~3f%29%29" class="RktValLink" data-pltdoc="x">port-writes-special?</a></span> will return
<span class="RktVal">#f</span> when applied to the port.</p><p>If a procedure is supplied, it takes three arguments: the special
value to write, a boolean that is <span class="RktVal">#f</span> if the procedure can
buffer the special value and block indefinitely, and a boolean
that is <span class="RktVal">#t</span> if the procedure should enable breaks while
blocking. The result is one of the following:</p><ul><li><p>a non-event true value, which indicates that the special is
written;</p></li><li><p><span class="RktVal">#f</span> if the special could not be written, perhaps
because an internal buffer could not be completely flushed;</p></li><li><p>a synchronizable event (see <a href="sync.html" data-pltdoc="x">Events</a>) that acts like
the result of <span class="RktVar">get-write-special-evt</span> to complete the write.</p></li></ul><p>Since <span class="RktVar">write-out-special</span> can return an event,
passing the first argument to an implementation of
<span class="RktVar">get-write-special-evt</span> is acceptable as a
<span class="RktVar">write-out-special</span>.</p><p>As for <span class="RktVar">write-out</span>, the <span class="RktVal">#f</span> result is discouraged,
since it can lead to busy waiting. Also as for <span class="RktVar">write-out</span>,
an event produced by <span class="RktVar">write-out-special</span> is allowed
to produce <span class="RktVal">#f</span> or another event like itself. The
<span class="RktVar">write-out-special</span> procedure is always called with
breaks disabled, independent of whether breaks were enabled when
the write was requested by a client of the port.</p></li><li><p><span class="RktVar">get-write-evt</span> &#8212;<wbr></wbr> either <span class="RktVal">#f</span> (the
default) or a procedure of three arguments:</p><ul><li><p>an immutable byte string containing bytes to write;</p></li><li><p>a non-negative exact integer for a starting offset
(inclusive) into the byte string; and</p></li><li><p>a non-negative exact integer for an ending offset
(exclusive) into the byte string.</p></li></ul><p>The result is a synchronizable event (see <a href="sync.html" data-pltdoc="x">Events</a>) to act as
the result of <span class="RktSym"><a href="Byte_and_String_Output.html#%28def._%28%28quote._~23~25kernel%29._write-bytes-avail-evt%29%29" class="RktValLink" data-pltdoc="x">write-bytes-avail-evt</a></span> for the port (i.e.,
to complete a write or flush), which becomes available only as
data is committed to the port&rsquo;s underlying device, and whose
result is the number of bytes written.</p><p>If <span class="RktVar">get-write-evt</span> is <span class="RktVal">#f</span>, then
<span class="RktSym"><a href="Byte_and_String_Output.html#%28def._%28%28quote._~23~25kernel%29._port-writes-atomic~3f%29%29" class="RktValLink" data-pltdoc="x">port-writes-atomic?</a></span> will produce <span class="RktVal">#f</span> when applied
to the port, and the port will not be a valid argument to
procedures such as <span class="RktSym"><a href="Byte_and_String_Output.html#%28def._%28%28quote._~23~25kernel%29._write-bytes-avail-evt%29%29" class="RktValLink" data-pltdoc="x">write-bytes-avail-evt</a></span>.
Otherwise, an event returned by <span class="RktVar">get-write-evt</span> must
not cause data to be written to the port unless the event is
chosen in a synchronization, and it must write to the port if the
event is chosen (i.e., the write must appear atomic with respect
to the synchronization).</p><p>If the event&rsquo;s result integer is larger than the supplied
byte-string range, the <span class="RktSym"><a href="exns.html#%28def._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._exn~3afail~3acontract%29%29" class="RktValLink" data-pltdoc="x">exn:fail:contract</a></span> exception is raised by a wrapper
on the event. If the start and end indices are the same (i.e., no
bytes are to be written), then the event should produce <span class="RktVal">0</span>
when the buffer is completely flushed. (If the port has no buffer,
then it is effectively always flushed.)</p><p>If the event raises an exception, due to write or commit
operations, it must not have committed any new bytes (though it
may have committed previously buffered bytes).</p><p>Naturally, a port&rsquo;s events may be used in multiple threads
simultaneously (if the port is accessible in multiple
threads). The port is responsible for its own internal
synchronization.</p></li><li><p><span class="RktVar">get-write-special-evt</span> &#8212;<wbr></wbr> either <span class="RktVal">#f</span>
(the default), or a procedure to handle <span class="RktSym"><a href="Byte_and_String_Output.html#%28def._%28%28quote._~23~25kernel%29._write-special-evt%29%29" class="RktValLink" data-pltdoc="x">write-special-evt</a></span>
calls for the port. This argument must be <span class="RktVal">#f</span> if either
<span class="RktVar">write-out-special</span> or <span class="RktVar">get-write-evt</span>
is <span class="RktVal">#f</span>, and it must be a procedure if both of those
arguments are procedures.</p><p>If it is a procedure, it takes one argument: the special value to
write. The resulting event (with its constraints) is analogous to
the result of <span class="RktVar">get-write-evt</span>.</p><p>If the event raises an exception, due to write or commit
operations, it must not have committed the special value (though
it may have committed previously buffered bytes and values).</p></li><li><p><span class="RktVar">get-location</span> &#8212;<wbr></wbr> either <span class="RktVal">#f</span> (the
default), or a procedure that takes no arguments and returns three
values: the line number for the next item written to the port&rsquo;s
stream (a positive number or <span class="RktVal">#f</span>), the column number for
the next item written to port&rsquo;s stream (a non-negative number or
<span class="RktVal">#f</span>), and the position for the next item written to port&rsquo;s
stream (a positive number or <span class="RktVal">#f</span>). See also
<a href="linecol.html" data-pltdoc="x">Counting Positions, Lines, and Columns</a>.</p><p>This procedure is called to implement <span class="RktSym"><a href="linecol.html#%28def._%28%28quote._~23~25kernel%29._port-next-location%29%29" class="RktValLink" data-pltdoc="x">port-next-location</a></span>
for the port, but only if line counting is enabled for the port
via <span class="RktSym"><a href="linecol.html#%28def._%28%28quote._~23~25kernel%29._port-count-lines%21%29%29" class="RktValLink" data-pltdoc="x">port-count-lines!</a></span> (in which case
<span class="RktVar">count-lines!</span> is called).</p></li><li><p><span class="RktVar">count-lines!</span> &#8212;<wbr></wbr> a procedure of no arguments
that is called if and when line counting is enabled for the port.
The default procedure is <span class="RktSym"><a href="void.html#%28def._%28%28quote._~23~25kernel%29._void%29%29" class="RktValLink" data-pltdoc="x">void</a></span>.</p></li><li><p><span class="RktVar">init-position</span> &#8212;<wbr></wbr> normally an exact, positive integer
that determines the position of the port&rsquo;s first item, which is
used by <span class="RktSym"><a href="port-buffers.html#%28def._%28%28quote._~23~25kernel%29._file-position%29%29" class="RktValLink" data-pltdoc="x">file-position</a></span> or when line counting is
<span style="font-style: italic">not</span> enabled for the port. The default is <span class="RktVal">1</span>. If
<span class="RktVar">init-position</span> is <span class="RktVal">#f</span>, the port is treated as
having an unknown position. If <span class="RktVar">init-position</span> is a port,
then the given port&rsquo;s position is always used for the new port&rsquo;s
position. If <span class="RktVar">init-position</span> is a procedure, it is called
as needed to obtain the port&rsquo;s position.</p></li><li><p><span class="RktVar">buffer-mode</span> &#8212;<wbr></wbr> either <span class="RktVal">#f</span> (the
default) or a procedure that accepts zero or one arguments. If
<span class="RktVar">buffer-mode</span> is <span class="RktVal">#f</span>, then the resulting
port does not support a buffer-mode setting. Otherwise, the
procedure is called with one symbol argument (<span class="RktVal">'</span><span class="RktVal">block</span>,
<span class="RktVal">'</span><span class="RktVal">line</span>, or <span class="RktVal">'</span><span class="RktVal">none</span>) to set the buffer mode, and it is
called with zero arguments to get the current buffer mode. In the
latter case, the result must be <span class="RktVal">'</span><span class="RktVal">block</span>, <span class="RktVal">'</span><span class="RktVal">line</span>,
<span class="RktVal">'</span><span class="RktVal">none</span>, or <span class="RktVal">#f</span> (unknown). See <a href="port-buffers.html" data-pltdoc="x">Port Buffers and Positions</a>
for more information on buffer modes.</p></li></ul><p><div class="SIntrapara">Examples:</div><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktCmt">;</span><span class="RktCmt">&nbsp;</span><span class="RktCmt">A port that writes anything to nowhere:</span></td></tr><tr><td><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">&gt; </span><span class="RktPn">(</span><span class="RktSym"><a href="define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span><span class="hspace">&nbsp;</span><span class="RktSym">/dev/null-out</span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="hspace">&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym"><a href="customport.html#%28def._%28%28quote._~23~25kernel%29._make-output-port%29%29" class="RktValLink" data-pltdoc="x">make-output-port</a></span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="hspace">&nbsp;&nbsp;&nbsp;</span><span class="RktVal">'</span><span class="RktVal">null</span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="hspace">&nbsp;&nbsp;&nbsp;</span><span class="RktSym"><a href="sync.html#%28def._%28%28quote._~23~25kernel%29._always-evt%29%29" class="RktValLink" data-pltdoc="x">always-evt</a></span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="hspace">&nbsp;&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym"><a href="lambda.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._lambda%29%29" class="RktStxLink" data-pltdoc="x">lambda</a></span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">s</span><span class="hspace">&nbsp;</span><span class="RktSym">start</span><span class="hspace">&nbsp;</span><span class="RktSym">end</span><span class="hspace">&nbsp;</span><span class="RktSym">non-block?</span><span class="hspace">&nbsp;</span><span class="RktSym">breakable?</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym"><a href="generic-numbers.html#%28def._%28%28quote._~23~25kernel%29._-%29%29" class="RktValLink" data-pltdoc="x"><span class="nobreak">-</span></a></span><span class="hspace">&nbsp;</span><span class="RktSym">end</span><span class="hspace">&nbsp;</span><span class="RktSym">start</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="hspace">&nbsp;&nbsp;&nbsp;</span><span class="RktSym"><a href="void.html#%28def._%28%28quote._~23~25kernel%29._void%29%29" class="RktValLink" data-pltdoc="x">void</a></span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="hspace">&nbsp;&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym"><a href="lambda.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._lambda%29%29" class="RktStxLink" data-pltdoc="x">lambda</a></span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">special</span><span class="hspace">&nbsp;</span><span class="RktSym">non-block?</span><span class="hspace">&nbsp;</span><span class="RktSym">breakable?</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span><span class="RktVal">#t</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="hspace">&nbsp;&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym"><a href="lambda.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._lambda%29%29" class="RktStxLink" data-pltdoc="x">lambda</a></span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">s</span><span class="hspace">&nbsp;</span><span class="RktSym">start</span><span class="hspace">&nbsp;</span><span class="RktSym">end</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym"><a href="sync.html#%28def._%