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
}.