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 <time.h>
8 : #include <errno.h>
9 :
10 : #include "native_client/src/shared/platform/nacl_clock.h"
11 :
12 : #include "native_client/src/include/nacl_macros.h"
13 : #include "native_client/src/shared/platform/nacl_host_desc.h"
14 : #include "native_client/src/shared/platform/nacl_log.h"
15 : #include "native_client/src/shared/platform/nacl_sync.h"
16 : #include "native_client/src/shared/platform/nacl_sync_checked.h"
17 : #include "native_client/src/shared/platform/nacl_time.h"
18 : #include "native_client/src/shared/platform/win/nacl_time_types.h"
19 : #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
20 :
21 : /*
22 : * Windows does not implement POSIX.1-2001, so we must emulate the
23 : * clock_get{res,time} functions using Windows primitives.
24 : *
25 : * We assume that NaClTimeInit has been invoked. This is true w/
26 : * NaClPlatformInit.
27 : */
28 :
29 : #define MAGIC_OFFSET (0xd00f05) /* random offset so monotonic != real */
30 :
31 : static int g_NaClClock_is_initialized = 0;
32 : struct NaClMutex g_nacl_clock_mu;
33 : struct nacl_abi_timeval g_nacl_clock_tv;
34 :
35 15 : int NaClClockInit(void) {
36 15 : if (0 != NaClGetTimeOfDay(&g_nacl_clock_tv)) {
37 0 : return 0;
38 : }
39 15 : g_NaClClock_is_initialized = NaClMutexCtor(&g_nacl_clock_mu);
40 15 : return g_NaClClock_is_initialized;
41 15 : }
42 :
43 11 : void NaClClockFini(void) {
44 11 : NaClMutexDtor(&g_nacl_clock_mu);
45 11 : }
46 :
47 : int NaClClockGetRes(nacl_clockid_t clk_id,
48 0 : struct nacl_abi_timespec *res) {
49 0 : int rv = -NACL_ABI_EINVAL;
50 : uint64_t t_resolution_ns;
51 :
52 0 : if (!g_NaClClock_is_initialized) {
53 : NaClLog(LOG_FATAL,
54 0 : "NaClClockGetRes invoked without successful NaClClockInit\n");
55 : }
56 0 : switch (clk_id) {
57 : case NACL_CLOCK_REALTIME:
58 : case NACL_CLOCK_MONOTONIC:
59 : case NACL_CLOCK_PROCESS_CPUTIME_ID:
60 : case NACL_CLOCK_THREAD_CPUTIME_ID:
61 0 : t_resolution_ns = NaClTimerResolutionNanoseconds();
62 0 : res->tv_sec = (nacl_abi_time_t) (t_resolution_ns / NACL_NANOS_PER_UNIT);
63 0 : res->tv_nsec = (int32_t) (t_resolution_ns % NACL_NANOS_PER_UNIT);
64 : /*
65 : * very surprised if res->tv_sec != 0, since that would be a
66 : * rather low resolution timer!
67 : */
68 0 : rv = 0;
69 : break;
70 : }
71 :
72 0 : return rv;
73 0 : }
74 :
75 0 : static INLINE uint64_t FiletimeToUint64(FILETIME ft) {
76 0 : return (((uint64_t) ft.dwHighDateTime << 32) | ft.dwLowDateTime);
77 0 : }
78 :
79 : int NaClClockGetTime(nacl_clockid_t clk_id,
80 1 : struct nacl_abi_timespec *tp) {
81 1 : int rv = -NACL_ABI_EINVAL;
82 : struct nacl_abi_timeval tv;
83 : uint64_t t_mono_prev_us;
84 : uint64_t t_mono_cur_us;
85 : FILETIME t_creat;
86 : FILETIME t_exit;
87 : FILETIME t_kernel;
88 : FILETIME t_user;
89 : uint64_t tick_ns;
90 :
91 1 : if (!g_NaClClock_is_initialized) {
92 : NaClLog(LOG_FATAL,
93 0 : "NaClClockGetTime invoked without successful NaClClockInit\n");
94 : }
95 1 : switch (clk_id) {
96 : case NACL_CLOCK_REALTIME:
97 1 : rv = NaClGetTimeOfDay(&tv);
98 1 : if (0 == rv) {
99 1 : tp->tv_sec = tv.nacl_abi_tv_sec;
100 1 : tp->tv_nsec = tv.nacl_abi_tv_usec * 1000;
101 : }
102 1 : break;
103 : case NACL_CLOCK_MONOTONIC:
104 : /*
105 : * Get real time, compare with last monotonic time. If later
106 : * than last monotonic time, set last monotonic time to real
107 : * time timestamp; otherwise we leave last monotonoic time
108 : * alone. In either case, return last monotonic time.
109 : *
110 : * The interpretation used here is that "monotonic" means
111 : * monotonic non-decreasing, as opposed to monotonic increasing.
112 : * We don't assume that GetTimeOfDay only yields high-order bits
113 : * so we can replace low-order bits of the time value with a
114 : * counter to fake monotonicity. We are dangerously close to
115 : * the resolution limit of 1ns imposed by the timespec structure
116 : * already -- it's only a few Moore's Law generations away where
117 : * we may have to return the same time stamp for repeated calls
118 : * to clock_gettime (if CPU frequency clock is continued to be
119 : * used to drive performance counters; RTDSC is moving to a
120 : * fixed rate [constant_tsc], fortunately).
121 : */
122 1 : rv = NaClGetTimeOfDay(&tv);
123 1 : if (0 == rv) {
124 1 : NaClXMutexLock(&g_nacl_clock_mu);
125 : t_mono_prev_us = g_nacl_clock_tv.nacl_abi_tv_sec * 1000000
126 1 : + g_nacl_clock_tv.nacl_abi_tv_usec;
127 : t_mono_cur_us = tv.nacl_abi_tv_sec * 1000000
128 1 : + tv.nacl_abi_tv_usec;
129 1 : if (t_mono_cur_us > t_mono_prev_us) {
130 1 : g_nacl_clock_tv = tv;
131 : }
132 1 : tp->tv_sec = g_nacl_clock_tv.nacl_abi_tv_sec + MAGIC_OFFSET;
133 1 : tp->tv_nsec = g_nacl_clock_tv.nacl_abi_tv_usec * 1000;
134 1 : NaClXMutexUnlock(&g_nacl_clock_mu);
135 1 : rv = 0;
136 : }
137 1 : break;
138 : case NACL_CLOCK_PROCESS_CPUTIME_ID:
139 : if (GetProcessTimes(GetCurrentProcess(),
140 0 : &t_creat, &t_exit, &t_kernel, &t_user)) {
141 0 : tick_ns = (FiletimeToUint64(t_kernel) + FiletimeToUint64(t_user)) * 100;
142 0 : tp->tv_sec = tick_ns / NACL_NANOS_PER_UNIT;
143 0 : tp->tv_nsec = tick_ns % NACL_NANOS_PER_UNIT;
144 0 : rv = 0;
145 : }
146 0 : break;
147 : case NACL_CLOCK_THREAD_CPUTIME_ID:
148 : if (GetThreadTimes(GetCurrentThread(),
149 0 : &t_creat, &t_exit, &t_kernel, &t_user)) {
150 0 : tick_ns = (FiletimeToUint64(t_kernel) + FiletimeToUint64(t_user)) * 100;
151 0 : tp->tv_sec = tick_ns / NACL_NANOS_PER_UNIT;
152 0 : tp->tv_nsec = tick_ns % NACL_NANOS_PER_UNIT;
153 0 : rv = 0;
154 : }
155 : break;
156 : }
157 1 : return rv;
158 1 : }
|