Errno::EBADF is sometimes raised instead of IOError when TCPSocket#readline is 
called after TCPSocket#close
-----------------------------------------------------------------------------------------------------------

                 Key: JRUBY-5514
                 URL: http://jira.codehaus.org/browse/JRUBY-5514
             Project: JRuby
          Issue Type: Bug
    Affects Versions: JRuby 1.6RC2, JRuby 1.5.6, JRuby 1.5.1
         Environment: Linux desk4 2.6.32-28-generic #55-Ubuntu SMP Mon Jan 10 
23:42:43 UTC 2011 x86_64 GNU/Linux
java version "1.6.0_22"
Java(TM) SE Runtime Environment (build 1.6.0_22-b04)
Java HotSpot(TM) 64-Bit Server VM (build 17.1-b03, mixed mode)
            Reporter: Alex Young
            Assignee: Thomas E Enebo
            Priority: Minor


When TCPSocket#readline is called after a TCPSocket#close on the same client 
socket, if the #close comes from another thread, sometimes an Errno::EBADF is 
the result instead of an IOError: closed stream.

Tracing through the code, what's happening is that the ChannelDescriptor 
responds to the getline() call with a BadDescriptorException because the 
underlying Channel responds false to isOpen(), which on the face of it seems 
wrong but I'm not familiar enough with the semantics to make a convincing 
argument. Also, given that the readStream.getline() call is guarded by a 
beforeBlockingCall(), I suspect that this actually indicates a race somewhere 
else in the code.

It is proving difficult to narrow this down to a single test case, but the 
following code at least demonstrates the problem:

  require 'socket'

  server = TCPServer.new(0)
  server_thread = Thread.new{ server.accept while true }

  exceptions = []

  1000.times do |i|
    client_socket = TCPSocket.new("localhost", server.addr[1])
    close_thread = Thread.new{ sleep(Kernel.rand/100); client_socket.close }
    read_thread = Thread.new do 
      sleep(Kernel.rand/100); 
      begin
        client_socket.readline
      rescue Exception => e
        exceptions << e
      end
    end
  
    close_thread.join
    read_thread.join
  end

  p exceptions.map{|e| e.class.to_s}.inject({}){|m,r| m.merge r => 
true}.keys.sort

The final output is, for me:

  ["EOFError", "Errno::EBADF", "Errno::EPIPE", "IOError"]

EOFError and IOError are expected. EBADF and EPIPE are not.

-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: 
http://jira.codehaus.org/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira

        

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply via email to