english
version "1.0"
identify "xyz"
#: Copyright (c) 1998-2005 by Wayne C. Gramlich.
#, All rights reserved.
module io_dispatcher
#: This module implements an I/O dispatcher.
#,
#, The concept behind the I/O dispatcher is that it allows a program
#, to deal with multiple channels of I/O simultaineously. This is
#, accomplished via having a separate call back routine for each I/O
#, channel. Whenever there is input available (for an input channel) or
#, output capacity is available (for an output channel), its corresponding
#, call back routine is invoked to deal with the I/O activity. In addition
#, to standard file/network input/output, the I/O dispatcher can listen
#, for network connections on one and/or more ports and perform time
#, delayed wake up calls. Finally, it is possible to have one or more
#, call backs that are invoked when no I/O activity is present; these are
#, called idle call backs. An any call back routine can poll the
#, {io_dispatcher} object to determine whether there is any pending
#, I/O avaiable. Before each callback routine returns, it has the option
#, of performing some operations control when (or if) the call back
#, routine will next be invoked. If every callback routine in the
#, {io_dispatcher} is careful to never perform a blocking I/O opertaion
#, the {io_dispatcher} will never `freeze up'.
#,
#, Until co-types are implemented in STIPPLE, the io_dispatcher object is
#, based around a single parameterized type called {state}. Each I/O
#, channel has potentially its own instantiation of a {state} object. While
#, I/O channels can share the same {state} object, there is no requirement
#, that they do so. One common usage of the {state} type is share a
#, {state} record across all I/O channels. Another common usage of the
#, {state} type is that is will be implemented as a variant type and each
#, I/O channel will get its own instantiation of the variant type. The
#, callback routine will use a STIPPLE extract statement to obtain the
#, necessary information for the callback.
#,
#, Ultimately, the {io_dispatcher} module is organized around the
#, capabilities of the Unix select(2) system call.
define io_dispatcher[state] #: Input/Output dispatcher
record
actual_read_file_set file_set #: Actual files ready for reading
actual_write_file_set file_set #: Actual files ready for writing
actual_exception_file_set file_set #: Actual files with exceptions
desired_read_file_set file_set #: Desired files for reading
desired_write_file_set file_set #: Desired files for writing
desired_exception_file_set file_set #: Desired files for exceptions
io_listens vector[io_listen[state]] #: List of ports to listen to
read_channels vector[read_channel[state]] #: List of read channels
result string #: Return result
run logical #: {true} => keep running
trace_stream out_stream #: Tracing stream
unix_system unix_system #: Unix system to use
write_channels vector[write_channel[state]] #: List of write channels
generate address_get, allocate, erase, identical, print
define io_listen[state] #: One network listen `channel'
routine_types
procedure listen_call_back
takes channel_pair[state], state
returns_nothing
procedure read_call_back
takes read_channel[state]
returns_nothing
procedure write_call_back
takes write_channel[state]
returns_nothing
record
io_dispatcher io_dispatcher[state] #: Parent I/O Dispatcher
internet_address unsigned #: The internet address to listen on
listen_call_back listen_call_back #: The listen call back
listen_socket_number unsigned #: Socket number to listen on
listen_state state #: Listen call back {state} object
port unsigned #: The port address to listen to
read_buffer_size unsigned #: Read buffer size
read_call_back read_call_back #: Read call back routine
read_state state #: Read call back {state} object
write_buffer_size unsigned #: Write buffer size
write_call_back write_call_back #: Write call back routine
write_state state #: Write call back {state} object
generate address_get, allocate, erase, identical, print
define channel_pair[state] #: A read/write channel pair
record
read_channel read_channel[state] #: The {read_channel} object
write_channel write_channel[state] #: The {write_channel} object
generate address_get, allocate, erase, identical, print
define read_channel[state] #: One read channel
routine_types
procedure call_back
takes read_channel[state]
returns_nothing
record
buffer memory #: I/O buffer
call_back call_back #: Call back procedure
contains unsigned #: Good bytes contained in {buffer}
done logical #: {true}=>connection out of data
file_descriptor_number unsigned #: File descriptor number
id unsigned #: Identifier
index unsigned #: Index into {read_channels}
io_dispatcher io_dispatcher[state] #: Parent {io_dispatcher} object
label string #: String for label
needed unsigned #: Needed number of bytes
offset unsigned #: Offset to first byte in {buffer}
state state #: I/O channel {state} object
total_in unsigned #: Total bytes read into buffer
total_out unsigned #: Total bytes read out of buffer
generate address_get, allocate, erase, identical, print
define write_channel[state] #: One Input/Output channel
routine_types
procedure call_back
takes write_channel[state]
returns_nothing
record
buffer memory #: I/O buffer
call_back call_back #: Call back procedure
contains unsigned #: Good bytes contained in {buffer}
file_descriptor_number unsigned #: File descriptor number
id unsigned #: Identifier
index unsigned #: Index into {write_channels}
io_dispatcher io_dispatcher[state] #: Parent {io_dispatcher} object
label string #: String for label
needed unsigned #: Needed number of bytes
offset unsigned #: Offset to first byte in {buffer}
state state #: I/O channel {state} object
generate address_get, allocate,erase, identical, print
#: {io_dispatcher} routines:
procedure activate@io_dispatcher[state]
takes
io_dispatcher io_dispatcher[state]
returns string
#: This procedure will activate the {io_dispatcher} object so that
#, it will start performing I/O via the various activated call back
#, procedures. Whenever there is no more pending I/O (i.e. all
#, files and/or sockets are closed and no more listens are active),
#, this procedure will return with a return value of ??@{string}.
#, Alternatively, a call to {terminate}@{io_dispatcher}() will cause
#, an immediate return with with a return value that is specified as
#, an argument to {terminate}().
procedure connect@io_dispatcher[state]
routine_types
procedure read_call_back
takes read_channel[state]
returns_nothing
procedure write_call_back
takes write_channel[state]
returns_nothing
takes
io_dispatcher io_dispatcher[state]
internet_address unsigned
port unsigned
read_buffer_size unsigned
read_call_back read_call_back
read_state state
write_buffer_size unsigned
write_call_back write_call_back
write_state state
returns channel_pair[state]
#: This procedure will cause {io_dispatcher} to establish a network
#, connection port {port} of internet address {internet_address}
#, return a {channel_pair} object that contains the corresponding
#, {read_channel} and {write_channel} objects. The {read_channel}
#, has a read buffer size of {read_buffer_size} and a call back
#, procedure of {read_call_back}. The {write_channel} has a write
#, buffer size of {write_buffer_size} and a call back procedure of
#, {write_call_back}. The {read_state} object is passed into the
#, read {read_channel} object and the {write_state} object is passed
#, into the write {write_channel} object. If the network connection
#, is not successfully established ??@{channel_pair}[{state}] is
#, returned. Please invoke {unix_system}@{status_get}() to potentially
#, find out why the connection did not succeed.
#,
#, Unfortunately, the current implementation of this operation can
#, cause the I/O dispatcher to block for 10's of seconds. Sorry.
procedure channel_pair_allocate@io_dispatcher[state]
routine_types
procedure read_call_back
takes read_channel[state]
returns_nothing
procedure write_call_back
takes write_channel[state]
returns_nothing
takes
io_dispatcher io_dispatcher[state]
file_descriptor_number unsigned
read_call_back read_call_back
read_state state
read_buffer_size unsigned
write_call_back write_call_back
write_state state
write_buffer_size unsigned
returns channel_pair[state]
#: This procedure will allocate a {channel_pair} object that
#, contains a {read_channel} and {write_channel} initialized
#, with {file_descriptor}, {read_call_back}, {read_state},
#, {read_buffer_size}, {write_call_back}, {write_state}, and
#, {write_buffer_size}.
procedure create@io_dispatcher[state]
takes
unix_system unix_system
returns io_dispatcher[state]
#: This procedure will create and new unactivated {io_dispatcher} object.
procedure listen@io_dispatcher[state]
routine_types
procedure listen_call_back
takes channel_pair[state], state
returns_nothing
procedure read_call_back
takes read_channel[state]
returns_nothing
procedure write_call_back
takes write_channel[state]
returns_nothing
takes
io_dispatcher io_dispatcher[state]
internet_address unsigned
port unsigned
queue_length unsigned
listen_call_back listen_call_back
listen_state state
read_buffer_size unsigned
read_call_back read_call_back
read_state state
write_buffer_size unsigned
write_call_back write_call_back
write_state state
returns logical
#: This procedure will cause {io_dispatcher} to listent for network
#, connections on port {port} of internet address {internet_address}
#, and a queue length of {queue_length} (see {listen}@{unix_system}().)
#, Whenever a connection is requested, it will create a {read_channel}
#, and a {write_channel} object and add them to the active channel list
#, for {io_dispatcher}. The {read_channel} will be created to have
#, buffer size of {read_buffer_size}, a call back routine of
#, {read_call_back}, and a state value of {read_state}. Similarly,
#, the {write_channel} object will be created to have buffer size of
#, {write_buffer_size}, a call back routine of {write_call_back},
#, and a state value of {read_state}. Both I/O channels will be
#, created with ??@{string} as the channel label and 0 as the
#, channel identifier. After the two channels have been created,
#, {listen_call_back} is invoked with the newly created {read_channel},
#, the newly created {write_channel}, and {listen_state} as its three
#, arguments.
procedure read_channel_allocate@io_dispatcher[state]
routine_types
procedure call_back
takes read_channel[state]
returns_nothing
takes
io_dispatcher io_dispatcher[state]
file_descriptor_number unsigned
call_back call_back
state state
buffer_size unsigned
label string
id unsigned
returns read_channel[state]
#: This procedure cause an read I/O channel object to be allocated to
#, read data from {file_descriptor_number}. Whenever, there is data
#, to be read, {call_back} will be invoked with with the {read_channel}
#, that is returned by this procedure. A memory buffer of size
#, {buffer_size} bytes is allocated and stored in the returned
#, {read_channel} object. {state}, {label}, and {id} are stored
#, in the returned {read_channel} object as well. The returned
#, {read_channel} is returned in the activated state.
procedure read_channel_deallocate@io_dispatcher[state]
takes
io_dispatcher io_dispatcher[state]
read_channel read_channel[state]
returns_nothing
#: This procedure will deallocate {read_channel} from {io_dispatcher}.
procedure standard_out_allocate@io_dispatcher[state]
routine_types
procedure call_back
takes write_channel[state]
returns_nothing
takes
io_dispatcher io_dispatcher[state]
call_back call_back
state state
buffer_size unsigned
label string
id unsigned
returns write_channel[state]
#: This will return a {write_channel} object for writing to the
#, standard output file descriptor. The the return {write_channel}
#, object will contain {call_back}, {state}, {label}, {id}, and a
#, memory buffer of size {buffer_size}.
#,
#, IMPORTANT: This procdure will change the standard output file
#, descriptor to be non-blocking. This effect propogates to the
#, standard blocking style output streams. If that is not your
#, goal, you can open "/dev/tty" instead.
procedure terminate@io_dispatcher[state]
takes
io_dispatcher io_dispatcher[state]
result string
returns_nothing
#: This procedure cause the {io_dispatcher} to immediately terminate
#, with a return value of {return_result}.
procedure unlisten@io_dispatcher[state]
takes
io_dispatcher io_dispatcher[state]
internet_address unsigned
port unsigned
returns_nothing
#: This procedure will cause {io_dispatcher} to stop listening for
#, network connections on port {port} on internet address
#, {internet_address}.
procedure write_channel_allocate@io_dispatcher[state]
routine_types
procedure call_back
takes write_channel[state]
returns_nothing
takes
io_dispatcher io_dispatcher[state]
file_descriptor_number unsigned
call_back call_back
state state
buffer_size unsigned
label string
id unsigned
returns write_channel[state]
#: This procedure cause a write I/O channel object to be allocated to
#, write data to {file_descriptor_number}. Whenever, there is data
#, capacity to be write, {call_back} will be invoked with with the
#, {write_channel} that is returned by this procedure. A memory
#, buffer of size {buffer_size} bytes is allocated d and stored in
#, the returned {write_channel} object. {state}, {label},
#, and {id} are stored in the returned {write_channel} object as well.
#, The returned {write_object} is returned in the activated state.
procedure write_channel_deallocate@io_dispatcher[state]
takes
io_dispatcher io_dispatcher[state]
write_channel write_channel[state]
returns_nothing
#: This procedure will deallocate {write_channel} from {io_dispatcher}.
#: {channel_pair} routines:
procedure close@channel_pair[state]
takes
channel_pair channel_pair[state]
returns_nothing
#: This procedure will close {channel_pair}.
procedure create@channel_pair[state]
takes
read_channel read_channel[state]
write_channel write_channel[state]
returns channel_pair[state]
#: This procedure will create and return a new {channel_pair} object
#, that contains {read_channel} and {write_channel}.
procedure idle@channel_pair[state]
takes
channel_pair channel_pair[state]
returns logical
#: This procdure will return {true}@{logical} if {channel_pair} has
#, no pending input or output and {false} otherwise.
procedure no_more_data@channel_pair[state]
takes
channel_pair channel_pair[state]
returns logical
#: This procedure will return {true}@{logical} if {channel_pair} has
#, no more data to be read (i.e. end-of-file or connection closed.)
#, Otherwise, {false}@{logical} is returned.
procedure state_set@channel_pair[state]
takes
channel_pair channel_pair[state]
state state
returns_nothing
#: This procedure will set the state of the {read_channel} and
#, {write_channel} objects to {state}.
procedure transfer@channel_pair[state]
takes
to_channel_pair channel_pair[state]
from_channel_pair channel_pair[state]
amount unsigned
returns unsigned
#: This procedure will cause up to {amount} bytes from the the
#, {read_channel} object in {from_channel_pair} to be transfered
#, to the {write_channel} object in {to_channel_pair}. The number
#, of bytes actually transfered is returned.
procedure transfer_all@channel_pair[state]
takes
to_channel_pair channel_pair[state]
from_channel_pair channel_pair[state]
returns unsigned
#: This procedure will transfer as many bytes from the the {read_channel}
#, object in {from_channel_pair} to the {write_channel} object in
#, {to_channel_pair}. The number of bytes actually transfered is returned.
#: {read_channel} routines:
procedure absorb@read_channel[state]
takes
read_channel read_channel[state]
amount unsigned
returns unsigned
#: This procedure will cause {amount} bytes from {read_channel}
#, to be marked as read. The number of bytes actually marked
#, as read is returned.
procedure deallocate@read_channel[state]
takes
read_channel read_channel[state]
returns_nothing
#: This procedure will deallocate {read_channel} from its {io_dispatcher}
#, scheduler.
procedure fetch1@read_channel[state]
takes
read_channel read_channel[state]
index unsigned
returns unsigned
#: This procedure will return the {index}'th byte from {read_channel}'s
#, active content.
procedure idle@read_channel[state]
takes
read_channel read_channel[state]
returns logical
#: This procedure will return {true} if there is currently
#, no data in {read_channel} waiting to be read out.
procedure no_more_data@read_channel[state]
takes
read_channel read_channel[state]
returns logical
#: This procedure will return {true}@{logical} if {read_channel}
#, will return no more data and {false} otherwise.
procedure update@read_channel[state]
takes
read_channel read_channel[state]
returns_nothing
#: This procedure will update whether or not the select statement
#, should care about this {read_channel}.
#: {write_channel} routines:
procedure available_get@write_channel[state]
takes
write_channel write_channel[state]
returns unsigned
#: This procedure will return the number of available bytes in
#, the {write_channel} buffer.
procedure character_append@write_channel[state]
takes
write_channel write_channel[state]
character character
returns_nothing
#: This procedure will append {character} to the end of {write_channel}.
procedure string_append@write_channel[state]
takes
write_channel write_channel[state]
text string
returns_nothing
#: This procedure will append {text} to the end of {write_channel}.
procedure deallocate@write_channel[state]
takes
write_channel write_channel[state]
returns_nothing
#: This procedure will deallocate {write_channel} from its {io_dispatcher}
#, scheduler.
procedure disable@write_channel[state]
takes
write_channel write_channel[state]
returns_nothing
#: This procedure will disable call backs from {write_channel}.
procedure enable@write_channel[state]
takes
write_channel write_channel[state]
returns_nothing
#: This procedure will enable call backs from {write_channel}.
procedure idle@write_channel[state]
takes
write_channel write_channel[state]
returns logical
#: This procedure will return {true} if there is currently
#, no data in {write_channel} waiting to be written out.
procedure transfer@write_channel[state]
takes
write_channel write_channel[state]
read_channel read_channel[state]
amount unsigned
returns unsigned
#: This procedure will attempt to transfer {amount} bytes from
#, {read_channel} to {write_channel}. The actual number of
#, bytes transfered is returned.
procedure transfer_all@write_channel[state]
takes
write_channel write_channel[state]
read_channel read_channel[state]
returns unsigned
#: This procedure will attempt to transfer as many bytes from
#, {read_channel} to {write_channel} as it possible can.
#, The actual number of bytes transfered is returned.
procedure update@write_channel[state]
takes
write_channel write_channel[state]
returns_nothing
#: This procedure will update whether or not the select statement
#, should care about this {write_channel}.