diff --git a/ChangeLog b/ChangeLog index 641e921d96..fa43db1d04 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Tue Sep 3 12:09:08 2013 Tanaka Akira + + * process.c (rb_clock_gettime): Support times() based monotonic clock. + (rb_clock_getres): Ditto. + Tue Sep 3 12:03:02 2013 Tanaka Akira * bignum.c (str2big_scan_digits): Extracted from rb_cstr_to_inum. diff --git a/process.c b/process.c index 07649f1b0c..e2bd716d85 100644 --- a/process.c +++ b/process.c @@ -6926,6 +6926,17 @@ get_mach_timebase_info(void) * [:MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC] * Use mach_absolute_time(), available on Darwin. * The resolution is CPU dependent. + * [:TIMES_BASED_CLOCK_MONOTONIC] + * Use the result value of times() defined by POSIX. + * POSIX defines it as "times() shall return the elapsed real time, in clock ticks, since an arbitrary point in the past (for example, system start-up time)". + * For example, GNU/Linux returns a value based on jiffies and it is monotonic. + * However, 4.4BSD uses gettimeofday() and it is not monotonic. + * (FreeBSD uses clock_gettime(CLOCK_MONOTONIC) instead, though.) + * The resolution is the clock tick. + * "getconf CLK_TCK" command shows the clock ticks per second. + * (The clock ticks per second is defined by HZ macro in older systems.) + * If it is 100 and clock_t is 32 bits integer type, the resolution is 10 milli second and + * cannot represent over 497 days. * * Emulations for +CLOCK_PROCESS_CPUTIME_ID+: * [:GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID] @@ -7022,6 +7033,24 @@ rb_clock_gettime(int argc, VALUE *argv) goto success; } +#ifdef HAVE_TIMES +#define RUBY_TIMES_BASED_CLOCK_MONOTONIC \ + ID2SYM(rb_intern("TIMES_BASED_CLOCK_MONOTONIC")) + if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) { + struct tms buf; + clock_t c; + unsigned_clock_t uc; + c = times(&buf); + if (c == (clock_t)-1) + rb_sys_fail("times"); + uc = (unsigned_clock_t)c; + tt.count = (int32_t)(uc % 1000000000); + tt.giga_count = (uc / 1000000000); + denominators[num_denominators++] = get_clk_tck(); + goto success; + } +#endif + #ifdef RUSAGE_SELF #define RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID \ ID2SYM(rb_intern("GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID")) @@ -7186,6 +7215,15 @@ rb_clock_getres(int argc, VALUE *argv) } #endif +#ifdef RUBY_TIMES_BASED_CLOCK_MONOTONIC + if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) { + tt.count = 1; + tt.giga_count = 0; + denominators[num_denominators++] = get_clk_tck(); + goto success; + } +#endif + #ifdef RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) { tt.giga_count = 0; diff --git a/test/ruby/test_process.rb b/test/ruby/test_process.rb index 8b15679671..fa69d4b916 100644 --- a/test/ruby/test_process.rb +++ b/test/ruby/test_process.rb @@ -1693,6 +1693,16 @@ EOS assert_kind_of(Float, t, "Process.clock_gettime(:#{n})") end + def test_clock_gettime_TIMES_BASED_CLOCK_MONOTONIC + n = :TIMES_BASED_CLOCK_MONOTONIC + begin + t = Process.clock_gettime(n) + rescue Errno::EINVAL + return + end + assert_kind_of(Float, t, "Process.clock_gettime(:#{n})") + end + def test_clock_gettime_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID n = :GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID begin @@ -1761,6 +1771,18 @@ EOS assert_equal(1000000000, Process.clock_getres(n, :nanosecond)) end + def test_clock_getres_TIMES_BASED_CLOCK_MONOTONIC + n = :TIMES_BASED_CLOCK_MONOTONIC + begin + t = Process.clock_getres(n) + rescue Errno::EINVAL + return + end + assert_kind_of(Float, t, "Process.clock_getres(:#{n})") + f = Process.clock_getres(n, :hertz) + assert_equal(0, f - f.floor) + end + def test_clock_getres_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID n = :GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID begin