thread.c: favor timespec internally
This results in fewer conversion on common modern systems with support for clock_gettime, pthread_cond_timedwait and ppoll. gettimeofday is declared obsolete by POSIX.1-2008, so it is yet another reason to move away from it. This also appears to result in the reduction of compatibility code required for dealing with inconsistent implementations of "struct timeval".tv_sec In the future, this will also result in fewer conversions for kqueue and pselect if we elect to use them. [ruby-core:85416] [Feature #14452] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62272 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
b16eaf8632
commit
0abd9b7f25
215
thread.c
215
thread.c
@ -91,17 +91,17 @@ static VALUE sym_on_blocking;
|
|||||||
static VALUE sym_never;
|
static VALUE sym_never;
|
||||||
static ID id_locals;
|
static ID id_locals;
|
||||||
|
|
||||||
static void sleep_timeval(rb_thread_t *th, struct timeval time, int spurious_check);
|
static void sleep_timespec(rb_thread_t *, struct timespec, int spurious_check);
|
||||||
static void sleep_forever(rb_thread_t *th, int nodeadlock, 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 void rb_thread_sleep_deadly_allow_spurious_wakeup(void);
|
||||||
static int rb_threadptr_dead(rb_thread_t *th);
|
static int rb_threadptr_dead(rb_thread_t *th);
|
||||||
static void rb_check_deadlock(rb_vm_t *vm);
|
static void rb_check_deadlock(rb_vm_t *vm);
|
||||||
static int rb_threadptr_pending_interrupt_empty_p(const rb_thread_t *th);
|
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 const char *thread_status_name(rb_thread_t *th, int detail);
|
||||||
static void timeval_add(struct timeval *, const struct timeval *);
|
static void timespec_add(struct timespec *, const struct timespec *);
|
||||||
static void timeval_sub(struct timeval *, const struct timeval *);
|
static void timespec_sub(struct timespec *, const struct timespec *);
|
||||||
static int timeval_update_expire(struct timeval *, const struct timeval *);
|
static int timespec_update_expire(struct timespec *, const struct timespec *);
|
||||||
static void getclockofday(struct timeval *);
|
static void getclockofday(struct timespec *);
|
||||||
|
|
||||||
#define eKillSignal INT2FIX(0)
|
#define eKillSignal INT2FIX(0)
|
||||||
#define eTerminateSignal INT2FIX(1)
|
#define eTerminateSignal INT2FIX(1)
|
||||||
@ -209,8 +209,7 @@ vm_living_thread_num(rb_vm_t *vm)
|
|||||||
# define USE_POLL
|
# define USE_POLL
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_POLL
|
static struct timespec *
|
||||||
static inline struct timespec *
|
|
||||||
timespec_for(struct timespec *ts, const struct timeval *tv)
|
timespec_for(struct timespec *ts, const struct timeval *tv)
|
||||||
{
|
{
|
||||||
if (tv) {
|
if (tv) {
|
||||||
@ -220,7 +219,17 @@ timespec_for(struct timespec *ts, const struct timeval *tv)
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
static struct timeval *
|
||||||
|
timeval_for(struct timeval *tv, const struct timespec *ts)
|
||||||
|
{
|
||||||
|
if (tv && ts) {
|
||||||
|
tv->tv_sec = ts->tv_sec;
|
||||||
|
tv->tv_usec = ts->tv_nsec / 1000;
|
||||||
|
return tv;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#if THREAD_DEBUG
|
#if THREAD_DEBUG
|
||||||
#ifdef HAVE_VA_ARGS_MACRO
|
#ifdef HAVE_VA_ARGS_MACRO
|
||||||
@ -529,13 +538,13 @@ rb_thread_terminate_all(void)
|
|||||||
terminate_all(vm, th);
|
terminate_all(vm, th);
|
||||||
|
|
||||||
while (vm_living_thread_num(vm) > 1) {
|
while (vm_living_thread_num(vm) > 1) {
|
||||||
struct timeval tv = { 1, 0 };
|
struct timespec ts = { 1, 0 };
|
||||||
/*
|
/*
|
||||||
* Thread exiting routine in thread_start_func_2 notify
|
* Thread exiting routine in thread_start_func_2 notify
|
||||||
* me when the last sub-thread exit.
|
* me when the last sub-thread exit.
|
||||||
*/
|
*/
|
||||||
sleeping = 1;
|
sleeping = 1;
|
||||||
native_sleep(th, &tv);
|
native_sleep(th, &ts);
|
||||||
RUBY_VM_CHECK_INTS_BLOCKING(ec);
|
RUBY_VM_CHECK_INTS_BLOCKING(ec);
|
||||||
sleeping = 0;
|
sleeping = 0;
|
||||||
}
|
}
|
||||||
@ -873,7 +882,7 @@ rb_thread_create(VALUE (*fn)(ANYARGS), void *arg)
|
|||||||
|
|
||||||
struct join_arg {
|
struct join_arg {
|
||||||
rb_thread_t *target, *waiting;
|
rb_thread_t *target, *waiting;
|
||||||
struct timeval *limit;
|
struct timespec *limit;
|
||||||
};
|
};
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
@ -902,11 +911,11 @@ thread_join_sleep(VALUE arg)
|
|||||||
{
|
{
|
||||||
struct join_arg *p = (struct join_arg *)arg;
|
struct join_arg *p = (struct join_arg *)arg;
|
||||||
rb_thread_t *target_th = p->target, *th = p->waiting;
|
rb_thread_t *target_th = p->target, *th = p->waiting;
|
||||||
struct timeval to;
|
struct timespec to;
|
||||||
|
|
||||||
if (p->limit) {
|
if (p->limit) {
|
||||||
getclockofday(&to);
|
getclockofday(&to);
|
||||||
timeval_add(&to, p->limit);
|
timespec_add(&to, p->limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (target_th->status != THREAD_KILLED) {
|
while (target_th->status != THREAD_KILLED) {
|
||||||
@ -918,7 +927,7 @@ thread_join_sleep(VALUE arg)
|
|||||||
th->vm->sleeper--;
|
th->vm->sleeper--;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (timeval_update_expire(p->limit, &to)) {
|
if (timespec_update_expire(p->limit, &to)) {
|
||||||
thread_debug("thread_join: timeout (thid: %"PRI_THREAD_ID")\n",
|
thread_debug("thread_join: timeout (thid: %"PRI_THREAD_ID")\n",
|
||||||
thread_id_str(target_th));
|
thread_id_str(target_th));
|
||||||
return Qfalse;
|
return Qfalse;
|
||||||
@ -935,7 +944,7 @@ thread_join_sleep(VALUE arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
thread_join(rb_thread_t *target_th, struct timeval *tv)
|
thread_join(rb_thread_t *target_th, struct timespec *ts)
|
||||||
{
|
{
|
||||||
rb_thread_t *th = GET_THREAD();
|
rb_thread_t *th = GET_THREAD();
|
||||||
struct join_arg arg;
|
struct join_arg arg;
|
||||||
@ -949,7 +958,7 @@ thread_join(rb_thread_t *target_th, struct timeval *tv)
|
|||||||
|
|
||||||
arg.target = target_th;
|
arg.target = target_th;
|
||||||
arg.waiting = th;
|
arg.waiting = th;
|
||||||
arg.limit = tv;
|
arg.limit = ts;
|
||||||
|
|
||||||
thread_debug("thread_join (thid: %"PRI_THREAD_ID", status: %s)\n",
|
thread_debug("thread_join (thid: %"PRI_THREAD_ID", status: %s)\n",
|
||||||
thread_id_str(target_th), thread_status_name(target_th, TRUE));
|
thread_id_str(target_th), thread_status_name(target_th, TRUE));
|
||||||
@ -994,7 +1003,7 @@ thread_join(rb_thread_t *target_th, struct timeval *tv)
|
|||||||
return target_th->self;
|
return target_th->self;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct timeval double2timeval(double);
|
static struct timespec double2timespec(double);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* call-seq:
|
||||||
@ -1039,8 +1048,8 @@ static VALUE
|
|||||||
thread_join_m(int argc, VALUE *argv, VALUE self)
|
thread_join_m(int argc, VALUE *argv, VALUE self)
|
||||||
{
|
{
|
||||||
VALUE limit;
|
VALUE limit;
|
||||||
struct timeval timeval;
|
struct timespec timespec;
|
||||||
struct timeval *tv = 0;
|
struct timespec *ts = 0;
|
||||||
|
|
||||||
rb_scan_args(argc, argv, "01", &limit);
|
rb_scan_args(argc, argv, "01", &limit);
|
||||||
|
|
||||||
@ -1051,16 +1060,16 @@ thread_join_m(int argc, VALUE *argv, VALUE self)
|
|||||||
switch (TYPE(limit)) {
|
switch (TYPE(limit)) {
|
||||||
case T_NIL: break;
|
case T_NIL: break;
|
||||||
case T_FIXNUM:
|
case T_FIXNUM:
|
||||||
timeval.tv_sec = NUM2TIMET(limit);
|
timespec.tv_sec = NUM2TIMET(limit);
|
||||||
timeval.tv_usec = 0;
|
timespec.tv_nsec = 0;
|
||||||
tv = &timeval;
|
ts = ×pec;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
timeval = double2timeval(rb_num2dbl(limit));
|
timespec = double2timespec(rb_num2dbl(limit));
|
||||||
tv = &timeval;
|
ts = ×pec;
|
||||||
}
|
}
|
||||||
|
|
||||||
return thread_join(rb_thread_ptr(self), tv);
|
return thread_join(rb_thread_ptr(self), ts);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1090,47 +1099,36 @@ thread_value(VALUE self)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The type of tv_sec in struct timeval is time_t in POSIX.
|
* Back when we used "struct timeval", not all platforms implemented
|
||||||
* But several systems violate POSIX.
|
* tv_sec as time_t. Nowadays we use "struct timespec" and tv_sec
|
||||||
*
|
* seems to be implemented more consistently across platforms.
|
||||||
* OpenBSD 5.2 (amd64):
|
* At least other parts of our code hasn't had to deal with non-time_t
|
||||||
* time_t: int (signed 32bit integer)
|
* tv_sec in timespec...
|
||||||
* tv_sec: long (signed 64bit integer)
|
|
||||||
*
|
|
||||||
* MinGW-w64 (x64):
|
|
||||||
* time_t: long long (signed 64bit integer)
|
|
||||||
* tv_sec: long (signed 32bit integer)
|
|
||||||
*/
|
*/
|
||||||
|
#define TIMESPEC_SEC_MAX TIMET_MAX
|
||||||
|
#define TIMESPEC_SEC_MIN TIMET_MIN
|
||||||
|
|
||||||
#if SIGNEDNESS_OF_TIME_T < 0 /* signed */
|
static struct timespec
|
||||||
# define TIMEVAL_SEC_MAX SIGNED_INTEGER_MAX(TYPEOF_TIMEVAL_TV_SEC)
|
double2timespec(double d)
|
||||||
# define TIMEVAL_SEC_MIN SIGNED_INTEGER_MIN(TYPEOF_TIMEVAL_TV_SEC)
|
|
||||||
#elif SIGNEDNESS_OF_TIME_T > 0 /* unsigned */
|
|
||||||
# define TIMEVAL_SEC_MAX ((TYPEOF_TIMEVAL_TV_SEC)(~(unsigned_time_t)0))
|
|
||||||
# define TIMEVAL_SEC_MIN ((TYPEOF_TIMEVAL_TV_SEC)0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static struct timeval
|
|
||||||
double2timeval(double d)
|
|
||||||
{
|
{
|
||||||
/* assume timeval.tv_sec has same signedness as time_t */
|
/* assume timespec.tv_sec has same signedness as time_t */
|
||||||
const double TIMEVAL_SEC_MAX_PLUS_ONE = (2*(double)(TIMEVAL_SEC_MAX/2+1));
|
const double TIMESPEC_SEC_MAX_PLUS_ONE = TIMET_MAX_PLUS_ONE;
|
||||||
|
|
||||||
struct timeval time;
|
struct timespec time;
|
||||||
|
|
||||||
if (TIMEVAL_SEC_MAX_PLUS_ONE <= d) {
|
if (TIMESPEC_SEC_MAX_PLUS_ONE <= d) {
|
||||||
time.tv_sec = TIMEVAL_SEC_MAX;
|
time.tv_sec = TIMESPEC_SEC_MAX;
|
||||||
time.tv_usec = 999999;
|
time.tv_nsec = 999999999;
|
||||||
}
|
}
|
||||||
else if (d <= TIMEVAL_SEC_MIN) {
|
else if (d <= TIMESPEC_SEC_MIN) {
|
||||||
time.tv_sec = TIMEVAL_SEC_MIN;
|
time.tv_sec = TIMESPEC_SEC_MIN;
|
||||||
time.tv_usec = 0;
|
time.tv_nsec = 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
time.tv_sec = (TYPEOF_TIMEVAL_TV_SEC)d;
|
time.tv_sec = (time_t)d;
|
||||||
time.tv_usec = (int)((d - (time_t)d) * 1e6);
|
time.tv_nsec = (long)((d - (time_t)d) * 1e9);
|
||||||
if (time.tv_usec < 0) {
|
if (time.tv_nsec < 0) {
|
||||||
time.tv_usec += (int)1e6;
|
time.tv_nsec += (long)1e9;
|
||||||
time.tv_sec -= 1;
|
time.tv_sec -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1162,81 +1160,74 @@ sleep_forever(rb_thread_t *th, int deadlockable, int spurious_check)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
getclockofday(struct timeval *tp)
|
getclockofday(struct timespec *ts)
|
||||||
{
|
{
|
||||||
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
|
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
|
||||||
struct timespec ts;
|
if (clock_gettime(CLOCK_MONOTONIC, ts) == 0)
|
||||||
|
return;
|
||||||
if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
|
|
||||||
tp->tv_sec = ts.tv_sec;
|
|
||||||
tp->tv_usec = (int)(ts.tv_nsec / 1000);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
#endif
|
||||||
{
|
rb_timespec_now(ts);
|
||||||
gettimeofday(tp, NULL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
timeval_add(struct timeval *dst, const struct timeval *tv)
|
timespec_add(struct timespec *dst, const struct timespec *ts)
|
||||||
{
|
{
|
||||||
if (TIMEVAL_SEC_MAX - tv->tv_sec < dst->tv_sec)
|
if (TIMESPEC_SEC_MAX - ts->tv_sec < dst->tv_sec)
|
||||||
dst->tv_sec = TIMEVAL_SEC_MAX;
|
dst->tv_sec = TIMESPEC_SEC_MAX;
|
||||||
else
|
else
|
||||||
dst->tv_sec += tv->tv_sec;
|
dst->tv_sec += ts->tv_sec;
|
||||||
if ((dst->tv_usec += tv->tv_usec) >= 1000000) {
|
if ((dst->tv_nsec += ts->tv_nsec) >= 1000000000) {
|
||||||
if (dst->tv_sec == TIMEVAL_SEC_MAX) {
|
if (dst->tv_sec == TIMESPEC_SEC_MAX) {
|
||||||
dst->tv_usec = 999999;
|
dst->tv_nsec = 999999999;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
dst->tv_sec++;
|
dst->tv_sec++;
|
||||||
dst->tv_usec -= 1000000;
|
dst->tv_nsec -= 1000000000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
timeval_sub(struct timeval *dst, const struct timeval *tv)
|
timespec_sub(struct timespec *dst, const struct timespec *tv)
|
||||||
{
|
{
|
||||||
dst->tv_sec -= tv->tv_sec;
|
dst->tv_sec -= tv->tv_sec;
|
||||||
if ((dst->tv_usec -= tv->tv_usec) < 0) {
|
if ((dst->tv_nsec -= tv->tv_nsec) < 0) {
|
||||||
--dst->tv_sec;
|
--dst->tv_sec;
|
||||||
dst->tv_usec += 1000000;
|
dst->tv_nsec += 1000000000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
timeval_update_expire(struct timeval *tv, const struct timeval *to)
|
timespec_update_expire(struct timespec *ts, const struct timespec *to)
|
||||||
{
|
{
|
||||||
struct timeval tvn;
|
struct timespec now;
|
||||||
|
|
||||||
getclockofday(&tvn);
|
getclockofday(&now);
|
||||||
if (to->tv_sec < tvn.tv_sec) return 1;
|
if (to->tv_sec < now.tv_sec) return 1;
|
||||||
if (to->tv_sec == tvn.tv_sec && to->tv_usec <= tvn.tv_usec) return 1;
|
if (to->tv_sec == now.tv_sec && to->tv_nsec <= now.tv_nsec) return 1;
|
||||||
thread_debug("timeval_update_expire: "
|
thread_debug("timespec_update_expire: "
|
||||||
"%"PRI_TIMET_PREFIX"d.%.6ld > %"PRI_TIMET_PREFIX"d.%.6ld\n",
|
"%"PRI_TIMET_PREFIX"d.%.6ld > %"PRI_TIMET_PREFIX"d.%.6ld\n",
|
||||||
(time_t)to->tv_sec, (long)to->tv_usec,
|
(time_t)to->tv_sec, (long)to->tv_nsec,
|
||||||
(time_t)tvn.tv_sec, (long)tvn.tv_usec);
|
(time_t)now.tv_sec, (long)now.tv_nsec);
|
||||||
*tv = *to;
|
*ts = *to;
|
||||||
timeval_sub(tv, &tvn);
|
timespec_sub(ts, &now);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
sleep_timeval(rb_thread_t *th, struct timeval tv, int spurious_check)
|
sleep_timespec(rb_thread_t *th, struct timespec ts, int spurious_check)
|
||||||
{
|
{
|
||||||
struct timeval to;
|
struct timespec to;
|
||||||
enum rb_thread_status prev_status = th->status;
|
enum rb_thread_status prev_status = th->status;
|
||||||
|
|
||||||
getclockofday(&to);
|
getclockofday(&to);
|
||||||
timeval_add(&to, &tv);
|
timespec_add(&to, &ts);
|
||||||
th->status = THREAD_STOPPED;
|
th->status = THREAD_STOPPED;
|
||||||
RUBY_VM_CHECK_INTS_BLOCKING(th->ec);
|
RUBY_VM_CHECK_INTS_BLOCKING(th->ec);
|
||||||
while (th->status == THREAD_STOPPED) {
|
while (th->status == THREAD_STOPPED) {
|
||||||
native_sleep(th, &tv);
|
native_sleep(th, &ts);
|
||||||
RUBY_VM_CHECK_INTS_BLOCKING(th->ec);
|
RUBY_VM_CHECK_INTS_BLOCKING(th->ec);
|
||||||
if (timeval_update_expire(&tv, &to))
|
if (timespec_update_expire(&ts, &to))
|
||||||
break;
|
break;
|
||||||
if (!spurious_check)
|
if (!spurious_check)
|
||||||
break;
|
break;
|
||||||
@ -1269,7 +1260,10 @@ void
|
|||||||
rb_thread_wait_for(struct timeval time)
|
rb_thread_wait_for(struct timeval time)
|
||||||
{
|
{
|
||||||
rb_thread_t *th = GET_THREAD();
|
rb_thread_t *th = GET_THREAD();
|
||||||
sleep_timeval(th, time, 1);
|
struct timespec ts;
|
||||||
|
|
||||||
|
timespec_for(&ts, &time);
|
||||||
|
sleep_timespec(th, ts, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3766,17 +3760,17 @@ retryable(int e)
|
|||||||
((fds1) ? rb_fd_dup(fds1, fds2) : (void)0)
|
((fds1) ? rb_fd_dup(fds1, fds2) : (void)0)
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
update_timeval(struct timeval *timeout, const struct timeval *to)
|
update_timespec(struct timespec *timeout, const struct timespec *to)
|
||||||
{
|
{
|
||||||
if (timeout) {
|
if (timeout) {
|
||||||
struct timeval tvn;
|
struct timespec now;
|
||||||
|
|
||||||
getclockofday(&tvn);
|
getclockofday(&now);
|
||||||
*timeout = *to;
|
*timeout = *to;
|
||||||
timeval_sub(timeout, &tvn);
|
timespec_sub(timeout, &now);
|
||||||
|
|
||||||
if (timeout->tv_sec < 0) timeout->tv_sec = 0;
|
if (timeout->tv_sec < 0) timeout->tv_sec = 0;
|
||||||
if (timeout->tv_usec < 0) timeout->tv_usec = 0;
|
if (timeout->tv_nsec < 0) timeout->tv_nsec = 0;
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@ -3790,18 +3784,19 @@ do_select(int n, rb_fdset_t *const readfds, rb_fdset_t *const writefds,
|
|||||||
rb_fdset_t MAYBE_UNUSED(orig_read);
|
rb_fdset_t MAYBE_UNUSED(orig_read);
|
||||||
rb_fdset_t MAYBE_UNUSED(orig_write);
|
rb_fdset_t MAYBE_UNUSED(orig_write);
|
||||||
rb_fdset_t MAYBE_UNUSED(orig_except);
|
rb_fdset_t MAYBE_UNUSED(orig_except);
|
||||||
struct timeval to;
|
struct timespec to;
|
||||||
|
struct timespec ts;
|
||||||
rb_thread_t *th = GET_THREAD();
|
rb_thread_t *th = GET_THREAD();
|
||||||
|
|
||||||
#define do_select_update() \
|
#define do_select_update() \
|
||||||
(restore_fdset(readfds, &orig_read), \
|
(restore_fdset(readfds, &orig_read), \
|
||||||
restore_fdset(writefds, &orig_write), \
|
restore_fdset(writefds, &orig_write), \
|
||||||
restore_fdset(exceptfds, &orig_except), \
|
restore_fdset(exceptfds, &orig_except), \
|
||||||
update_timeval(timeout, &to))
|
update_timespec(&ts, &to))
|
||||||
|
|
||||||
if (timeout) {
|
if (timeout) {
|
||||||
getclockofday(&to);
|
getclockofday(&to);
|
||||||
timeval_add(&to, timeout);
|
timespec_add(&to, timespec_for(&ts, timeout));
|
||||||
}
|
}
|
||||||
|
|
||||||
#define fd_init_copy(f) \
|
#define fd_init_copy(f) \
|
||||||
@ -3816,7 +3811,7 @@ do_select(int n, rb_fdset_t *const readfds, rb_fdset_t *const writefds,
|
|||||||
|
|
||||||
BLOCKING_REGION({
|
BLOCKING_REGION({
|
||||||
result = native_fd_select(n, readfds, writefds, exceptfds,
|
result = native_fd_select(n, readfds, writefds, exceptfds,
|
||||||
timeout, th);
|
timeval_for(timeout, &ts), th);
|
||||||
if (result < 0) lerrno = errno;
|
if (result < 0) lerrno = errno;
|
||||||
}, ubf_select, th, FALSE);
|
}, ubf_select, th, FALSE);
|
||||||
|
|
||||||
@ -3935,12 +3930,14 @@ rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
|
|||||||
struct pollfd fds;
|
struct pollfd fds;
|
||||||
int result = 0, lerrno;
|
int result = 0, lerrno;
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
struct timeval to;
|
struct timespec to;
|
||||||
|
struct timespec *tsp = 0;
|
||||||
rb_thread_t *th = GET_THREAD();
|
rb_thread_t *th = GET_THREAD();
|
||||||
|
|
||||||
if (timeout) {
|
if (timeout) {
|
||||||
getclockofday(&to);
|
getclockofday(&to);
|
||||||
timeval_add(&to, timeout);
|
timespec_add(&to, timespec_for(&ts, timeout));
|
||||||
|
tsp = &ts;
|
||||||
}
|
}
|
||||||
|
|
||||||
fds.fd = fd;
|
fds.fd = fd;
|
||||||
@ -3950,13 +3947,13 @@ rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
|
|||||||
fds.revents = 0;
|
fds.revents = 0;
|
||||||
lerrno = 0;
|
lerrno = 0;
|
||||||
BLOCKING_REGION({
|
BLOCKING_REGION({
|
||||||
result = ppoll(&fds, 1, timespec_for(&ts, timeout), NULL);
|
result = ppoll(&fds, 1, tsp, NULL);
|
||||||
if (result < 0) lerrno = errno;
|
if (result < 0) lerrno = errno;
|
||||||
}, ubf_select, th, FALSE);
|
}, ubf_select, th, FALSE);
|
||||||
|
|
||||||
RUBY_VM_CHECK_INTS_BLOCKING(th->ec);
|
RUBY_VM_CHECK_INTS_BLOCKING(th->ec);
|
||||||
} while (result < 0 && retryable(errno = lerrno) &&
|
} while (result < 0 && retryable(errno = lerrno) &&
|
||||||
update_timeval(timeout, &to));
|
update_timespec(&ts, &to));
|
||||||
if (result < 0) return -1;
|
if (result < 0) return -1;
|
||||||
|
|
||||||
if (fds.revents & POLLNVAL) {
|
if (fds.revents & POLLNVAL) {
|
||||||
|
@ -366,7 +366,6 @@ static struct timespec
|
|||||||
native_cond_timeout(rb_nativethread_cond_t *cond, struct timespec timeout_rel)
|
native_cond_timeout(rb_nativethread_cond_t *cond, struct timespec timeout_rel)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct timeval tv;
|
|
||||||
struct timespec timeout;
|
struct timespec timeout;
|
||||||
struct timespec now;
|
struct timespec now;
|
||||||
|
|
||||||
@ -381,25 +380,14 @@ native_cond_timeout(rb_nativethread_cond_t *cond, struct timespec timeout_rel)
|
|||||||
if (cond->clockid != CLOCK_REALTIME)
|
if (cond->clockid != CLOCK_REALTIME)
|
||||||
rb_bug("unsupported clockid %"PRIdVALUE, (SIGNED_VALUE)cond->clockid);
|
rb_bug("unsupported clockid %"PRIdVALUE, (SIGNED_VALUE)cond->clockid);
|
||||||
#endif
|
#endif
|
||||||
|
rb_timespec_now(&now);
|
||||||
ret = gettimeofday(&tv, 0);
|
|
||||||
if (ret != 0)
|
|
||||||
rb_sys_fail(0);
|
|
||||||
now.tv_sec = tv.tv_sec;
|
|
||||||
now.tv_nsec = tv.tv_usec * 1000;
|
|
||||||
|
|
||||||
#if USE_MONOTONIC_COND
|
#if USE_MONOTONIC_COND
|
||||||
out:
|
out:
|
||||||
#endif
|
#endif
|
||||||
timeout.tv_sec = now.tv_sec;
|
timeout.tv_sec = now.tv_sec;
|
||||||
timeout.tv_nsec = now.tv_nsec;
|
timeout.tv_nsec = now.tv_nsec;
|
||||||
timeout.tv_sec += timeout_rel.tv_sec;
|
timespec_add(&timeout, &timeout_rel);
|
||||||
timeout.tv_nsec += timeout_rel.tv_nsec;
|
|
||||||
|
|
||||||
if (timeout.tv_nsec >= 1000*1000*1000) {
|
|
||||||
timeout.tv_sec++;
|
|
||||||
timeout.tv_nsec -= 1000*1000*1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (timeout.tv_sec < now.tv_sec)
|
if (timeout.tv_sec < now.tv_sec)
|
||||||
timeout.tv_sec = TIMET_MAX;
|
timeout.tv_sec = TIMET_MAX;
|
||||||
@ -905,7 +893,6 @@ register_cached_thread_and_wait(void)
|
|||||||
{
|
{
|
||||||
rb_nativethread_cond_t cond = RB_NATIVETHREAD_COND_INIT;
|
rb_nativethread_cond_t cond = RB_NATIVETHREAD_COND_INIT;
|
||||||
volatile rb_thread_t *th_area = 0;
|
volatile rb_thread_t *th_area = 0;
|
||||||
struct timeval tv;
|
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
struct cached_thread_entry *entry =
|
struct cached_thread_entry *entry =
|
||||||
(struct cached_thread_entry *)malloc(sizeof(struct cached_thread_entry));
|
(struct cached_thread_entry *)malloc(sizeof(struct cached_thread_entry));
|
||||||
@ -914,9 +901,8 @@ register_cached_thread_and_wait(void)
|
|||||||
return 0; /* failed -> terminate thread immediately */
|
return 0; /* failed -> terminate thread immediately */
|
||||||
}
|
}
|
||||||
|
|
||||||
gettimeofday(&tv, 0);
|
rb_timespec_now(&ts);
|
||||||
ts.tv_sec = tv.tv_sec + 60;
|
ts.tv_sec += 60;
|
||||||
ts.tv_nsec = tv.tv_usec * 1000;
|
|
||||||
|
|
||||||
rb_native_mutex_lock(&thread_cache_lock);
|
rb_native_mutex_lock(&thread_cache_lock);
|
||||||
{
|
{
|
||||||
@ -1072,18 +1058,13 @@ ubf_pthread_cond_signal(void *ptr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
native_sleep(rb_thread_t *th, struct timeval *timeout_tv)
|
native_sleep(rb_thread_t *th, struct timespec *timeout_rel)
|
||||||
{
|
{
|
||||||
struct timespec timeout;
|
struct timespec timeout;
|
||||||
rb_nativethread_lock_t *lock = &th->interrupt_lock;
|
rb_nativethread_lock_t *lock = &th->interrupt_lock;
|
||||||
rb_nativethread_cond_t *cond = &th->native_thread_data.sleep_cond;
|
rb_nativethread_cond_t *cond = &th->native_thread_data.sleep_cond;
|
||||||
|
|
||||||
if (timeout_tv) {
|
if (timeout_rel) {
|
||||||
struct timespec timeout_rel;
|
|
||||||
|
|
||||||
timeout_rel.tv_sec = timeout_tv->tv_sec;
|
|
||||||
timeout_rel.tv_nsec = timeout_tv->tv_usec * 1000;
|
|
||||||
|
|
||||||
/* Solaris cond_timedwait() return EINVAL if an argument is greater than
|
/* Solaris cond_timedwait() return EINVAL if an argument is greater than
|
||||||
* current_time + 100,000,000. So cut up to 100,000,000. This is
|
* current_time + 100,000,000. So cut up to 100,000,000. This is
|
||||||
* considered as a kind of spurious wakeup. The caller to native_sleep
|
* considered as a kind of spurious wakeup. The caller to native_sleep
|
||||||
@ -1092,12 +1073,12 @@ native_sleep(rb_thread_t *th, struct timeval *timeout_tv)
|
|||||||
* See also [Bug #1341] [ruby-core:29702]
|
* See also [Bug #1341] [ruby-core:29702]
|
||||||
* http://download.oracle.com/docs/cd/E19683-01/816-0216/6m6ngupgv/index.html
|
* http://download.oracle.com/docs/cd/E19683-01/816-0216/6m6ngupgv/index.html
|
||||||
*/
|
*/
|
||||||
if (timeout_rel.tv_sec > 100000000) {
|
if (timeout_rel->tv_sec > 100000000) {
|
||||||
timeout_rel.tv_sec = 100000000;
|
timeout_rel->tv_sec = 100000000;
|
||||||
timeout_rel.tv_nsec = 0;
|
timeout_rel->tv_nsec = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
timeout = native_cond_timeout(cond, timeout_rel);
|
timeout = native_cond_timeout(cond, *timeout_rel);
|
||||||
}
|
}
|
||||||
|
|
||||||
GVL_UNLOCK_BEGIN();
|
GVL_UNLOCK_BEGIN();
|
||||||
@ -1111,8 +1092,8 @@ native_sleep(rb_thread_t *th, struct timeval *timeout_tv)
|
|||||||
thread_debug("native_sleep: interrupted before sleep\n");
|
thread_debug("native_sleep: interrupted before sleep\n");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!timeout_tv)
|
if (!timeout_rel)
|
||||||
rb_native_cond_wait(cond, lock);
|
rb_native_cond_wait(cond, lock);
|
||||||
else
|
else
|
||||||
native_cond_timedwait(cond, lock, &timeout);
|
native_cond_timedwait(cond, lock, &timeout);
|
||||||
}
|
}
|
||||||
|
@ -252,8 +252,8 @@ rb_mutex_lock(VALUE self)
|
|||||||
|
|
||||||
while (mutex->th != th) {
|
while (mutex->th != th) {
|
||||||
enum rb_thread_status prev_status = th->status;
|
enum rb_thread_status prev_status = th->status;
|
||||||
struct timeval *timeout = 0;
|
struct timespec *timeout = 0;
|
||||||
struct timeval tv = { 0, 100000 }; /* 100ms */
|
struct timespec ts = { 0, 100000000 }; /* 100ms */
|
||||||
|
|
||||||
th->status = THREAD_STOPPED_FOREVER;
|
th->status = THREAD_STOPPED_FOREVER;
|
||||||
th->locking_mutex = self;
|
th->locking_mutex = self;
|
||||||
@ -265,7 +265,7 @@ rb_mutex_lock(VALUE self)
|
|||||||
*/
|
*/
|
||||||
if ((vm_living_thread_num(th->vm) == th->vm->sleeper) &&
|
if ((vm_living_thread_num(th->vm) == th->vm->sleeper) &&
|
||||||
!patrol_thread) {
|
!patrol_thread) {
|
||||||
timeout = &tv;
|
timeout = &ts;
|
||||||
patrol_thread = th;
|
patrol_thread = th;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -427,8 +427,8 @@ rb_mutex_sleep_forever(VALUE time)
|
|||||||
static VALUE
|
static VALUE
|
||||||
rb_mutex_wait_for(VALUE time)
|
rb_mutex_wait_for(VALUE time)
|
||||||
{
|
{
|
||||||
struct timeval *t = (struct timeval *)time;
|
struct timespec *t = (struct timespec*)time;
|
||||||
sleep_timeval(GET_THREAD(), *t, 0); /* permit spurious check */
|
sleep_timespec(GET_THREAD(), *t, 0); /* permit spurious check */
|
||||||
return Qnil;
|
return Qnil;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -447,7 +447,10 @@ rb_mutex_sleep(VALUE self, VALUE timeout)
|
|||||||
rb_ensure(rb_mutex_sleep_forever, Qnil, rb_mutex_lock, self);
|
rb_ensure(rb_mutex_sleep_forever, Qnil, rb_mutex_lock, self);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
rb_ensure(rb_mutex_wait_for, (VALUE)&t, rb_mutex_lock, self);
|
struct timespec ts;
|
||||||
|
VALUE tsp = (VALUE)timespec_for(&ts, &t);
|
||||||
|
|
||||||
|
rb_ensure(rb_mutex_wait_for, tsp, rb_mutex_lock, self);
|
||||||
}
|
}
|
||||||
end = time(0) - beg;
|
end = time(0) - beg;
|
||||||
return INT2FIX(end);
|
return INT2FIX(end);
|
||||||
|
@ -271,10 +271,10 @@ rb_w32_Sleep(unsigned long msec)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
native_sleep(rb_thread_t *th, struct timeval *tv)
|
native_sleep(rb_thread_t *th, struct timespec *ts)
|
||||||
{
|
{
|
||||||
const volatile DWORD msec = (tv) ?
|
const volatile DWORD msec = (ts) ?
|
||||||
(DWORD)(tv->tv_sec * 1000 + tv->tv_usec / 1000) : INFINITE;
|
(DWORD)(ts->tv_sec * 1000 + ts->tv_nsec / 1000000) : INFINITE;
|
||||||
|
|
||||||
GVL_UNLOCK_BEGIN();
|
GVL_UNLOCK_BEGIN();
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user