clock_gettime-4.patch

Akira Tanaka, 08/05/2013 09:50 PM

Download (9.2 KB)

View differences:

configure.in (working copy)
1262 1262
@%:@include <sys/resource.h>
1263 1263
])
1264 1264
RUBY_REPLACE_TYPE(off_t, [], OFFT)
1265
RUBY_REPLACE_TYPE(clockid_t, [], CLOCKID)
1265 1266

  
1266 1267
AC_CACHE_CHECK(for prototypes, rb_cv_have_prototypes,
1267 1268
  [AC_TRY_COMPILE([int foo(int x) { return 0; }], [return foo(10);],
test/ruby/test_process.rb (working copy)
1658 1658
    end
1659 1659
  end if windows?
1660 1660

  
1661
  def test_clock_gettime
1662
    t1 = Process.clock_gettime(Process::CLOCK_REALTIME, :nanoseconds)
1663
    t2 = Time.now; t2 = t2.tv_sec * 1000000000 + t2.tv_nsec
1664
    t3 = Process.clock_gettime(Process::CLOCK_REALTIME, :nanoseconds)
1665
    assert_operator(t1, :<=, t2)
1666
    assert_operator(t2, :<=, t3)
1667
    assert_raise(Errno::EINVAL) { Process.clock_gettime(:foo) }
1668
  end
1669

  
1661 1670
end
process.c (working copy)
68 68
# include "nacl/unistd.h"
69 69
#endif
70 70

  
71

  
71
#ifdef HAVE_SYS_TIME_H
72
#include <sys/time.h>
73
#endif
72 74
#ifdef HAVE_SYS_TIMES_H
73 75
#include <sys/times.h>
74 76
#endif
......
6627 6629
#define rb_proc_times rb_f_notimplement
6628 6630
#endif
6629 6631

  
6632
/*
6633
 *  call-seq:
6634
 *     Process.clock_gettime(clk_id [, unit])   -> number
6635
 *
6636
 *  Returns a time returned by POSIX clock_gettime() function.
6637
 *
6638
 *  _clk_id_ specifies a kind of clock.
6639
 *  It is specifed as a constant which begins with <code>Process::CLOCK_</code>
6640
 *  such like <code>Process::CLOCK_REALTIME</code> and
6641
 *  <code>Process::CLOCK_MONOTONIC</code>.
6642
 *  The supported constants depends on OS and version.
6643
 *  Ruby provides following type of _clk_id_ if available.
6644
 *
6645
 *  [CLOCK_REALTIME] SUSv2 to 4, Linux 2.5.63, FreeBSD 3.0, NetBSD 2.0, OpenBSD 2.1
6646
 *  [CLOCK_MONOTONIC] SUSv3 to 4, Linux 2.5.63, FreeBSD 3.0, NetBSD 2.0, OpenBSD 3.4
6647
 *  [CLOCK_PROCESS_CPUTIME_ID] SUSv3 to 4, Linux 2.5.63
6648
 *  [CLOCK_THREAD_CPUTIME_ID] SUSv3 to 4, Linux 2.5.63
6649
 *  [CLOCK_VIRTUAL] FreeBSD 3.0, OpenBSD 2.1
6650
 *  [CLOCK_PROF] FreeBSD 3.0, OpenBSD 2.1
6651
 *  [CLOCK_REALTIME_FAST] FreeBSD 8.1
6652
 *  [CLOCK_REALTIME_PRECISE] FreeBSD 8.1
6653
 *  [CLOCK_MONOTONIC_FAST] FreeBSD 8.1
6654
 *  [CLOCK_MONOTONIC_PRECISE] FreeBSD 8.1
6655
 *  [CLOCK_MONOTONIC_RAW] Linux 2.6.28
6656
 *  [CLOCK_UPTIME] FreeBSD 7.0
6657
 *  [CLOCK_UPTIME_FAST] FreeBSD 8.1
6658
 *  [CLOCK_UPTIME_PRECISE] FreeBSD 8.1
6659
 *  [CLOCK_SECOND] FreeBSD 8.1
6660
 *
6661
 *  If the given _clk_id_ is not supported, Errno::EINVAL is raised.
6662
 *
6663
 *  _unit_ specifies a type of the return value.
6664
 *
6665
 *  [:float_seconds] number of seconds as a float (default)
6666
 *  [:float_milliseconds] number of milliseconds as a float
6667
 *  [:float_microseconds] number of microseconds as a float
6668
 *  [:milliseconds] number of milliseconds as an integer
6669
 *  [:microseconds] number of microseconds as an integer
6670
 *  [:nanoseconds] number of nanoseconds as an integer
6671
 *
6672
 *  The underlying function, clock_gettime(), returns a number of nanoseconds.
6673
 *  Float object (IEEE 754 double) is not enough to represent
6674
 *  the return value for CLOCK_REALTIME.
6675
 *  If the exact nanoseconds value is required, use :nanoseconds as _unit_.
6676
 *
6677
 *  The origin (zero) of the returned value varies.
6678
 *  For example, system start up time, process start up time, the Epoch, etc.
6679
 *
6680
 *  The origin in CLOCK_REALTIME is defined as the Epoch
6681
 *  (1970-01-01 00:00:00 UTC).
6682
 *  But some systems count leap seconds and others doesn't.
6683
 *  So the result can be interpreted differently across systems.
6684
 *
6685
 *    p Process.clock_gettime(Process::CLOCK_MONOTONIC)
6686
 *    #=> 2684827897652283
6687
 *
6688
 */
6689
VALUE
6690
rb_clock_gettime(int argc, VALUE *argv)
6691
{
6692
    struct timespec ts;
6693
    VALUE clk_id, unit;
6694
    int ret;
6695
    long factor;
6696

  
6697
    rb_scan_args(argc, argv, "11", &clk_id, &unit);
6698

  
6699
    if (SYMBOL_P(clk_id)) {
6700
        /*
6701
         * Non-clock_gettime clocks are provided by symbol clk_id.
6702
         *
6703
         * gettimeofday is always available on platforms supported by Ruby.
6704
         * POSIX_GETTIMEOFDAY_CLOCK_REALTIME is used for
6705
         * CLOCK_REALTIME if clock_gettime is not available.
6706
         */
6707
#define RUBY_POSIX_GETTIMEOFDAY_CLOCK_REALTIME ID2SYM(rb_intern("POSIX_GETTIMEOFDAY_CLOCK_REALTIME"))
6708
        if (clk_id == RUBY_POSIX_GETTIMEOFDAY_CLOCK_REALTIME) {
6709
            struct timeval tv;
6710
            ret = gettimeofday(&tv, 0);
6711
            if (ret != 0)
6712
                rb_sys_fail("gettimeofday");
6713
            ts.tv_sec = tv.tv_sec;
6714
            ts.tv_nsec = tv.tv_usec * 1000;
6715
            goto success;
6716
        }
6717

  
6718
#define RUBY_POSIX_TIME_CLOCK_REALTIME ID2SYM(rb_intern("POSIX_TIME_CLOCK_REALTIME"))
6719
        if (clk_id == RUBY_POSIX_TIME_CLOCK_REALTIME) {
6720
            time_t t;
6721
            t = time(NULL);
6722
            if (t == (time_t)-1)
6723
                rb_sys_fail("time");
6724
            ts.tv_sec = t;
6725
            ts.tv_nsec = 0;
6726
            goto success;
6727
        }
6728
    }
6729
    else {
6730
#if defined(HAVE_CLOCK_GETTIME)
6731
        clockid_t c;
6732
        c = NUM2CLOCKID(clk_id);
6733
        ret = clock_gettime(c, &ts);
6734
        if (ret == -1)
6735
            rb_sys_fail("clock_gettime");
6736
        goto success;
6737
#endif
6738
    }
6739
    /* EINVAL emulates clock_gettime behavior when clock_id is invalid. */
6740
    errno = EINVAL;
6741
    rb_sys_fail(0);
6742

  
6743
  success:
6744
    if (unit == ID2SYM(rb_intern("nanoseconds"))) {
6745
        factor = 1000000000;
6746
        goto return_integer;
6747
    }
6748
    else if (unit == ID2SYM(rb_intern("microseconds"))) {
6749
        factor = 1000000;
6750
        goto return_integer;
6751
    }
6752
    else if (unit == ID2SYM(rb_intern("milliseconds"))) {
6753
        factor = 1000;
6754
        goto return_integer;
6755
    }
6756
    else if (unit == ID2SYM(rb_intern("float_microseconds"))) {
6757
        factor = 1000000;
6758
        goto return_float;
6759
    }
6760
    else if (unit == ID2SYM(rb_intern("float_milliseconds"))) {
6761
        factor = 1000;
6762
        goto return_float;
6763
    }
6764
    else if (NIL_P(unit) || unit == ID2SYM(rb_intern("float_seconds"))) {
6765
        factor = 1;
6766
        goto return_float;
6767
    }
6768
    else {
6769
        rb_raise(rb_eArgError, "unexpected unit: %"PRIsVALUE, unit);
6770
    }
6771

  
6772
  return_float:
6773
    return DBL2NUM((ts.tv_sec + 1e-9 * (double)ts.tv_nsec) / factor);
6774

  
6775
  return_integer:
6776
#if defined(HAVE_LONG_LONG)
6777
    if (!MUL_OVERFLOW_SIGNED_INTEGER_P(factor, (LONG_LONG)ts.tv_sec,
6778
                LLONG_MIN, LLONG_MAX-(factor-1))) {
6779
        return LL2NUM(ts.tv_nsec/(1000000000/factor) + factor * (LONG_LONG)ts.tv_sec);
6780
    }
6781
#endif
6782
    return rb_funcall(LONG2FIX(ts.tv_nsec/(1000000000/factor)), '+', 1,
6783
            rb_funcall(LONG2FIX(factor), '*', 1, TIMET2NUM(ts.tv_sec)));
6784
}
6785

  
6630 6786
VALUE rb_mProcess;
6631 6787
VALUE rb_mProcUID;
6632 6788
VALUE rb_mProcGID;
......
6885 7041

  
6886 7042
    rb_define_module_function(rb_mProcess, "times", rb_proc_times, 0);
6887 7043

  
7044
#ifdef CLOCK_REALTIME
7045
    rb_define_const(rb_mProcess, "CLOCK_REALTIME", CLOCKID2NUM(CLOCK_REALTIME));
7046
#elif defined(RUBY_POSIX_GETTIMEOFDAY_CLOCK_REALTIME)
7047
    rb_define_const(rb_mProcess, "CLOCK_REALTIME", RUBY_POSIX_GETTIMEOFDAY_CLOCK_REALTIME);
7048
#endif
7049
#ifdef CLOCK_MONOTONIC
7050
    rb_define_const(rb_mProcess, "CLOCK_MONOTONIC", CLOCKID2NUM(CLOCK_MONOTONIC));
7051
#endif
7052
#ifdef CLOCK_PROCESS_CPUTIME_ID
7053
    rb_define_const(rb_mProcess, "CLOCK_PROCESS_CPUTIME_ID", CLOCKID2NUM(CLOCK_PROCESS_CPUTIME_ID));
7054
#endif
7055
#ifdef CLOCK_THREAD_CPUTIME_ID
7056
    rb_define_const(rb_mProcess, "CLOCK_THREAD_CPUTIME_ID", CLOCKID2NUM(CLOCK_THREAD_CPUTIME_ID));
7057
#endif
7058
#ifdef CLOCK_VIRTUAL
7059
    rb_define_const(rb_mProcess, "CLOCK_VIRTUAL", CLOCKID2NUM(CLOCK_VIRTUAL));
7060
#endif
7061
#ifdef CLOCK_PROF
7062
    rb_define_const(rb_mProcess, "CLOCK_PROF", CLOCKID2NUM(CLOCK_PROF));
7063
#endif
7064
#ifdef CLOCK_REALTIME_FAST
7065
    rb_define_const(rb_mProcess, "CLOCK_REALTIME_FAST", CLOCKID2NUM(CLOCK_REALTIME_FAST));
7066
#endif
7067
#ifdef CLOCK_REALTIME_PRECISE
7068
    rb_define_const(rb_mProcess, "CLOCK_REALTIME_PRECISE", CLOCKID2NUM(CLOCK_REALTIME_PRECISE));
7069
#endif
7070
#ifdef CLOCK_MONOTONIC_FAST
7071
    rb_define_const(rb_mProcess, "CLOCK_MONOTONIC_FAST", CLOCKID2NUM(CLOCK_MONOTONIC_FAST));
7072
#endif
7073
#ifdef CLOCK_MONOTONIC_PRECISE
7074
    rb_define_const(rb_mProcess, "CLOCK_MONOTONIC_PRECISE", CLOCKID2NUM(CLOCK_MONOTONIC_PRECISE));
7075
#endif
7076
#ifdef CLOCK_MONOTONIC_RAW
7077
    rb_define_const(rb_mProcess, "CLOCK_MONOTONIC_RAW", CLOCKID2NUM(CLOCK_MONOTONIC_RAW));
7078
#endif
7079
#ifdef CLOCK_UPTIME
7080
    rb_define_const(rb_mProcess, "CLOCK_UPTIME", CLOCKID2NUM(CLOCK_UPTIME));
7081
#endif
7082
#ifdef CLOCK_UPTIME_FAST
7083
    rb_define_const(rb_mProcess, "CLOCK_UPTIME_FAST", CLOCKID2NUM(CLOCK_UPTIME_FAST));
7084
#endif
7085
#ifdef CLOCK_UPTIME_PRECISE
7086
    rb_define_const(rb_mProcess, "CLOCK_UPTIME_PRECISE", CLOCKID2NUM(CLOCK_UPTIME_PRECISE));
7087
#endif
7088
#ifdef CLOCK_SECOND
7089
    rb_define_const(rb_mProcess, "CLOCK_SECOND", CLOCKID2NUM(CLOCK_SECOND));
7090
#endif
7091
    rb_define_module_function(rb_mProcess, "clock_gettime", rb_clock_gettime, -1);
7092

  
6888 7093
#if defined(HAVE_TIMES) || defined(_WIN32)
6889 7094
    rb_cProcessTms = rb_struct_define("Tms", "utime", "stime", "cutime", "cstime", NULL);
6890 7095
#endif