summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--test/ruby/test_sleep.rb10
-rw-r--r--thread.c29
-rw-r--r--win32/win32.c38
4 files changed, 69 insertions, 13 deletions
diff --git a/ChangeLog b/ChangeLog
index ab91451cd..b37132a7d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+Wed Jul 30 17:48:15 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/win32.c (rb_w32_select): recalc the rest of timeout for each
+ iterations. [ruby-core:18015]
+
Tue Jul 29 23:37:37 2008 Yusuke Endoh <mame@tsg.ne.jp>
* io.c (io_ungetc): raise NotImplementedError when ungetc is called
diff --git a/test/ruby/test_sleep.rb b/test/ruby/test_sleep.rb
new file mode 100644
index 000000000..675fdc974
--- /dev/null
+++ b/test/ruby/test_sleep.rb
@@ -0,0 +1,10 @@
+require 'test/unit'
+
+class TestSleep < Test::Unit::TestCase
+ def test_sleep_5sec
+ start = Time.now
+ sleep 5
+ slept = Time.now-start
+ assert_in_delta(5.0, slept, 0.1, "[ruby-core:18015]: longer than expected")
+ end
+end
diff --git a/thread.c b/thread.c
index c25e8b1f6..f6e7ff279 100644
--- a/thread.c
+++ b/thread.c
@@ -1957,7 +1957,7 @@ cmp_tv(const struct timeval *a, const struct timeval *b)
}
static int
-subst(struct timeval *rest, const struct timeval *wait)
+subtract_tv(struct timeval *rest, const struct timeval *wait)
{
while (rest->tv_usec < wait->tv_usec) {
if (rest->tv_sec <= wait->tv_sec) {
@@ -1982,10 +1982,18 @@ do_select(int n, fd_set *read, fd_set *write, fd_set *except,
#ifndef linux
double limit = 0;
struct timeval wait_rest;
+# if defined(__CYGWIN__) || defined(_WIN32)
+ struct timeval start_time;
+# endif
if (timeout) {
- limit = timeofday() +
- (double)timeout->tv_sec+(double)timeout->tv_usec*1e-6;
+# if defined(__CYGWIN__) || defined(_WIN32)
+ gettimeofday(&start_time, NULL);
+ limit = (double)start_time.tv_sec + (double)start_time.tv_usec*1e-6;
+# else
+ limit = timeofday();
+# endif
+ limit += (double)timeout->tv_sec+(double)timeout->tv_usec*1e-6;
wait_rest = *timeout;
timeout = &wait_rest;
}
@@ -2000,6 +2008,7 @@ do_select(int n, fd_set *read, fd_set *write, fd_set *except,
#if defined(__CYGWIN__) || defined(_WIN32)
{
+ int finish = 0;
/* polling duration: 100ms */
struct timeval wait_100ms, *wait;
wait_100ms.tv_sec = 0;
@@ -2017,9 +2026,19 @@ do_select(int n, fd_set *read, fd_set *write, fd_set *except,
if (write) *write = orig_write;
if (except) *except = orig_except;
wait = &wait_100ms;
- } while (__th->interrupt_flag == 0 && (timeout == 0 || subst(timeout, &wait_100ms)));
+ if (timeout) {
+ struct timeval elapsed;
+ gettimeofday(&elapsed, NULL);
+ subtract_tv(&elapsed, &start_time);
+ if (!subtract_tv(timeout, &elapsed)) {
+ finish = 1;
+ break;
+ }
+ if (cmp_tv(&wait_100ms, timeout) < 0) wait = timeout;
+ }
+ } while (__th->interrupt_flag == 0);
}, 0, 0);
- } while (result == 0 && (timeout == 0 || subst(timeout, &wait_100ms)));
+ } while (result == 0 && !finish);
}
#else
BLOCKING_REGION({
diff --git a/win32/win32.c b/win32/win32.c
index 1d667cfa8..9285b44a4 100644
--- a/win32/win32.c
+++ b/win32/win32.c
@@ -2143,7 +2143,7 @@ do_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
}
static inline int
-subst(struct timeval *rest, const struct timeval *wait)
+subtract(struct timeval *rest, const struct timeval *wait)
{
while (rest->tv_usec < wait->tv_usec) {
if (rest->tv_sec <= wait->tv_sec) {
@@ -2174,7 +2174,7 @@ compare(const struct timeval *t1, const struct timeval *t2)
#undef Sleep
int WSAAPI
rb_w32_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
- struct timeval *timeout)
+ struct timeval *timeout)
{
int r;
fd_set pipe_rd;
@@ -2183,11 +2183,29 @@ rb_w32_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
fd_set else_wr;
fd_set except;
int nonsock = 0;
+ struct timeval limit;
if (nfds < 0 || (timeout && (timeout->tv_sec < 0 || timeout->tv_usec < 0))) {
errno = EINVAL;
return -1;
}
+
+ if (timeout) {
+ if (timeout->tv_sec < 0 ||
+ timeout->tv_usec < 0 ||
+ timeout->tv_usec >= 1000000) {
+ errno = EINVAL;
+ return -1;
+ }
+ gettimeofday(&limit, NULL);
+ limit.tv_sec += timeout->tv_sec;
+ limit.tv_usec += timeout->tv_usec;
+ if (limit.tv_usec >= 1000000) {
+ limit.tv_usec -= 1000000;
+ limit.tv_sec++;
+ }
+ }
+
if (!NtSocketsInitialized) {
StartSockets();
}
@@ -2223,10 +2241,9 @@ rb_w32_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
struct timeval rest;
struct timeval wait;
struct timeval zero;
- if (timeout) rest = *timeout;
wait.tv_sec = 0; wait.tv_usec = 10 * 1000; // 10ms
zero.tv_sec = 0; zero.tv_usec = 0; // 0ms
- do {
+ for (;;) {
if (nonsock) {
// modifying {else,pipe,cons}_rd is safe because
// if they are modified, function returns immediately.
@@ -2242,8 +2259,7 @@ rb_w32_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
break;
}
else {
- struct timeval *dowait =
- compare(&rest, &wait) < 0 ? &rest : &wait;
+ struct timeval *dowait = &wait;
fd_set orig_rd;
fd_set orig_wr;
@@ -2257,10 +2273,16 @@ rb_w32_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
if (wr) *wr = orig_wr;
if (ex) *ex = orig_ex;
- // XXX: should check the time select spent
+ if (timeout) {
+ struct timeval now;
+ gettimeofday(&now, NULL);
+ rest = limit;
+ if (!subtract(&rest, &now)) break;
+ if (compare(&rest, &wait) < 0) dowait = &rest;
+ }
Sleep(dowait->tv_sec * 1000 + dowait->tv_usec / 1000);
}
- } while (!timeout || subst(&rest, &wait));
+ }
}
return r;