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