There are two types of I/O objects in Scheme 48, channels and ports. Channels are the raw, unbuffered ports of the operating system. The only I/O operations the VM supports for channels are block reads and writes. Ports are the actual Scheme ports and are implemented in Scheme, with some support from the VM for READ-CHAR, PEEK-CHAR, and WRITE-CHAR for efficiency. The run-time system provides ports that are buffered versions of channels. Other sorts of ports are in big/more-port.scm.

Source files:

  rts/port.scm            port operations and port handlers
  rts/current-port.scm    current-input-port, etc.
  rts/channel.scm         blocking on channels and handling i/o interrupts
  rts/channel-port.scm    ports that read and write to channels
  rts/low.scm             CHANNEL-READ and CHANNEL-WRITE
  big/more-port.scm       additional kinds of ports
  vm/arch.scm             fields of ports and channels
  vm/prim-io.scm          VM i/o opcodes
  vm/vmio.scm             implementation of channels


The VM instructions that deal with channels are:

(OPEN-CHANNEL <spec> <mode>) -> channel
<mode> is a from the enumeration OPEN-CHANNEL-OPTION in arch.scm. <spec> is either a filename (as a string) or an OS port (as a one-word code-vector), depending on the mode.

(CLOSE-CHANNEL <channel>) -> unspecific

(CHANNEL-MAYBE-READ <string-or-code-vector> <start-index> <count> <wait?> <channel>) -> number of bytes read or the eof-object

(CHANNEL-MAYBE-WRITE <string-or-code-vector> <start-index> <count> <channel>) -> number of bytes written
These read or write up to the specified number of characters or bytes from or to the string or code-vector, with the first character or byte going at <start-index>.

(CHANNEL-ABORT <channel>) -> number of bytes read or written or the eof-object
This aborts any pending read or write operation on the channel. The return value reflects any partial completion.

CHANNEL-MAYBE-READ and CHANNEL-MAYBE-WRITE do not block. If the read or write cannot be completed immediately a PENDING-CHANNEL-I/O exception is raised. It is then up to the run-time system to either wait or run some other thread. The VM raises an I/O-COMPLETION interrupt whenever an i/o operation completes.

Because CHANNEL-MAYBE-READ and CHANNEL-MAYBE-WRITE are awkward to use, the RTS defines somewhat simpler versions:

(CHANNEL-READ <buffer> <start> <needed> <channel>)
-> number of bytes read or the eof-object
(CHANNEL-WRITE <buffer> <start> <count> <channel>)
-> unspecified
<Buffer> is either a string or code vector and <start> is the index of the first character read or written. <Needed> is one of: N > 0 : the call returns when this many characters has been read or an EOF is reached. 'IMMEDIATE : the call reads as many characters as are available and returns immediately. 'ANY : the call returns as soon as at least one character has been read or an EOF is reached.

<Count> is the number of characters to be written. CHANNEL-READ will read the requested number of characters unless an EOF is reached. CHANNEL-WRITE will write the requested number of characters.


Ports are actual Scheme port and are (usually) buffered. They are fully exposed to the run-time system. The VM instructions on ports could be implemented in Scheme; they are in the VM for efficiency. Buffers are code-vectors (this is a micro-hack; strings have a slightly higher overhead because of the null terminating byte for C compatibility) (code-vectors are just vectors of bytes).

The fields of a port are:

a bit set represented as a fixnum. Indices into this bit set are from the PORT-STATUS-OPTIONS enumeration in arch.scm. The current bits are: input, output, open-for-input, open-for-output.

a record containing three procedures. These handle printing the port, closing the port, and filling (for input ports) or emptying (for output ports) buffers.

Whatever stuff the handler needs.

used by the system to guarentee the atomicity of i/o operations.

a code-vector. The input or output buffer of the port.
a fixnum. The index of the next byte to read or written.
a fixnum. One past the end of the valid/available buffer space.
true if the next read to this port should return EOF.

Additional operations on ports:

(READ-BLOCK string-or-code-vector start count input-port)
Read COUNT bytes into STRING-OR-CODE-VECTOR starting at index START. Returns the number of bytes read. Only an end-of-file will prevent the requested number of bytes from being read.

(WRITE-STRING string output-port)
Write the characters in the string to the port.

(WRITE-BLOCK string-or-code-vector start count output-port)
The output counterpart to READ-BLOCK. This always writes out the requested number of bytes. Its return value is unspecified.

(FORCE_OUTPUT output-port)
Causes any buffered characters to be written out.

The current error port, analogous to Scheme's CURRENT-INPUT-PORT and CURRENT-OUTPUT-PORT.

The system maintains a list of output ports whose buffers should be periodically flushed. The default output port and ports made by OPEN-OUTPUT-FILE are on this list. (PERIODICALLY-FORCE-OUTPUT! <output-port>) may be used to add others.


Every port has a handler with three procedures. The first two are used for printing and closing ports and have the same type for all ports:

(DISCLOSE port-data) -> disclose list
(CLOSE port-data) -> unspecific

For CLOSE, The system takes care of modifying the port's status.

The third procedure is used to fill and empty buffers. Its arguments and return values depend on the kind of port:

Buffered output ports:

(BUFFER-PROC port-data buffer start-index byte-count) -> unspecific
BYTE-COUNT bytes should be copied from the buffer beginning at START-INDEX. The buffer may be either a string or a code-vector.

Unbuffered output ports:

(BUFFER-PROC port-data char) -> unspecific
Write out the given character. The system uses this for the default error port.

Input ports:

(BUFFER-PROC data buffer start-index needed-bytes) -> EOF or number of bytes read (before an EOF)
Bytes should be copied into the buffer starting at START-INDEX. The buffer may be either a string or a code-vector.

NEEDED-BYTES is one of:

The call should return immediately after transfering whatever number of bytes are currently available, possibly none (this is used for CHAR-READY?). The maximum number of characters is determined by the length of BUFFER.
The call should wait until at least one byte is available or an EOF occurs (used for READ-CHAR and PEEK-CHAR). The maximum number of characters is determined by the length of BUFFER.
N > 0 The call should wait until N bytes have been copied into the buffer
or an EOF occurs. If the return value is less than NEEDED-BYTES the port code inserts an EOF after the last byte.

Ports and the Virtual Machine

Ports could be implemented entirely in Scheme, with no support from the VM. For efficiency reasons VM instructions are supplied for three port operations:

(READ-CHAR <port>)
(PEEK-CHAR <port>)
(WRITE-CHAR <char> <port>)

For each of these, if there is sufficient data or space in the appropriate buffer the VM performs the operation. Otherwise a buffer-full/empty exception is raised and the exception handler uses the buffer procedure from the port's handler to fill or empty the buffer.


Ownership, Maintenance and Disclaimers

Scheme48 Manual Top Page

Envision Manual Top Page

Last modified