I/O system
==========

Scheme48 supports a sophisticated, non-blocking, user-extensible I/O system untied to any particular operating system's I/O facilities.  It is based in three levels: channels, ports, and the facilities already built with both ports and channels in Scheme48, such as buffering.

Ports
-----

While channels provide the low-level interface directly to the OS's I/O facilities, ports provide a more abstract & generalized mechanism for I/O transmission. Rather than being specific to channels or being themselves primitive I/O devices, ports are functionally parameterized. This section describes the usual I/O operations on ports.  The next section describes the programmatic port parameterization mechanism, and the section following that describes the most commonly used built-in port abstraction, ports atop channels.

Port operations
...............

The following names are exported by the i/o structure.

 -- procedure: input-port? value returns boolean
 -- procedure: output-port? value returns boolean
     These return #t if their argument is both a port and either an input port or output port, respectively, or #f if neither condition is true.

 -- procedure: close-input-port port returns unspecified
 -- procedure: close-output-port port returns unspecified
     Closes PORT, which must be an input port or an output port, respectively.

 -- procedure: char-ready? [port] returns boolean
 -- procedure: output-port-ready? port returns boolean
     Char-ready? returns a true value if there is a character ready to be read from PORT and #f if there is no character ready.  PORT defaults to the current input port if absent; see below on current ports.  Output-port-ready? returns a true value if PORT is ready to receive a single written character and #f if not.

 -- procedure: read-block block start count port [wait?] returns count-read or EOF
 -- procedure: write-block block start count port returns count-written
 -- procedure: write-string string port returns char-count-written
     Read-block attempts to read COUNT elements from PORT into BLOCK, which may be a string or a byte vector, starting at START.  If fewer than COUNT characters or bytes are available to read from PORT, and WAIT? is a true value or absent, read-block will wait until COUNT characters are available and read into BLOCK; if WAIT? is #f, read-block immediately returns.  Read-block returns the number of elements read into BLOCK, or an end of file object if the stream's end is immediately encountered.  Write-block writes COUNT elements from BLOCK, which may be a string or a byte vector, starting at START to PORT.  Write-string is a convenience atop write-block for writing the entirety of a string to a port.

 -- procedure: newline [port] returns unspecified
     Writes a newline character or character sequence to the output port PORT.  PORT defaults to the current output port; see below on current ports.

 -- procedure: disclose-port port returns disclosed
     Returns a disclosed representation of PORT; see Writer.

 -- procedure: force-output port returns unspecified
     Forces all buffered output in the output port PORT to be sent.

 -- procedure: make-null-output-port returns output-port
     Returns an output port that will ignore any output it receives.

Current ports
.............

Scheme48 keeps in its Fluid/dynamic bindings, dynamic environment a set of `current' ports.  These include R5RS's current input and output ports, as well as ports for general noise produced by the system, and ports for where error messages are printed.  These procedures are exported by the i/o structure.

 -- procedure: current-input-port returns input-port
 -- procedure: current-output-port returns output-port
 -- procedure: current-noise-port returns output-port
 -- procedure: current-error-port returns output-port
     These return the values in the current dynamic environment of the respective ports.  Current-input-port and current-output-port are also exported by the scheme structure.

 -- procedure: input-port-option arguments returns input-port
 -- procedure: output-port-option arguments returns output-port
     These are utilities for retrieving optional input and output port arguments from rest argument lists, defaulting to the current input or output ports.  For example, assuming the newline character sequence is simply #\newline, newline might be written as:

          (define (newline . maybe-port)
            (write-char #\newline (output-port-option maybe-port))) lisp

 -- procedure: silently thunk returns values
     This stifles output from the current noise port in the dynamic extent of THUNK, which is applied to zero arguments.  Silently returns the values that THUNK returns.

 -- procedure: with-current-ports input output error thunk returns values
     With-current-ports dynamically binds the current input, output, and error ports to INPUT, OUTPUT, and ERROR, respectively, in the dynamic extent of THUNK, which is applied to zero arguments.  The current noise port is also bound to ERROR.  With-current-ports returns the values that THUNK returns.

Similarly to with-current-ports, the i/o-internal structure also exports these procedures:

 -- procedure: call-with-current-input-port port thunk returns values
 -- procedure: call-with-current-output-port port thunk returns values
 -- procedure: call-with-current-noise-port port thunk returns values
     These bind individual current ports for the dynamic extent of each THUNK, which is applied to zero arguments.  These all return the values that THUNK returns.

Programmatic ports
------------------

Ports are user-extensible; all primitive port operations on them --- read-char, write-block, etc --- are completely generalized.  Abstractions for buffered ports are also available.

Port data type
..............

The ports structure defines the basis of the port data type and exports the following procedures.

 -- procedure: make-port handler status lock data buffer index limit pending-eof? returns port
     Port constructor.  The arguments are all the fields of ports, which are described below.  Note that make-port is rarely called directly; usually one will use one of the buffered port constructors instead.

 -- procedure: port-handler port returns port-handler
 -- procedure: port-buffer port returns buffer or #f
 -- procedure: port-lock port returns value
 -- procedure: port-status port returns integer-status
 -- procedure: port-data port returns value
 -- procedure: port-index port returns integer or #f
 -- procedure: port-limit port returns integer or #f
 -- procedure: port-pending-eof? port returns boolean
     Accessors for the port fields:

     handler
          The handler is the functional parameterization mechanism: it provides all the port's operations, such as reading/writing blocks, disclosing (see Writer) the port, closing the port, etcT. See Port handlers.

     buffer
          The buffer is used for buffered ports, where it is a Bitwise manipulation, byte vector.  It may be any value for unbuffered ports.

     lock
          This misnamed field was originally used for a mutual exclusion lock, before optimistic concurrency was made the native synchronization mechanism in Scheme48.  It is now used as a `timestamp' for buffered ports: it is provisionally written to with a unique value when a thread resets the index to reüse the buffer, and it is provisionally read from when reading from the buffer.  In this way, if the buffer is reset while another thread is reading from it, the other thread's proposal is invalidated by the different value in memory than what was there when it logged the old timestamp in its proposal.

     status
          A mask from the port-status-options enumeration; see Miscellaneous I/O internals.

     data
          Arbitrary data for particular kinds of ports.  For example, for a port that tracks line & column information (see I/O extensions), this might be a record containing the underlying port, the line number, and the column number.

     index
          The current index into a buffered port's buffer.  If the port is not buffered, this is #f.

     limit
          The limit of the index field for a buffered port's buffer.  When the index field is equal to the limit field, the buffer is full.  If the port is not buffered, this is #f.

     pending-eof?
          For output ports, this is a boolean flag indicating whether the buffer has been forced to output recently.  For input ports, this is a boolean flag indicating whether an end of file is pending after reading through the current buffer.

 -- procedure: set-port-lock! port value returns unspecified
 -- procedure: set-port-status! port status returns unspecified
 -- procedure: set-port-data! port data returns unspecified
 -- procedure: set-port-index! port index returns unspecified
 -- procedure: set-port-limit! port index returns unspecified
 -- procedure: set-port-pending-eof?! port pending-eof? returns unspecified
     These assign respective fields of ports.  The buffer and handler fields, however, are immutable.

 -- procedure: provisional-port-handler port returns port-handler
 -- procedure: provisional-port-lock port returns value
 -- procedure: provisional-port-status port returns integer-status
 -- procedure: provisional-port-data port returns value
 -- procedure: provisional-port-index port returns integer or #f
 -- procedure: provisional-port-limit port returns integer or #f
 -- procedure: provisional-port-pending-eof? port returns boolean
 -- procedure: provisional-set-port-lock! port value returns unspecified
 -- procedure: provisional-set-port-status! port status returns unspecified
 -- procedure: provisional-set-port-data! port data returns unspecified
 -- procedure: provisional-set-port-index! port index returns unspecified
 -- procedure: provisional-set-port-limit! port index returns unspecified
 -- procedure: provisional-set-port-pending-eof?! port pending-eof? returns unspecified
     Provisional versions of the above port accessors & modifiers; that is, accessors & modifiers that log in the current proposal, if there is one.

Port handlers
.............

Port handlers store a port's specific operations for the general port operations, such as block reads and writes, buffer flushing, etcT.  Port handler constructors, including make-port-handler & the buffered port handlers in the next section, are available from the i/o-internal structure.

 -- procedure: make-port-handler discloser closer char-reader/writer block-reader/writer readiness-tester buffer-forcer returns port-handler
     Basic port handler constructor.  The arguments are used for the port handler fields.  Each field contains a procedure.  The expected semantics of each procedure depend on whether the port is for input or output.  Input ports do not use the buffer-forcer field.  The first two fields are independent of the type of port:

     discloser, port, disclosed
          Returns a disclosed representation of the port, ie a list whose car is the `type name' of this handler (usually with a suffix of either -input-port or -output-port) followed by a list of all of the components to be printed; see Writer.

     closer, port, ignored
          Closes PORT.  This operation corresponds with the close-input-port & close-output-port procedures.

     For input ports, the remaining fields are:

     char-reader, port consume?, char
          Reads a single character from PORT.  If CONSUME? is true, the character should be consumed from PORT; if CONSUME? is #f, however, the character should be left in PORT's input stream.  If CONSUME? is true, this operation corresponds with read-char; if it is #f, this operation corresponds with peek-char.

     block-reader, port block start count wait?, count-written or EOF
          Attempts to read COUNT characters from PORT's input stream into the string or byte vector BLOCK, starting at START. In the case that an insufficient number of characters is available, if WAIT? is true, the procedure should wait until all of the wanted characters are available; otherwise, if WAIT? is #f, the block reader should immediately return.  In either case, it returns the number of characters that were read into BLOCK, or an end of file object if it immediately reached the end of the stream.  Buffered ports will typically just copy elements from the buffer into BLOCK, rather than reading from any internal I/O channel in PORT.  This operation corresponds with read-block.

     readiness-tester, port, boolean
          Returns a true value if there is a character available to be read in PORT or #f if not.  This operation corresponds with the char-ready? procedure.

     For output ports, the remaining fields are:

     char-writer, port char, ignored
          Writes the single character CHAR to PORT.  This operation corresponds with write-char.

     block-writer, port block start count, count-written
          Writes COUNT characters to PORT from BLOCK, starting at START.  BLOCK may be a string or a byte vector.  This will usually involve copying contents of BLOCK to PORT's buffer, if it is buffered.  This operation corresponds with write-block.

     readiness-tester, port, boolean
          Returns a true value if PORT is ready to receive a character and #f if not.

     buffer-forcer, port necessary?, ignored
          For buffered ports, this is intended to force all buffered output to the actual internal I/O channel of PORT.  NECESSARY? tells whether or not it is absolutely necessary to force all the output immediately; if it is #t, the buffer forcer is required to force all output in the buffer before it returns.  If NECESSARY? is #f, not only may it just register an I/O transaction without waiting for it to complete, but it also should not signal an error if PORT is already closed.  For unbuffered ports, this operation need not do anything at all.

Buffered ports & handlers
.........................

Along with bare port handlers, Scheme48 provides conveniences for many patterns of buffered ports & port handlers.  These names are exported by the i/o-internal structure.  Buffered ports are integrated with Scheme48's Optimistic concurrency, optimistic concurrency facilities.

Note: Although internally buffered ports are integrated with optimistic concurrency, operations on buffered ports, like operations on channels, cannot be reliably fusibly atomic.

 -- procedure: make-buffered-input-port handler data buffer index limit returns input-port
 -- procedure: make-buffered-output-port handler data buffer index limit returns output-port
     Constructors for buffered ports.  HANDLER is the port's handler, which is usually constructed with one of the buffered port handler constructors (see below).  DATA is arbitrary data to go in the port's data field.  BUFFER is a byte vector whose length is greater than or equal to both INDEX & LIMIT. INDEX is the initial index into BUFFER to go in the port's index field.  LIMIT is the limit in the port's buffer, to go into the port's limit field; nothing will be written into BUFFER at or past LIMIT.

 -- procedure: make-unbuffered-input-port handler data returns input-port
 -- procedure: make-unbuffered-output-port handler data returns output-port
     Conveniences for ports that are explicitly not buffered.  Only the relevant fields are passed; all fields pertaining to buffering are initialized with #f.

 -- procedure: make-buffered-input-port-handler discloser closer buffer-filler readiness-tester returns port-handler
     This creates a port handler for buffered input ports.  The arguments are as follows:

     discloser, port-data, disclosed
     closer, port-data, ignored
          DISCLOSER & CLOSER are like the similarly named regular port handler fields, but they are applied directly to the port's data, not to the port itself.

     buffer-filler, port wait?, committed?
          Used to fill PORT's buffer when it no longer has contents from which to read in its current buffer.  WAIT? is a boolean flag, #t if the operation should wait until the I/O transaction necessary to fill the buffer completes, or #f if it may simply initiate an I/O transaction but not wait until it completes (eg, use channel-maybe-commit-and-read, but not wait on the condition variable passed to channel-maybe-commit-and-read). BUFFER-FILLER is called with a fresh proposal in place, and it is the responsibility of BUFFER-FILLER to commit it.  It returns a boolean flag denoting whether the proposal was committed. The last call in BUFFER-FILLER is usually either (maybe-commit) or a call to a procedure that causes that effect (eg, one of the operation on condition variables that commits the current proposal. See condition variables.)

     readiness-tester, port, [committed? ready?]
          Called when char-ready? is applied to PORT and the buffer of PORT is empty.  Like BUFFER-FILLER, READINESS-TESTER is applied with a fresh proposal in place, which it should attempt to commit.  READINESS-TESTER should return two values, each a boolean flag: the first denotes whether or not the current proposal was successfully committed, and, if it was successful, whether or not a character is ready.

 -- procedure: make-buffered-output-port-handler discloser buffer-emptier readiness-tester returns port-handler
     This creates a port handler for buffered output ports.  DISCLOSER & CLOSER are as with buffered input ports.  The remaining fields are as follows:

     buffer-emptier, port necessary?, committed?
          BUFFER-EMPTIER is used when PORT's buffer is full and needs to be emptied.  It is called with a fresh proposal in place.  It should reset PORT's index field, call note-buffer-reuse! to invalidate other threads' transactions on the recycled buffer, and attempt to commit the new proposal installed.  It returns a boolean flag indicating whether or not the commit succeeded.

     readiness-tester, port, [committed? ready?]
          READINESS-TESTER is applied to PORT when its buffer is full (ie its index & limit fields are equal) and output-port-ready? is applied to PORT.  After performing the test, it should attempt to commit the current proposal and then return two values: whether it succeeded in committing the current proposal, and, if it was successful, whether or not a character is ready to be outputted.

 -- constant: default-buffer-size returns integer
     The default size for port buffers.  This happens to be 4096 in the current version of Scheme48.

 -- procedure: note-buffer-reuse! port returns unspecified
 -- procedure: check-buffer-timestamp! port returns unspecified
     These are used to signal the resetting of a buffer between multiple threads.  Note-buffer-reuse! is called --- in the case of an output port --- when a buffer fills up, is emptied, and flushed; or --- in the case of an input port --- when a buffer is emptied and needs to be refilled.  Note-buffer-reuse! logs in the current proposal a fresh value to store in PORT.  When that proposal is committed, this fresh value is stored in the port.  Other threads that were using PORT's buffer call check-buffer-timestamp!, which logs a read in the current proposal.  If another thread commits a buffer reüse to memory, that read will be invalidated, invalidating the whole transaction.

Miscellaneous I/O internals
---------------------------

All of these but port-status-options are exported by the i/o-internal structure; the port-status-options enumeration is exported by the architecture structure, but it deserves mention in this section.

 -- enumeration: port-status-options

          (define-enumeration port-status-options
            (input
             output
             open-for-input
             open-for-output)) lisp
          Enumeration of indices into a port's status field bit set.

 -- procedure: open-input-port? port returns boolean
 -- procedure: open-output-port? port returns boolean
     These return true values if PORT is both an input or output port, respectively, and open.

 -- constant: open-input-port-status returns integer-status
 -- constant: open-output-port-status returns integer-status
     The bitwise masks of enumerands from the port-status-options enumeration signifying an open input or output port, respectively.

 -- procedure: make-input-port-closed! port returns unspecified
 -- procedure: make-output-port-closed! port returns unspecified
     These set the status of PORT, which must be an input or output port, respectively, to indicate that it is closed.

 -- procedure: eof-object returns eof-object
     Returns the EOF object token.  This is the only value that will answer true to R5RS's eof-object? predicate.

 -- procedure: force-output-if-open port returns unspecified
     This forces PORT's output if it is an open output port, and does not block.

 -- procedure: periodically-force-output! port returns unspecified
 -- procedure: periodically-flushed-ports returns port-list
     Periodically-force-output! registers PORT to be forced periodically.  Only a weak reference to PORT in this registry is held, however, so this cannot cause accidental space leaks. Periodically-flushed-ports returns a list of all ports in this registry.  Note that the returned list holds strong references to all of its elements.  Periodically-flushed-ports does not permit thread context switches, or interrupts of any sort, while it runs.

Channels
--------

Channels represent the OS's native I/O transmission channels.  On Unix, channels are essentially boxed file descriptors, for example. The only operations on channels are block reads & writes.  Blocks in this sense may be either strings or Bitwise manipulation, byte vectors.

Low-level channel operations
............................

The low-level base of the interface to channels described here is exported from the channels structure.

 -- procedure: channel? returns boolean
     Disjoint type predicate for channels.

 -- procedure: channel-id channel returns value
 -- procedure: channel-status channel returns integer-enumerand
 -- procedure: channel-os-index channel returns integer
     Channel-id returns CHANNEL's id.  The id is some identifying characteristic of channels.  For example, file channels' ids are usually the corresponding filenames; channels such as the standard input, output, or error output channels have names like "standard input" and "standard output". Channel-status returns the current status of CHANNEL; see the channel-status-option enumeration below. Channel-os-index returns the OS-specific integer index of CHANNEL.  On Unix, for example, this is the channel's file descriptor.

 -- procedure: open-channel filename option close-silently? returns channel
     Open-channel opens a channel for a file given its filename. OPTION specifies what type of channel this is; see the channel-status-option enumeration below.  CLOSE-SILENTLY? is a boolean that specifies whether a message should be printed (on Unix, to stderr) when the resulting channel is closed after a garbage collector finds it unreachable.

 -- procedure: close-channel channel returns unspecified
     Closes CHANNEL after aborting any potential pending I/O transactions it may have been involved with.

 -- procedure: channel-ready? channel returns boolean
     If CHANNEL is an input channel: returns #t if there is input ready to be read from CHANNEL or #f if not; if CHANNEL is an output channel: returns #t if a write would immediately take place upon calling channel-maybe-write, ie channel-maybe-write would not return #f, or #f if not.

 -- procedure: channel-maybe-read channel buffer start-index octet-count wait? returns octet count read, error status cell, EOF object, or #f
 -- procedure: channel-maybe-write channel buffer start-index octet-count returns octet count written, error status cell, or #f
 -- procedure: channel-abort channel returns unspecified
     Channel-maybe-read attempts to read OCTET-COUNT octets from CHANNEL into BUFFER, starting at START-INDEX. If a low-level I/O error occurs, it returns a cell containing a token given by the operating system indicating what kind of error occurred. If WAIT? is #t, and CHANNEL is not ready to be read from, CHANNEL is registered for the VM's event polling mechanism, and channel-maybe-read returns #f.  Otherwise, it returns either the number of octets read, or an EOF object if CHANNEL was was at the end.

     Channel-maybe-write attempts to write OCTET-COUNT octets to CHANNEL from BUFFER, starting at START-INDEX.  If a low-level I/O error occurs, it returns a cell indicating a token given by the operating system indicating what kind of error occurred. If no such low-level error occurs, it registers CHANNEL for the VM's event polling mechanism and returns #f iff zero octets were immediately written or the number of octets immediately written if any were.

     Channel-abort aborts any pending operation registered for the VM's event polling mechanism.

 -- procedure: open-channels-list returns channel-list
     Returns a list of all open channels in order of the os-index field.

 -- enumeration: channel-status-option

          (define-enumeration channel-status-option
            (closed
             input
             output
             special-input
             special-output)) lisp
          Enumeration for a channel's status.  The closed enumerand is
          used only after a channel has been closed.  Note that this is
          not suitable for a bit mask; that is, one may choose exactly
          one of the enumerands, not use a bit mask of status options.  For
          example, to open a file frob for input that one wishes the
          garbage collector to be silent about on closing it:

               (open-channel "frob"
                             (enum channel-status-option input)
                             #t)
                   => #{Input-channel "frob"} lisp

Higher-level channel operations
...............................

More convenient abstractions for operating on channels, based on Higher-level synchronization, condition variables, are provided from the channel-i/o structure.  They are integrated with Scheme48's Optimistic concurrency, optimistic concurrency facilities.

Note: Transactions on channels can not be atomic in the sense of optimistic concurrency.  Since they involve communication with the outside world, they are irrevocable transactions, and thus an invalidated proposal cannot retract the transaction on the channel.

 -- procedure: channel-maybe-commit-and-read channel buffer start-index octet-count condvar wait? returns committed?
 -- procedure: channel-maybe-commit-and-write channel buffer start-index octet-count condvar returns committed?
     These attempt to commit the current proposal.  If they fail, they immediately return #f; otherwise, they proceed, and return #t.  If the commit succeeded, these procedures attempt an I/O transaction, without blocking.  Channel-maybe-commit-and-read attempts to read OCTET-COUNT octets into BUFFER, starting at START-INDEX, from CHANNEL. Channel-maybe-commit-and-write attempts to write OCTET-COUNT octets from BUFFER, starting at START-INDEX, to CHANNEL.  CONDVAR is noted as waiting for the completion of the I/O transaction.  When the I/O transaction finally completes --- in the case of a read, there are octets ready to be read into BUFFER from CHANNEL or the end of the file was struck; in the case of a write, CHANNEL is ready to receive some octets ---, CONDVAR is set to the result of the I/O transaction: the number of octets read, an I/O error condition, or an EOF object, for reads; and the number of octets written or an I/O error condition, for writes.

 -- procedure: channel-maybe-commit-and-close channel closer returns committed?
     Attempts to commit the current proposal; if successful, this aborts any wait on CHANNEL, sets the result of any condvars waiting on CHANNEL to the EOF object, closes CHANNEL by applying CLOSER to CHANNEL (in theory, CLOSER could be anything; usually, however, it is close-channel from the channels structure or some wrapper around it), and returns #t.  If the commit failed, channel-maybe-commit-and-close immediately returns #f.

 -- procedure: channel-write channel buffer start-index octet-count returns octet-count-written
     Atomically attempts to write OCTET-COUNT octets to CHANNEL from BUFFER, starting at START-INDEX in BUFFER.  If no I/O transaction immediately occurs --- what would result in channel-maybe-write returning #f ---, channel-write blocks until something does happen.  It returns the number of octets written to CHANNEL.

 -- procedure: wait-for-channel channel condvar returns unspecified
     Registers CONDVAR so that it will be set to the result of some prior I/O transaction when some I/O event regarding CHANNEL occurs.  (Contrary to the name, this does not actually wait or block. One must still use maybe-commit-and-wait-for-condvar on CONDVAR; see condition variables.)  This is useful primarily in conjunction with calling foreign I/O routines that register channels with the VM's event polling system.

     Note: wait-for-channel must be called with interrupts disabled.

Channel ports
-------------

Built-in to Scheme48 are ports made atop channels.  These are what are created by R5RS's standard file operations.  The following names are exported by the channel-ports structure.

 -- procedure: call-with-input-file filename receiver returns values
 -- procedure: call-with-output-file filename receiver returns values
 -- procedure: with-input-from-file filename thunk returns values
 -- procedure: with-output-to-file filename thunk returns values
 -- procedure: open-input-file filename returns input-port
 -- procedure: open-output-file filename returns output-port
     Standard R5RS file I/O operations.  (These are also exported by the scheme structure.)  The call-with-...put-file operations open the specified type of port and apply RECEIVER to it; after RECEIVER returns normally (ie nothing is done if there is a throw out of RECEIVER), they close the port and return the values that RECEIVER returned.  With-input-from-file & with-output-to-file do similarly, but, rather than applying THUNK to the port, they dynamically bind the current input & output ports, respectively, to the newly opened ports. Call-with-input-file, call-with-output-file, with-input-from-file, and with-output-to-file return the values that THUNK returns.  Open-input-file & open-output-file just open input & output ports; users of these operations must close them manually.

 -- procedure: input-channel->port channel [buffer-size] returns port
 -- procedure: output-channel->port channel [buffer-size] returns port
     These create input & output ports atop the given channels and optional buffer sizes.  The default buffer size is 4096 bytes.

 -- procedure: input-channel+closer->port channel closer [buffer-size] returns port
 -- procedure: output-channel+closer->port channel closer [buffer-size] returns port
     Similarly, these create input & output ports atop the given channels and optional buffer sizes, but they allow for extra cleanup when the resulting ports are closed.

 -- procedure: port->channel port returns channel or #f
     If PORT is a port created by the system's channel ports facility, port->channel returns the channel it was created atop; otherwise port->channel returns #f.

 -- procedure: force-channel-output-ports! returns unspecified
     This attempts to force as much output as possible from all of the ports based on channels.  This is used by Scheme48's POSIX libraries before forking the current process.