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_ANDROID)
7
8#include "vm/os.h"
9
10#include <android/log.h> // NOLINT
11#include <errno.h> // NOLINT
12#include <limits.h> // NOLINT
13#include <malloc.h> // NOLINT
14#include <sys/resource.h> // NOLINT
15#include <sys/time.h> // NOLINT
16#include <sys/types.h> // NOLINT
17#include <time.h> // NOLINT
18#include <unistd.h> // NOLINT
19
20#include "platform/utils.h"
21#include "vm/code_observers.h"
22#include "vm/dart.h"
23#include "vm/isolate.h"
24#include "vm/zone.h"
25
26namespace dart {
27
28DEFINE_FLAG(bool,
29 android_log_to_stderr,
30 false,
31 "Send Dart VM logs to stdout and stderr instead of the Android "
32 "system logs.");
33
34// Android CodeObservers.
35
36#ifndef PRODUCT
37
38DEFINE_FLAG(bool,
39 generate_perf_events_symbols,
40 false,
41 "Generate events symbols for profiling with perf");
42
43class PerfCodeObserver : public CodeObserver {
44 public:
45 PerfCodeObserver() : out_file_(NULL) {
46 Dart_FileOpenCallback file_open = Dart::file_open_callback();
47 if (file_open == NULL) {
48 return;
49 }
50 intptr_t pid = getpid();
51 char* filename = OS::SCreate(NULL, "/tmp/perf-%" Pd ".map", pid);
52 out_file_ = (*file_open)(filename, true);
53 free(filename);
54 }
55
56 ~PerfCodeObserver() {
57 Dart_FileCloseCallback file_close = Dart::file_close_callback();
58 if ((file_close == NULL) || (out_file_ == NULL)) {
59 return;
60 }
61 (*file_close)(out_file_);
62 }
63
64 virtual bool IsActive() const {
65 return FLAG_generate_perf_events_symbols && (out_file_ != NULL);
66 }
67
68 virtual void Notify(const char* name,
69 uword base,
70 uword prologue_offset,
71 uword size,
72 bool optimized,
73 const CodeComments* comments) {
74 Dart_FileWriteCallback file_write = Dart::file_write_callback();
75 if ((file_write == NULL) || (out_file_ == NULL)) {
76 return;
77 }
78 const char* marker = optimized ? "*" : "";
79 char* buffer =
80 OS::SCreate(Thread::Current()->zone(), "%" Px " %" Px " %s%s\n", base,
81 size, marker, name);
82 (*file_write)(buffer, strlen(buffer), out_file_);
83 }
84
85 private:
86 void* out_file_;
87
88 DISALLOW_COPY_AND_ASSIGN(PerfCodeObserver);
89};
90
91#endif // !PRODUCT
92
93const char* OS::Name() {
94 return "android";
95}
96
97intptr_t OS::ProcessId() {
98 return static_cast<intptr_t>(getpid());
99}
100
101static bool LocalTime(int64_t seconds_since_epoch, tm* tm_result) {
102 time_t seconds = static_cast<time_t>(seconds_since_epoch);
103 if (seconds != seconds_since_epoch) return false;
104 struct tm* error_code = localtime_r(&seconds, tm_result);
105 return error_code != NULL;
106}
107
108const char* OS::GetTimeZoneName(int64_t seconds_since_epoch) {
109 tm decomposed;
110 bool succeeded = LocalTime(seconds_since_epoch, &decomposed);
111 // If unsuccessful, return an empty string like V8 does.
112 return (succeeded && (decomposed.tm_zone != NULL)) ? decomposed.tm_zone : "";
113}
114
115int OS::GetTimeZoneOffsetInSeconds(int64_t seconds_since_epoch) {
116 tm decomposed;
117 bool succeeded = LocalTime(seconds_since_epoch, &decomposed);
118 // Even if the offset was 24 hours it would still easily fit into 32 bits.
119 // If unsuccessful, return zero like V8 does.
120 return succeeded ? static_cast<int>(decomposed.tm_gmtoff) : 0;
121}
122
123int OS::GetLocalTimeZoneAdjustmentInSeconds() {
124 // TODO(floitsch): avoid excessive calls to tzset?
125 tzset();
126 // Even if the offset was 24 hours it would still easily fit into 32 bits.
127 // Note that Unix and Dart disagree on the sign.
128 return static_cast<int>(-timezone);
129}
130
131int64_t OS::GetCurrentTimeMillis() {
132 return GetCurrentTimeMicros() / 1000;
133}
134
135int64_t OS::GetCurrentTimeMicros() {
136 // gettimeofday has microsecond resolution.
137 struct timeval tv;
138 if (gettimeofday(&tv, NULL) < 0) {
139 UNREACHABLE();
140 return 0;
141 }
142 return (static_cast<int64_t>(tv.tv_sec) * 1000000) + tv.tv_usec;
143}
144
145int64_t OS::GetCurrentMonotonicTicks() {
146 struct timespec ts;
147 if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
148 UNREACHABLE();
149 return 0;
150 }
151 // Convert to nanoseconds.
152 int64_t result = ts.tv_sec;
153 result *= kNanosecondsPerSecond;
154 result += ts.tv_nsec;
155 return result;
156}
157
158int64_t OS::GetCurrentMonotonicFrequency() {
159 return kNanosecondsPerSecond;
160}
161
162int64_t OS::GetCurrentMonotonicMicros() {
163 int64_t ticks = GetCurrentMonotonicTicks();
164 ASSERT(GetCurrentMonotonicFrequency() == kNanosecondsPerSecond);
165 return ticks / kNanosecondsPerMicrosecond;
166}
167
168int64_t OS::GetCurrentThreadCPUMicros() {
169 struct timespec ts;
170 if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts) != 0) {
171 UNREACHABLE();
172 return -1;
173 }
174 int64_t result = ts.tv_sec;
175 result *= kMicrosecondsPerSecond;
176 result += (ts.tv_nsec / kNanosecondsPerMicrosecond);
177 return result;
178}
179
180int64_t OS::GetCurrentThreadCPUMicrosForTimeline() {
181 return OS::GetCurrentThreadCPUMicros();
182}
183
184// TODO(5411554): May need to hoist these architecture dependent code
185// into a architecture specific file e.g: os_ia32_linux.cc
186intptr_t OS::ActivationFrameAlignment() {
187#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64) || \
188 defined(TARGET_ARCH_ARM64)
189 const int kMinimumAlignment = 16;
190#elif defined(TARGET_ARCH_ARM)
191 const int kMinimumAlignment = 8;
192#else
193#error Unsupported architecture.
194#endif
195 intptr_t alignment = kMinimumAlignment;
196 // TODO(5411554): Allow overriding default stack alignment for
197 // testing purposes.
198 // Flags::DebugIsInt("stackalign", &alignment);
199 ASSERT(Utils::IsPowerOfTwo(alignment));
200 ASSERT(alignment >= kMinimumAlignment);
201 return alignment;
202}
203
204int OS::NumberOfAvailableProcessors() {
205 return sysconf(_SC_NPROCESSORS_ONLN);
206}
207
208void OS::Sleep(int64_t millis) {
209 int64_t micros = millis * kMicrosecondsPerMillisecond;
210 SleepMicros(micros);
211}
212
213void OS::SleepMicros(int64_t micros) {
214 struct timespec req; // requested.
215 struct timespec rem; // remainder.
216 int64_t seconds = micros / kMicrosecondsPerSecond;
217 micros = micros - seconds * kMicrosecondsPerSecond;
218 int64_t nanos = micros * kNanosecondsPerMicrosecond;
219 req.tv_sec = seconds;
220 req.tv_nsec = nanos;
221 while (true) {
222 int r = nanosleep(&req, &rem);
223 if (r == 0) {
224 break;
225 }
226 // We should only ever see an interrupt error.
227 ASSERT(errno == EINTR);
228 // Copy remainder into requested and repeat.
229 req = rem;
230 }
231}
232
233void OS::DebugBreak() {
234 __builtin_trap();
235}
236
237DART_NOINLINE uintptr_t OS::GetProgramCounter() {
238 return reinterpret_cast<uintptr_t>(
239 __builtin_extract_return_addr(__builtin_return_address(0)));
240}
241
242void OS::Print(const char* format, ...) {
243 va_list args;
244 va_start(args, format);
245 if (FLAG_android_log_to_stderr) {
246 vfprintf(stderr, format, args);
247 } else {
248 // Forward to the Android log for remote access.
249 __android_log_vprint(ANDROID_LOG_INFO, "DartVM", format, args);
250 }
251 va_end(args);
252}
253
254void OS::VFPrint(FILE* stream, const char* format, va_list args) {
255 vfprintf(stream, format, args);
256 fflush(stream);
257}
258
259char* OS::SCreate(Zone* zone, const char* format, ...) {
260 va_list args;
261 va_start(args, format);
262 char* buffer = VSCreate(zone, format, args);
263 va_end(args);
264 return buffer;
265}
266
267char* OS::VSCreate(Zone* zone, const char* format, va_list args) {
268 // Measure.
269 va_list measure_args;
270 va_copy(measure_args, args);
271 intptr_t len = Utils::VSNPrint(NULL, 0, format, measure_args);
272 va_end(measure_args);
273
274 char* buffer;
275 if (zone) {
276 buffer = zone->Alloc<char>(len + 1);
277 } else {
278 buffer = reinterpret_cast<char*>(malloc(len + 1));
279 }
280 ASSERT(buffer != NULL);
281
282 // Print.
283 va_list print_args;
284 va_copy(print_args, args);
285 Utils::VSNPrint(buffer, len + 1, format, print_args);
286 va_end(print_args);
287 return buffer;
288}
289
290bool OS::StringToInt64(const char* str, int64_t* value) {
291 ASSERT(str != NULL && strlen(str) > 0 && value != NULL);
292 int32_t base = 10;
293 char* endptr;
294 int i = 0;
295 if (str[0] == '-') {
296 i = 1;
297 } else if (str[0] == '+') {
298 i = 1;
299 }
300 if ((str[i] == '0') && (str[i + 1] == 'x' || str[i + 1] == 'X') &&
301 (str[i + 2] != '\0')) {
302 base = 16;
303 }
304 errno = 0;
305 if (base == 16) {
306 // Unsigned 64-bit hexadecimal integer literals are allowed but
307 // immediately interpreted as signed 64-bit integers.
308 *value = static_cast<int64_t>(strtoull(str, &endptr, base));
309 } else {
310 *value = strtoll(str, &endptr, base);
311 }
312 return ((errno == 0) && (endptr != str) && (*endptr == 0));
313}
314
315void OS::RegisterCodeObservers() {
316#ifndef PRODUCT
317 if (FLAG_generate_perf_events_symbols) {
318 CodeObservers::Register(new PerfCodeObserver);
319 }
320#endif // !PRODUCT
321}
322
323void OS::PrintErr(const char* format, ...) {
324 va_list args;
325 va_start(args, format);
326 if (FLAG_android_log_to_stderr) {
327 vfprintf(stderr, format, args);
328 } else {
329 // Forward to the Android log for remote access.
330 __android_log_vprint(ANDROID_LOG_ERROR, "DartVM", format, args);
331 }
332 va_end(args);
333}
334
335void OS::Init() {}
336
337void OS::Cleanup() {}
338
339void OS::PrepareToAbort() {}
340
341void OS::Abort() {
342 PrepareToAbort();
343 abort();
344}
345
346void OS::Exit(int code) {
347 exit(code);
348}
349
350} // namespace dart
351
352#endif // defined(HOST_OS_ANDROID)
353