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/include/portability.h"
11 : #include "native_client/src/shared/platform/nacl_host_desc.h"
12 : #include "native_client/src/shared/platform/nacl_log.h"
13 : #include "native_client/src/shared/platform/nacl_time.h"
14 : #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
15 :
16 : /*
17 : * OSX does not include POSIX.1-2011 functions, so we emulate using
18 : * Mach calls.
19 : */
20 : #include <mach/mach.h>
21 : #include <mach/mach_time.h>
22 : #include <mach/task.h>
23 : #include <mach/task_info.h>
24 : #include <mach/thread_info.h>
25 : #include <pthread.h>
26 :
27 : static int g_NaClClock_is_initialized = 0;
28 : static mach_timebase_info_data_t g_NaCl_time_base_info;
29 :
30 : int NaClClockInit(void) {
31 331 : g_NaClClock_is_initialized = (mach_timebase_info(&g_NaCl_time_base_info)
32 : == KERN_SUCCESS);
33 :
34 331 : return g_NaClClock_is_initialized;
35 : }
36 :
37 53 : void NaClClockFini(void) {}
38 :
39 8 : int NaClClockGetRes(nacl_clockid_t clk_id,
40 8 : struct nacl_abi_timespec *res) {
41 8 : int rv = -NACL_ABI_EINVAL;
42 8 : uint64_t t_resolution_ns;
43 8 : struct timespec host_res;
44 :
45 8 : if (!g_NaClClock_is_initialized) {
46 0 : NaClLog(LOG_FATAL,
47 : "NaClClockGetRes invoked without successful NaClClockInit\n");
48 0 : }
49 16 : switch (clk_id) {
50 : case NACL_CLOCK_REALTIME:
51 2 : t_resolution_ns = NaClTimerResolutionNanoseconds();
52 2 : host_res.tv_sec = (time_t) (t_resolution_ns / NACL_NANOS_PER_UNIT);
53 2 : host_res.tv_nsec = (long) (t_resolution_ns % NACL_NANOS_PER_UNIT);
54 2 : rv = 0;
55 2 : break;
56 : case NACL_CLOCK_MONOTONIC:
57 2 : host_res.tv_sec = 0;
58 : /* round up */
59 2 : host_res.tv_nsec = ((g_NaCl_time_base_info.numer
60 : + g_NaCl_time_base_info.denom - 1)
61 : / g_NaCl_time_base_info.denom);
62 2 : rv = 0;
63 2 : break;
64 : case NACL_CLOCK_PROCESS_CPUTIME_ID:
65 : case NACL_CLOCK_THREAD_CPUTIME_ID:
66 4 : host_res.tv_sec = 0;
67 4 : host_res.tv_nsec = 1;
68 4 : rv = 0;
69 4 : break;
70 : }
71 8 : if (0 == rv) {
72 8 : res->tv_sec = host_res.tv_sec;
73 8 : res->tv_nsec = host_res.tv_nsec;
74 8 : }
75 8 : return rv;
76 : }
77 :
78 6337431 : int NaClClockGetTime(nacl_clockid_t clk_id,
79 6337431 : struct nacl_abi_timespec *tp) {
80 6337431 : int rv = -NACL_ABI_EINVAL;
81 6337431 : struct nacl_abi_timeval tv;
82 6337431 : uint64_t tick_cur;
83 6337431 : uint64_t tick_ns;
84 6337431 : struct task_absolutetime_info absolutetime_info;
85 6337431 : thread_basic_info_data_t _basic_info;
86 6337431 : thread_basic_info_t basic_info = &_basic_info;
87 6337431 : mach_msg_type_number_t count;
88 :
89 6337431 : if (!g_NaClClock_is_initialized) {
90 0 : NaClLog(LOG_FATAL,
91 : "NaClClockGetTime invoked without successful NaClClockInit\n");
92 0 : }
93 12674862 : switch (clk_id) {
94 : case NACL_CLOCK_REALTIME:
95 9 : rv = NaClGetTimeOfDay(&tv);
96 9 : if (0 == rv) {
97 9 : tp->tv_sec = tv.nacl_abi_tv_sec;
98 9 : tp->tv_nsec = tv.nacl_abi_tv_usec * 1000;
99 9 : }
100 9 : break;
101 : case NACL_CLOCK_MONOTONIC:
102 6337396 : tick_cur = mach_absolute_time();
103 : /*
104 : * mach_absolute_time() returns ticks since boot, with enough
105 : * bits for several hundred years if the ticks occur at one per
106 : * nanosecond. numer/denom gives ns/tick, and the scaling
107 : * arithmetic should not result in over/underflows.
108 : */
109 6337396 : tick_ns = (tick_cur * g_NaCl_time_base_info.numer
110 : / g_NaCl_time_base_info.denom);
111 6337396 : tp->tv_sec = tick_ns / 1000000000;
112 6337396 : tp->tv_nsec = tick_ns % 1000000000;
113 6337396 : rv = 0;
114 6337396 : break;
115 : case NACL_CLOCK_PROCESS_CPUTIME_ID:
116 13 : count = TASK_ABSOLUTETIME_INFO_COUNT;
117 :
118 13 : if (KERN_SUCCESS != task_info(mach_task_self(),
119 : TASK_ABSOLUTETIME_INFO,
120 : (task_info_t) &absolutetime_info,
121 : &count)) {
122 0 : break;
123 : }
124 13 : tp->tv_sec = ((absolutetime_info.total_user
125 : + absolutetime_info.total_system)
126 : / NACL_NANOS_PER_UNIT);
127 13 : tp->tv_nsec = ((absolutetime_info.total_user
128 : + absolutetime_info.total_system)
129 : % NACL_NANOS_PER_UNIT);
130 13 : rv = 0;
131 13 : break;
132 : case NACL_CLOCK_THREAD_CPUTIME_ID:
133 13 : count = THREAD_BASIC_INFO_COUNT;
134 :
135 : /*
136 : * Don't use mach_thread_self() because it requires a separate
137 : * mach_port_deallocate() system call to release it. Instead, rely on
138 : * pthread's cached copy of the port.
139 : */
140 13 : if (KERN_SUCCESS == thread_info(pthread_mach_thread_np(pthread_self()),
141 : THREAD_BASIC_INFO,
142 : (thread_info_t) basic_info,
143 : &count)) {
144 13 : tick_ns = ((basic_info->user_time.microseconds
145 : + basic_info->system_time.microseconds)
146 : * NACL_NANOS_PER_MICRO);
147 13 : tp->tv_sec = (basic_info->user_time.seconds
148 : + basic_info->system_time.seconds
149 : + (tick_ns / NACL_NANOS_PER_UNIT));
150 13 : tp->tv_nsec = tick_ns % NACL_NANOS_PER_UNIT;
151 13 : rv = 0;
152 13 : }
153 13 : break;
154 : }
155 6337431 : return rv;
156 : }
|