Flutter Engine
The Flutter Engine
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
uint8_t value
uint32_t uint32_t * format
va_start(args, format)
exit(kErrorExitCode)
va_end(args)
Definition: dart_vm.cc:33
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
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
CanvasImage Image
Definition: dart_ui.cc:55