From: Sam Steingold
Subject: clear-input
Date: 
Message-ID: <uoe5yh5p7.fsf@gnu.org>
is (clear-input s) supposed to do
(loop :for c = (read-char-no-hang s nil nil) :while c)
-- 
Sam Steingold (http://www.podval.org/~sds) running w2k
<http://www.openvotingconsortium.org/> <http://www.memri.org/>
<http://www.mideasttruth.com/> <http://truepeace.org>
The world will end in 5 minutes.  Please log out.

From: Barry Margolin
Subject: Re: clear-input
Date: 
Message-ID: <barmar-4B9BCB.09232910102005@comcast.dca.giganews.com>
In article <·············@gnu.org>, Sam Steingold <···@gnu.org> wrote:

> is (clear-input s) supposed to do
> (loop :for c = (read-char-no-hang s nil nil) :while c)

I think they should be pretty much equivalent.  If you manage to type 
something really quickly while the loop is running, it will be cleared 
out, whereas I'd expect CLEAR-INPUT to atomically zap the input buffer.  
But since you can never really guarantee timing issues like this, I 
don't think this is a visible difference.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
From: Sam Steingold
Subject: Re: clear-input
Date: 
Message-ID: <u64s54flx.fsf@gnu.org>
> * Barry Margolin <······@nyhz.zvg.rqh> [2005-10-10 09:23:29 -0400]:
>
> In article <·············@gnu.org>, Sam Steingold <···@gnu.org> wrote:
>
>> is (clear-input s) supposed to do
>> (loop :for c = (read-char-no-hang s nil nil) :while c)
>
> I think they should be pretty much equivalent.  If you manage to type
> something really quickly while the loop is running, it will be cleared
> out, whereas I'd expect CLEAR-INPUT to atomically zap the input
> buffer.  But since you can never really guarantee timing issues like
> this, I don't think this is a visible difference.

this is not quite what I was asking about.

forget about interactivity & races.

suppose S is a file stream (or a socket).
what should (clear-input s) do?
- discard unread-char information?
- discard the contents of the buffer (if the stream is buffered)?
  [note that the outcome of this action is unpredictable and
   unreproducible because buffering strategy may depend on many factors]
- (loop :for c = (read-char-no-hang s nil nil) :while c)

more specifically:
barring race conditions, does this return :EOF?

(progn (clear-input s) (read-char-no-hang s nil :EOF))

-- 
Sam Steingold (http://www.podval.org/~sds) running w2k
<http://www.honestreporting.com> <http://www.jihadwatch.org/>
<http://www.palestinefacts.org/> <http://truepeace.org> <http://www.memri.org/>
If Perl is the solution, you're solving the wrong problem. - Erik Naggum
From: Duane Rettig
Subject: Re: clear-input
Date: 
Message-ID: <44q7pp758.fsf@franz.com>
Sam Steingold <···@gnu.org> writes:

>> * Barry Margolin <······@nyhz.zvg.rqh> [2005-10-10 09:23:29 -0400]:
>>
>> In article <·············@gnu.org>, Sam Steingold <···@gnu.org> wrote:
>>
>>> is (clear-input s) supposed to do
>>> (loop :for c = (read-char-no-hang s nil nil) :while c)
>>
>> I think they should be pretty much equivalent.  If you manage to type
>> something really quickly while the loop is running, it will be cleared
>> out, whereas I'd expect CLEAR-INPUT to atomically zap the input
>> buffer.  But since you can never really guarantee timing issues like
>> this, I don't think this is a visible difference.
>
> this is not quite what I was asking about.

I think I know.  While we were designing simple-streams we ran into
these issues.  I don't remember all of the example situations we
encountered, but the final design bespeaks the requirements we saw.

In simple-streams, CLEAR-INPUT has two components: a strategy component
(essentially, hard-wired behavior) and a device component (a Generic
Function, device-clear-input), which implements a personality based
on the stream's class.  There is also an extra optional "buffer-only"
argument to clear-input that allows any actual I/O to be circumvented
(this is useful in bootstrapping situations).

The strategy component always clears the buffer, and then calls the
device-clear-input method with the stream and the buffer-only argument.

The actual method for clearing more than the buffer is dealt with by
various device-clear-input methods:
 - a catch-all method on the simple-stream class does nothing.
 - a method on terminal-simple-stream checks the buffer-only argument -
   if non-nil it does the equivalent of the read-char-no-hang loop,
   except that if any data is available it uses simple-stream's
   read-octets function to get as much of the data as possible in
   one read, rather than looping one-character at a time.
 - an encapsulating stream method checks the stream's handle, and
   if it is itself a stream, and if the buffer-only argument is non-nil,
   it calls clear-input recursively on that handle.

There are no specific methods by default on socket streams, which
are siblings to terminal streams but which have slightly different
semantics.

> forget about interactivity & races.
>
> suppose S is a file stream (or a socket).
> what should (clear-input s) do?
> - discard unread-char information?

Definitely.

> - discard the contents of the buffer (if the stream is buffered)?
>   [note that the outcome of this action is unpredictable and
>    unreproducible because buffering strategy may depend on many factors]

Yes.

> - (loop :for c = (read-char-no-hang s nil nil) :while c)

This depends on whether clear-input makes sense for the stream.

> more specifically:
> barring race conditions, does this return :EOF?
>
> (progn (clear-input s) (read-char-no-hang s nil :EOF))

I don't think it should.  Clear-input doesn't have the eof-error-p
and eof-value arguments that other read-like functions have.  And
what does EOF really mean on a socket stream?  Usually it's just a
marker, rather than a state, as it is on other streams.

-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: Sam Steingold
Subject: Re: clear-input
Date: 
Message-ID: <uy85016tp.fsf@gnu.org>
Thanks for the elucidation.

> * Duane Rettig <·····@senam.pbz> [2005-10-10 11:18:59 -0700]:
>
>> more specifically:
>> barring race conditions, does this return :EOF?
>>
>> (progn (clear-input s) (read-char-no-hang s nil :EOF))
>
> I don't think it should.  Clear-input doesn't have the eof-error-p
> and eof-value arguments that other read-like functions have.  And
> what does EOF really mean on a socket stream?  Usually it's just a
> marker, rather than a state, as it is on other streams.

it appears that you mis-read my code:

(progn (clear-input s)
       (read-char-no-hang s nil :EOF))

barring race conditions, does this return :EOF?

(If I am wrong you indeed mean what you said:
> what does EOF really mean on a socket stream?
it means that select() says that no input is available).

-- 
Sam Steingold (http://www.podval.org/~sds) running w2k
<http://pmw.org.il/> <http://ffii.org/> <http://www.camera.org>
<http://www.openvotingconsortium.org/> <http://www.dhimmi.com/>
Lisp is not dead, it just smells funny.
From: Duane Rettig
Subject: Re: clear-input
Date: 
Message-ID: <4irw46pq2.fsf@franz.com>
Sam Steingold <···@gnu.org> writes:

> Thanks for the elucidation.

No problem.

>> * Duane Rettig <·····@senam.pbz> [2005-10-10 11:18:59 -0700]:
>>
>>> more specifically:
>>> barring race conditions, does this return :EOF?
>>>
>>> (progn (clear-input s) (read-char-no-hang s nil :EOF))
>>
>> I don't think it should.  Clear-input doesn't have the eof-error-p
>> and eof-value arguments that other read-like functions have.  And
>> what does EOF really mean on a socket stream?  Usually it's just a
>> marker, rather than a state, as it is on other streams.
>
> it appears that you mis-read my code:

Oops.  You're right.  Actually, I recall now seeing the code
correctly, but I must have blanked when I was actually answering
the last question - it was a non-trivial amount of time between
my first reading and the answer, with some source code research
between times, though that is no excuse for such a brain fart.

> (progn (clear-input s)
>        (read-char-no-hang s nil :EOF))
>
> barring race conditions, does this return :EOF?

No, unless an EOF character is sent and is interpreted as such.
Sockets are unique from other stream devices in that they do not
get into an "end-of-file" state (in that there is no _further_ data -
note that this is different from the phrase "no character/data
available" - the former suggests permanancy and the latter suggests
a transient situation).  And since a socket tends to be used to
transmit more than one unit of data usually associated with a
file/chunk/document, there has to be a means to delineate between
these units of data, and that usually is done by way of a character
interpreted as an end-of-file.  In a chunking stream, the chunks are
ended by a CR/LF sequence, but the chunks themselves are sub-units of
a larger unit that represents a file or document; the end-of-file
situation in that case is triggered there by a null chunk being
sent, or precisely CR/LF/CR/LF.  But however it is sent, the end-of-file
situation must be distinguishable from a no-data-available situation,
which merely means that not all of the data being sent has arrived
yet.

> (If I am wrong you indeed mean what you said:

Your point is apropos (and incorrect) whether or not I had meant
what I had said:

>> what does EOF really mean on a socket stream?
> it means that select() says that no input is available).

How then can you distinguish that situation from the one called
out by the spec, where "If no character is available, read-char-no-hang
returns nil."?

-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: Sam Steingold
Subject: Re: clear-input
Date: 
Message-ID: <u7jck0z5m.fsf@gnu.org>
> * Duane Rettig <·····@senam.pbz> [2005-10-11 08:24:53 -0700]:
>
>> (progn (clear-input s)
>>        (read-char-no-hang s nil :EOF))
>>
>> barring race conditions, does this return :EOF?
>
> No, unless an EOF character is sent and is interpreted as such.

of course.  now it was my turn to "brain fart".

what I am asking about is:

does this:

(progn (clear-input s)
       (read-char-no-hang s nil nil))

return NIL?

-- 
Sam Steingold (http://www.podval.org/~sds) running w2k
<http://www.camera.org> <http://www.memri.org/>
<http://truepeace.org> <http://www.honestreporting.com> <http://pmw.org.il/>
Please wait, MS Windows are preparing the blue screen of death.
From: Duane Rettig
Subject: Re: clear-input
Date: 
Message-ID: <47jcj7wln.fsf@franz.com>
Sam Steingold <···@gnu.org> writes:

>> * Duane Rettig <·····@senam.pbz> [2005-10-11 08:24:53 -0700]:
>>
>>> (progn (clear-input s)
>>>        (read-char-no-hang s nil :EOF))
>>>
>>> barring race conditions, does this return :EOF?
>>
>> No, unless an EOF character is sent and is interpreted as such.
>
> of course.  now it was my turn to "brain fart".
>
> what I am asking about is:
>
> does this:
>
> (progn (clear-input s)
>        (read-char-no-hang s nil nil))
>
> return NIL?

I'd say that the answer is "maybe".

I would say that like in any asynchronous situation, the important
issue is one of appearence to the user - in unrelated but similar
situations:

  - memory access ordering in a multiple-processor world is not
based on when events actually take place, but when they _appear_ to
take place.  This leaves some leeway to the hardware to perform
caching and to delay slow actions, as long as there can be no
scenario in which the other machine can see the mis-ordering and can
identify it as such.

 - CLOS class update; the reinitialization of an instance whose class
has changed must be done before the next operation on that instance,
but can be delayed until the time of that operation.  To the observer,
this lazy class-change is no different than an implementation which
searches through memory for all instances of that class and updates
them as a part of the change-class operation - except that fewer cpu
cycles are consumed.

In the same way, "clears any available input" is time dependent and
asynchronous, and thus there is no way to know that data didn't become
available in the few cycles between the time the clear-input finished
its operation and the time the read-char-no-hang actually queried the
same socket stream.  The real question is whether differences in
such behavior can be detected by the observing program.

There are some cases that we can crank down a little bit on each end:

 1.  An interactive stream can detect such a difference; it tends to
have both an input side and an output side, and the output side creates
the marker that denotes where the input side must be at the time
it (the output side) is flushed.  In case my explanation is too complex,
think of a prompt; it often occurs on interactive streams, and serves
as a "start your input here" marker.  One would expect that the input
coming into that interactive stream would be generated after the prompt,
so one would have to implement clear-input to flush all of its buffer,
and in an expression like

(progn (write-some-prompt s)
       (clear-input s)
       (read-char-no-hang s nil nil))

it would be generally safe to assume a NIL result, assuming that
in a multiple thread lisp the interactive stream is only attached
to one lisp thread, and assuming that the interaction is with
a human or at human speed.  This is because the "device" on the
very end of an interactive stream tends to be a human, which would
not respond on the keyboard (the input device ultimately attached
to the stream) until the prompt appears at the terminal (the output
device).

 2.  In a stream that deals with quantum data, such as an encrypted
input coming in buffer-fulls, a clear-input which does not at least
empty the buffer might produce input that changes detectably.  So
at the very least clear-input should clear the buffer.

There may be other cases which can be whittled down, but what we are
finally left with in sockets is the ambiguous case where clear-input
would clear the buffer, but not query the lower level device to see
if it had anything else to offer.  This case can't be detected by
the program and so it need not be done.

In Allegro CL's implementation of simple-streams, we define
the complete-flushing of input for terminal-simple-streams, but
define nothing for socket-streams.  However, as is the intention
and design of simple-streams, it is the socket programmer's
prerogative to specialize a socket stream to allow for this
full-flushing of input, and whether or not such flushing can be
truly guaranteed depends on the usage of the stream.  If the
stream is being used interactively, it is likely that the
guarantee can be made - if the guarantee cannot be made, then it
is not necessarily useful.

-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: Barry Margolin
Subject: Re: clear-input
Date: 
Message-ID: <barmar-F19ADC.18391811102005@comcast.dca.giganews.com>
In article <·············@franz.com>, Duane Rettig <·····@franz.com> 
wrote:

> Sam Steingold <···@gnu.org> writes:
> > (progn (clear-input s)
> >        (read-char-no-hang s nil :EOF))
> >
> > barring race conditions, does this return :EOF?
> 
> No, unless an EOF character is sent and is interpreted as such.
> Sockets are unique from other stream devices in that they do not
> get into an "end-of-file" state (in that there is no _further_ data -
> note that this is different from the phrase "no character/data
> available" - the former suggests permanancy and the latter suggests
> a transient situation).

It sounds to me like you're using "end-of-file state" differently from 
most other socket APIs.  With most APIs, a TCP socket will enter EOF 
state when a FIN segment is received, which indicates that no more data 
will be sent on that connection.  The corresponding process does this by 
closing its socket, or calling something like shutdown() that lets you 
perform a half-close.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
From: Duane Rettig
Subject: Re: clear-input
Date: 
Message-ID: <4achfbiik.fsf@franz.com>
Barry Margolin <······@alum.mit.edu> writes:

> In article <·············@franz.com>, Duane Rettig <·····@franz.com> 
> wrote:
>
>> Sam Steingold <···@gnu.org> writes:
>> > (progn (clear-input s)
>> >        (read-char-no-hang s nil :EOF))
>> >
>> > barring race conditions, does this return :EOF?
>> 
>> No, unless an EOF character is sent and is interpreted as such.
>> Sockets are unique from other stream devices in that they do not
>> get into an "end-of-file" state (in that there is no _further_ data -
>> note that this is different from the phrase "no character/data
>> available" - the former suggests permanancy and the latter suggests
>> a transient situation).
>
> It sounds to me like you're using "end-of-file state" differently from 
> most other socket APIs.  With most APIs, a TCP socket will enter EOF 
> state when a FIN segment is received, which indicates that no more data 
> will be sent on that connection.  The corresponding process does this by 
> closing its socket, or calling something like shutdown() that lets you 
> perform a half-close.

Yes, you're right.  I didn't want to bring another wrinkle into it by
talking about shutting down sockets, and that resulted in a misspoken
statement (the answer to the question "does this return :EOF?" is
"No, unless an EOF character is sent or the socket on the other side
is closed wihout having any unread data".  Since we weren't really
talking about EOF's, though, as Sam realized in his next reply, I
didn't want to muddy the waters with extra complexity.  Here, is a
situation where ANSI's definition of streams doesn't fit very well
into socket protocol norms - If you send information to a socket and
the other side doesn't bother reading the data but shuts down,
instead of an eof you get a "connection reset by peer" error based
on the previous write operation.

Note that I maintain the first portion of my statement - EOF can be a
character sent as well as a state of the stream, not at the TCP level,
but at a higher level - consider a socket, say, a connection to an
interactive device (say, a cooked terminal not directly connected to
the machine the program is running on).  In that situation, an EOF is
what we've termed a "soft eof" in simple-streams terminology.  You would
want the stream to act the same way that the cooked terminal acts when
a Control-D is typed.  Not OOB, like a Control-C, but just a character
or a character sequence to be interpreted at the higher level end
(i.e. read-char-no-hang) as an eof.

In general, the term EOF is a hard one to nail down, because it acts
differently in different situations.  What does it mean to have "no
further data"?  For example, it would be tempting to equate a hard
eof in a socket (e.g. the other side has shut down and now we see
an EOF on reading from this side) as the same as an EOF in a
file stream; but an EOF in a file stream is postional rather than
stateful, in that one can easily remove the EOF state by setting the
position backwards in the file.  That flies in the face of the ANSI
definition "no further data".  Not fair, you say?  Further means
positionally in the file, you say?  Well, what does position mean in
a socket?  File-position doesn't even work on a socket!  No, the use
the word "further" is not really defined in ANSI CL's definition of
"end of file".  Here's another example that kills a positional concept
of "further"; suppose you want to emulate unix's "tail -f ..." filter -
when the reading comes to the end of the file, is that an EOF
situation?  And so on...

-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182