ruby-changes:30425
From: akr <ko1@a...>
Date: Sun, 11 Aug 2013 11:59:44 +0900 (JST)
Subject: [ruby-changes:30425] akr:r42504 (trunk): * process.c (rb_clock_gettime): New method.
akr 2013-08-11 11:59:30 +0900 (Sun, 11 Aug 2013) New Revision: 42504 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=42504 Log: * process.c (rb_clock_gettime): New method. This is accepted in the meeting: https://bugs.ruby-lang.org/projects/ruby/wiki/DevelopersMeeting20130809 This method is accepted as a CRuby feature. I.e. Other Ruby implementations don't need to implement it. Modified files: trunk/ChangeLog trunk/NEWS trunk/configure.in trunk/process.c trunk/test/ruby/test_process.rb Index: configure.in =================================================================== --- configure.in (revision 42503) +++ configure.in (revision 42504) @@ -1262,6 +1262,7 @@ RUBY_REPLACE_TYPE(rlim_t, [int long "lon https://github.com/ruby/ruby/blob/trunk/configure.in#L1262 @%:@include <sys/resource.h> ]) RUBY_REPLACE_TYPE(off_t, [], OFFT) +RUBY_REPLACE_TYPE(clockid_t, [], CLOCKID) AC_CACHE_CHECK(for prototypes, rb_cv_have_prototypes, [AC_TRY_COMPILE([int foo(int x) { return 0; }], [return foo(10);], Index: ChangeLog =================================================================== --- ChangeLog (revision 42503) +++ ChangeLog (revision 42504) @@ -1,3 +1,11 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Sun Aug 11 11:54:38 2013 Tanaka Akira <akr@f...> + + * process.c (rb_clock_gettime): New method. + This is accepted in the meeting: + https://bugs.ruby-lang.org/projects/ruby/wiki/DevelopersMeeting20130809 + This method is accepted as a CRuby feature. + I.e. Other Ruby implementations don't need to implement it. + Sun Aug 11 10:40:48 2013 Zachary Scott <e@z...> * lib/time.rb: [DOC] Correcting rdoc visibility of time.rb constants Index: process.c =================================================================== --- process.c (revision 42503) +++ process.c (revision 42504) @@ -68,7 +68,9 @@ https://github.com/ruby/ruby/blob/trunk/process.c#L68 # include "nacl/unistd.h" #endif - +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif #ifdef HAVE_SYS_TIMES_H #include <sys/times.h> #endif @@ -6635,6 +6637,161 @@ rb_proc_times(VALUE obj) https://github.com/ruby/ruby/blob/trunk/process.c#L6637 #define rb_proc_times rb_f_notimplement #endif +/* + * call-seq: + * Process.clock_gettime(clk_id [, unit]) -> number + * + * Returns a time returned by POSIX clock_gettime() function. + * + * _clk_id_ specifies a kind of clock. + * It is specifed as a constant which begins with <code>Process::CLOCK_</code> + * such like <code>Process::CLOCK_REALTIME</code> and + * <code>Process::CLOCK_MONOTONIC</code>. + * The supported constants depends on OS and version. + * Ruby provides following type of _clk_id_ if available. + * + * [CLOCK_REALTIME] SUSv2 to 4, Linux 2.5.63, FreeBSD 3.0, NetBSD 2.0, OpenBSD 2.1 + * [CLOCK_MONOTONIC] SUSv3 to 4, Linux 2.5.63, FreeBSD 3.0, NetBSD 2.0, OpenBSD 3.4 + * [CLOCK_PROCESS_CPUTIME_ID] SUSv3 to 4, Linux 2.5.63 + * [CLOCK_THREAD_CPUTIME_ID] SUSv3 to 4, Linux 2.5.63 + * [CLOCK_VIRTUAL] FreeBSD 3.0, OpenBSD 2.1 + * [CLOCK_PROF] FreeBSD 3.0, OpenBSD 2.1 + * [CLOCK_REALTIME_FAST] FreeBSD 8.1 + * [CLOCK_REALTIME_PRECISE] FreeBSD 8.1 + * [CLOCK_MONOTONIC_FAST] FreeBSD 8.1 + * [CLOCK_MONOTONIC_PRECISE] FreeBSD 8.1 + * [CLOCK_MONOTONIC_RAW] Linux 2.6.28 + * [CLOCK_UPTIME] FreeBSD 7.0 + * [CLOCK_UPTIME_FAST] FreeBSD 8.1 + * [CLOCK_UPTIME_PRECISE] FreeBSD 8.1 + * [CLOCK_SECOND] FreeBSD 8.1 + * + * If the given _clk_id_ is not supported, Errno::EINVAL is raised. + * + * _unit_ specifies a type of the return value. + * + * [:float_seconds] number of seconds as a float (default) + * [:float_milliseconds] number of milliseconds as a float + * [:float_microseconds] number of microseconds as a float + * [:milliseconds] number of milliseconds as an integer + * [:microseconds] number of microseconds as an integer + * [:nanoseconds] number of nanoseconds as an integer + * + * The underlying function, clock_gettime(), returns a number of nanoseconds. + * Float object (IEEE 754 double) is not enough to represent + * the return value for CLOCK_REALTIME. + * If the exact nanoseconds value is required, use :nanoseconds as _unit_. + * + * The origin (zero) of the returned value varies. + * For example, system start up time, process start up time, the Epoch, etc. + * + * The origin in CLOCK_REALTIME is defined as the Epoch + * (1970-01-01 00:00:00 UTC). + * But some systems count leap seconds and others doesn't. + * So the result can be interpreted differently across systems. + * Time.now is recommended over CLOCK_REALTIME. + * + * p Process.clock_gettime(Process::CLOCK_MONOTONIC) + * #=> 896053.968060096 + * + */ +VALUE +rb_clock_gettime(int argc, VALUE *argv) +{ + struct timespec ts; + VALUE clk_id, unit; + int ret; + long factor; + + rb_scan_args(argc, argv, "11", &clk_id, &unit); + + if (SYMBOL_P(clk_id)) { + /* + * Non-clock_gettime clocks are provided by symbol clk_id. + * + * gettimeofday is always available on platforms supported by Ruby. + * POSIX_GETTIMEOFDAY_CLOCK_REALTIME is used for + * CLOCK_REALTIME if clock_gettime is not available. + */ +#define RUBY_POSIX_GETTIMEOFDAY_CLOCK_REALTIME ID2SYM(rb_intern("POSIX_GETTIMEOFDAY_CLOCK_REALTIME")) + if (clk_id == RUBY_POSIX_GETTIMEOFDAY_CLOCK_REALTIME) { + struct timeval tv; + ret = gettimeofday(&tv, 0); + if (ret != 0) + rb_sys_fail("gettimeofday"); + ts.tv_sec = tv.tv_sec; + ts.tv_nsec = tv.tv_usec * 1000; + goto success; + } + +#define RUBY_POSIX_TIME_CLOCK_REALTIME ID2SYM(rb_intern("POSIX_TIME_CLOCK_REALTIME")) + if (clk_id == RUBY_POSIX_TIME_CLOCK_REALTIME) { + time_t t; + t = time(NULL); + if (t == (time_t)-1) + rb_sys_fail("time"); + ts.tv_sec = t; + ts.tv_nsec = 0; + goto success; + } + } + else { +#if defined(HAVE_CLOCK_GETTIME) + clockid_t c; + c = NUM2CLOCKID(clk_id); + ret = clock_gettime(c, &ts); + if (ret == -1) + rb_sys_fail("clock_gettime"); + goto success; +#endif + } + /* EINVAL emulates clock_gettime behavior when clock_id is invalid. */ + errno = EINVAL; + rb_sys_fail(0); + + success: + if (unit == ID2SYM(rb_intern("nanoseconds"))) { + factor = 1000000000; + goto return_integer; + } + else if (unit == ID2SYM(rb_intern("microseconds"))) { + factor = 1000000; + goto return_integer; + } + else if (unit == ID2SYM(rb_intern("milliseconds"))) { + factor = 1000; + goto return_integer; + } + else if (unit == ID2SYM(rb_intern("float_microseconds"))) { + factor = 1000000; + goto return_float; + } + else if (unit == ID2SYM(rb_intern("float_milliseconds"))) { + factor = 1000; + goto return_float; + } + else if (NIL_P(unit) || unit == ID2SYM(rb_intern("float_seconds"))) { + factor = 1; + goto return_float; + } + else { + rb_raise(rb_eArgError, "unexpected unit: %"PRIsVALUE, unit); + } + + return_float: + return DBL2NUM((ts.tv_sec + 1e-9 * (double)ts.tv_nsec) / factor); + + return_integer: +#if defined(HAVE_LONG_LONG) + if (!MUL_OVERFLOW_SIGNED_INTEGER_P(factor, (LONG_LONG)ts.tv_sec, + LLONG_MIN, LLONG_MAX-(factor-1))) { + return LL2NUM(ts.tv_nsec/(1000000000/factor) + factor * (LONG_LONG)ts.tv_sec); + } +#endif + return rb_funcall(LONG2FIX(ts.tv_nsec/(1000000000/factor)), '+', 1, + rb_funcall(LONG2FIX(factor), '*', 1, TIMET2NUM(ts.tv_sec))); +} + VALUE rb_mProcess; VALUE rb_mProcUID; VALUE rb_mProcGID; @@ -6893,6 +7050,55 @@ Init_process(void) https://github.com/ruby/ruby/blob/trunk/process.c#L7050 rb_define_module_function(rb_mProcess, "times", rb_proc_times, 0); +#ifdef CLOCK_REALTIME + rb_define_const(rb_mProcess, "CLOCK_REALTIME", CLOCKID2NUM(CLOCK_REALTIME)); +#elif defined(RUBY_POSIX_GETTIMEOFDAY_CLOCK_REALTIME) + rb_define_const(rb_mProcess, "CLOCK_REALTIME", RUBY_POSIX_GETTIMEOFDAY_CLOCK_REALTIME); +#endif +#ifdef CLOCK_MONOTONIC + rb_define_const(rb_mProcess, "CLOCK_MONOTONIC", CLOCKID2NUM(CLOCK_MONOTONIC)); +#endif +#ifdef CLOCK_PROCESS_CPUTIME_ID + rb_define_const(rb_mProcess, "CLOCK_PROCESS_CPUTIME_ID", CLOCKID2NUM(CLOCK_PROCESS_CPUTIME_ID)); +#endif +#ifdef CLOCK_THREAD_CPUTIME_ID + rb_define_const(rb_mProcess, "CLOCK_THREAD_CPUTIME_ID", CLOCKID2NUM(CLOCK_THREAD_CPUTIME_ID)); +#endif +#ifdef CLOCK_VIRTUAL + rb_define_const(rb_mProcess, "CLOCK_VIRTUAL", CLOCKID2NUM(CLOCK_VIRTUAL)); +#endif +#ifdef CLOCK_PROF + rb_define_const(rb_mProcess, "CLOCK_PROF", CLOCKID2NUM(CLOCK_PROF)); +#endif +#ifdef CLOCK_REALTIME_FAST + rb_define_const(rb_mProcess, "CLOCK_REALTIME_FAST", CLOCKID2NUM(CLOCK_REALTIME_FAST)); +#endif +#ifdef CLOCK_REALTIME_PRECISE + rb_define_const(rb_mProcess, "CLOCK_REALTIME_PRECISE", CLOCKID2NUM(CLOCK_REALTIME_PRECISE)); +#endif +#ifdef CLOCK_MONOTONIC_FAST + rb_define_const(rb_mProcess, "CLOCK_MONOTONIC_FAST", CLOCKID2NUM(CLOCK_MONOTONIC_FAST)); +#endif +#ifdef CLOCK_MONOTONIC_PRECISE + rb_define_const(rb_mProcess, "CLOCK_MONOTONIC_PRECISE", CLOCKID2NUM(CLOCK_MONOTONIC_PRECISE)); +#endif +#ifdef CLOCK_MONOTONIC_RAW + rb_define_const(rb_mProcess, "CLOCK_MONOTONIC_RAW", CLOCKID2NUM(CLOCK_MONOTONIC_RAW)); +#endif +#ifdef CLOCK_UPTIME + rb_define_const(rb_mProcess, "CLOCK_UPTIME", CLOCKID2NUM(CLOCK_UPTIME)); +#endif +#ifdef CLOCK_UPTIME_FAST + rb_define_const(rb_mProcess, "CLOCK_UPTIME_FAST", CLOCKID2NUM(CLOCK_UPTIME_FAST)); +#endif +#ifdef CLOCK_UPTIME_PRECISE + rb_define_const(rb_mProcess, "CLOCK_UPTIME_PRECISE", CLOCKID2NUM(CLOCK_UPTIME_PRECISE)); +#endif +#ifdef CLOCK_SECOND + rb_define_const(rb_mProcess, "CLOCK_SECOND", CLOCKID2NUM(CLOCK_SECOND)); +#endif + rb_define_module_function(rb_mProcess, "clock_gettime", rb_clock_gettime, -1); + #if defined(HAVE_TIMES) || defined(_WIN32) rb_cProcessTms = rb_struct_define("Tms", "utime", "stime", "cutime", "cstime", NULL); #endif Index: NEWS =================================================================== --- NEWS (revision 42503) +++ NEWS (revision 42504) @@ -57,9 +57,11 @@ with all sufficient information, see the https://github.com/ruby/ruby/blob/trunk/NEWS#L57 * Mutex#owned? is no longer experimental. * Process - * New alternative methods to $0/$0=: - * Process.argv0() returns the original value of $0. - * Process.setproctitle() sets the process title without affecting $0. + * New methods: + * alternative methods to $0/$0=: + * Process.argv0() returns the original value of $0. + * Process.setproctitle() sets the process title without affecting $0. + * Process.clock_gettime * String * New methods: Index: test/ruby/test_process.rb =================================================================== --- test/ruby/test_process.rb (revision 42503) +++ test/ruby/test_process.rb (revision 42504) @@ -1660,4 +1660,13 @@ EOS https://github.com/ruby/ruby/blob/trunk/test/ruby/test_process.rb#L1660 end end if windows? + def test_clock_gettime + t1 = Process.clock_gettime(Process::CLOCK_REALTIME, :nanoseconds) + t2 = Time.now; t2 = t2.tv_sec * 1000000000 + t2.tv_nsec + t3 = Process.clock_gettime(Process::CLOCK_REALTIME, :nanoseconds) + assert_operator(t1, :<=, t2) + assert_operator(t2, :<=, t3) + assert_raise(Errno::EINVAL) { Process.clock_gettime(:foo) } + end + end -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/