Thank you for the tip, using sysread does fix this problem. But after
further tests, I found another problem. Apparently, as Ara.T.Howard
pointed out before, Kernel#select and IO#sysread seems to be a bad mix.
Every sockets Kernel#select returns seems to be buffered, as this code
shows :

	require 'socket'
	Thread.new do
		sleep 2
		client = TCPSocket.new('localhost', '1999') 
		loop do
			sleep 1
			client.syswrite "message"
		end
	end
	server = TCPServer.new("0.0.0.0","1999")
	thr = Thread.new do
		socks = []
		loop do
			rs,wd,ed = select(socks+[server],nil,nil)
			rs.each do |sock|
				if sock == server
					n_sock = server.accept
					n_sock.fcntl(Fcntl::F_SETFL,
	
Fcntl::O_NONBLOCK)
					socks.push n_sock
					#This call will not raise an
IOError
					#because this socket in not
buffered yet.
					puts n_sock.sysread(100)
				elsif sock.closed? || sock.eof?
					socks.delete sock
				else
					#This call however will raise an
IOError.
					puts sock.sysread(100)
				end
			end
		end
	end
	thr.join

Is it a normal behavior? If so, does an option to allow Kernel#select to
returns non-buffered IO exists?

Yannick

-----Original Message-----
From: Tanaka Akira [mailto:akr / m17n.org] 
Sent: Saturday, March 27, 2004 2:26 AM
To: ruby-talk ML
Subject: Re: non blocking read and thread

In article <000001c4134c$0cbe5920$0300a8c0@boulba>,
  "yannick" <yannick / dazzlebox.com> writes:

> You are right, after further tests; it looks like a thread scheduling
> problem, it could perhaps be solved by making the thread critical, but
> then it only return the EAGAIN error. Well, it seems I'm stock here,
> better find another way around :-)

I recommend sysread instead of IO#read with nonblocking mode.

However, your first script is interesting because it transit
multithread to singlethread after sock.read(100) is started.

When there are two or more threads, Ruby calls select(2) before each
IO operation for thread scheduling.  But Ruby doesn't call select(2)
when there is only one thread.

Your first script invokes following system calls.

% strace -e read,write,select ruby tst1
...
select(0, [], [], [], {0, 0})           = 0 (Timeout)
select(6, [5], [], [], {1, 999368})     = 0 (Timeout)
select(6, [5], [], [], {0, 3115})       = 0 (Timeout)
select(6, [5], [], [], {0, 0})          = 0 (Timeout)
select(9, [5], [7], [], NULL)           = 2 (in [5], out [7])
write(1, "try to read it...\n", 18)     = 18
(*1) select(9, [8], [], [], {0, 0})          = 0 (Timeout)
write(1, "send a message\n", 15)        = 15
select(9, [8], [7], [], NULL)           = 1 (out [7])
write(7, "message", 7)                  = 7
select(9, [8], [7], [], NULL)           = 2 (in [8], out [7])
select(9, [8], [], [], {0, 0})          = 1 (in [8], left {0, 0})
write(7, "\n", 1)                       = 1
(*2) read(8, "message\n", 1024)              = 8
(*3) read(8, 0x4001a000, 1024)               = -1 EAGAIN (Resource
temporarily unavailable)
write(1, "done !\n", 7)                 = 7

System calls corresponding to sock.read(100) is (*1), (*2) and (*3)

(*1) Check sock is readable or not.  Since it is not readable yet,
     it blocks and switch to other thread.
(*2) Read 8bytes from sock: "message\n".
(*3) Occur EAGAIN.  It terminates sock.read(100).

What interesting is that select is not called before (*3).
If select is called at (*3), it blocks forever.
This means that there are no thread other than the main thread.
Actually the client thread is finished before (*2).

So sock.read(100) blocks at first(*1) by select because multithread.
But it doesn't block at last(*3) because singlethread.

I think this behavior is very confusing.
-- 
Tanaka Akira