Skip to content

Commit c0e2f98

Browse files
author
normal
committed
thread.c: avoid FP in C-API time calculations
FP arithmetic can lose precision in some cases leading to premature wakeup and wasting CPU cycles. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62183 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
1 parent c915390 commit c0e2f98

File tree

1 file changed

+40
-69
lines changed

1 file changed

+40
-69
lines changed

thread.c

Lines changed: 40 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@ static ID id_locals;
9494
static void sleep_timeval(rb_thread_t *th, struct timeval time, int spurious_check);
9595
static void sleep_forever(rb_thread_t *th, int nodeadlock, int spurious_check);
9696
static void rb_thread_sleep_deadly_allow_spurious_wakeup(void);
97-
static double timeofday(void);
9897
static int rb_threadptr_dead(rb_thread_t *th);
9998
static void rb_check_deadlock(rb_vm_t *vm);
10099
static int rb_threadptr_pending_interrupt_empty_p(const rb_thread_t *th);
@@ -201,6 +200,17 @@ vm_living_thread_num(rb_vm_t *vm)
201200
return vm->living_thread_num;
202201
}
203202

203+
static inline struct timespec *
204+
timespec_for(struct timespec *ts, const struct timeval *tv)
205+
{
206+
if (tv) {
207+
ts->tv_sec = tv->tv_sec;
208+
ts->tv_nsec = tv->tv_usec * 1000;
209+
return ts;
210+
}
211+
return 0;
212+
}
213+
204214
#if THREAD_DEBUG
205215
#ifdef HAVE_VA_ARGS_MACRO
206216
void rb_thread_debug(const char *file, int line, const char *fmt, ...);
@@ -1245,24 +1255,6 @@ rb_thread_sleep_deadly_allow_spurious_wakeup(void)
12451255
sleep_forever(GET_THREAD(), TRUE, FALSE);
12461256
}
12471257

1248-
static double
1249-
timeofday(void)
1250-
{
1251-
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
1252-
struct timespec tp;
1253-
1254-
if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) {
1255-
return (double)tp.tv_sec + (double)tp.tv_nsec * 1e-9;
1256-
}
1257-
else
1258-
#endif
1259-
{
1260-
struct timeval tv;
1261-
gettimeofday(&tv, NULL);
1262-
return (double)tv.tv_sec + (double)tv.tv_usec * 1e-6;
1263-
}
1264-
}
1265-
12661258
void
12671259
rb_thread_wait_for(struct timeval time)
12681260
{
@@ -3763,17 +3755,20 @@ retryable(int e)
37633755
#define restore_fdset(fds1, fds2) \
37643756
((fds1) ? rb_fd_dup(fds1, fds2) : (void)0)
37653757

3766-
static inline void
3767-
update_timeval(struct timeval *timeout, double limit)
3758+
static inline int
3759+
update_timeval(struct timeval *timeout, const struct timeval *to)
37683760
{
37693761
if (timeout) {
3770-
double d = limit - timeofday();
3762+
struct timeval tvn;
3763+
3764+
getclockofday(&tvn);
3765+
*timeout = *to;
3766+
timeval_sub(timeout, &tvn);
37713767

3772-
timeout->tv_sec = (time_t)d;
3773-
timeout->tv_usec = (int)((d-(double)timeout->tv_sec)*1e6);
3774-
if (timeout->tv_sec < 0) timeout->tv_sec = 0;
3775-
if (timeout->tv_usec < 0) timeout->tv_usec = 0;
3768+
if (timeout->tv_sec < 0) timeout->tv_sec = 0;
3769+
if (timeout->tv_usec < 0) timeout->tv_usec = 0;
37763770
}
3771+
return TRUE;
37773772
}
37783773

37793774
static int
@@ -3785,22 +3780,18 @@ do_select(int n, rb_fdset_t *const readfds, rb_fdset_t *const writefds,
37853780
rb_fdset_t MAYBE_UNUSED(orig_read);
37863781
rb_fdset_t MAYBE_UNUSED(orig_write);
37873782
rb_fdset_t MAYBE_UNUSED(orig_except);
3788-
double limit = 0;
3789-
struct timeval wait_rest;
3783+
struct timeval to;
37903784
rb_thread_t *th = GET_THREAD();
37913785

37923786
#define do_select_update() \
37933787
(restore_fdset(readfds, &orig_read), \
37943788
restore_fdset(writefds, &orig_write), \
37953789
restore_fdset(exceptfds, &orig_except), \
3796-
update_timeval(timeout, limit), \
3797-
TRUE)
3790+
update_timeval(timeout, &to))
37983791

37993792
if (timeout) {
3800-
limit = timeofday();
3801-
limit += (double)timeout->tv_sec+(double)timeout->tv_usec*1e-6;
3802-
wait_rest = *timeout;
3803-
timeout = &wait_rest;
3793+
getclockofday(&to);
3794+
timeval_add(&to, timeout);
38043795
}
38053796

38063797
#define fd_init_copy(f) \
@@ -3934,57 +3925,37 @@ ppoll(struct pollfd *fds, nfds_t nfds,
39343925
}
39353926
#endif
39363927

3937-
static inline void
3938-
update_timespec(struct timespec *timeout, double limit)
3939-
{
3940-
if (timeout) {
3941-
double d = limit - timeofday();
3942-
3943-
timeout->tv_sec = (long)d;
3944-
timeout->tv_nsec = (long)((d-(double)timeout->tv_sec)*1e9);
3945-
if (timeout->tv_sec < 0) timeout->tv_sec = 0;
3946-
if (timeout->tv_nsec < 0) timeout->tv_nsec = 0;
3947-
}
3948-
}
3949-
39503928
/*
39513929
* returns a mask of events
39523930
*/
39533931
int
3954-
rb_wait_for_single_fd(int fd, int events, struct timeval *tv)
3932+
rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
39553933
{
39563934
struct pollfd fds;
39573935
int result = 0, lerrno;
3958-
double limit = 0;
39593936
struct timespec ts;
3960-
struct timespec *timeout = NULL;
3937+
struct timeval to;
39613938
rb_thread_t *th = GET_THREAD();
39623939

3963-
#define poll_update() \
3964-
(update_timespec(timeout, limit), \
3965-
TRUE)
3966-
3967-
if (tv) {
3968-
ts.tv_sec = tv->tv_sec;
3969-
ts.tv_nsec = tv->tv_usec * 1000;
3970-
limit = timeofday();
3971-
limit += (double)tv->tv_sec + (double)tv->tv_usec * 1e-6;
3972-
timeout = &ts;
3940+
if (timeout) {
3941+
getclockofday(&to);
3942+
timeval_add(&to, timeout);
39733943
}
39743944

39753945
fds.fd = fd;
39763946
fds.events = (short)events;
39773947

39783948
do {
3979-
fds.revents = 0;
3980-
lerrno = 0;
3981-
BLOCKING_REGION({
3982-
result = ppoll(&fds, 1, timeout, NULL);
3983-
if (result < 0) lerrno = errno;
3984-
}, ubf_select, th, FALSE);
3985-
3986-
RUBY_VM_CHECK_INTS_BLOCKING(th->ec);
3987-
} while (result < 0 && retryable(errno = lerrno) && poll_update());
3949+
fds.revents = 0;
3950+
lerrno = 0;
3951+
BLOCKING_REGION({
3952+
result = ppoll(&fds, 1, timespec_for(&ts, timeout), NULL);
3953+
if (result < 0) lerrno = errno;
3954+
}, ubf_select, th, FALSE);
3955+
3956+
RUBY_VM_CHECK_INTS_BLOCKING(th->ec);
3957+
} while (result < 0 && retryable(errno = lerrno) &&
3958+
update_timeval(timeout, &to));
39883959
if (result < 0) return -1;
39893960

39903961
if (fds.revents & POLLNVAL) {

0 commit comments

Comments
 (0)