1 | // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 | // for details. All rights reserved. Use of this source code is governed by a |
3 | // BSD-style license that can be found in the LICENSE file. |
4 | |
5 | #include "vm/globals.h" |
6 | #if defined(HOST_OS_MACOS) |
7 | |
8 | #include "vm/os.h" |
9 | |
10 | #include <errno.h> // NOLINT |
11 | #include <limits.h> // NOLINT |
12 | #include <mach/clock.h> // NOLINT |
13 | #include <mach/mach.h> // NOLINT |
14 | #include <mach/mach_time.h> // NOLINT |
15 | #include <sys/resource.h> // NOLINT |
16 | #include <sys/time.h> // NOLINT |
17 | #include <unistd.h> // NOLINT |
18 | #if HOST_OS_IOS |
19 | #include <syslog.h> // NOLINT |
20 | #endif |
21 | |
22 | #include "platform/utils.h" |
23 | #include "vm/isolate.h" |
24 | #include "vm/zone.h" |
25 | |
26 | namespace dart { |
27 | |
28 | const char* OS::Name() { |
29 | #if HOST_OS_IOS |
30 | return "ios" ; |
31 | #else |
32 | return "macos" ; |
33 | #endif |
34 | } |
35 | |
36 | intptr_t OS::ProcessId() { |
37 | return static_cast<intptr_t>(getpid()); |
38 | } |
39 | |
40 | static bool LocalTime(int64_t seconds_since_epoch, tm* tm_result) { |
41 | time_t seconds = static_cast<time_t>(seconds_since_epoch); |
42 | if (seconds != seconds_since_epoch) return false; |
43 | struct tm* error_code = localtime_r(&seconds, tm_result); |
44 | return error_code != NULL; |
45 | } |
46 | |
47 | const char* OS::GetTimeZoneName(int64_t seconds_since_epoch) { |
48 | tm decomposed; |
49 | bool succeeded = LocalTime(seconds_since_epoch, &decomposed); |
50 | // If unsuccessful, return an empty string like V8 does. |
51 | return (succeeded && (decomposed.tm_zone != NULL)) ? decomposed.tm_zone : "" ; |
52 | } |
53 | |
54 | int OS::GetTimeZoneOffsetInSeconds(int64_t seconds_since_epoch) { |
55 | tm decomposed; |
56 | bool succeeded = LocalTime(seconds_since_epoch, &decomposed); |
57 | // Even if the offset was 24 hours it would still easily fit into 32 bits. |
58 | // If unsuccessful, return zero like V8 does. |
59 | return succeeded ? static_cast<int>(decomposed.tm_gmtoff) : 0; |
60 | } |
61 | |
62 | int OS::GetLocalTimeZoneAdjustmentInSeconds() { |
63 | // TODO(floitsch): avoid excessive calls to tzset? |
64 | tzset(); |
65 | // Even if the offset was 24 hours it would still easily fit into 32 bits. |
66 | // Note that Unix and Dart disagree on the sign. |
67 | return static_cast<int>(-timezone); |
68 | } |
69 | |
70 | int64_t OS::GetCurrentTimeMillis() { |
71 | return GetCurrentTimeMicros() / 1000; |
72 | } |
73 | |
74 | int64_t OS::GetCurrentTimeMicros() { |
75 | // gettimeofday has microsecond resolution. |
76 | struct timeval tv; |
77 | if (gettimeofday(&tv, NULL) < 0) { |
78 | UNREACHABLE(); |
79 | return 0; |
80 | } |
81 | return (static_cast<int64_t>(tv.tv_sec) * 1000000) + tv.tv_usec; |
82 | } |
83 | |
84 | static mach_timebase_info_data_t timebase_info; |
85 | |
86 | int64_t OS::GetCurrentMonotonicTicks() { |
87 | if (timebase_info.denom == 0) { |
88 | kern_return_t kr = mach_timebase_info(&timebase_info); |
89 | ASSERT(KERN_SUCCESS == kr); |
90 | } |
91 | ASSERT(timebase_info.denom != 0); |
92 | // timebase_info converts absolute time tick units into nanoseconds. |
93 | int64_t result = mach_absolute_time(); |
94 | result *= timebase_info.numer; |
95 | result /= timebase_info.denom; |
96 | return result; |
97 | } |
98 | |
99 | int64_t OS::GetCurrentMonotonicFrequency() { |
100 | return kNanosecondsPerSecond; |
101 | } |
102 | |
103 | int64_t OS::GetCurrentMonotonicMicros() { |
104 | ASSERT(GetCurrentMonotonicFrequency() == kNanosecondsPerSecond); |
105 | return GetCurrentMonotonicTicks() / kNanosecondsPerMicrosecond; |
106 | } |
107 | |
108 | int64_t OS::GetCurrentThreadCPUMicros() { |
109 | #if HOST_OS_IOS |
110 | // Thread CPU time appears unreliable on iOS, sometimes incorrectly reporting |
111 | // no time elapsed. |
112 | return -1; |
113 | #else |
114 | mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT; |
115 | thread_basic_info_data_t info_data; |
116 | thread_basic_info_t info = &info_data; |
117 | mach_port_t thread_port = pthread_mach_thread_np(pthread_self()); |
118 | kern_return_t r = |
119 | thread_info(thread_port, THREAD_BASIC_INFO, (thread_info_t)info, &count); |
120 | ASSERT(r == KERN_SUCCESS); |
121 | int64_t thread_cpu_micros = |
122 | (info->system_time.seconds + info->user_time.seconds); |
123 | thread_cpu_micros *= kMicrosecondsPerSecond; |
124 | thread_cpu_micros += info->user_time.microseconds; |
125 | thread_cpu_micros += info->system_time.microseconds; |
126 | return thread_cpu_micros; |
127 | #endif |
128 | } |
129 | |
130 | int64_t OS::GetCurrentThreadCPUMicrosForTimeline() { |
131 | return OS::GetCurrentThreadCPUMicros(); |
132 | } |
133 | |
134 | intptr_t OS::ActivationFrameAlignment() { |
135 | #if HOST_OS_IOS |
136 | #if TARGET_ARCH_ARM |
137 | // Even if we generate code that maintains a stronger alignment, we cannot |
138 | // assert the stronger stack alignment because C++ code will not maintain it. |
139 | return 8; |
140 | #elif TARGET_ARCH_ARM64 |
141 | return 16; |
142 | #elif TARGET_ARCH_IA32 |
143 | return 16; // iOS simulator |
144 | #elif TARGET_ARCH_X64 |
145 | return 16; // iOS simulator |
146 | #else |
147 | #error Unimplemented |
148 | #endif |
149 | #else // HOST_OS_IOS |
150 | // OS X activation frames must be 16 byte-aligned; see "Mac OS X ABI |
151 | // Function Call Guide". |
152 | return 16; |
153 | #endif // HOST_OS_IOS |
154 | } |
155 | |
156 | int OS::NumberOfAvailableProcessors() { |
157 | return sysconf(_SC_NPROCESSORS_ONLN); |
158 | } |
159 | |
160 | void OS::Sleep(int64_t millis) { |
161 | int64_t micros = millis * kMicrosecondsPerMillisecond; |
162 | SleepMicros(micros); |
163 | } |
164 | |
165 | void OS::SleepMicros(int64_t micros) { |
166 | struct timespec req; // requested. |
167 | struct timespec rem; // remainder. |
168 | int64_t seconds = micros / kMicrosecondsPerSecond; |
169 | if (seconds > kMaxInt32) { |
170 | // Avoid truncation of overly large sleep values. |
171 | seconds = kMaxInt32; |
172 | } |
173 | micros = micros - seconds * kMicrosecondsPerSecond; |
174 | int64_t nanos = micros * kNanosecondsPerMicrosecond; |
175 | req.tv_sec = static_cast<int32_t>(seconds); |
176 | req.tv_nsec = static_cast<long>(nanos); // NOLINT (long used in timespec). |
177 | while (true) { |
178 | int r = nanosleep(&req, &rem); |
179 | if (r == 0) { |
180 | break; |
181 | } |
182 | // We should only ever see an interrupt error. |
183 | ASSERT(errno == EINTR); |
184 | // Copy remainder into requested and repeat. |
185 | req = rem; |
186 | } |
187 | } |
188 | |
189 | void OS::DebugBreak() { |
190 | __builtin_trap(); |
191 | } |
192 | |
193 | DART_NOINLINE uintptr_t OS::GetProgramCounter() { |
194 | return reinterpret_cast<uintptr_t>( |
195 | __builtin_extract_return_addr(__builtin_return_address(0))); |
196 | } |
197 | |
198 | void OS::Print(const char* format, ...) { |
199 | #if HOST_OS_IOS |
200 | va_list args; |
201 | va_start(args, format); |
202 | vsyslog(LOG_INFO, format, args); |
203 | va_end(args); |
204 | #else |
205 | va_list args; |
206 | va_start(args, format); |
207 | VFPrint(stdout, format, args); |
208 | va_end(args); |
209 | #endif |
210 | } |
211 | |
212 | void OS::VFPrint(FILE* stream, const char* format, va_list args) { |
213 | vfprintf(stream, format, args); |
214 | fflush(stream); |
215 | } |
216 | |
217 | char* OS::SCreate(Zone* zone, const char* format, ...) { |
218 | va_list args; |
219 | va_start(args, format); |
220 | char* buffer = VSCreate(zone, format, args); |
221 | va_end(args); |
222 | return buffer; |
223 | } |
224 | |
225 | char* OS::VSCreate(Zone* zone, const char* format, va_list args) { |
226 | // Measure. |
227 | va_list measure_args; |
228 | va_copy(measure_args, args); |
229 | intptr_t len = Utils::VSNPrint(NULL, 0, format, measure_args); |
230 | va_end(measure_args); |
231 | |
232 | char* buffer; |
233 | if (zone) { |
234 | buffer = zone->Alloc<char>(len + 1); |
235 | } else { |
236 | buffer = reinterpret_cast<char*>(malloc(len + 1)); |
237 | } |
238 | ASSERT(buffer != NULL); |
239 | |
240 | // Print. |
241 | va_list print_args; |
242 | va_copy(print_args, args); |
243 | Utils::VSNPrint(buffer, len + 1, format, print_args); |
244 | va_end(print_args); |
245 | return buffer; |
246 | } |
247 | |
248 | bool OS::StringToInt64(const char* str, int64_t* value) { |
249 | ASSERT(str != NULL && strlen(str) > 0 && value != NULL); |
250 | int32_t base = 10; |
251 | char* endptr; |
252 | int i = 0; |
253 | if (str[0] == '-') { |
254 | i = 1; |
255 | } else if (str[0] == '+') { |
256 | i = 1; |
257 | } |
258 | if ((str[i] == '0') && (str[i + 1] == 'x' || str[i + 1] == 'X') && |
259 | (str[i + 2] != '\0')) { |
260 | base = 16; |
261 | } |
262 | errno = 0; |
263 | if (base == 16) { |
264 | // Unsigned 64-bit hexadecimal integer literals are allowed but |
265 | // immediately interpreted as signed 64-bit integers. |
266 | *value = static_cast<int64_t>(strtoull(str, &endptr, base)); |
267 | } else { |
268 | *value = strtoll(str, &endptr, base); |
269 | } |
270 | return ((errno == 0) && (endptr != str) && (*endptr == 0)); |
271 | } |
272 | |
273 | void OS::RegisterCodeObservers() {} |
274 | |
275 | void OS::PrintErr(const char* format, ...) { |
276 | #if HOST_OS_IOS |
277 | va_list args; |
278 | va_start(args, format); |
279 | vsyslog(LOG_ERR, format, args); |
280 | va_end(args); |
281 | #else |
282 | va_list args; |
283 | va_start(args, format); |
284 | VFPrint(stderr, format, args); |
285 | va_end(args); |
286 | #endif |
287 | } |
288 | |
289 | void OS::Init() { |
290 | // See https://github.com/dart-lang/sdk/issues/29539 |
291 | // This is a workaround for a macos bug, we eagerly call localtime_r so that |
292 | // libnotify is initialized early before any fork happens. |
293 | struct timeval tv; |
294 | if (gettimeofday(&tv, NULL) < 0) { |
295 | FATAL1("gettimeofday returned an error (%s)\n" , strerror(errno)); |
296 | return; |
297 | } |
298 | tm decomposed; |
299 | struct tm* error_code = localtime_r(&(tv.tv_sec), &decomposed); |
300 | if (error_code == NULL) { |
301 | FATAL1("localtime_r returned an error (%s)\n" , strerror(errno)); |
302 | return; |
303 | } |
304 | } |
305 | |
306 | void OS::Cleanup() {} |
307 | |
308 | void OS::PrepareToAbort() {} |
309 | |
310 | void OS::Abort() { |
311 | PrepareToAbort(); |
312 | abort(); |
313 | } |
314 | |
315 | void OS::Exit(int code) { |
316 | exit(code); |
317 | } |
318 | |
319 | } // namespace dart |
320 | |
321 | #endif // defined(HOST_OS_MACOS) |
322 | |