Previous: Port handlers, Up: Programmatic ports
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 facilities.
Note: Although internally buffered ports are integrated with optimistic concurrency, operations on buffered ports, like operations on channels, cannot be reliably fusibly atomic.
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'sindex
field. Limit is the limit in the port's buffer, to go into the port'slimit
field; nothing will be written into buffer at or past limit.
Conveniences for ports that are explicitly not buffered. Only the relevant fields are passed; all fields pertaining to buffering are initialized with
#f
.
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 (e.g., usechannel-maybe-commit-and-read
, but not wait on the condition variable passed tochannel-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 (e.g., 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.
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, callnote-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 (i.e. its
index
&limit
fields are equal) andoutput-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.
The default size for port buffers. This happens to be 4096 in the current version of Scheme48.
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 callcheck-buffer-timestamp!
, which logs a read in the current proposal. If another thread commits a buffer reuse to memory, that read will be invalidated, invalidating the whole transaction.