From: Marcus Rueckert Date: 2011-03-16T20:32:06+09:00 Subject: [ruby-core:35506] Re: TCPServer internals - chasing EBADF error On 2011-03-16 19:57:30 +0900, Xavier Shay wrote: > 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? smells like a race condition. darix -- openSUSE - SUSE Linux is my linux openSUSE is good for you www.opensuse.org