In article <87ocz0ck56.fsf / fsij.org>, Tanaka Akira <akr / fsij.org> writes: >> two threads reading from the same socket at same time produces race condition whichs locks interpreter >> >> info at: http://coderrr.wordpress.com/2008/12/10/mri-io-deadlock/ > > I investigated the problem. There is similar problem with write. % uname -mrsv Linux 2.6.18-6-486 #1 Mon Oct 13 15:35:23 UTC 2008 i686 % ./ruby -ve ' p $$ Thread.new { loop { p Time.now; sleep 1 } } r, w = IO.pipe w.write "a" * (65536-4096) 2.times { Thread.new { w.write "a"*2049 } } sleep 10 ' ruby 1.8.7 (2008-12-26 revision 21066) [i686-linux] 13272 Sat Dec 27 12:50:09 +0900 2008 (interpreter blocks here) Updated patch: % svn diff --diff-cmd diff -x '-u -p' Index: eval.c =================================================================== --- eval.c (revision 21047) +++ eval.c (working copy) @@ -10961,6 +10961,7 @@ rb_thread_schedule() rb_thread_t next; /* OK */ rb_thread_t th; rb_thread_t curr; + rb_thread_t th_found = 0; int found = 0; fd_set readfds; @@ -11110,24 +11111,18 @@ rb_thread_schedule() FOREACH_THREAD_FROM(curr, th) { if ((th->wait_for&WAIT_FD) && FD_ISSET(th->fd, &readfds)) { /* Wake up only one thread per fd. */ - FD_CLR(th->fd, &readfds); - th->status = THREAD_RUNNABLE; - th->fd = 0; - th->wait_for = 0; + th_found = th; found = 1; + break; } if ((th->wait_for&WAIT_SELECT) && (match_fds(&readfds, &th->readfds, max) || match_fds(&writefds, &th->writefds, max) || match_fds(&exceptfds, &th->exceptfds, max))) { /* Wake up only one thread per fd. */ - th->status = THREAD_RUNNABLE; - th->wait_for = 0; - n = intersect_fds(&readfds, &th->readfds, max) + - intersect_fds(&writefds, &th->writefds, max) + - intersect_fds(&exceptfds, &th->exceptfds, max); - th->select_value = n; - found = 1; + th_found = th; + found = 1; + break; } } END_FOREACH_FROM(curr, th); @@ -11143,9 +11138,23 @@ rb_thread_schedule() next = th; break; } - if (th->status == THREAD_RUNNABLE && th->stk_ptr) { - if (!next || next->priority < th->priority) - next = th; + if ((th->status == THREAD_RUNNABLE || th == th_found) && th->stk_ptr) { + if (!next || next->priority < th->priority) { + if (th == th_found) { + th_found->status = THREAD_RUNNABLE; + th_found->wait_for = 0; + if (th->wait_for&WAIT_FD) { + th_found->fd = 0; + } + else { /* th->wait_for&WAIT_SELECT */ + n = intersect_fds(&readfds, &th_found->readfds, max) + + intersect_fds(&writefds, &th_found->writefds, max) + + intersect_fds(&exceptfds, &th_found->exceptfds, max); + th_found->select_value = n; + } + } + next = th; + } } } END_FOREACH_FROM(curr, th); -- Tanaka Akira