help with non-blocking input

From: Erik Ostrom <eostrom_at_ccs.neu.edu>
Date: Sun, 12 Mar 1995 14:45:39 -0500

For my main STk project (a MUD client, basically), I need to be able to read
input from a socket as it comes in, without blocking the whole program. With
ready-char?, this is possible but requires busy-waiting. (I could constantly
run `(after 1 see-if-there's-more-input)' or something.)

Tk provides a way to do this, Tk_CreateFileHandler. I've been trying to
figure out the best way to offer it at the Scheme level, but I'm not sure, so
I thought I'd ask for comments. (If people know how other Scheme
implementations offer similar possibilities, that'd be great.)

A first implementation offered this only for sockets, which was pretty easy
because I only had to change one file. It didn't feel right, though; the
functionality was available for all input ports. So what I have now is an
STk primitive:

   (set-port-callback! port proc)

   `port' must be an input port (and not a string port); `proc' must be
   either #f of a procedure of zero arguments.

   If `proc' is a procedure, then whenever new input is available from `port',
   `proc' will be called. `proc' is also called when `port' is closed.
   `proc' is expected to determine `port' from its environment, and use
   ready-char? and other I/O functions to read whatever input is available
   from the port.

   If `proc' is #f, any previously set callback will be cancelled.

I've been using this for a while now, and it seems to work... okay. Here are
the problems I've found:

1. In order to protect proc from garbage collection, the input port remembers
    proc. This means adding an element to the port structure--and I'm not
    sure of the effect of that. It may add extra storage to every cell in
    the system--or it may not.

    This could be taken care of by taking the standard Tk-glue approach:
    Instead of `proc', pass in a string describing a function call, and
    you're responsible for protecting the procedure yourself. I don't like
    this, though, and especially in this case it seems unnecessary--there's
    no use for Tk argument substitution.

2. When a port closes, due to the interaction of Scheme and Tk, you _must_
    delete the file-handler for the port (if you set one). If you don't,
    Tk just keeps on telling you the port is closed. It seems like there
    should be a way to automate this, but I haven't figured out how to do
    it and still notify the Scheme code that the port is closed.

I also need to get input as soon as it comes in, rather than waiting for a
buffer to fill. I'm currently doing this with a setbuf() call in
STk_set_port_callback; I'm starting to think it'd be a good idea to decouple
these. Buffering should probably be set when the port is opened, but I'd
be loathe to mess with R4RS port creation procedures.

Okay. Does anyone else have comments on the implementation or design of this
stuff? It seems like something of general utility--for example, you could run
a shell or any other terminal-based program in an STk window. So I'd like to
find a good way of doing it, and hopefully get it integrated into the real
release (Hi, Erick) so I don't have to merge my changes in with each new
version.

Thanks for any help
--Erik
Received on Sun Mar 12 1995 - 20:47:09 CET

This archive was generated by hypermail 2.3.0 : Mon Jul 21 2014 - 19:38:59 CEST