Index: src/platform-win32.cc |
diff --git a/src/platform-win32.cc b/src/platform-win32.cc |
index cdd9a4fb4694c5835648964fa147c273423f8278..c136631f00272659ed76f845ca8fd59c965ddd4d 100644 |
--- a/src/platform-win32.cc |
+++ b/src/platform-win32.cc |
@@ -38,6 +38,7 @@ |
#endif // MINGW_HAS_SECURE_API |
#endif // __MINGW32__ |
+#define V8_WIN32_HEADERS_FULL |
#include "win32-headers.h" |
#include "v8.h" |
@@ -245,15 +246,19 @@ void MathSetup() { |
// timestamps are represented as a doubles in milliseconds since 00:00:00 UTC, |
// January 1, 1970. |
-class Win32Time { |
+class Time { |
public: |
// Constructors. |
- explicit Win32Time(double jstime); |
- Win32Time(int year, int mon, int day, int hour, int min, int sec); |
+ Time(); |
+ explicit Time(double jstime); |
+ Time(int year, int mon, int day, int hour, int min, int sec); |
// Convert timestamp to JavaScript representation. |
double ToJSTime(); |
+ // Set timestamp to current time. |
+ void SetToCurrentTime(); |
+ |
// Returns the local timezone offset in milliseconds east of UTC. This is |
// the number of milliseconds you must add to UTC to get local time, i.e. |
// LocalOffset(CET) = 3600000 and LocalOffset(PST) = -28800000. This |
@@ -295,6 +300,10 @@ class Win32Time { |
// Return whether or not daylight savings time is in effect at this time. |
bool InDST(); |
+ // Return the difference (in milliseconds) between this timestamp and |
+ // another timestamp. |
+ int64_t Diff(Time* other); |
+ |
// Accessor for FILETIME representation. |
FILETIME& ft() { return time_.ft_; } |
@@ -316,20 +325,26 @@ class Win32Time { |
// Static variables. |
-bool Win32Time::tz_initialized_ = false; |
-TIME_ZONE_INFORMATION Win32Time::tzinfo_; |
-char Win32Time::std_tz_name_[kTzNameSize]; |
-char Win32Time::dst_tz_name_[kTzNameSize]; |
+bool Time::tz_initialized_ = false; |
+TIME_ZONE_INFORMATION Time::tzinfo_; |
+char Time::std_tz_name_[kTzNameSize]; |
+char Time::dst_tz_name_[kTzNameSize]; |
+ |
+ |
+// Initialize timestamp to start of epoc. |
+Time::Time() { |
+ t() = 0; |
+} |
// Initialize timestamp from a JavaScript timestamp. |
-Win32Time::Win32Time(double jstime) { |
+Time::Time(double jstime) { |
t() = static_cast<int64_t>(jstime) * kTimeScaler + kTimeEpoc; |
} |
// Initialize timestamp from date/time components. |
-Win32Time::Win32Time(int year, int mon, int day, int hour, int min, int sec) { |
+Time::Time(int year, int mon, int day, int hour, int min, int sec) { |
SYSTEMTIME st; |
st.wYear = year; |
st.wMonth = mon; |
@@ -343,14 +358,14 @@ Win32Time::Win32Time(int year, int mon, int day, int hour, int min, int sec) { |
// Convert timestamp to JavaScript timestamp. |
-double Win32Time::ToJSTime() { |
+double Time::ToJSTime() { |
return static_cast<double>((t() - kTimeEpoc) / kTimeScaler); |
} |
// Guess the name of the timezone from the bias. |
// The guess is very biased towards the northern hemisphere. |
-const char* Win32Time::GuessTimezoneNameFromBias(int bias) { |
+const char* Time::GuessTimezoneNameFromBias(int bias) { |
static const int kHour = 60; |
switch (-bias) { |
case -9*kHour: return "Alaska"; |
@@ -375,7 +390,7 @@ const char* Win32Time::GuessTimezoneNameFromBias(int bias) { |
// Initialize timezone information. The timezone information is obtained from |
// windows. If we cannot get the timezone information we fall back to CET. |
// Please notice that this code is not thread-safe. |
-void Win32Time::TzSet() { |
+void Time::TzSet() { |
// Just return if timezone information has already been initialized. |
if (tz_initialized_) return; |
@@ -424,16 +439,78 @@ void Win32Time::TzSet() { |
} |
+// Return the difference in milliseconds between this and another timestamp. |
+int64_t Time::Diff(Time* other) { |
+ return (t() - other->t()) / kTimeScaler; |
+} |
+ |
+ |
+// Set timestamp to current time. |
+void Time::SetToCurrentTime() { |
+ // The default GetSystemTimeAsFileTime has a ~15.5ms resolution. |
+ // Because we're fast, we like fast timers which have at least a |
+ // 1ms resolution. |
+ // |
+ // timeGetTime() provides 1ms granularity when combined with |
+ // timeBeginPeriod(). If the host application for v8 wants fast |
+ // timers, it can use timeBeginPeriod to increase the resolution. |
+ // |
+ // Using timeGetTime() has a drawback because it is a 32bit value |
+ // and hence rolls-over every ~49days. |
+ // |
+ // To use the clock, we use GetSystemTimeAsFileTime as our base; |
+ // and then use timeGetTime to extrapolate current time from the |
+ // start time. To deal with rollovers, we resync the clock |
+ // any time when more than kMaxClockElapsedTime has passed or |
+ // whenever timeGetTime creates a rollover. |
+ |
+ static bool initialized = false; |
+ static TimeStamp init_time; |
+ static DWORD init_ticks; |
+ static const int64_t kHundredNanosecondsPerSecond = 10000000; |
+ static const int64_t kMaxClockElapsedTime = |
+ 60*kHundredNanosecondsPerSecond; // 1 minute |
+ |
+ // If we are uninitialized, we need to resync the clock. |
+ bool needs_resync = !initialized; |
+ |
+ // Get the current time. |
+ TimeStamp time_now; |
+ GetSystemTimeAsFileTime(&time_now.ft_); |
+ DWORD ticks_now = timeGetTime(); |
+ |
+ // Check if we need to resync due to clock rollover. |
+ needs_resync |= ticks_now < init_ticks; |
+ |
+ // Check if we need to resync due to elapsed time. |
+ needs_resync |= (time_now.t_ - init_time.t_) > kMaxClockElapsedTime; |
+ |
+ // Check if we need to resync due to backwards time change. |
+ needs_resync |= time_now.t_ < init_time.t_; |
+ |
+ // Resync the clock if necessary. |
+ if (needs_resync) { |
+ GetSystemTimeAsFileTime(&init_time.ft_); |
+ init_ticks = ticks_now = timeGetTime(); |
+ initialized = true; |
+ } |
+ |
+ // Finally, compute the actual time. Why is this so hard. |
+ DWORD elapsed = ticks_now - init_ticks; |
+ this->time_.t_ = init_time.t_ + (static_cast<int64_t>(elapsed) * 10000); |
+} |
+ |
+ |
// Return the local timezone offset in milliseconds east of UTC. This |
// takes into account whether daylight saving is in effect at the time. |
// Only times in the 32-bit Unix range may be passed to this function. |
// Also, adding the time-zone offset to the input must not overflow. |
// The function EquivalentTime() in date.js guarantees this. |
-int64_t Win32Time::LocalOffset() { |
+int64_t Time::LocalOffset() { |
// Initialize timezone information, if needed. |
TzSet(); |
- Win32Time rounded_to_second(*this); |
+ Time rounded_to_second(*this); |
rounded_to_second.t() = rounded_to_second.t() / 1000 / kTimeScaler * |
1000 * kTimeScaler; |
// Convert to local time using POSIX localtime function. |
@@ -464,7 +541,7 @@ int64_t Win32Time::LocalOffset() { |
// Return whether or not daylight savings time is in effect at this time. |
-bool Win32Time::InDST() { |
+bool Time::InDST() { |
// Initialize timezone information, if needed. |
TzSet(); |
@@ -488,14 +565,14 @@ bool Win32Time::InDST() { |
// Return the daylight savings time offset for this time. |
-int64_t Win32Time::DaylightSavingsOffset() { |
+int64_t Time::DaylightSavingsOffset() { |
return InDST() ? 60 * kMsPerMinute : 0; |
} |
// Returns a string identifying the current timezone for the |
// timestamp taking into account daylight saving. |
-char* Win32Time::LocalTimezone() { |
+char* Time::LocalTimezone() { |
// Return the standard or DST time zone name based on whether daylight |
// saving is in effect at the given time. |
return InDST() ? dst_tz_name_ : std_tz_name_; |
@@ -537,14 +614,22 @@ int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) { |
// Returns current time as the number of milliseconds since |
// 00:00:00 UTC, January 1, 1970. |
double OS::TimeCurrentMillis() { |
- return Time::Now().ToJsTime(); |
+ Time t; |
+ t.SetToCurrentTime(); |
+ return t.ToJSTime(); |
+} |
+ |
+ |
+// Returns the tickcounter based on timeGetTime. |
+int64_t OS::Ticks() { |
+ return timeGetTime() * 1000; // Convert to microseconds. |
} |
// Returns a string identifying the current timezone taking into |
// account daylight saving. |
const char* OS::LocalTimezone(double time) { |
- return Win32Time(time).LocalTimezone(); |
+ return Time(time).LocalTimezone(); |
} |
@@ -552,7 +637,7 @@ const char* OS::LocalTimezone(double time) { |
// taking daylight savings time into account. |
double OS::LocalTimeOffset() { |
// Use current time, rounded to the millisecond. |
- Win32Time t(TimeCurrentMillis()); |
+ Time t(TimeCurrentMillis()); |
// Time::LocalOffset inlcudes any daylight savings offset, so subtract it. |
return static_cast<double>(t.LocalOffset() - t.DaylightSavingsOffset()); |
} |
@@ -561,7 +646,7 @@ double OS::LocalTimeOffset() { |
// Returns the daylight savings offset in milliseconds for the given |
// time. |
double OS::DaylightSavingsOffset(double time) { |
- int64_t offset = Win32Time(time).DaylightSavingsOffset(); |
+ int64_t offset = Time(time).DaylightSavingsOffset(); |
return static_cast<double>(offset); |
} |