Line data Source code
1 : /**
2 : * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 : * SPDX-License-Identifier: Apache-2.0.
4 : */
5 :
6 : #include <aws/common/clock.h>
7 :
8 : #include <time.h>
9 :
10 : static const uint64_t NS_PER_SEC = 1000000000;
11 :
12 : #if defined(CLOCK_MONOTONIC_RAW)
13 0 : # define HIGH_RES_CLOCK CLOCK_MONOTONIC_RAW
14 : #else
15 : # define HIGH_RES_CLOCK CLOCK_MONOTONIC
16 : #endif
17 :
18 : /* This entire compilation branch has two goals. First, prior to OSX Sierra, clock_gettime does not exist on OSX, so we
19 : * already need to branch on that. Second, even if we compile on a newer OSX, which we will always do for bindings (e.g.
20 : * python, dotnet, java etc...), we have to worry about the same lib being loaded on an older version, and thus, we'd
21 : * get linker errors at runtime. To avoid this, we do a dynamic load
22 : * to keep the function out of linker tables and only use the symbol if the current running process has access to the
23 : * function. */
24 : #if defined(__MACH__)
25 : # include <AvailabilityMacros.h>
26 : # include <aws/common/thread.h>
27 : # include <dlfcn.h>
28 : # include <sys/time.h>
29 :
30 : static int s_legacy_get_time(uint64_t *timestamp) {
31 : struct timeval tv;
32 : int ret_val = gettimeofday(&tv, NULL);
33 :
34 : if (ret_val) {
35 : return aws_raise_error(AWS_ERROR_CLOCK_FAILURE);
36 : }
37 :
38 : uint64_t secs = (uint64_t)tv.tv_sec;
39 : uint64_t u_secs = (uint64_t)tv.tv_usec;
40 : *timestamp = (secs * NS_PER_SEC) + (u_secs * 1000);
41 : return AWS_OP_SUCCESS;
42 : }
43 :
44 : # if MAC_OS_X_VERSION_MAX_ALLOWED >= 101200
45 : static aws_thread_once s_thread_once_flag = AWS_THREAD_ONCE_STATIC_INIT;
46 : static int (*s_gettime_fn)(clockid_t __clock_id, struct timespec *__tp) = NULL;
47 :
48 : static void s_do_osx_loads(void *user_data) {
49 : (void)user_data;
50 : s_gettime_fn = (int (*)(clockid_t __clock_id, struct timespec * __tp)) dlsym(RTLD_DEFAULT, "clock_gettime");
51 : }
52 :
53 : int aws_high_res_clock_get_ticks(uint64_t *timestamp) {
54 : aws_thread_call_once(&s_thread_once_flag, s_do_osx_loads, NULL);
55 : int ret_val = 0;
56 :
57 : if (s_gettime_fn) {
58 : struct timespec ts;
59 : ret_val = s_gettime_fn(HIGH_RES_CLOCK, &ts);
60 :
61 : if (ret_val) {
62 : return aws_raise_error(AWS_ERROR_CLOCK_FAILURE);
63 : }
64 :
65 : uint64_t secs = (uint64_t)ts.tv_sec;
66 : uint64_t n_secs = (uint64_t)ts.tv_nsec;
67 : *timestamp = (secs * NS_PER_SEC) + n_secs;
68 : return AWS_OP_SUCCESS;
69 : }
70 :
71 : return s_legacy_get_time(timestamp);
72 : }
73 :
74 : int aws_sys_clock_get_ticks(uint64_t *timestamp) {
75 : aws_thread_call_once(&s_thread_once_flag, s_do_osx_loads, NULL);
76 : int ret_val = 0;
77 :
78 : if (s_gettime_fn) {
79 : struct timespec ts;
80 : ret_val = s_gettime_fn(CLOCK_REALTIME, &ts);
81 : if (ret_val) {
82 : return aws_raise_error(AWS_ERROR_CLOCK_FAILURE);
83 : }
84 :
85 : uint64_t secs = (uint64_t)ts.tv_sec;
86 : uint64_t n_secs = (uint64_t)ts.tv_nsec;
87 : *timestamp = (secs * NS_PER_SEC) + n_secs;
88 : return AWS_OP_SUCCESS;
89 : }
90 : return s_legacy_get_time(timestamp);
91 : }
92 : # else
93 : int aws_high_res_clock_get_ticks(uint64_t *timestamp) {
94 : return s_legacy_get_time(timestamp);
95 : }
96 :
97 : int aws_sys_clock_get_ticks(uint64_t *timestamp) {
98 : return s_legacy_get_time(timestamp);
99 : }
100 :
101 : # endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 101200 */
102 : /* Everywhere else, just link clock_gettime in directly */
103 : #else
104 0 : int aws_high_res_clock_get_ticks(uint64_t *timestamp) {
105 0 : int ret_val = 0;
106 0 :
107 0 : struct timespec ts;
108 0 :
109 0 : ret_val = clock_gettime(HIGH_RES_CLOCK, &ts);
110 0 :
111 0 : if (ret_val) {
112 0 : return aws_raise_error(AWS_ERROR_CLOCK_FAILURE);
113 0 : }
114 0 :
115 0 : uint64_t secs = (uint64_t)ts.tv_sec;
116 0 : uint64_t n_secs = (uint64_t)ts.tv_nsec;
117 0 : *timestamp = (secs * NS_PER_SEC) + n_secs;
118 0 : return AWS_OP_SUCCESS;
119 0 : }
120 :
121 0 : int aws_sys_clock_get_ticks(uint64_t *timestamp) {
122 0 : int ret_val = 0;
123 0 :
124 0 : struct timespec ts;
125 0 : ret_val = clock_gettime(CLOCK_REALTIME, &ts);
126 0 : if (ret_val) {
127 0 : return aws_raise_error(AWS_ERROR_CLOCK_FAILURE);
128 0 : }
129 0 :
130 0 : uint64_t secs = (uint64_t)ts.tv_sec;
131 0 : uint64_t n_secs = (uint64_t)ts.tv_nsec;
132 0 : *timestamp = (secs * NS_PER_SEC) + n_secs;
133 0 :
134 0 : return AWS_OP_SUCCESS;
135 0 : }
136 : #endif /* defined(__MACH__) */
|