# io-wait-pthread.api
#
# Interface to a server pthread designed to basically just
# sit in a loop doing C select() over and over on whatever
# file/pipe/socket descriptors are of current interest.
#
# Our main purpose is to offload I/O blocking from the
# main threadkit pthread so that it can run full speed # Threadkit is from
src/lib/src/lib/thread-kit/src/core-thread-kit/threadkit.api# while we sit around waiting for network packets to arrive. # threadkit is from
src/lib/src/lib/thread-kit/src/core-thread-kit/threadkit.pkg#
# A secondary purpose of io_wait_pthread is to provide the
# clock threadkit needs to drive its pre-emptive timeslicing.
# Reppy's original CML implementation uses SIGALRM for this,
# but this has two critical disadvantages:
#
# o SIGALRM is a bottleneck resource which everyone wants
# to control.
#
# o Worse, SIGALRM interrupts "slow" system calls, causing
# them to return EINTR instead of a useful result, requiring
# the relevant C code to re-try. We can ensure that our own
# C support code does this, but one call -- connect() --
# *cannot* be retried, and we cannot be sure that all C
# libraries linked into the runtime will retry properly
# on EINTR. (In fact, I'd bet good odds that some will not.)
#
# By having our select() time out regularly and generate
# a timeslice clock for threadkit based on those timeouts
# we avoid those problems completely.
#
# See also:
#
#
src/lib/std/src/pthread/cpu-bound-task-pthreads.api#
src/lib/std/src/pthread/io-bound-task-pthreads.api# Compiled by:
#
src/lib/std/standard.libstipulate
package tim = time; # time is from
src/lib/std/time.pkg package pth = pthread; # pthread is from
src/lib/std/src/pthread.pkg package wio = winix::io; # winix::io is from
src/lib/std/src/posix/winix-io.pkgherein
# This api is implemented in:
#
#
src/lib/std/src/pthread/io-wait-pthread.pkg #
api Io_Wait_Pthread {
#
is_running: Void -> Bool; # Returns TRUE iff the server pthread is running.
#
start: String -> Bool; # Clear the internal wait-request list and
# start the select() pthread running (if it is not already running).
# Returns TRUE if it started the server pthread, in which case 'String' will be logged as the client requesting startup.
# Returns FALSE if server pthread was already running.
Do_Stop
=
{ who: String,
reply: Void -> Void
};
stop: Do_Stop -> Void;
Do_Echo
=
{ what: String, # Primarily to test that the server is running.
reply: String -> Void
};
echo: Do_Echo -> Void;
Do_Note_Iod_Reader
=
{ io_descriptor: wio::Io_Descriptor,
read_fn: wio::Io_Descriptor -> Void # Call this closure ("function") on iod whenever input is available.
};
note_iod_reader: Do_Note_Iod_Reader -> Void;
drop_iod_reader: wio::Io_Descriptor -> Void;
Do_Note_Iod_Writer
=
{ io_descriptor: wio::Io_Descriptor,
write_fn: wio::Io_Descriptor -> Void # Call this closure ("function") on iod whenever input is available.
};
note_iod_writer: Do_Note_Iod_Writer -> Void;
drop_iod_writer: wio::Io_Descriptor -> Void;
Do_Note_Iod_Oobder
=
{ io_descriptor: wio::Io_Descriptor,
oobd_fn: wio::Io_Descriptor -> Void # Call this closure ("function") on iod whenever out-of-band-data ("oobd") is available.
};
note_iod_oobder: Do_Note_Iod_Oobder -> Void;
drop_iod_oobder: wio::Io_Descriptor -> Void;
get_timeout_interval: Void -> tim::Time;
set_timeout_interval: tim::Time -> Void;
#
# The main job of io-wait-pthread.pkg is to sit
# eternally in loop running wio::wait_for_io_opportunity.
# These two calls control the timeout for that call.
drop_per_loop_fn: (Ref (Void -> Void)) -> Void;
note_per_loop_fn: (Ref (Void -> Void)) -> Void; # Call will be ignored if given refcell is already present in internal list.
#
# The io_wait_pthread timeslider uses us to generate
# its (approximately) 50Hz timeslicing "clock". It uses
#
# note_per_loop_fn
#
# to register a function with us to be called once
# per outer loop (and consequently approximately once
# per timeout interval).
#
# For generality we internally support a list of such
# per-loop fns rather than a single such fn, all of which
# get called once per outer loop.
#
# For flexibility we also support removing per-loop fns
# from our internal list via
#
# note_per_loop_fn
#
# (This might be needed if switching to an entirely
# different threadkit scheduler, say.)
#
# To do this we must be able to compare list entries
# for equality. Equality comparisons are not supported
# for Void->Void values, but they are supported for
# refcells -- this is the main reason we wrap per-loop fns
# in refcells in these two calls. (We never assign to
# these refcells, although our client -- threadkit scheduler
# -- could do so if it wished.)
#
# Note that if there is a lot of I/O going on, the
# loop fn may be called much more frequently than the
# timeout interval would suggest. It is up to the
# client to deal with this, if it is a problem.
};
end;
## Code by Jeff Prothero: Copyright (c) 2010-2012,
## released under Gnu Public Licence version 3.