On Mon, 5 Sep 2005, Bill Kelly wrote:

> From: "Bill Kelly" <billk / cts.com>
>
>>>> require 'socket'
>> => true
>>>> require 'thread'
>> => true
>>>> cl = TCPSocket.new("localhost", 12345)
>> => #<TCPSocket:0x2dbaf88>
>>>> th1 = Thread.new {  sleep(1.0) until cl.eof?  }
>> => #<Thread:0x2db6dd0 sleep>
>>>> th2 = Thread.new {  sleep(1.0) until cl.eof?  }
>> => #<Thread:0x2db2bb8 sleep>
>>>> cl.eof?
>>
>>    ^^^^^^^^ hang
>
>
> I guess it must be something very basic I'm not aware of
> about #eof? ... Because even:
>
>>>> require 'socket'
>> => true
>>>> require 'thread'
>> => true
>>>> cl = TCPSocket.new("localhost", 12345)
>> => #<TCPSocket:0x2dbaf88>
>>>> cl.eof?
>
> hangs.
>
>
> Is it not possible to check for EOF without blocking?

sometimes yes, sometimes no, or so it seems:

   [ahoward@localhost ~]$ cat a.rb
   require 'socket'
   s = TCPSocket::new '127.0.0.1', 80
   s.eof?

   [ahoward@localhost ~]$ strace ruby a.rb 2>&1
   ...
   ...
   ...
   read(3


and, from io.c:

   /*
    *  call-seq:
    *     ios.eof     => true or false
    *     ios.eof?    => true or false
    *
    *  Returns true if <em>ios</em> is at end of file. The stream must be
    *  opened for reading or an <code>IOError</code> will be raised.
    *
    *     f = File.new("testfile")
    *     dummy = f.readlines
    *     f.eof   #=> true
    */

   VALUE
   rb_io_eof(io)
       VALUE io;
   {
       OpenFile *fptr;
       int ch;

       GetOpenFile(io, fptr);
       rb_io_check_readable(fptr);

       if (feof(fptr->f)) return Qtrue;
       if (READ_DATA_PENDING(fptr->f)) return Qfalse;
       READ_CHECK(fptr->f);
       clearerr(fptr->f);
       TRAP_BEG;
       ch = getc(fptr->f);          // look here !!!
       TRAP_END;

       if (ch != EOF) {
           ungetc(ch, fptr->f);
           return Qfalse;
       }
       rb_io_check_closed(fptr);
       clearerr(fptr->f);
       return Qtrue;
   }


i'm no systems/network guy - but it seems like maybe one shouldn't try to read
a char from anything like a socket, pipe, etc. that might hang for a read in
this case...  i dunno how to check for this kind of thing though... maybe:

   if(fseek(fptr->f) == EBADF) {
     return Qnil;                 // we can't tell for this stream!
   }
   else {
     TRAP_BEG;
     ch = getc(fptr->f);
     TRAP_END;
   }


or maybe an error could be thrown up front for this case (Errno::EWOULDBLOCK
for example)... but this doesn't seem right since you may want to check eof
for a socket at times... nil could mean "don't know."

anyhow... it sure makes sense that it'd block though...

hth.

-a
-- 
===============================================================================
| email :: ara [dot] t [dot] howard [at] noaa [dot] gov
| phone :: 303.497.6469
| Your life dwells amoung the causes of death
| Like a lamp standing in a strong breeze.  --Nagarjuna
===============================================================================