1 : /*
2 : * Copyright (c) 2012 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can be
4 : * found in the LICENSE file.
5 : */
6 :
7 : #include "native_client/src/shared/platform/nacl_clock.h"
8 :
9 : #include "native_client/src/include/nacl_macros.h"
10 : #include "native_client/src/shared/platform/nacl_host_desc.h"
11 : #include "native_client/src/shared/platform/nacl_log.h"
12 : #include "native_client/src/shared/platform/nacl_time.h"
13 : #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
14 :
15 : /*
16 : * OSX does not include POSIX.1-2011 functions, so we emulate using
17 : * Mach calls.
18 : */
19 : #include <mach/mach_time.h>
20 :
21 : static int g_NaClClock_is_initialized = 0;
22 : static mach_timebase_info_data_t g_NaCl_time_base_info;
23 :
24 43 : int NaClClockInit(void) {
25 43 : g_NaClClock_is_initialized = (mach_timebase_info(&g_NaCl_time_base_info)
26 : == KERN_SUCCESS);
27 :
28 43 : return g_NaClClock_is_initialized;
29 : }
30 :
31 29 : void NaClClockFini(void) {}
32 :
33 : int NaClClockGetRes(nacl_clockid_t clk_id,
34 0 : struct nacl_abi_timespec *res) {
35 0 : int rv = -NACL_ABI_EINVAL;
36 : uint64_t t_resolution_ns;
37 : struct timespec host_res;
38 :
39 0 : if (!g_NaClClock_is_initialized) {
40 0 : NaClLog(LOG_FATAL,
41 : "NaClClockGetRes invoked without successful NaClClockInit\n");
42 : }
43 0 : switch (clk_id) {
44 : case NACL_CLOCK_REALTIME:
45 0 : t_resolution_ns = NaClTimerResolutionNanoseconds();
46 0 : host_res.tv_sec = (time_t) (t_resolution_ns / NACL_NANOS_PER_UNIT);
47 0 : host_res.tv_nsec = (long) (t_resolution_ns % NACL_NANOS_PER_UNIT);
48 0 : rv = 0;
49 0 : break;
50 : case NACL_CLOCK_MONOTONIC:
51 0 : host_res.tv_sec = 0;
52 : /* round up */
53 0 : host_res.tv_nsec = ((g_NaCl_time_base_info.numer
54 : + g_NaCl_time_base_info.denom - 1)
55 : / g_NaCl_time_base_info.denom);
56 0 : rv = 0;
57 0 : break;
58 : case NACL_CLOCK_PROCESS_CPUTIME_ID:
59 : case NACL_CLOCK_THREAD_CPUTIME_ID:
60 0 : rv = -NACL_ABI_EINVAL;
61 : break;
62 : }
63 0 : if (0 == rv) {
64 0 : res->tv_sec = host_res.tv_sec;
65 0 : res->tv_nsec = host_res.tv_nsec;
66 : }
67 0 : return rv;
68 : }
69 :
70 : int NaClClockGetTime(nacl_clockid_t clk_id,
71 3 : struct nacl_abi_timespec *tp) {
72 3 : int rv = -NACL_ABI_EINVAL;
73 : struct nacl_abi_timeval tv;
74 : uint64_t tick_cur;
75 : uint64_t tick_ns;
76 :
77 3 : if (!g_NaClClock_is_initialized) {
78 0 : NaClLog(LOG_FATAL,
79 : "NaClClockGetTime invoked without successful NaClClockInit\n");
80 : }
81 3 : switch (clk_id) {
82 : case NACL_CLOCK_REALTIME:
83 1 : rv = NaClGetTimeOfDay(&tv);
84 1 : if (0 == rv) {
85 1 : tp->tv_sec = tv.nacl_abi_tv_sec;
86 1 : tp->tv_nsec = tv.nacl_abi_tv_usec * 1000;
87 : }
88 1 : break;
89 : case NACL_CLOCK_MONOTONIC:
90 2 : tick_cur = mach_absolute_time();
91 : /*
92 : * mach_absolute_time() returns ticks since boot, with enough
93 : * bits for several hundred years if the ticks occur at one per
94 : * nanosecond. numer/denom gives ns/tick, and the scaling
95 : * arithmetic should not result in over/underflows.
96 : */
97 2 : tick_ns = (tick_cur * g_NaCl_time_base_info.numer
98 : / g_NaCl_time_base_info.denom);
99 2 : tp->tv_sec = tick_ns / 1000000000;
100 2 : tp->tv_nsec = tick_ns % 1000000000;
101 2 : rv = 0;
102 2 : break;
103 : case NACL_CLOCK_PROCESS_CPUTIME_ID:
104 : case NACL_CLOCK_THREAD_CPUTIME_ID:
105 0 : rv = -NACL_ABI_EINVAL;
106 : break;
107 : }
108 3 : return rv;
109 : }
|