[#35446] [Ruby 1.9 - Bug #4477][Open] Kernel:exec and backtick (`) don't work for certain system commands — Joachim Wuttke <j.wuttke@...>

10 messages 2011/03/07

[#35476] [Ruby 1.9 - Bug #4489][Open] [PATCH] Encodings with /-(unix|dos|mac)\Z/ — "James M. Lawrence" <quixoticsycophant@...>

20 messages 2011/03/10

[#35552] [Ruby 1.9 - Feature #4523][Open] Kernel#require to return the path of the loaded file — Alex Young <alex@...>

14 messages 2011/03/24

[#35565] [Ruby 1.9 - Feature #4531][Open] [PATCH 0/7] use poll() instead of select() in certain cases — Eric Wong <normalperson@...>

33 messages 2011/03/28

[#35566] [Ruby 1.9 - Feature #4532][Open] [PATCH] add IO#pread and IO#pwrite methods — Eric Wong <normalperson@...>

12 messages 2011/03/28

[#35586] [Ruby 1.9 - Feature #4538][Open] [PATCH (cleanup)] avoid unnecessary select() calls before doing I/O — Eric Wong <normalperson@...>

9 messages 2011/03/29

[ruby-core:35505] TCPServer internals - chasing EBADF error

From: Xavier Shay <xavier-list@...>
Date: 2011-03-16 10:57:30 UTC
List: ruby-core #35505
Hello,
The following code intermittently raises an EBADF error and I am trying 
to figure out why.

     require 'socket'
     8.times do
       fork do
         1000.times do
           sleep (rand / 1000.0)
           begin
             server = TCPServer.new('127.0.0.1', 5678)
             server.close
           rescue Errno::EADDRINUSE => e
           end
         end
       end
     end

I am running on an 8 core ubuntu machine with ruby 1.9.2.
I have been reading through the ruby source and here is what I have 
discovered:
- TCPServer.new ends up calling init_inetsock_internal in 
ext/socket/tcpsocket.c, which calls socket(2) and bind(2) to create a socket
- EBADF is one of bind's documented errors, and can be caused by binding 
to a closed socket 
(http://www.gnu.org/s/libc/manual/html_node/Error-Codes.html)

 From that I have two hypotheses:
1) socket is called at the same time 2 processes, returning the same FD. 
It is closed by one process before the other binds.
2) socket picks up a FD that has been "closed" by ruby but not quite 
"closed" properly by the OS, and tries to bind to it.

I am at a bit of a loss as to where to go next. I was trying to track 
down IO#close which led me to rb_io_close in io.c - I can't quite figure 
out how this actually closes the socket (I was expecting a system call 
to close). It leads to thread_fd_close_i in thread.c and I can't figure 
what this is doing either.

Can anyone shed some light?

Cheers,
Xavier

PS For context, the equivalent of the above code is causing problems in 
the selenium-webdriver gem. I can fix it easily enough with some proper 
locking, but I am interested in understanding the root cause a bit better.

In This Thread

Prev Next