Project

General

Profile

Misc #14431 ยป 0001-thread.c-remove-FP-from-time-calculations.patch

normalperson (Eric Wong), 02/02/2018 05:26 AM

View differences:

thread.c
static void sleep_timeval(rb_thread_t *th, struct timeval time, int spurious_check);
static void sleep_forever(rb_thread_t *th, int nodeadlock, int spurious_check);
static void rb_thread_sleep_deadly_allow_spurious_wakeup(void);
static double timeofday(void);
static int rb_threadptr_dead(rb_thread_t *th);
static void rb_check_deadlock(rb_vm_t *vm);
static int rb_threadptr_pending_interrupt_empty_p(const rb_thread_t *th);
static const char *thread_status_name(rb_thread_t *th, int detail);
static void timeval_add(struct timeval *, const struct timeval *);
static void timeval_sub(struct timeval *, const struct timeval *);
static int timeval_update_expire(struct timeval *, const struct timeval *);
static void getclockofday(struct timeval *);
#define eKillSignal INT2FIX(0)
#define eTerminateSignal INT2FIX(1)
......
return vm->living_thread_num;
}
static inline struct timespec *
timespec_for(struct timespec *ts, const struct timeval *tv)
{
if (tv) {
ts->tv_sec = tv->tv_sec;
ts->tv_nsec = tv->tv_usec * 1000;
return ts;
}
return 0;
}
#if THREAD_DEBUG
#ifdef HAVE_VA_ARGS_MACRO
void rb_thread_debug(const char *file, int line, const char *fmt, ...);
......
}
}
static struct timeval double2timeval(double d);
void
rb_thread_terminate_all(void)
{
......
terminate_all(vm, th);
while (vm_living_thread_num(vm) > 1) {
struct timeval tv = double2timeval(1.0);
struct timeval tv = { 1, 0 };
/*
* Thread exiting routine in thread_start_func_2 notify
* me when the last sub-thread exit.
......
}
/* +infty, for this purpose */
#define DELAY_INFTY 1E30
struct join_arg {
rb_thread_t *target, *waiting;
double delay;
struct timeval *limit;
};
static VALUE
......
{
struct join_arg *p = (struct join_arg *)arg;
rb_thread_t *target_th = p->target, *th = p->waiting;
const int forever = p->delay == DELAY_INFTY;
const double limit = forever ? 0 : timeofday() + p->delay;
struct timeval to;
if (p->limit) {
getclockofday(&to);
timeval_add(&to, p->limit);
}
while (target_th->status != THREAD_KILLED) {
if (forever) {
if (!p->limit) {
th->status = THREAD_STOPPED_FOREVER;
th->vm->sleeper++;
rb_check_deadlock(th->vm);
......
th->vm->sleeper--;
}
else {
double now = timeofday();
struct timeval tv;
if (now > limit) {
if (timeval_update_expire(p->limit, &to)) {
thread_debug("thread_join: timeout (thid: %"PRI_THREAD_ID")\n",
thread_id_str(target_th));
return Qfalse;
}
tv = double2timeval(limit - now);
th->status = THREAD_STOPPED;
native_sleep(th, &tv);
native_sleep(th, p->limit);
}
RUBY_VM_CHECK_INTS_BLOCKING(th->ec);
th->status = THREAD_RUNNABLE;
......
}
static VALUE
thread_join(rb_thread_t *target_th, double delay)
thread_join(rb_thread_t *target_th, struct timeval *tv)
{
rb_thread_t *th = GET_THREAD();
struct join_arg arg;
......
arg.target = target_th;
arg.waiting = th;
arg.delay = delay;
arg.limit = tv;
thread_debug("thread_join (thid: %"PRI_THREAD_ID", status: %s)\n",
thread_id_str(target_th), thread_status_name(target_th, TRUE));
......
return target_th->self;
}
static struct timeval double2timeval(double);
/*
* call-seq:
* thr.join -> thr
......
static VALUE
thread_join_m(int argc, VALUE *argv, VALUE self)
{
double delay = DELAY_INFTY;
VALUE limit;
struct timeval timeval;
struct timeval *tv = 0;
rb_scan_args(argc, argv, "01", &limit);
if (!NIL_P(limit)) {
delay = rb_num2dbl(limit);
/*
* This supports INFINITY and negative values, so we can't use
* rb_time_interval right now...
*/
switch (TYPE(limit)) {
case T_NIL: break;
case T_FIXNUM:
case T_BIGNUM:
timeval.tv_sec = NUM2TIMET(limit);
timeval.tv_usec = 0;
tv = &timeval;
break;
default:
timeval = double2timeval(rb_num2dbl(limit));
tv = &timeval;
}
return thread_join(rb_thread_ptr(self), delay);
return thread_join(rb_thread_ptr(self), tv);
}
/*
......
thread_value(VALUE self)
{
rb_thread_t *th = rb_thread_ptr(self);
thread_join(th, DELAY_INFTY);
thread_join(th, 0);
return th->value;
}
......
}
}
static void
timeval_sub(struct timeval *dst, const struct timeval *tv)
{
dst->tv_sec -= tv->tv_sec;
if ((dst->tv_usec -= tv->tv_usec) < 0) {
--dst->tv_sec;
dst->tv_usec += 1000000;
}
}
static int
timeval_update_expire(struct timeval *tv, const struct timeval *to)
{
......
"%"PRI_TIMET_PREFIX"d.%.6ld > %"PRI_TIMET_PREFIX"d.%.6ld\n",
(time_t)to->tv_sec, (long)to->tv_usec,
(time_t)tvn.tv_sec, (long)tvn.tv_usec);
tv->tv_sec = to->tv_sec - tvn.tv_sec;
if ((tv->tv_usec = to->tv_usec - tvn.tv_usec) < 0) {
--tv->tv_sec;
tv->tv_usec += 1000000;
}
*tv = *to;
timeval_sub(tv, &tvn);
return 0;
}
......
sleep_forever(GET_THREAD(), TRUE, FALSE);
}
static double
timeofday(void)
{
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
struct timespec tp;
if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) {
return (double)tp.tv_sec + (double)tp.tv_nsec * 1e-9;
}
else
#endif
{
struct timeval tv;
gettimeofday(&tv, NULL);
return (double)tv.tv_sec + (double)tv.tv_usec * 1e-6;
}
}
void
rb_thread_wait_for(struct timeval time)
{
......
#define restore_fdset(fds1, fds2) \
((fds1) ? rb_fd_dup(fds1, fds2) : (void)0)
static inline void
update_timeval(struct timeval *timeout, double limit)
static inline int
update_timeval(struct timeval *timeout, const struct timeval *to)
{
if (timeout) {
double d = limit - timeofday();
struct timeval tvn;
timeout->tv_sec = (time_t)d;
timeout->tv_usec = (int)((d-(double)timeout->tv_sec)*1e6);
if (timeout->tv_sec < 0) timeout->tv_sec = 0;
if (timeout->tv_usec < 0) timeout->tv_usec = 0;
getclockofday(&tvn);
*timeout = *to;
timeval_sub(timeout, &tvn);
if (timeout->tv_sec < 0) timeout->tv_sec = 0;
if (timeout->tv_usec < 0) timeout->tv_usec = 0;
}
return TRUE;
}
static int
......
rb_fdset_t MAYBE_UNUSED(orig_read);
rb_fdset_t MAYBE_UNUSED(orig_write);
rb_fdset_t MAYBE_UNUSED(orig_except);
double limit = 0;
struct timeval wait_rest;
struct timeval to;
rb_thread_t *th = GET_THREAD();
#define do_select_update() \
(restore_fdset(readfds, &orig_read), \
restore_fdset(writefds, &orig_write), \
restore_fdset(exceptfds, &orig_except), \
update_timeval(timeout, limit), \
TRUE)
update_timeval(timeout, &to))
if (timeout) {
limit = timeofday();
limit += (double)timeout->tv_sec+(double)timeout->tv_usec*1e-6;
wait_rest = *timeout;
timeout = &wait_rest;
getclockofday(&to);
timeval_add(&to, timeout);
}
#define fd_init_copy(f) \
......
}
#endif
static inline void
update_timespec(struct timespec *timeout, double limit)
{
if (timeout) {
double d = limit - timeofday();
timeout->tv_sec = (long)d;
timeout->tv_nsec = (long)((d-(double)timeout->tv_sec)*1e9);
if (timeout->tv_sec < 0) timeout->tv_sec = 0;
if (timeout->tv_nsec < 0) timeout->tv_nsec = 0;
}
}
/*
* returns a mask of events
*/
int
rb_wait_for_single_fd(int fd, int events, struct timeval *tv)
rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
{
struct pollfd fds;
int result = 0, lerrno;
double limit = 0;
struct timespec ts;
struct timespec *timeout = NULL;
struct timeval to;
rb_thread_t *th = GET_THREAD();
#define poll_update() \
(update_timespec(timeout, limit), \
TRUE)
if (tv) {
ts.tv_sec = tv->tv_sec;
ts.tv_nsec = tv->tv_usec * 1000;
limit = timeofday();
limit += (double)tv->tv_sec + (double)tv->tv_usec * 1e-6;
timeout = &ts;
if (timeout) {
getclockofday(&to);
timeval_add(&to, timeout);
}
fds.fd = fd;
fds.events = (short)events;
do {
fds.revents = 0;
lerrno = 0;
BLOCKING_REGION({
result = ppoll(&fds, 1, timeout, NULL);
if (result < 0) lerrno = errno;
}, ubf_select, th, FALSE);
RUBY_VM_CHECK_INTS_BLOCKING(th->ec);
} while (result < 0 && retryable(errno = lerrno) && poll_update());
fds.revents = 0;
lerrno = 0;
BLOCKING_REGION({
result = ppoll(&fds, 1, timespec_for(&ts, timeout), NULL);
if (result < 0) lerrno = errno;
}, ubf_select, th, FALSE);
RUBY_VM_CHECK_INTS_BLOCKING(th->ec);
} while (result < 0 && retryable(errno = lerrno) &&
update_timeval(timeout, &to));
if (result < 0) return -1;
if (fds.revents & POLLNVAL) {
-
    (1-1/1)