PreviousUpNext

15.3.517  src/lib/std/src/pthread/io-wait-pthread.api

# 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.lib

stipulate
    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.pkg
herein

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


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext