From: zimbatm Date: 2008-05-02T02:45:55+09:00 Subject: [PATCH] Monotonic timeofday() Hi ruby-core. here I am again, with a new revision of my monotonic patch. I still hope that one day it will be integrated :) = Problem This is a subtle problem that is mostly problematic on long running processes. If the computer's system clock is set back for a certain delta, the scheduled threads will wait for that delta time + their scheduled time before being activated again. This is due to the fact that they uses the epoch-based gettimeofday() time source. = Solution The general solution is to use a monotonic clock because monotonicity is the guarantee that you won't go back in time. Those clocks are not epoch-based but it doesn't matter because thread scheduling is only using deltas of times. The implemented solution uses the POSIX clock_gettime function, which has a CLOCK_MONOTONIC flag. clock_gettime(), on most BSD, should be in the libc. On linux, it is required to link ruby against librt.so, which is part of the libc6 package. The Darwin (OS X) kernel does not implement the clock_gettime function. Since clock_gettime() doesn't guarantee you that your system provides such clock, I also had to add an init function to check the clock availability, plus the gettimeofday() fallback. = Patch Index: eval.c =================================================================== --- eval.c (revision 16252) +++ eval.c (working copy) @@ -28,6 +28,12 @@ #define EXIT_FAILURE 1 #endif +#ifdef HAVE_UNISTD_H +#include +#include +#include +#endif + #include #include "st.h" @@ -1340,6 +1346,7 @@ void Init_stack _((VALUE*)); void Init_heap _((void)); void Init_ext _((void)); +void Init_clock _((void)); #ifdef HAVE_NATIVETHREAD static rb_nativethread_t ruby_thid; @@ -1382,6 +1389,7 @@ rb_origenviron = environ; #endif + Init_clock(); Init_stack((void*)&state); Init_heap(); PUSH_SCOPE(); @@ -10245,13 +10253,32 @@ curr_thread->safe = level; } +static int clock_monotonic = 0; + +void +Init_clock() +{ +#ifdef CLOCK_MONOTONIC + struct timespec tp; + clock_monotonic = (clock_gettime(CLOCK_MONOTONIC, &tp) == 0); +#endif +} + /* Return the current time as a floating-point number */ static double timeofday() { - struct timeval tv; - gettimeofday(&tv, NULL); - return (double)tv.tv_sec + (double)tv.tv_usec * 1e-6; + if (clock_monotonic) { +#ifdef CLOCK_MONOTONIC + struct timespec tp; + clock_gettime(CLOCK_MONOTONIC, &tp); + return (double)tp.tv_sec + (double)tp.tv_nsec * 1e-9; +#endif + } else { + struct timeval tv; + gettimeofday(&tv, NULL); + return (double)tv.tv_sec + (double)tv.tv_usec * 1e-6; + } } #define STACK(addr) (th->stk_pos<(VALUE*)(addr) && (VALUE*)(addr)stk_pos+th->stk_len) = QA Q: on what branch is your code based ? A: I used the ruby_1_8 branch Q: timeofday() might be used by some code that needs epoch-based time ? A: I have grep'ed trough the code but might have missed something Q: is there a similar solution for windows ? A: I don't know any Windows API that guarantees clock monotonicity. Q: why didn't you rename timeofday() ? A: It would hide the purpose of the patch. It is a good idea although. Q: how do I know if my ruby instance uses the monotonic clock ? (like I'm running a rails application on a vserver) A: use "strace" :) . I don't think there is a Scheduled class where I could publish that information.