Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
os_macos.cc
Go to the documentation of this file.
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(DART_HOST_OS_MACOS)
7
8#include "vm/os.h"
9
10#include <dlfcn.h> // NOLINT
11#include <errno.h> // NOLINT
12#include <limits.h> // NOLINT
13#include <mach-o/loader.h> // NOLINT
14#include <mach/clock.h> // NOLINT
15#include <mach/mach.h> // NOLINT
16#include <mach/mach_time.h> // NOLINT
17#include <sys/resource.h> // NOLINT
18#include <sys/time.h> // NOLINT
19#include <unistd.h> // NOLINT
20#if DART_HOST_OS_IOS
21#include <syslog.h> // NOLINT
22#endif
23
24#include "platform/utils.h"
25#include "vm/image_snapshot.h"
26#include "vm/isolate.h"
27#include "vm/timeline.h"
28#include "vm/zone.h"
29
30namespace dart {
31
32intptr_t OS::ProcessId() {
33 return static_cast<intptr_t>(getpid());
34}
35
36static bool LocalTime(int64_t seconds_since_epoch, tm* tm_result) {
37 time_t seconds = static_cast<time_t>(seconds_since_epoch);
38 if (seconds != seconds_since_epoch) return false;
39 struct tm* error_code = localtime_r(&seconds, tm_result);
40 return error_code != nullptr;
41}
42
43const char* OS::GetTimeZoneName(int64_t seconds_since_epoch) {
44 tm decomposed;
45 bool succeeded = LocalTime(seconds_since_epoch, &decomposed);
46 // If unsuccessful, return an empty string like V8 does.
47 return (succeeded && (decomposed.tm_zone != nullptr)) ? decomposed.tm_zone
48 : "";
49}
50
51int OS::GetTimeZoneOffsetInSeconds(int64_t seconds_since_epoch) {
52 tm decomposed;
53 bool succeeded = LocalTime(seconds_since_epoch, &decomposed);
54 // Even if the offset was 24 hours it would still easily fit into 32 bits.
55 // If unsuccessful, return zero like V8 does.
56 return succeeded ? static_cast<int>(decomposed.tm_gmtoff) : 0;
57}
58
60 return GetCurrentTimeMicros() / 1000;
61}
62
64 // gettimeofday has microsecond resolution.
65 struct timeval tv;
66 if (gettimeofday(&tv, nullptr) < 0) {
68 return 0;
69 }
70 return (static_cast<int64_t>(tv.tv_sec) * 1000000) + tv.tv_usec;
71}
72
74 return clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW);
75}
76
79}
80
84}
85
87 return clock_gettime_nsec_np(CLOCK_THREAD_CPUTIME_ID) /
89}
90
92#if defined(SUPPORT_TIMELINE)
93 if (Timeline::recorder_discards_clock_values()) return -1;
95#else
96 return -1;
97#endif
98}
99
101#if DART_HOST_OS_IOS
102#if TARGET_ARCH_ARM
103 // Even if we generate code that maintains a stronger alignment, we cannot
104 // assert the stronger stack alignment because C++ code will not maintain it.
105 return 8;
106#elif TARGET_ARCH_ARM64
107 return 16;
108#elif TARGET_ARCH_IA32
109 return 16; // iOS simulator
110#elif TARGET_ARCH_X64
111 return 16; // iOS simulator
112#else
113#error Unimplemented
114#endif
115#else // DART_HOST_OS_IOS
116 // OS X activation frames must be 16 byte-aligned; see "Mac OS X ABI
117 // Function Call Guide".
118 return 16;
119#endif // DART_HOST_OS_IOS
120}
121
123 return sysconf(_SC_NPROCESSORS_ONLN);
124}
125
126void OS::Sleep(int64_t millis) {
127 int64_t micros = millis * kMicrosecondsPerMillisecond;
128 SleepMicros(micros);
129}
130
131void OS::SleepMicros(int64_t micros) {
132 struct timespec req; // requested.
133 struct timespec rem; // remainder.
134 int64_t seconds = micros / kMicrosecondsPerSecond;
135 if (seconds > kMaxInt32) {
136 // Avoid truncation of overly large sleep values.
137 seconds = kMaxInt32;
138 }
139 micros = micros - seconds * kMicrosecondsPerSecond;
140 int64_t nanos = micros * kNanosecondsPerMicrosecond;
141 req.tv_sec = static_cast<int32_t>(seconds);
142 req.tv_nsec = static_cast<long>(nanos); // NOLINT (long used in timespec).
143 while (true) {
144 int r = nanosleep(&req, &rem);
145 if (r == 0) {
146 break;
147 }
148 // We should only ever see an interrupt error.
149 ASSERT(errno == EINTR);
150 // Copy remainder into requested and repeat.
151 req = rem;
152 }
153}
154
155void OS::DebugBreak() {
156 __builtin_trap();
157}
158
159DART_NOINLINE uintptr_t OS::GetProgramCounter() {
160 return reinterpret_cast<uintptr_t>(
161 __builtin_extract_return_addr(__builtin_return_address(0)));
162}
163
164void OS::Print(const char* format, ...) {
165#if DART_HOST_OS_IOS
166 va_list args;
168 vsyslog(LOG_INFO, format, args);
169 va_end(args);
170#else
171 va_list args;
173 VFPrint(stdout, format, args);
174 va_end(args);
175#endif
176}
177
178void OS::VFPrint(FILE* stream, const char* format, va_list args) {
179 vfprintf(stream, format, args);
180 fflush(stream);
181}
182
183char* OS::SCreate(Zone* zone, const char* format, ...) {
184 va_list args;
186 char* buffer = VSCreate(zone, format, args);
187 va_end(args);
188 return buffer;
189}
190
191char* OS::VSCreate(Zone* zone, const char* format, va_list args) {
192 // Measure.
193 va_list measure_args;
194 va_copy(measure_args, args);
195 intptr_t len = Utils::VSNPrint(nullptr, 0, format, measure_args);
196 va_end(measure_args);
197
198 char* buffer;
199 if (zone) {
200 buffer = zone->Alloc<char>(len + 1);
201 } else {
202 buffer = reinterpret_cast<char*>(malloc(len + 1));
203 }
204 ASSERT(buffer != nullptr);
205
206 // Print.
207 va_list print_args;
208 va_copy(print_args, args);
209 Utils::VSNPrint(buffer, len + 1, format, print_args);
210 va_end(print_args);
211 return buffer;
212}
213
214bool OS::StringToInt64(const char* str, int64_t* value) {
215 ASSERT(str != nullptr && strlen(str) > 0 && value != nullptr);
216 int32_t base = 10;
217 char* endptr;
218 int i = 0;
219 if (str[0] == '-') {
220 i = 1;
221 } else if (str[0] == '+') {
222 i = 1;
223 }
224 if ((str[i] == '0') && (str[i + 1] == 'x' || str[i + 1] == 'X') &&
225 (str[i + 2] != '\0')) {
226 base = 16;
227 }
228 errno = 0;
229 if (base == 16) {
230 // Unsigned 64-bit hexadecimal integer literals are allowed but
231 // immediately interpreted as signed 64-bit integers.
232 *value = static_cast<int64_t>(strtoull(str, &endptr, base));
233 } else {
234 *value = strtoll(str, &endptr, base);
235 }
236 return ((errno == 0) && (endptr != str) && (*endptr == 0));
237}
238
240
241void OS::PrintErr(const char* format, ...) {
242#if DART_HOST_OS_IOS
243 va_list args;
245 vsyslog(LOG_ERR, format, args);
246 va_end(args);
247#else
248 va_list args;
250 VFPrint(stderr, format, args);
251 va_end(args);
252#endif
253}
254
255void OS::Init() {
256 // See https://github.com/dart-lang/sdk/issues/29539
257 // This is a workaround for a macos bug, we eagerly call localtime_r so that
258 // libnotify is initialized early before any fork happens.
259 struct timeval tv;
260 if (gettimeofday(&tv, nullptr) < 0) {
261 FATAL("gettimeofday returned an error (%s)\n", strerror(errno));
262 return;
263 }
264 tm decomposed;
265 struct tm* error_code = localtime_r(&(tv.tv_sec), &decomposed);
266 if (error_code == nullptr) {
267 FATAL("localtime_r returned an error (%s)\n", strerror(errno));
268 return;
269 }
270}
271
272void OS::Cleanup() {}
273
274void OS::PrepareToAbort() {}
275
276void OS::Abort() {
278 abort();
279}
280
281void OS::Exit(int code) {
282 exit(code);
283}
284
285OS::BuildId OS::GetAppBuildId(const uint8_t* snapshot_instructions) {
286 // First return the build ID information from the instructions image if
287 // available.
288 const Image instructions_image(snapshot_instructions);
289 if (auto* const image_build_id = instructions_image.build_id()) {
290 return {instructions_image.build_id_length(), image_build_id};
291 }
292 const uint8_t* dso_base = GetAppDSOBase(snapshot_instructions);
293 const auto& macho_header =
294 *reinterpret_cast<const struct mach_header*>(dso_base);
295 // We assume host endianness in the Mach-O file.
296 if (macho_header.magic != MH_MAGIC && macho_header.magic != MH_MAGIC_64) {
297 return {0, nullptr};
298 }
299 const size_t macho_header_size = macho_header.magic == MH_MAGIC
300 ? sizeof(struct mach_header)
301 : sizeof(struct mach_header_64);
302 const uint8_t* it = dso_base + macho_header_size;
303 const uint8_t* end = it + macho_header.sizeofcmds;
304 while (it < end) {
305 const auto& current_cmd = *reinterpret_cast<const struct load_command*>(it);
306 if ((current_cmd.cmd & ~LC_REQ_DYLD) == LC_UUID) {
307 const auto& uuid_cmd = *reinterpret_cast<const struct uuid_command*>(it);
308 return {
309 static_cast<intptr_t>(uuid_cmd.cmdsize - sizeof(struct load_command)),
310 uuid_cmd.uuid};
311 }
312 it += current_cmd.cmdsize;
313 }
314 return {0, nullptr};
315}
316
317} // namespace dart
318
319#endif // defined(DART_HOST_OS_MACOS)
#define LOG_INFO(...)
#define UNREACHABLE()
Definition assert.h:248
static DART_NORETURN void Exit(int code)
static int NumberOfAvailableProcessors()
static const char * GetTimeZoneName(int64_t seconds_since_epoch)
static void SleepMicros(int64_t micros)
static int64_t GetCurrentTimeMillis()
static void RegisterCodeObservers()
static int64_t GetCurrentMonotonicMicros()
static void static void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
static void Sleep(int64_t millis)
static void Print(const char *format,...) PRINTF_ATTRIBUTE(1
static bool StringToInt64(const char *str, int64_t *value)
static BuildId GetAppBuildId(const uint8_t *snapshot_instructions)
static const uint8_t * GetAppDSOBase(const uint8_t *snapshot_instructions)
Definition os.cc:13
static void Init()
static int64_t GetCurrentTimeMicros()
static intptr_t ActivationFrameAlignment()
static void static void static void VFPrint(FILE *stream, const char *format, va_list args)
static void Cleanup()
static void DebugBreak()
static DART_NORETURN void Abort()
static char static char * VSCreate(Zone *zone, const char *format, va_list args)
static int64_t GetCurrentThreadCPUMicros()
static uintptr_t GetProgramCounter()
static intptr_t ProcessId()
static void PrepareToAbort()
static int64_t GetCurrentMonotonicFrequency()
static char * SCreate(Zone *zone, const char *format,...) PRINTF_ATTRIBUTE(2
static int64_t GetCurrentMonotonicTicks()
static int64_t GetCurrentMonotonicMicrosForTimeline()
static int GetTimeZoneOffsetInSeconds(int64_t seconds_since_epoch)
static int static int VSNPrint(char *str, size_t size, const char *format, va_list args)
#define ASSERT(E)
#define FATAL(error)
glong glong end
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
static const uint8_t buffer[]
uint8_t value
uint32_t uint32_t * format
va_start(args, format)
exit(kErrorExitCode)
va_end(args)
constexpr intptr_t kMicrosecondsPerMillisecond
Definition globals.h:561
constexpr intptr_t kMicrosecondsPerSecond
Definition globals.h:562
constexpr intptr_t kNanosecondsPerMicrosecond
Definition globals.h:564
void * malloc(size_t size)
Definition allocation.cc:19
constexpr intptr_t kNanosecondsPerSecond
Definition globals.h:567
constexpr int32_t kMaxInt32
Definition globals.h:483
CanvasImage Image
Definition dart_ui.cc:55