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_WINDOWS)
7
8#include "vm/os.h"
9
10#include <malloc.h> // NOLINT
11#include <process.h> // NOLINT
12#include <psapi.h> // NOLINT
13#include <time.h> // NOLINT
14
15#include "platform/assert.h"
16#include "platform/utils.h"
17#include "vm/os_thread.h"
18#include "vm/zone.h"
19
20namespace dart {
21
22// Defined in vm/os_thread_win.cc
23extern bool private_flag_windows_run_tls_destructors;
24
25const char* OS::Name() {
26 return "windows";
27}
28
29intptr_t OS::ProcessId() {
30 return static_cast<intptr_t>(GetCurrentProcessId());
31}
32
33// As a side-effect sets the globals _timezone, _daylight and _tzname.
34static bool LocalTime(int64_t seconds_since_epoch, tm* tm_result) {
35 time_t seconds = static_cast<time_t>(seconds_since_epoch);
36 if (seconds != seconds_since_epoch) {
37 return false;
38 }
39 // localtime_s implicitly sets _timezone, _daylight and _tzname.
40 errno_t error_code = localtime_s(tm_result, &seconds);
41 return error_code == 0;
42}
43
44static int GetDaylightSavingBiasInSeconds() {
45 TIME_ZONE_INFORMATION zone_information;
46 memset(&zone_information, 0, sizeof(zone_information));
47 if (GetTimeZoneInformation(&zone_information) == TIME_ZONE_ID_INVALID) {
48 // By default the daylight saving offset is an hour.
49 return -60 * 60;
50 } else {
51 return static_cast<int>(zone_information.DaylightBias * 60);
52 }
53}
54
55const char* OS::GetTimeZoneName(int64_t seconds_since_epoch) {
56 TIME_ZONE_INFORMATION zone_information;
57 memset(&zone_information, 0, sizeof(zone_information));
58
59 // Initialize and grab the time zone data.
60 _tzset();
61 DWORD status = GetTimeZoneInformation(&zone_information);
62 if (GetTimeZoneInformation(&zone_information) == TIME_ZONE_ID_INVALID) {
63 // If we can't get the time zone data, the Windows docs indicate that we
64 // are probably out of memory. Return an empty string.
65 return "";
66 }
67
68 // Figure out whether we're in standard or daylight.
69 bool daylight_savings = (status == TIME_ZONE_ID_DAYLIGHT);
70 if (status == TIME_ZONE_ID_UNKNOWN) {
71 tm local_time;
72 if (LocalTime(seconds_since_epoch, &local_time)) {
73 daylight_savings = (local_time.tm_isdst == 1);
74 }
75 }
76
77 // Convert the wchar string to a null-terminated utf8 string.
78 wchar_t* wchar_name = daylight_savings ? zone_information.DaylightName
79 : zone_information.StandardName;
80 intptr_t utf8_len =
81 WideCharToMultiByte(CP_UTF8, 0, wchar_name, -1, NULL, 0, NULL, NULL);
82 char* name = ThreadState::Current()->zone()->Alloc<char>(utf8_len + 1);
83 WideCharToMultiByte(CP_UTF8, 0, wchar_name, -1, name, utf8_len, NULL, NULL);
84 name[utf8_len] = '\0';
85 return name;
86}
87
88int OS::GetTimeZoneOffsetInSeconds(int64_t seconds_since_epoch) {
89 tm decomposed;
90 // LocalTime will set _timezone.
91 bool succeeded = LocalTime(seconds_since_epoch, &decomposed);
92 if (succeeded) {
93 int inDaylightSavingsTime = decomposed.tm_isdst;
94 ASSERT(inDaylightSavingsTime == 0 || inDaylightSavingsTime == 1);
95 // Dart and Windows disagree on the sign of the bias.
96 int offset = static_cast<int>(-_timezone);
97 if (inDaylightSavingsTime == 1) {
98 static int daylight_bias = GetDaylightSavingBiasInSeconds();
99 // Subtract because windows and Dart disagree on the sign.
100 offset = offset - daylight_bias;
101 }
102 return offset;
103 } else {
104 // Return zero like V8 does.
105 return 0;
106 }
107}
108
109int OS::GetLocalTimeZoneAdjustmentInSeconds() {
110 // TODO(floitsch): avoid excessive calls to _tzset?
111 _tzset();
112 // Dart and Windows disagree on the sign of the bias.
113 return static_cast<int>(-_timezone);
114}
115
116int64_t OS::GetCurrentTimeMillis() {
117 return GetCurrentTimeMicros() / 1000;
118}
119
120int64_t OS::GetCurrentTimeMicros() {
121 static const int64_t kTimeEpoc = 116444736000000000LL;
122 static const int64_t kTimeScaler = 10; // 100 ns to us.
123
124 // Although win32 uses 64-bit integers for representing timestamps,
125 // these are packed into a FILETIME structure. The FILETIME
126 // structure is just a struct representing a 64-bit integer. The
127 // TimeStamp union allows access to both a FILETIME and an integer
128 // representation of the timestamp. The Windows timestamp is in
129 // 100-nanosecond intervals since January 1, 1601.
130 union TimeStamp {
131 FILETIME ft_;
132 int64_t t_;
133 };
134 TimeStamp time;
135 GetSystemTimeAsFileTime(&time.ft_);
136 return (time.t_ - kTimeEpoc) / kTimeScaler;
137}
138
139static int64_t qpc_ticks_per_second = 0;
140
141int64_t OS::GetCurrentMonotonicTicks() {
142 if (qpc_ticks_per_second == 0) {
143 // QueryPerformanceCounter not supported, fallback.
144 return GetCurrentTimeMicros();
145 }
146 // Grab performance counter value.
147 LARGE_INTEGER now;
148 QueryPerformanceCounter(&now);
149 return static_cast<int64_t>(now.QuadPart);
150}
151
152int64_t OS::GetCurrentMonotonicFrequency() {
153 if (qpc_ticks_per_second == 0) {
154 // QueryPerformanceCounter not supported, fallback.
155 return kMicrosecondsPerSecond;
156 }
157 return qpc_ticks_per_second;
158}
159
160int64_t OS::GetCurrentMonotonicMicros() {
161 int64_t ticks = GetCurrentMonotonicTicks();
162 int64_t frequency = GetCurrentMonotonicFrequency();
163
164 // Convert to microseconds.
165 int64_t seconds = ticks / frequency;
166 int64_t leftover_ticks = ticks - (seconds * frequency);
167 int64_t result = seconds * kMicrosecondsPerSecond;
168 result += ((leftover_ticks * kMicrosecondsPerSecond) / frequency);
169 return result;
170}
171
172int64_t OS::GetCurrentThreadCPUMicros() {
173 // TODO(johnmccutchan): Implement. See base/time_win.cc for details.
174 return -1;
175}
176
177int64_t OS::GetCurrentThreadCPUMicrosForTimeline() {
178 return OS::GetCurrentThreadCPUMicros();
179}
180
181intptr_t OS::ActivationFrameAlignment() {
182#if defined(TARGET_ARCH_ARM64)
183 return 16;
184#elif defined(TARGET_ARCH_ARM)
185 return 8;
186#elif defined(_WIN64)
187 // Windows 64-bit ABI requires the stack to be 16-byte aligned.
188 return 16;
189#else
190 // No requirements on Win32.
191 return 1;
192#endif
193}
194
195int OS::NumberOfAvailableProcessors() {
196 SYSTEM_INFO info;
197 GetSystemInfo(&info);
198 return info.dwNumberOfProcessors;
199}
200
201void OS::Sleep(int64_t millis) {
202 ::Sleep(millis);
203}
204
205void OS::SleepMicros(int64_t micros) {
206 // Windows only supports millisecond sleeps.
207 if (micros < kMicrosecondsPerMillisecond) {
208 // Calling ::Sleep with 0 has no determined behaviour, round up.
209 micros = kMicrosecondsPerMillisecond;
210 }
211 OS::Sleep(micros / kMicrosecondsPerMillisecond);
212}
213
214void OS::DebugBreak() {
215#if defined(_MSC_VER)
216 // Microsoft Visual C/C++ or drop-in replacement.
217 __debugbreak();
218#elif defined(__GCC__)
219 __builtin_trap();
220#else
221 // Microsoft style assembly.
222 __asm {
223 int 3
224 }
225#endif
226}
227
228DART_NOINLINE uintptr_t OS::GetProgramCounter() {
229 return reinterpret_cast<uintptr_t>(_ReturnAddress());
230}
231
232void OS::Print(const char* format, ...) {
233 va_list args;
234 va_start(args, format);
235 VFPrint(stdout, format, args);
236 va_end(args);
237}
238
239void OS::VFPrint(FILE* stream, const char* format, va_list args) {
240 vfprintf(stream, format, args);
241 fflush(stream);
242}
243
244char* OS::SCreate(Zone* zone, const char* format, ...) {
245 va_list args;
246 va_start(args, format);
247 char* buffer = VSCreate(zone, format, args);
248 va_end(args);
249 return buffer;
250}
251
252char* OS::VSCreate(Zone* zone, const char* format, va_list args) {
253 // Measure.
254 va_list measure_args;
255 va_copy(measure_args, args);
256 intptr_t len = Utils::VSNPrint(NULL, 0, format, measure_args);
257 va_end(measure_args);
258
259 char* buffer;
260 if (zone) {
261 buffer = zone->Alloc<char>(len + 1);
262 } else {
263 buffer = reinterpret_cast<char*>(malloc(len + 1));
264 }
265 ASSERT(buffer != NULL);
266
267 // Print.
268 va_list print_args;
269 va_copy(print_args, args);
270 Utils::VSNPrint(buffer, len + 1, format, print_args);
271 va_end(print_args);
272 return buffer;
273}
274
275bool OS::StringToInt64(const char* str, int64_t* value) {
276 ASSERT(str != NULL && strlen(str) > 0 && value != NULL);
277 int32_t base = 10;
278 char* endptr;
279 int i = 0;
280 if (str[0] == '-') {
281 i = 1;
282 } else if (str[0] == '+') {
283 i = 1;
284 }
285 if ((str[i] == '0') && (str[i + 1] == 'x' || str[i + 1] == 'X') &&
286 (str[i + 2] != '\0')) {
287 base = 16;
288 }
289 errno = 0;
290 if (base == 16) {
291 // Unsigned 64-bit hexadecimal integer literals are allowed but
292 // immediately interpreted as signed 64-bit integers.
293 *value = static_cast<int64_t>(_strtoui64(str, &endptr, base));
294 } else {
295 *value = _strtoi64(str, &endptr, base);
296 }
297 return ((errno == 0) && (endptr != str) && (*endptr == 0));
298}
299
300void OS::RegisterCodeObservers() {}
301
302void OS::PrintErr(const char* format, ...) {
303 va_list args;
304 va_start(args, format);
305 VFPrint(stderr, format, args);
306 va_end(args);
307}
308
309void OS::Init() {
310 static bool init_once_called = false;
311 if (init_once_called) {
312 return;
313 }
314 init_once_called = true;
315 // Do not pop up a message box when abort is called.
316 _set_abort_behavior(0, _WRITE_ABORT_MSG);
317 ThreadLocalData::Init();
318 LARGE_INTEGER ticks_per_sec;
319 if (!QueryPerformanceFrequency(&ticks_per_sec)) {
320 qpc_ticks_per_second = 0;
321 } else {
322 qpc_ticks_per_second = static_cast<int64_t>(ticks_per_sec.QuadPart);
323 }
324}
325
326void OS::Cleanup() {
327 // TODO(zra): Enable once VM can shutdown cleanly.
328 // ThreadLocalData::Cleanup();
329}
330
331void OS::PrepareToAbort() {
332 // TODO(zra): Remove once VM shuts down cleanly.
333 private_flag_windows_run_tls_destructors = false;
334}
335
336void OS::Abort() {
337 PrepareToAbort();
338 abort();
339}
340
341void OS::Exit(int code) {
342 // TODO(zra): Remove once VM shuts down cleanly.
343 private_flag_windows_run_tls_destructors = false;
344 // On Windows we use ExitProcess so that threads can't clobber the exit_code.
345 // See: https://code.google.com/p/nativeclient/issues/detail?id=2870
346 ::ExitProcess(code);
347}
348
349} // namespace dart
350
351#endif // defined(HOST_OS_WINDOWS)
352