From 5c17ceb012bf172cc8f0c908e769bb0abb4c3338 Mon Sep 17 00:00:00 2001 From: wyhaines Date: Tue, 26 Jan 2010 18:06:41 +0000 Subject: Backport #2039 [ruby-core:25339]; backported r24413, r24416, r24442 to fix a problem with IO#select and threads. This is the same issue as Bug #199 3 [ruby-core:25114]. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8_6@26435 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 8 +++++-- eval.c | 77 +++++++++++++++++++++++++++++++++++---------------------------- 2 files changed, 49 insertions(+), 36 deletions(-) diff --git a/ChangeLog b/ChangeLog index aaabf1175c..b4c9318a96 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,8 +1,12 @@ +Tue Jan 26 3:03:00 2010 Kirk Haines + + * eval.c: Backport #2039 [ruby-core:25339]; backported r24413, r24416, r24442 to fix a problem with IO#select and threads. This is the same issues as Bug #1993 [ruby-core:25114]. + Thu Jan 21 5:10:00 2010 Kirk Haines - * eval.c: Backport #2592 [ruby-core:27525]; Added an ifndef for WIN32 so that F_GETFD isn't used on that platform. Fixes a build issue. + * eval.c: Backport #2592 [ruby-core:27525]; Added an ifndef for WIN32 so that F_GETFD isn't used on that platform. Fixes a build issue. r26361 - * dln.c: Bug #2220 [ruby-core:26117]; Patch to fix dln.c so that extensions work properly under Snow Leopard. + * dln.c: Bug #2220 [ruby-core:26117]; Patch to fix dln.c so that extensions work properly under Snow Leopard. 26361 Sun Jan 10 8:00:00 2010 Kirk Haines diff --git a/eval.c b/eval.c index b1dbbf0750..188fe8da5d 100644 --- a/eval.c +++ b/eval.c @@ -9913,6 +9913,7 @@ extern VALUE rb_last_status; #define WAIT_TIME (1<<2) #define WAIT_JOIN (1<<3) #define WAIT_PID (1<<4) +#define WAIT_DONE (1<<5) /* +infty, for this purpose */ #define DELAY_INFTY 1E30 @@ -10737,6 +10738,7 @@ rb_thread_schedule() now = -1.0; FOREACH_THREAD_FROM(curr, th) { + th->wait_for &= ~WAIT_DONE; if (!found && th->status <= THREAD_RUNNABLE) { found = 1; } @@ -10769,7 +10771,12 @@ rb_thread_schedule() if (now < 0.0) now = timeofday(); th_delay = th->delay - now; if (th_delay <= 0.0) { - th->status = THREAD_RUNNABLE; + if (th->wait_for & WAIT_SELECT) { + need_select = 1; + } + else { + th->status = THREAD_RUNNABLE; + } found = 1; } else if (th_delay < delay) { @@ -10888,22 +10895,22 @@ rb_thread_schedule() if (n > 0) { now = -1.0; /* Some descriptors are ready. - * Choose a thread which may run next. - * Don't change the status of threads which don't run next. + * The corresponding threads are runnable as next. + * Mark them with WAIT_DONE. + * Don't change the status to runnable here because + * threads which don't run next should not be changed. */ FOREACH_THREAD_FROM(curr, th) { if ((th->wait_for&WAIT_FD) && FD_ISSET(th->fd, &readfds)) { - th_found = th; + th->wait_for |= WAIT_DONE; 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))) { - th_found = th; + th->wait_for |= WAIT_DONE; found = 1; - break; } } END_FOREACH_FROM(curr, th); @@ -10915,31 +10922,32 @@ rb_thread_schedule() } FOREACH_THREAD_FROM(curr, th) { - if (th->status == THREAD_TO_KILL) { - next = th; - break; - } - 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; + if (th->status == THREAD_TO_KILL) { + next = th; + break; + } + if ((th->status == THREAD_RUNNABLE || (th->wait_for & WAIT_DONE)) && th->stk_ptr) { + if (!next || next->priority < th->priority) { + next = th; } - } + } } END_FOREACH_FROM(curr, th); + if (next && (next->wait_for & WAIT_DONE)) { + next->status = THREAD_RUNNABLE; + if (next->wait_for&WAIT_FD) { + next->fd = 0; + } + else { /* next->wait_for&WAIT_SELECT */ + n = intersect_fds(&readfds, &next->readfds, max) + + intersect_fds(&writefds, &next->writefds, max) + + intersect_fds(&exceptfds, &next->exceptfds, max); + next->select_value = n; + } + next->wait_for = 0; + } + if (!next) { /* raise fatal error to main thread */ curr_thread->node = ruby_current_node; @@ -10949,15 +10957,16 @@ rb_thread_schedule() TRAP_END; } FOREACH_THREAD_FROM(curr, th) { + int wait_for = th->wait_for & ~WAIT_DONE; warn_printf("deadlock 0x%lx: %s:", th->thread, thread_status_name(th->status)); - if (th->wait_for & WAIT_FD) warn_printf("F(%d)", th->fd); - if (th->wait_for & WAIT_SELECT) warn_printf("S"); - if (th->wait_for & WAIT_TIME) warn_printf("T(%f)", th->delay); - if (th->wait_for & WAIT_JOIN) + if (wait_for & WAIT_FD) warn_printf("F(%d)", th->fd); + if (wait_for & WAIT_SELECT) warn_printf("S"); + if (wait_for & WAIT_TIME) warn_printf("T(%f)", th->delay); + if (wait_for & WAIT_JOIN) warn_printf("J(0x%lx)", th->join ? th->join->thread : 0); - if (th->wait_for & WAIT_PID) warn_printf("P"); - if (!th->wait_for) warn_printf("-"); + if (wait_for & WAIT_PID) warn_printf("P"); + if (!wait_for) warn_printf("-"); warn_printf(" %s - %s:%d\n", th==main_thread ? "(main)" : "", th->node->nd_file, nd_line(th->node)); -- cgit v1.2.3