summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwyhaines <wyhaines@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2010-01-26 18:06:41 +0000
committerwyhaines <wyhaines@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2010-01-26 18:06:41 +0000
commit5c17ceb012bf172cc8f0c908e769bb0abb4c3338 (patch)
treea7c8326e0ba4817ef9bebc141c2c1c59994fffd8
parent5cf140d9ea404c13c81d09b1867e8f96e90c358e (diff)
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
-rw-r--r--ChangeLog8
-rw-r--r--eval.c77
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 <khaines@ruby-lang.org>
+
+ * 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 <khaines@ruby-lang.org>
- * 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 <khaines@ruby-lang.org>
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));