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
94 94
static void sleep_timeval(rb_thread_t *th, struct timeval time, int spurious_check);
95 95
static void sleep_forever(rb_thread_t *th, int nodeadlock, int spurious_check);
96 96
static void rb_thread_sleep_deadly_allow_spurious_wakeup(void);
97
static double timeofday(void);
98 97
static int rb_threadptr_dead(rb_thread_t *th);
99 98
static void rb_check_deadlock(rb_vm_t *vm);
100 99
static int rb_threadptr_pending_interrupt_empty_p(const rb_thread_t *th);
101 100
static const char *thread_status_name(rb_thread_t *th, int detail);
101
static void timeval_add(struct timeval *, const struct timeval *);
102
static void timeval_sub(struct timeval *, const struct timeval *);
103
static int timeval_update_expire(struct timeval *, const struct timeval *);
104
static void getclockofday(struct timeval *);
102 105

  
103 106
#define eKillSignal INT2FIX(0)
104 107
#define eTerminateSignal INT2FIX(1)
......
197 200
    return vm->living_thread_num;
198 201
}
199 202

  
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

  
200 214
#if THREAD_DEBUG
201 215
#ifdef HAVE_VA_ARGS_MACRO
202 216
void rb_thread_debug(const char *file, int line, const char *fmt, ...);
......
481 495
    }
482 496
}
483 497

  
484
static struct timeval double2timeval(double d);
485

  
486 498
void
487 499
rb_thread_terminate_all(void)
488 500
{
......
506 518
	terminate_all(vm, th);
507 519

  
508 520
	while (vm_living_thread_num(vm) > 1) {
509
	    struct timeval tv = double2timeval(1.0);
521
	    struct timeval tv = { 1, 0 };
510 522
	    /*
511 523
	     * Thread exiting routine in thread_start_func_2 notify
512 524
	     * me when the last sub-thread exit.
......
848 860
}
849 861

  
850 862

  
851
/* +infty, for this purpose */
852
#define DELAY_INFTY 1E30
853

  
854 863
struct join_arg {
855 864
    rb_thread_t *target, *waiting;
856
    double delay;
865
    struct timeval *limit;
857 866
};
858 867

  
859 868
static VALUE
......
882 891
{
883 892
    struct join_arg *p = (struct join_arg *)arg;
884 893
    rb_thread_t *target_th = p->target, *th = p->waiting;
885
    const int forever = p->delay == DELAY_INFTY;
886
    const double limit = forever ? 0 : timeofday() + p->delay;
894
    struct timeval to;
895

  
896
    if (p->limit) {
897
        getclockofday(&to);
898
        timeval_add(&to, p->limit);
899
    }
887 900

  
888 901
    while (target_th->status != THREAD_KILLED) {
889
	if (forever) {
902
	if (!p->limit) {
890 903
	    th->status = THREAD_STOPPED_FOREVER;
891 904
	    th->vm->sleeper++;
892 905
	    rb_check_deadlock(th->vm);
......
894 907
	    th->vm->sleeper--;
895 908
	}
896 909
	else {
897
	    double now = timeofday();
898
	    struct timeval tv;
899

  
900
	    if (now > limit) {
910
            if (timeval_update_expire(p->limit, &to)) {
901 911
		thread_debug("thread_join: timeout (thid: %"PRI_THREAD_ID")\n",
902 912
			     thread_id_str(target_th));
903 913
		return Qfalse;
904 914
	    }
905
	    tv = double2timeval(limit - now);
906 915
	    th->status = THREAD_STOPPED;
907
	    native_sleep(th, &tv);
916
	    native_sleep(th, p->limit);
908 917
	}
909 918
	RUBY_VM_CHECK_INTS_BLOCKING(th->ec);
910 919
	th->status = THREAD_RUNNABLE;
......
915 924
}
916 925

  
917 926
static VALUE
918
thread_join(rb_thread_t *target_th, double delay)
927
thread_join(rb_thread_t *target_th, struct timeval *tv)
919 928
{
920 929
    rb_thread_t *th = GET_THREAD();
921 930
    struct join_arg arg;
......
929 938

  
930 939
    arg.target = target_th;
931 940
    arg.waiting = th;
932
    arg.delay = delay;
941
    arg.limit = tv;
933 942

  
934 943
    thread_debug("thread_join (thid: %"PRI_THREAD_ID", status: %s)\n",
935 944
		 thread_id_str(target_th), thread_status_name(target_th, TRUE));
......
974 983
    return target_th->self;
975 984
}
976 985

  
986
static struct timeval double2timeval(double);
987

  
977 988
/*
978 989
 *  call-seq:
979 990
 *     thr.join          -> thr
......
1016 1027
static VALUE
1017 1028
thread_join_m(int argc, VALUE *argv, VALUE self)
1018 1029
{
1019
    double delay = DELAY_INFTY;
1020 1030
    VALUE limit;
1031
    struct timeval timeval;
1032
    struct timeval *tv = 0;
1021 1033

  
1022 1034
    rb_scan_args(argc, argv, "01", &limit);
1023
    if (!NIL_P(limit)) {
1024
	delay = rb_num2dbl(limit);
1035

  
1036
    /*
1037
     * This supports INFINITY and negative values, so we can't use
1038
     * rb_time_interval right now...
1039
     */
1040
    switch (TYPE(limit)) {
1041
      case T_NIL: break;
1042
      case T_FIXNUM:
1043
      case T_BIGNUM:
1044
        timeval.tv_sec = NUM2TIMET(limit);
1045
        timeval.tv_usec = 0;
1046
        tv = &timeval;
1047
        break;
1048
      default:
1049
        timeval = double2timeval(rb_num2dbl(limit));
1050
        tv = &timeval;
1025 1051
    }
1026 1052

  
1027
    return thread_join(rb_thread_ptr(self), delay);
1053
    return thread_join(rb_thread_ptr(self), tv);
1028 1054
}
1029 1055

  
1030 1056
/*
......
1045 1071
thread_value(VALUE self)
1046 1072
{
1047 1073
    rb_thread_t *th = rb_thread_ptr(self);
1048
    thread_join(th, DELAY_INFTY);
1074
    thread_join(th, 0);
1049 1075
    return th->value;
1050 1076
}
1051 1077

  
......
1160 1186
    }
1161 1187
}
1162 1188

  
1189
static void
1190
timeval_sub(struct timeval *dst, const struct timeval *tv)
1191
{
1192
    dst->tv_sec -= tv->tv_sec;
1193
    if ((dst->tv_usec -= tv->tv_usec) < 0) {
1194
	--dst->tv_sec;
1195
	dst->tv_usec += 1000000;
1196
    }
1197
}
1198

  
1163 1199
static int
1164 1200
timeval_update_expire(struct timeval *tv, const struct timeval *to)
1165 1201
{
......
1172 1208
		 "%"PRI_TIMET_PREFIX"d.%.6ld > %"PRI_TIMET_PREFIX"d.%.6ld\n",
1173 1209
		 (time_t)to->tv_sec, (long)to->tv_usec,
1174 1210
		 (time_t)tvn.tv_sec, (long)tvn.tv_usec);
1175
    tv->tv_sec = to->tv_sec - tvn.tv_sec;
1176
    if ((tv->tv_usec = to->tv_usec - tvn.tv_usec) < 0) {
1177
	--tv->tv_sec;
1178
	tv->tv_usec += 1000000;
1179
    }
1211
    *tv = *to;
1212
    timeval_sub(tv, &tvn);
1180 1213
    return 0;
1181 1214
}
1182 1215

  
......
1222 1255
    sleep_forever(GET_THREAD(), TRUE, FALSE);
1223 1256
}
1224 1257

  
1225
static double
1226
timeofday(void)
1227
{
1228
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
1229
    struct timespec tp;
1230

  
1231
    if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) {
1232
        return (double)tp.tv_sec + (double)tp.tv_nsec * 1e-9;
1233
    }
1234
    else
1235
#endif
1236
    {
1237
        struct timeval tv;
1238
        gettimeofday(&tv, NULL);
1239
        return (double)tv.tv_sec + (double)tv.tv_usec * 1e-6;
1240
    }
1241
}
1242

  
1243 1258
void
1244 1259
rb_thread_wait_for(struct timeval time)
1245 1260
{
......
3740 3755
#define restore_fdset(fds1, fds2) \
3741 3756
    ((fds1) ? rb_fd_dup(fds1, fds2) : (void)0)
3742 3757

  
3743
static inline void
3744
update_timeval(struct timeval *timeout, double limit)
3758
static inline int
3759
update_timeval(struct timeval *timeout, const struct timeval *to)
3745 3760
{
3746 3761
    if (timeout) {
3747
	double d = limit - timeofday();
3762
        struct timeval tvn;
3748 3763

  
3749
	timeout->tv_sec = (time_t)d;
3750
	timeout->tv_usec = (int)((d-(double)timeout->tv_sec)*1e6);
3751
	if (timeout->tv_sec < 0)  timeout->tv_sec = 0;
3752
	if (timeout->tv_usec < 0) timeout->tv_usec = 0;
3764
        getclockofday(&tvn);
3765
        *timeout = *to;
3766
        timeval_sub(timeout, &tvn);
3767

  
3768
        if (timeout->tv_sec < 0)  timeout->tv_sec = 0;
3769
        if (timeout->tv_usec < 0) timeout->tv_usec = 0;
3753 3770
    }
3771
    return TRUE;
3754 3772
}
3755 3773

  
3756 3774
static int
......
3762 3780
    rb_fdset_t MAYBE_UNUSED(orig_read);
3763 3781
    rb_fdset_t MAYBE_UNUSED(orig_write);
3764 3782
    rb_fdset_t MAYBE_UNUSED(orig_except);
3765
    double limit = 0;
3766
    struct timeval wait_rest;
3783
    struct timeval to;
3767 3784
    rb_thread_t *th = GET_THREAD();
3768 3785

  
3769 3786
#define do_select_update() \
3770 3787
    (restore_fdset(readfds, &orig_read), \
3771 3788
     restore_fdset(writefds, &orig_write), \
3772 3789
     restore_fdset(exceptfds, &orig_except), \
3773
     update_timeval(timeout, limit), \
3774
     TRUE)
3790
     update_timeval(timeout, &to))
3775 3791

  
3776 3792
    if (timeout) {
3777
	limit = timeofday();
3778
	limit += (double)timeout->tv_sec+(double)timeout->tv_usec*1e-6;
3779
	wait_rest = *timeout;
3780
	timeout = &wait_rest;
3793
        getclockofday(&to);
3794
        timeval_add(&to, timeout);
3781 3795
    }
3782 3796

  
3783 3797
#define fd_init_copy(f) \
......
3911 3925
}
3912 3926
#endif
3913 3927

  
3914
static inline void
3915
update_timespec(struct timespec *timeout, double limit)
3916
{
3917
    if (timeout) {
3918
	double d = limit - timeofday();
3919

  
3920
	timeout->tv_sec = (long)d;
3921
	timeout->tv_nsec = (long)((d-(double)timeout->tv_sec)*1e9);
3922
	if (timeout->tv_sec < 0)  timeout->tv_sec = 0;
3923
	if (timeout->tv_nsec < 0) timeout->tv_nsec = 0;
3924
    }
3925
}
3926

  
3927 3928
/*
3928 3929
 * returns a mask of events
3929 3930
 */
3930 3931
int
3931
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)
3932 3933
{
3933 3934
    struct pollfd fds;
3934 3935
    int result = 0, lerrno;
3935
    double limit = 0;
3936 3936
    struct timespec ts;
3937
    struct timespec *timeout = NULL;
3937
    struct timeval to;
3938 3938
    rb_thread_t *th = GET_THREAD();
3939 3939

  
3940
#define poll_update() \
3941
    (update_timespec(timeout, limit), \
3942
     TRUE)
3943

  
3944
    if (tv) {
3945
	ts.tv_sec = tv->tv_sec;
3946
	ts.tv_nsec = tv->tv_usec * 1000;
3947
	limit = timeofday();
3948
	limit += (double)tv->tv_sec + (double)tv->tv_usec * 1e-6;
3949
	timeout = &ts;
3940
    if (timeout) {
3941
        getclockofday(&to);
3942
        timeval_add(&to, timeout);
3950 3943
    }
3951 3944

  
3952 3945
    fds.fd = fd;
3953 3946
    fds.events = (short)events;
3954 3947

  
3955 3948
    do {
3956
	fds.revents = 0;
3957
	lerrno = 0;
3958
	BLOCKING_REGION({
3959
	    result = ppoll(&fds, 1, timeout, NULL);
3960
	    if (result < 0) lerrno = errno;
3961
	}, ubf_select, th, FALSE);
3962

  
3963
	RUBY_VM_CHECK_INTS_BLOCKING(th->ec);
3964
    } 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));
3965 3959
    if (result < 0) return -1;
3966 3960

  
3967 3961
    if (fds.revents & POLLNVAL) {
3968
-