WTF::ParkingLot should stop using std::chrono because std::chrono::duration casts...
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 5 Nov 2016 03:02:39 +0000 (03:02 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 5 Nov 2016 03:02:39 +0000 (03:02 +0000)
commit693621c97a2682b7fea524648db71802f8ef7fb9
tree75062e9d244fa94d43df6f12c2531cbdc9031005
parent581ab7b015186bb1949eef5e04596b20d16a05a1
WTF::ParkingLot should stop using std::chrono because std::chrono::duration casts are prone to overflows
https://bugs.webkit.org/show_bug.cgi?id=152045

Reviewed by Andy Estes.
Source/JavaScriptCore:

Probably the nicest example of why this patch is a good idea is the change in
AtomicsObject.cpp.

* jit/ICStats.cpp:
(JSC::ICStats::ICStats):
* runtime/AtomicsObject.cpp:
(JSC::atomicsFuncWait):

Source/WebCore:

No new layout tests because no new behavior. The new WTF time classes have some unit tests
in TestWebKitAPI.

* fileapi/ThreadableBlobRegistry.cpp:
(WebCore::ThreadableBlobRegistry::blobSize):
* platform/MainThreadSharedTimer.h:
* platform/SharedTimer.h:
* platform/ThreadTimers.cpp:
(WebCore::ThreadTimers::updateSharedTimer):
* platform/cf/MainThreadSharedTimerCF.cpp:
(WebCore::MainThreadSharedTimer::setFireInterval):
* platform/efl/MainThreadSharedTimerEfl.cpp:
(WebCore::MainThreadSharedTimer::setFireInterval):
* platform/glib/MainThreadSharedTimerGLib.cpp:
(WebCore::MainThreadSharedTimer::setFireInterval):
* platform/win/MainThreadSharedTimerWin.cpp:
(WebCore::MainThreadSharedTimer::setFireInterval):
* workers/WorkerRunLoop.cpp:
(WebCore::WorkerRunLoop::runInMode):

Source/WebKit2:

* Platform/IPC/Connection.cpp:
(IPC::Connection::SyncMessageState::wait):
(IPC::Connection::sendMessage):
(IPC::Connection::timeoutRespectingIgnoreTimeoutsForTesting):
(IPC::Connection::waitForMessage):
(IPC::Connection::sendSyncMessage):
(IPC::Connection::waitForSyncReply):
* Platform/IPC/Connection.h:
(IPC::Connection::sendSync):
(IPC::Connection::waitForAndDispatchImmediately):
* Platform/IPC/MessageSender.h:
(IPC::MessageSender::sendSync):
* UIProcess/ChildProcessProxy.h:
(WebKit::ChildProcessProxy::sendSync):
* UIProcess/Network/NetworkProcessProxy.cpp:
(WebKit::NetworkProcessProxy::sendProcessWillSuspendImminently):
* UIProcess/Storage/StorageManager.cpp:
(WebKit::StorageManager::applicationWillTerminate):
* UIProcess/WebProcessProxy.cpp:
(WebKit::WebProcessProxy::sendProcessWillSuspendImminently):
* UIProcess/WebResourceLoadStatisticsStore.cpp:
(WebKit::WebResourceLoadStatisticsStore::applicationWillTerminate):
* UIProcess/mac/RemoteLayerTreeDrawingAreaProxy.h:
* UIProcess/mac/RemoteLayerTreeDrawingAreaProxy.mm:
(-[WKOneShotDisplayLinkHandler displayLinkFired:]):
(WebKit::RemoteLayerTreeDrawingAreaProxy::commitLayerTree):
(WebKit::RemoteLayerTreeDrawingAreaProxy::didRefreshDisplay):
(WebKit::RemoteLayerTreeDrawingAreaProxy::waitForDidUpdateActivityState):
* UIProcess/mac/TiledCoreAnimationDrawingAreaProxy.mm:
(WebKit::TiledCoreAnimationDrawingAreaProxy::waitForDidUpdateActivityState):
* UIProcess/mac/WKImmediateActionController.mm:
(-[WKImmediateActionController immediateActionRecognizerWillBeginAnimation:]):
* UIProcess/mac/WebPageProxyMac.mm:
(WebKit::WebPageProxy::stringSelectionForPasteboard):
(WebKit::WebPageProxy::dataSelectionForPasteboard):
(WebKit::WebPageProxy::readSelectionFromPasteboard):
(WebKit::WebPageProxy::shouldDelayWindowOrderingForEvent):
(WebKit::WebPageProxy::acceptsFirstMouse):
* WebProcess/WebCoreSupport/WebChromeClient.cpp:
(WebKit::WebChromeClient::runBeforeUnloadConfirmPanel):
(WebKit::WebChromeClient::runJavaScriptAlert):
(WebKit::WebChromeClient::runJavaScriptConfirm):
(WebKit::WebChromeClient::runJavaScriptPrompt):
(WebKit::WebChromeClient::print):
(WebKit::WebChromeClient::exceededDatabaseQuota):
(WebKit::WebChromeClient::reachedApplicationCacheOriginQuota):
* WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:
(WebKit::WebFrameLoaderClient::dispatchDecidePolicyForResponse):
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::postSynchronousMessageForTesting):

Source/WTF:

We used to use 'double' for all time measurements. Sometimes it was milliseconds,
sometimes it was seconds. Sometimes we measured a span of time, sometimes we spoke of time
since some epoch. When we spoke of time since epoch, we either used a monotonic clock or
a wall clock. The type - always 'double' - never told us what kind of time we had, even
though there were roughly six of them (sec interval, ms interval, sec since epoch on wall,
ms since epoch on wall, sec since epoch monotonic, ms since epoch monotonic).

At some point, we thought that it would be a good idea to replace these doubles with
std::chrono. But since replacing some things with std::chrono, we found it to be terribly
inconvenient:

- Outrageous API. I never want to say std::chrono::milliseconds(blah). I never want to say
  std::chrono::steady_clock::timepoint. The syntax for duration_cast is ugly, and ideally
  duration_cast would not even be a thing.

- No overflow protection. std::chrono uses integers by default and using anything else is
  clumsy. But the integer math is done without regard for the rough edges of integer math,
  so any cast between std::chrono types risks overflow. Any comparison risks overflow
  because it may do conversions silently. We have even found bugs where some C++
  implementations had more overflows than others, which ends up being a special kind of
  hell. In many cases, the overflow also has nasal demons.

It's an error to represent time using integers. It would have been excusable back when
floating point math was not guaranteed to be supported on all platforms, but that would
have been a long time ago. Time is a continuous, infinite concept and it's a perfect fit
for floating point:

- Floating point preserves precision under multiplication in all but extreme cases, so
  using floating point for time means that unit conversions are almost completely
  lossless. This means that we don't have to think very hard about what units to use. In
  this patch, we use seconds almost everywhere. We only convert at boundaries, like an API
  boundary that wants something other than seconds.

- Floating point makes it easy to reason about infinity, which is something that time code
  wants to do a lot. Example: when would you like to timeout? Infinity please! This is the
  most elegant way of having an API support both a timeout variant and a no-timeout
  variant.

- Floating point does well-understood things when math goes wrong, and these things are
  pretty well optimized to match what a mathematician would do when computing with real
  numbers represented using scientific notation with a finite number of significant
  digits. This means that time math under floating point looks like normal math. On the
  other hand, std::chrono time math looks like garbage because you have to always check
  for multiple possible UB corners whenever you touch large integers. Integers that
  represent time are very likely to be large and you don't have to do much to overflow
  them. At this time, based on the number of bugs we have already seen due to chrono
  overflows, I am not certain that we even understand what are all of the corner cases
  that we should even check for.

This patch introduces a new set of timekeeping classes that are all based on double, and
all internally use seconds. These classes support algebraic typing. The classes are:

- Seconds: this is for measuring a duration.
- WallTime: time since epoch according to a wall clock (aka real time clock).
- MonotonicTime: time since epoch according to a monotonic clock.
- ClockType: enum that says either Wall or Monotonic.
- TimeWithDynamicClockType: a tuple of double and ClockType, which represents either a
  wall time or a monotonic time.

All of these classes behave like C++ values and are cheap to copy around since they are
very nearly POD. This supports comprehensive conversions between the various time types.
Most of this is by way of algebra. Here are just some of the rules we recognize:

WallTime = WallTime + Seconds
Seconds = WallTime - WallTime
MonotonicTime = MonotonicTime + Seconds
etc...

We support negative, infinite, and NaN times because math.

We support conversions between MonotonicTime and WallTime, like:

WallTime wt = mt.approximateWallTime()

This is called this "approximate" because the only way to do it is to get the current time
on both clocks and convert relative to that.

Many of our APIs would be happy using whatever notion of time the user wanted to use. For
those APIs, which includes Condition and ParkingLot, we have TimeWithDynamicClockType. You
can automatically convert WallTime or MonotonicTime to TimeWithDynamicClockType. This
means that if you use a WallTime with Condition::waitUntil, then Condition's internal
logic for when it should wake up makes its decision based on the current WallTime - but if
you use MonotonicTime then waitUntil will make its decision based on current
MonotonicTime. This is a greater level of flexibility than chrono allowed, since chrono
did not have the concept of a dynamic clock type.

This patch does not include conversions between std::chrono and these new time classes,
because past experience shows that we're quite bad at getting conversions between
std::chrono and anything else right. Also, I didn't need such conversion code because this
patch only converts code that transitively touches ParkingLot and Condition. It was easy
to get all of that code onto the new time classes.

* WTF.xcodeproj/project.pbxproj:
* wtf/AutomaticThread.cpp:
(WTF::AutomaticThread::start):
* wtf/CMakeLists.txt:
* wtf/ClockType.cpp: Added.
(WTF::printInternal):
* wtf/ClockType.h: Added.
* wtf/Condition.h:
(WTF::ConditionBase::waitUntil):
(WTF::ConditionBase::waitFor):
(WTF::ConditionBase::wait):
(WTF::ConditionBase::waitUntilWallClockSeconds): Deleted.
(WTF::ConditionBase::waitUntilMonotonicClockSeconds): Deleted.
(WTF::ConditionBase::waitForSeconds): Deleted.
(WTF::ConditionBase::waitForSecondsImpl): Deleted.
(WTF::ConditionBase::waitForImpl): Deleted.
(WTF::ConditionBase::absoluteFromRelative): Deleted.
* wtf/CrossThreadQueue.h:
(WTF::CrossThreadQueue<DataType>::waitForMessage):
* wtf/CurrentTime.cpp:
(WTF::sleep):
* wtf/MessageQueue.h:
(WTF::MessageQueue::infiniteTime): Deleted.
* wtf/MonotonicTime.cpp: Added.
(WTF::MonotonicTime::now):
(WTF::MonotonicTime::approximateWallTime):
(WTF::MonotonicTime::dump):
(WTF::MonotonicTime::sleep):
* wtf/MonotonicTime.h: Added.
(WTF::MonotonicTime::MonotonicTime):
(WTF::MonotonicTime::fromRawDouble):
(WTF::MonotonicTime::infinity):
(WTF::MonotonicTime::secondsSinceEpoch):
(WTF::MonotonicTime::approximateMonotonicTime):
(WTF::MonotonicTime::operator bool):
(WTF::MonotonicTime::operator+):
(WTF::MonotonicTime::operator-):
(WTF::MonotonicTime::operator+=):
(WTF::MonotonicTime::operator-=):
(WTF::MonotonicTime::operator==):
(WTF::MonotonicTime::operator!=):
(WTF::MonotonicTime::operator<):
(WTF::MonotonicTime::operator>):
(WTF::MonotonicTime::operator<=):
(WTF::MonotonicTime::operator>=):
* wtf/ParkingLot.cpp:
(WTF::ParkingLot::parkConditionallyImpl):
(WTF::ParkingLot::unparkOne):
(WTF::ParkingLot::unparkOneImpl):
(WTF::ParkingLot::unparkCount):
* wtf/ParkingLot.h:
(WTF::ParkingLot::parkConditionally):
(WTF::ParkingLot::compareAndPark):
* wtf/Seconds.cpp: Added.
(WTF::Seconds::operator+):
(WTF::Seconds::operator-):
(WTF::Seconds::dump):
(WTF::Seconds::sleep):
* wtf/Seconds.h: Added.
(WTF::Seconds::Seconds):
(WTF::Seconds::value):
(WTF::Seconds::seconds):
(WTF::Seconds::milliseconds):
(WTF::Seconds::microseconds):
(WTF::Seconds::nanoseconds):
(WTF::Seconds::fromMilliseconds):
(WTF::Seconds::fromMicroseconds):
(WTF::Seconds::fromNanoseconds):
(WTF::Seconds::infinity):
(WTF::Seconds::operator bool):
(WTF::Seconds::operator+):
(WTF::Seconds::operator-):
(WTF::Seconds::operator*):
(WTF::Seconds::operator/):
(WTF::Seconds::operator+=):
(WTF::Seconds::operator-=):
(WTF::Seconds::operator*=):
(WTF::Seconds::operator/=):
(WTF::Seconds::operator==):
(WTF::Seconds::operator!=):
(WTF::Seconds::operator<):
(WTF::Seconds::operator>):
(WTF::Seconds::operator<=):
(WTF::Seconds::operator>=):
* wtf/TimeWithDynamicClockType.cpp: Added.
(WTF::TimeWithDynamicClockType::now):
(WTF::TimeWithDynamicClockType::nowWithSameClock):
(WTF::TimeWithDynamicClockType::wallTime):
(WTF::TimeWithDynamicClockType::monotonicTime):
(WTF::TimeWithDynamicClockType::approximateWallTime):
(WTF::TimeWithDynamicClockType::approximateMonotonicTime):
(WTF::TimeWithDynamicClockType::operator-):
(WTF::TimeWithDynamicClockType::operator<):
(WTF::TimeWithDynamicClockType::operator>):
(WTF::TimeWithDynamicClockType::operator<=):
(WTF::TimeWithDynamicClockType::operator>=):
(WTF::TimeWithDynamicClockType::dump):
(WTF::TimeWithDynamicClockType::sleep):
* wtf/TimeWithDynamicClockType.h: Added.
(WTF::TimeWithDynamicClockType::TimeWithDynamicClockType):
(WTF::TimeWithDynamicClockType::fromRawDouble):
(WTF::TimeWithDynamicClockType::secondsSinceEpoch):
(WTF::TimeWithDynamicClockType::clockType):
(WTF::TimeWithDynamicClockType::withSameClockAndRawDouble):
(WTF::TimeWithDynamicClockType::operator bool):
(WTF::TimeWithDynamicClockType::operator+):
(WTF::TimeWithDynamicClockType::operator-):
(WTF::TimeWithDynamicClockType::operator+=):
(WTF::TimeWithDynamicClockType::operator-=):
(WTF::TimeWithDynamicClockType::operator==):
(WTF::TimeWithDynamicClockType::operator!=):
* wtf/WallTime.cpp: Added.
(WTF::WallTime::now):
(WTF::WallTime::approximateMonotonicTime):
(WTF::WallTime::dump):
(WTF::WallTime::sleep):
* wtf/WallTime.h: Added.
(WTF::WallTime::WallTime):
(WTF::WallTime::fromRawDouble):
(WTF::WallTime::infinity):
(WTF::WallTime::secondsSinceEpoch):
(WTF::WallTime::approximateWallTime):
(WTF::WallTime::operator bool):
(WTF::WallTime::operator+):
(WTF::WallTime::operator-):
(WTF::WallTime::operator+=):
(WTF::WallTime::operator-=):
(WTF::WallTime::operator==):
(WTF::WallTime::operator!=):
(WTF::WallTime::operator<):
(WTF::WallTime::operator>):
(WTF::WallTime::operator<=):
(WTF::WallTime::operator>=):
* wtf/threads/BinarySemaphore.cpp:
(WTF::BinarySemaphore::wait):
* wtf/threads/BinarySemaphore.h:

Tools:

* TestWebKitAPI/CMakeLists.txt:
* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WTF/Condition.cpp:
(TestWebKitAPI::TEST):
* TestWebKitAPI/Tests/WTF/SynchronizedFixedQueue.cpp:
(TestWebKitAPI::ToUpperConverter::stopProducing):
(TestWebKitAPI::ToUpperConverter::stopConsuming):
* TestWebKitAPI/Tests/WTF/Time.cpp: Added.
(WTF::operator<<):
(TestWebKitAPI::TEST):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208415 268f45cc-cd09-0410-ab3c-d52691b4dbfc
63 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/jit/ICStats.cpp
Source/JavaScriptCore/runtime/AtomicsObject.cpp
Source/WTF/ChangeLog
Source/WTF/WTF.xcodeproj/project.pbxproj
Source/WTF/wtf/AutomaticThread.cpp
Source/WTF/wtf/CMakeLists.txt
Source/WTF/wtf/ClockType.cpp [new file with mode: 0644]
Source/WTF/wtf/ClockType.h [new file with mode: 0644]
Source/WTF/wtf/Condition.h
Source/WTF/wtf/CrossThreadQueue.h
Source/WTF/wtf/CurrentTime.cpp
Source/WTF/wtf/MessageQueue.h
Source/WTF/wtf/MonotonicTime.cpp [new file with mode: 0644]
Source/WTF/wtf/MonotonicTime.h [new file with mode: 0644]
Source/WTF/wtf/ParkingLot.cpp
Source/WTF/wtf/ParkingLot.h
Source/WTF/wtf/Seconds.cpp [new file with mode: 0644]
Source/WTF/wtf/Seconds.h [new file with mode: 0644]
Source/WTF/wtf/TimeWithDynamicClockType.cpp [new file with mode: 0644]
Source/WTF/wtf/TimeWithDynamicClockType.h [new file with mode: 0644]
Source/WTF/wtf/WallTime.cpp [new file with mode: 0644]
Source/WTF/wtf/WallTime.h [new file with mode: 0644]
Source/WTF/wtf/threads/BinarySemaphore.cpp
Source/WTF/wtf/threads/BinarySemaphore.h
Source/WebCore/ChangeLog
Source/WebCore/fileapi/ThreadableBlobRegistry.cpp
Source/WebCore/platform/MainThreadSharedTimer.h
Source/WebCore/platform/SharedTimer.h
Source/WebCore/platform/ThreadTimers.cpp
Source/WebCore/platform/cf/MainThreadSharedTimerCF.cpp
Source/WebCore/platform/efl/MainThreadSharedTimerEfl.cpp
Source/WebCore/platform/glib/MainThreadSharedTimerGLib.cpp
Source/WebCore/platform/win/MainThreadSharedTimerWin.cpp
Source/WebCore/workers/WorkerRunLoop.cpp
Source/WebKit2/ChangeLog
Source/WebKit2/Platform/IPC/Connection.cpp
Source/WebKit2/Platform/IPC/Connection.h
Source/WebKit2/Platform/IPC/MessageSender.h
Source/WebKit2/UIProcess/AcceleratedDrawingAreaProxy.cpp
Source/WebKit2/UIProcess/ChildProcessProxy.h
Source/WebKit2/UIProcess/DrawingAreaProxy.h
Source/WebKit2/UIProcess/Network/NetworkProcessProxy.cpp
Source/WebKit2/UIProcess/Storage/StorageManager.cpp
Source/WebKit2/UIProcess/WebProcessProxy.cpp
Source/WebKit2/UIProcess/WebResourceLoadStatisticsStore.cpp
Source/WebKit2/UIProcess/ios/WKContentView.mm
Source/WebKit2/UIProcess/ios/WebPageProxyIOS.mm
Source/WebKit2/UIProcess/mac/RemoteLayerTreeDrawingAreaProxy.h
Source/WebKit2/UIProcess/mac/RemoteLayerTreeDrawingAreaProxy.mm
Source/WebKit2/UIProcess/mac/TiledCoreAnimationDrawingAreaProxy.h
Source/WebKit2/UIProcess/mac/TiledCoreAnimationDrawingAreaProxy.mm
Source/WebKit2/UIProcess/mac/WKImmediateActionController.mm
Source/WebKit2/UIProcess/mac/WebPageProxyMac.mm
Source/WebKit2/WebProcess/WebCoreSupport/WebChromeClient.cpp
Source/WebKit2/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp
Source/WebKit2/WebProcess/WebPage/WebPage.cpp
Tools/ChangeLog
Tools/TestWebKitAPI/CMakeLists.txt
Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
Tools/TestWebKitAPI/Tests/WTF/Condition.cpp
Tools/TestWebKitAPI/Tests/WTF/SynchronizedFixedQueue.cpp
Tools/TestWebKitAPI/Tests/WTF/Time.cpp [new file with mode: 0644]