Hello,

I have encountered bug in ruby threads.
It can be demonstrated by following script:

----simplebug.rb--------------------------
require 'socket'

PORT=8080

def handle_client(sock)
   5.times{ sock.write(sock.readline) } # echo few lines
   sock.close
end

trap('HUP') {
   puts 'Got SIGHUP'
}

server = TCPserver.open(PORT)
while true do
   sock = server.accept
   puts 'client accepted'
   Thread.start do
     handle_client(sock)
   end
end
------------------------------------------

Run script, run telnet session to talk with it.
Send SIGHUP signal to script.
Now ruby is doing blocking accept call (instead of select
which is required for ruby threads to work).
Test on telnet session that no more lines are echoed back.
If you initiate another new telnet session, blocking accept
will stop blocking and things will continue to work correctly
(till next SIGHUP signal).

This bug applies to following ruby versions:
ruby 1.6.7 (2002-05-10) [i686-linux]
ruby 1.6.7 (2002-03-19) [i386-linux]

I have been searching the BUG for a few hours.

First obvious BUG:
----part of file eval.c---------------------
         n = select(max+1, &readfds, &writefds, &exceptfds, delay_ptr);
         if (n < 0) {
             if (rb_trap_pending) rb_trap_exec();
             if (errno == EINTR) goto again;
#ifdef ERESTART
             if (errno == ERESTART) goto again;
#endif
---------------------------------------------
If rb_trap_exec is executed, errno is no longer valid

simple fix:
---------------------------------------------
         n = select(max+1, &readfds, &writefds, &exceptfds, delay_ptr);
         if (n < 0) {
             int tmperrno=errno;
             if (rb_trap_pending) rb_trap_exec();
             if (tmperrno == EINTR) goto again;
#ifdef ERESTART
             if (tmperrno == ERESTART) goto again;
#endif
---------------------------------------------

However this does not solve problem in the script above.
Problem is probably in thread switching somewhere.

call tree for rb_trap_exec
  rb_trap_exec:
    call signal_exec
    rb_signal_exec:
      call rb_thread_trap_eval
        rb_thread_trap_eval: call rb_thread_ready
        rb_thread_trap_eval: call rb_thread_restore_context
          ...


I currently don't have much time to dig in ruby source due to
school work.

Jakub Travnik
jabber://jtra / jabber.com
You can contact me also at irc.openprojects.net #ruby-lang