chrono.cpp revision 302408
1//===------------------------- chrono.cpp ---------------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is dual licensed under the MIT and the University of Illinois Open
6// Source Licenses. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "chrono"
11#include "cerrno"        // errno
12#include "system_error"  // __throw_system_error
13#include <time.h>        // clock_gettime, CLOCK_MONOTONIC and CLOCK_REALTIME
14
15#if !defined(CLOCK_REALTIME)
16#include <sys/time.h>        // for gettimeofday and timeval
17#endif
18
19#if !defined(_LIBCPP_HAS_NO_MONOTONIC_CLOCK) && !defined(CLOCK_MONOTONIC)
20#if __APPLE__
21#include <mach/mach_time.h>  // mach_absolute_time, mach_timebase_info_data_t
22#else
23#error "Monotonic clock not implemented"
24#endif
25#endif
26
27_LIBCPP_BEGIN_NAMESPACE_STD
28
29namespace chrono
30{
31
32// system_clock
33
34const bool system_clock::is_steady;
35
36system_clock::time_point
37system_clock::now() _NOEXCEPT
38{
39#ifdef CLOCK_REALTIME
40    struct timespec tp;
41    if (0 != clock_gettime(CLOCK_REALTIME, &tp))
42        __throw_system_error(errno, "clock_gettime(CLOCK_REALTIME) failed");
43    return time_point(seconds(tp.tv_sec) + microseconds(tp.tv_nsec / 1000));
44#else  // !CLOCK_REALTIME
45    timeval tv;
46    gettimeofday(&tv, 0);
47    return time_point(seconds(tv.tv_sec) + microseconds(tv.tv_usec));
48#endif  // CLOCK_REALTIME
49}
50
51time_t
52system_clock::to_time_t(const time_point& t) _NOEXCEPT
53{
54    return time_t(duration_cast<seconds>(t.time_since_epoch()).count());
55}
56
57system_clock::time_point
58system_clock::from_time_t(time_t t) _NOEXCEPT
59{
60    return system_clock::time_point(seconds(t));
61}
62
63#ifndef _LIBCPP_HAS_NO_MONOTONIC_CLOCK
64// steady_clock
65//
66// Warning:  If this is not truly steady, then it is non-conforming.  It is
67//  better for it to not exist and have the rest of libc++ use system_clock
68//  instead.
69
70const bool steady_clock::is_steady;
71
72#ifdef CLOCK_MONOTONIC
73
74steady_clock::time_point
75steady_clock::now() _NOEXCEPT
76{
77    struct timespec tp;
78    if (0 != clock_gettime(CLOCK_MONOTONIC, &tp))
79        __throw_system_error(errno, "clock_gettime(CLOCK_MONOTONIC) failed");
80    return time_point(seconds(tp.tv_sec) + nanoseconds(tp.tv_nsec));
81}
82
83#elif defined(__APPLE__)
84
85//   mach_absolute_time() * MachInfo.numer / MachInfo.denom is the number of
86//   nanoseconds since the computer booted up.  MachInfo.numer and MachInfo.denom
87//   are run time constants supplied by the OS.  This clock has no relationship
88//   to the Gregorian calendar.  It's main use is as a high resolution timer.
89
90// MachInfo.numer / MachInfo.denom is often 1 on the latest equipment.  Specialize
91//   for that case as an optimization.
92
93#pragma GCC visibility push(hidden)
94
95static
96steady_clock::rep
97steady_simplified()
98{
99    return static_cast<steady_clock::rep>(mach_absolute_time());
100}
101
102static
103double
104compute_steady_factor()
105{
106    mach_timebase_info_data_t MachInfo;
107    mach_timebase_info(&MachInfo);
108    return static_cast<double>(MachInfo.numer) / MachInfo.denom;
109}
110
111static
112steady_clock::rep
113steady_full()
114{
115    static const double factor = compute_steady_factor();
116    return static_cast<steady_clock::rep>(mach_absolute_time() * factor);
117}
118
119typedef steady_clock::rep (*FP)();
120
121static
122FP
123init_steady_clock()
124{
125    mach_timebase_info_data_t MachInfo;
126    mach_timebase_info(&MachInfo);
127    if (MachInfo.numer == MachInfo.denom)
128        return &steady_simplified;
129    return &steady_full;
130}
131
132#pragma GCC visibility pop
133
134steady_clock::time_point
135steady_clock::now() _NOEXCEPT
136{
137    static FP fp = init_steady_clock();
138    return time_point(duration(fp()));
139}
140
141#else
142#error "Monotonic clock not implemented"
143#endif
144
145#endif // !_LIBCPP_HAS_NO_MONOTONIC_CLOCK
146
147}
148
149_LIBCPP_END_NAMESPACE_STD
150