Skip to content
  • Charles Oliver Nutter's avatar
    89c9a9fd
    [ruby/net-http] Don't double-interrupt the test HTTP server · 89c9a9fd
    Charles Oliver Nutter authored
    The shutdown process here attempted to terminate the test server
    by interrupting it with Thread#kill, and then proceeded to close
    the server and join the thread. The kill does indeed interrupt
    the accept call, but the close call could also interrupt the
    thread as part of notifying blocked threads waiting on that
    socket call.
    
    In JRuby, where all of this can happen at the same time, it leads
    to the following scenario:
    
    * The server thread enters TCPServer#accept and blocks.
    * The main thread calls Thread#kill to interrupt the accept call.
    * The server thread wakes up and starts to propagate the kill.
      There is a slight delay between this wakeup and removing the
      server thread from the TCPServer's blocked threads list.
    * The main thread calls TCPServer#close, which sees that the server
      thread is still in the blocked list, so it initiates a second
      interrupt to raise IOError "closed in another thread" on the
      server thread.
    * As the kill is bubbling out, another check for interrupts occurs,
      causing it to see the new raise interrupt and propagate that
      instead of the active kill.
    * Because the server is now closed and the rescue here is empty,
      the server loop will endlessly attempt and fail to call accept.
    
    I was unable to determine how CRuby avoids this race. There may be
    code that prevents an active kill interrupt from triggering
    further interrupts.
    
    In order to get these tests running on JRuby, I've made the
    following changes:
    
    * Only kill the thread; one interrupt is sufficient to break it
      out of the accept call.
    * Ensure outside the server loop that the server gets closed. This
      happens within the server thread, so triggers no new interrupts.
    * Minor cleanup for the pattern of using @ssl_server or @server.
    
    This change avoids the race in JRuby (and possibly other parallel-
    threaded implementations) and does not impact the behavior of the
    tests.
    
    https://github.com/ruby/net-http/commit/54025b3870
    89c9a9fd
    [ruby/net-http] Don't double-interrupt the test HTTP server
    Charles Oliver Nutter authored
    The shutdown process here attempted to terminate the test server
    by interrupting it with Thread#kill, and then proceeded to close
    the server and join the thread. The kill does indeed interrupt
    the accept call, but the close call could also interrupt the
    thread as part of notifying blocked threads waiting on that
    socket call.
    
    In JRuby, where all of this can happen at the same time, it leads
    to the following scenario:
    
    * The server thread enters TCPServer#accept and blocks.
    * The main thread calls Thread#kill to interrupt the accept call.
    * The server thread wakes up and starts to propagate the kill.
      There is a slight delay between this wakeup and removing the
      server thread from the TCPServer's blocked threads list.
    * The main thread calls TCPServer#close, which sees that the server
      thread is still in the blocked list, so it initiates a second
      interrupt to raise IOError "closed in another thread" on the
      server thread.
    * As the kill is bubbling out, another check for interrupts occurs,
      causing it to see the new raise interrupt and propagate that
      instead of the active kill.
    * Because the server is now closed and the rescue here is empty,
      the server loop will endlessly attempt and fail to call accept.
    
    I was unable to determine how CRuby avoids this race. There may be
    code that prevents an active kill interrupt from triggering
    further interrupts.
    
    In order to get these tests running on JRuby, I've made the
    following changes:
    
    * Only kill the thread; one interrupt is sufficient to break it
      out of the accept call.
    * Ensure outside the server loop that the server gets closed. This
      happens within the server thread, so triggers no new interrupts.
    * Minor cleanup for the pattern of using @ssl_server or @server.
    
    This change avoids the race in JRuby (and possibly other parallel-
    threaded implementations) and does not impact the behavior of the
    tests.
    
    https://github.com/ruby/net-http/commit/54025b3870
Loading