haikuwebkit/Source/WTF/wtf/ParkingLot.cpp

812 lines
27 KiB
C++
Raw Permalink Normal View History

WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
/*
Silence leaks in ParkingLot https://bugs.webkit.org/show_bug.cgi?id=155510 Reviewed by Alexey Proskuryakov. ParkingLot has a concurrent hashtable that it reallocates on demand. It will not reallocate it in steady state. The hashtable is sized to accommodate the high watermark of the number of active threads - so long as the program doesn't just keep starting an unbounded number of threads that are all active, the hashtable will stop resizing. Each resize operation is designed to stay out of the way of the data-access-parallel normal path, in which two threads operating on different lock addresses don't have to synchronize. To do this, it simply drops the old hashtable without deleting it, so that threads that were still using it don't crash. They will realize that they have the wrong hashtable before doing anything bad, but we don't have a way of proving when all of those threads are no longer going to read from the old hashtables. So, we just leak them. This is a bounded leak, since the hashtable resizes exponentially. Thus the total memory utilization of all hashtables, including the leaked ones, converges to a linear function of the current hashtable's size (it's 2 * size of current hashtable). But this leak is a problem for leaks tools, which will always report this leak. This is not useful. It's better to silence the leak. That's what this patch does by ensuring that all hashtables, including leaked ones, end up in a global vector. This is perf-neutral. This requires making a StaticWordLock variant of WordLock. That's probably the biggest part of this change. * wtf/ParkingLot.cpp: * wtf/WordLock.cpp: (WTF::WordLockBase::lockSlow): (WTF::WordLockBase::unlockSlow): (WTF::WordLock::lockSlow): Deleted. (WTF::WordLock::unlockSlow): Deleted. * wtf/WordLock.h: (WTF::WordLockBase::lock): (WTF::WordLockBase::isLocked): (WTF::WordLock::WordLock): (WTF::WordLock::lock): Deleted. (WTF::WordLock::isLocked): Deleted. Canonical link: https://commits.webkit.org/173707@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@198345 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-03-17 18:54:15 +00:00
* Copyright (C) 2015-2016 Apple Inc. All rights reserved.
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
Use pragma once in WTF https://bugs.webkit.org/show_bug.cgi?id=190527 Reviewed by Chris Dumez. Source/WTF: We also need to consistently include wtf headers from within wtf so we can build wtf without symbol redefinition errors from including the copy in Source and the copy in the build directory. * wtf/ASCIICType.h: * wtf/Assertions.cpp: * wtf/Assertions.h: * wtf/Atomics.h: * wtf/AutomaticThread.cpp: * wtf/AutomaticThread.h: * wtf/BackwardsGraph.h: * wtf/Bag.h: * wtf/BagToHashMap.h: * wtf/BitVector.cpp: * wtf/BitVector.h: * wtf/Bitmap.h: * wtf/BloomFilter.h: * wtf/Box.h: * wtf/BubbleSort.h: * wtf/BumpPointerAllocator.h: * wtf/ByteOrder.h: * wtf/CPUTime.cpp: * wtf/CallbackAggregator.h: * wtf/CheckedArithmetic.h: * wtf/CheckedBoolean.h: * wtf/ClockType.cpp: * wtf/ClockType.h: * wtf/CommaPrinter.h: * wtf/CompilationThread.cpp: * wtf/CompilationThread.h: * wtf/Compiler.h: * wtf/ConcurrentPtrHashSet.cpp: * wtf/ConcurrentVector.h: * wtf/Condition.h: * wtf/CountingLock.cpp: * wtf/CrossThreadTaskHandler.cpp: * wtf/CryptographicUtilities.cpp: * wtf/CryptographicUtilities.h: * wtf/CryptographicallyRandomNumber.cpp: * wtf/CryptographicallyRandomNumber.h: * wtf/CurrentTime.cpp: * wtf/DataLog.cpp: * wtf/DataLog.h: * wtf/DateMath.cpp: * wtf/DateMath.h: * wtf/DecimalNumber.cpp: * wtf/DecimalNumber.h: * wtf/Deque.h: * wtf/DisallowCType.h: * wtf/Dominators.h: * wtf/DoublyLinkedList.h: * wtf/FastBitVector.cpp: * wtf/FastMalloc.cpp: * wtf/FastMalloc.h: * wtf/FeatureDefines.h: * wtf/FilePrintStream.cpp: * wtf/FilePrintStream.h: * wtf/FlipBytes.h: * wtf/FunctionDispatcher.cpp: * wtf/FunctionDispatcher.h: * wtf/GetPtr.h: * wtf/Gigacage.cpp: * wtf/GlobalVersion.cpp: * wtf/GraphNodeWorklist.h: * wtf/GregorianDateTime.cpp: * wtf/GregorianDateTime.h: * wtf/HashFunctions.h: * wtf/HashMap.h: * wtf/HashMethod.h: * wtf/HashSet.h: * wtf/HashTable.cpp: * wtf/HashTraits.h: * wtf/Indenter.h: * wtf/IndexSparseSet.h: * wtf/InlineASM.h: * wtf/Insertion.h: * wtf/IteratorAdaptors.h: * wtf/IteratorRange.h: * wtf/JSONValues.cpp: * wtf/JSValueMalloc.cpp: * wtf/LEBDecoder.h: * wtf/Language.cpp: * wtf/ListDump.h: * wtf/Lock.cpp: * wtf/Lock.h: * wtf/LockAlgorithm.h: * wtf/LockedPrintStream.cpp: * wtf/Locker.h: * wtf/MD5.cpp: * wtf/MD5.h: * wtf/MainThread.cpp: * wtf/MainThread.h: * wtf/MallocPtr.h: * wtf/MathExtras.h: * wtf/MediaTime.cpp: * wtf/MediaTime.h: * wtf/MemoryPressureHandler.cpp: * wtf/MessageQueue.h: * wtf/MetaAllocator.cpp: * wtf/MetaAllocator.h: * wtf/MetaAllocatorHandle.h: * wtf/MonotonicTime.cpp: * wtf/MonotonicTime.h: * wtf/NakedPtr.h: * wtf/NoLock.h: * wtf/NoTailCalls.h: * wtf/Noncopyable.h: * wtf/NumberOfCores.cpp: * wtf/NumberOfCores.h: * wtf/OSAllocator.h: * wtf/OSAllocatorPosix.cpp: * wtf/OSRandomSource.cpp: * wtf/OSRandomSource.h: * wtf/ObjcRuntimeExtras.h: * wtf/OrderMaker.h: * wtf/PackedIntVector.h: * wtf/PageAllocation.h: * wtf/PageBlock.cpp: * wtf/PageBlock.h: * wtf/PageReservation.h: * wtf/ParallelHelperPool.cpp: * wtf/ParallelHelperPool.h: * wtf/ParallelJobs.h: * wtf/ParallelJobsLibdispatch.h: * wtf/ParallelVectorIterator.h: * wtf/ParkingLot.cpp: * wtf/ParkingLot.h: * wtf/Platform.h: * wtf/PointerComparison.h: * wtf/Poisoned.cpp: * wtf/PrintStream.cpp: * wtf/PrintStream.h: * wtf/ProcessID.h: * wtf/ProcessPrivilege.cpp: * wtf/RAMSize.cpp: * wtf/RAMSize.h: * wtf/RandomDevice.cpp: * wtf/RandomNumber.cpp: * wtf/RandomNumber.h: * wtf/RandomNumberSeed.h: * wtf/RangeSet.h: * wtf/RawPointer.h: * wtf/ReadWriteLock.cpp: * wtf/RedBlackTree.h: * wtf/Ref.h: * wtf/RefCountedArray.h: * wtf/RefCountedLeakCounter.cpp: * wtf/RefCountedLeakCounter.h: * wtf/RefCounter.h: * wtf/RefPtr.h: * wtf/RetainPtr.h: * wtf/RunLoop.cpp: * wtf/RunLoop.h: * wtf/RunLoopTimer.h: * wtf/RunLoopTimerCF.cpp: * wtf/SHA1.cpp: * wtf/SHA1.h: * wtf/SaturatedArithmetic.h: (saturatedSubtraction): * wtf/SchedulePair.h: * wtf/SchedulePairCF.cpp: * wtf/SchedulePairMac.mm: * wtf/ScopedLambda.h: * wtf/Seconds.cpp: * wtf/Seconds.h: * wtf/SegmentedVector.h: * wtf/SentinelLinkedList.h: * wtf/SharedTask.h: * wtf/SimpleStats.h: * wtf/SingleRootGraph.h: * wtf/SinglyLinkedList.h: * wtf/SixCharacterHash.cpp: * wtf/SixCharacterHash.h: * wtf/SmallPtrSet.h: * wtf/Spectrum.h: * wtf/StackBounds.cpp: * wtf/StackBounds.h: * wtf/StackStats.cpp: * wtf/StackStats.h: * wtf/StackTrace.cpp: * wtf/StdLibExtras.h: * wtf/StreamBuffer.h: * wtf/StringHashDumpContext.h: * wtf/StringPrintStream.cpp: * wtf/StringPrintStream.h: * wtf/ThreadGroup.cpp: * wtf/ThreadMessage.cpp: * wtf/ThreadSpecific.h: * wtf/Threading.cpp: * wtf/Threading.h: * wtf/ThreadingPrimitives.h: * wtf/ThreadingPthreads.cpp: * wtf/TimeWithDynamicClockType.cpp: * wtf/TimeWithDynamicClockType.h: * wtf/TimingScope.cpp: * wtf/TinyLRUCache.h: * wtf/TinyPtrSet.h: * wtf/TriState.h: * wtf/TypeCasts.h: * wtf/UUID.cpp: * wtf/UnionFind.h: * wtf/VMTags.h: * wtf/ValueCheck.h: * wtf/Vector.h: * wtf/VectorTraits.h: * wtf/WallTime.cpp: * wtf/WallTime.h: * wtf/WeakPtr.h: * wtf/WeakRandom.h: * wtf/WordLock.cpp: * wtf/WordLock.h: * wtf/WorkQueue.cpp: * wtf/WorkQueue.h: * wtf/WorkerPool.cpp: * wtf/cf/LanguageCF.cpp: * wtf/cf/RunLoopCF.cpp: * wtf/cocoa/Entitlements.mm: * wtf/cocoa/MachSendRight.cpp: * wtf/cocoa/MainThreadCocoa.mm: * wtf/cocoa/MemoryFootprintCocoa.cpp: * wtf/cocoa/WorkQueueCocoa.cpp: * wtf/dtoa.cpp: * wtf/dtoa.h: * wtf/ios/WebCoreThread.cpp: * wtf/ios/WebCoreThread.h: * wtf/mac/AppKitCompatibilityDeclarations.h: * wtf/mac/DeprecatedSymbolsUsedBySafari.mm: * wtf/mbmalloc.cpp: * wtf/persistence/PersistentCoders.cpp: * wtf/persistence/PersistentDecoder.cpp: * wtf/persistence/PersistentEncoder.cpp: * wtf/spi/cf/CFBundleSPI.h: * wtf/spi/darwin/CommonCryptoSPI.h: * wtf/text/ASCIIFastPath.h: * wtf/text/ASCIILiteral.cpp: * wtf/text/AtomicString.cpp: * wtf/text/AtomicString.h: * wtf/text/AtomicStringHash.h: * wtf/text/AtomicStringImpl.cpp: * wtf/text/AtomicStringImpl.h: * wtf/text/AtomicStringTable.cpp: * wtf/text/AtomicStringTable.h: * wtf/text/Base64.cpp: * wtf/text/CString.cpp: * wtf/text/CString.h: * wtf/text/ConversionMode.h: * wtf/text/ExternalStringImpl.cpp: * wtf/text/IntegerToStringConversion.h: * wtf/text/LChar.h: * wtf/text/LineEnding.cpp: * wtf/text/StringBuffer.h: * wtf/text/StringBuilder.cpp: * wtf/text/StringBuilder.h: * wtf/text/StringBuilderJSON.cpp: * wtf/text/StringCommon.h: * wtf/text/StringConcatenate.h: * wtf/text/StringHash.h: * wtf/text/StringImpl.cpp: * wtf/text/StringImpl.h: * wtf/text/StringOperators.h: * wtf/text/StringView.cpp: * wtf/text/StringView.h: * wtf/text/SymbolImpl.cpp: * wtf/text/SymbolRegistry.cpp: * wtf/text/SymbolRegistry.h: * wtf/text/TextBreakIterator.cpp: * wtf/text/TextBreakIterator.h: * wtf/text/TextBreakIteratorInternalICU.h: * wtf/text/TextPosition.h: * wtf/text/TextStream.cpp: * wtf/text/UniquedStringImpl.h: * wtf/text/WTFString.cpp: * wtf/text/WTFString.h: * wtf/text/cocoa/StringCocoa.mm: * wtf/text/cocoa/StringViewCocoa.mm: * wtf/text/cocoa/TextBreakIteratorInternalICUCocoa.cpp: * wtf/text/icu/UTextProvider.cpp: * wtf/text/icu/UTextProvider.h: * wtf/text/icu/UTextProviderLatin1.cpp: * wtf/text/icu/UTextProviderLatin1.h: * wtf/text/icu/UTextProviderUTF16.cpp: * wtf/text/icu/UTextProviderUTF16.h: * wtf/threads/BinarySemaphore.cpp: * wtf/threads/BinarySemaphore.h: * wtf/threads/Signals.cpp: * wtf/unicode/CharacterNames.h: * wtf/unicode/Collator.h: * wtf/unicode/CollatorDefault.cpp: * wtf/unicode/UTF8.cpp: * wtf/unicode/UTF8.h: Tools: Put WorkQueue in namespace DRT so it does not conflict with WTF::WorkQueue. * DumpRenderTree/TestRunner.cpp: (TestRunner::queueLoadHTMLString): (TestRunner::queueLoadAlternateHTMLString): (TestRunner::queueBackNavigation): (TestRunner::queueForwardNavigation): (TestRunner::queueLoadingScript): (TestRunner::queueNonLoadingScript): (TestRunner::queueReload): * DumpRenderTree/WorkQueue.cpp: (WorkQueue::singleton): Deleted. (WorkQueue::WorkQueue): Deleted. (WorkQueue::queue): Deleted. (WorkQueue::dequeue): Deleted. (WorkQueue::count): Deleted. (WorkQueue::clear): Deleted. (WorkQueue::processWork): Deleted. * DumpRenderTree/WorkQueue.h: (WorkQueue::setFrozen): Deleted. * DumpRenderTree/WorkQueueItem.h: * DumpRenderTree/mac/DumpRenderTree.mm: (runTest): * DumpRenderTree/mac/FrameLoadDelegate.mm: (-[FrameLoadDelegate processWork:]): (-[FrameLoadDelegate webView:locationChangeDone:forDataSource:]): * DumpRenderTree/mac/TestRunnerMac.mm: (TestRunner::notifyDone): (TestRunner::forceImmediateCompletion): (TestRunner::queueLoad): * DumpRenderTree/win/DumpRenderTree.cpp: (runTest): * DumpRenderTree/win/FrameLoadDelegate.cpp: (FrameLoadDelegate::processWork): (FrameLoadDelegate::locationChangeDone): * DumpRenderTree/win/TestRunnerWin.cpp: (TestRunner::notifyDone): (TestRunner::forceImmediateCompletion): (TestRunner::queueLoad): Canonical link: https://commits.webkit.org/205473@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@237099 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2018-10-15 14:24:49 +00:00
#include <wtf/ParkingLot.h>
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
#include <mutex>
Use pragma once in WTF https://bugs.webkit.org/show_bug.cgi?id=190527 Reviewed by Chris Dumez. Source/WTF: We also need to consistently include wtf headers from within wtf so we can build wtf without symbol redefinition errors from including the copy in Source and the copy in the build directory. * wtf/ASCIICType.h: * wtf/Assertions.cpp: * wtf/Assertions.h: * wtf/Atomics.h: * wtf/AutomaticThread.cpp: * wtf/AutomaticThread.h: * wtf/BackwardsGraph.h: * wtf/Bag.h: * wtf/BagToHashMap.h: * wtf/BitVector.cpp: * wtf/BitVector.h: * wtf/Bitmap.h: * wtf/BloomFilter.h: * wtf/Box.h: * wtf/BubbleSort.h: * wtf/BumpPointerAllocator.h: * wtf/ByteOrder.h: * wtf/CPUTime.cpp: * wtf/CallbackAggregator.h: * wtf/CheckedArithmetic.h: * wtf/CheckedBoolean.h: * wtf/ClockType.cpp: * wtf/ClockType.h: * wtf/CommaPrinter.h: * wtf/CompilationThread.cpp: * wtf/CompilationThread.h: * wtf/Compiler.h: * wtf/ConcurrentPtrHashSet.cpp: * wtf/ConcurrentVector.h: * wtf/Condition.h: * wtf/CountingLock.cpp: * wtf/CrossThreadTaskHandler.cpp: * wtf/CryptographicUtilities.cpp: * wtf/CryptographicUtilities.h: * wtf/CryptographicallyRandomNumber.cpp: * wtf/CryptographicallyRandomNumber.h: * wtf/CurrentTime.cpp: * wtf/DataLog.cpp: * wtf/DataLog.h: * wtf/DateMath.cpp: * wtf/DateMath.h: * wtf/DecimalNumber.cpp: * wtf/DecimalNumber.h: * wtf/Deque.h: * wtf/DisallowCType.h: * wtf/Dominators.h: * wtf/DoublyLinkedList.h: * wtf/FastBitVector.cpp: * wtf/FastMalloc.cpp: * wtf/FastMalloc.h: * wtf/FeatureDefines.h: * wtf/FilePrintStream.cpp: * wtf/FilePrintStream.h: * wtf/FlipBytes.h: * wtf/FunctionDispatcher.cpp: * wtf/FunctionDispatcher.h: * wtf/GetPtr.h: * wtf/Gigacage.cpp: * wtf/GlobalVersion.cpp: * wtf/GraphNodeWorklist.h: * wtf/GregorianDateTime.cpp: * wtf/GregorianDateTime.h: * wtf/HashFunctions.h: * wtf/HashMap.h: * wtf/HashMethod.h: * wtf/HashSet.h: * wtf/HashTable.cpp: * wtf/HashTraits.h: * wtf/Indenter.h: * wtf/IndexSparseSet.h: * wtf/InlineASM.h: * wtf/Insertion.h: * wtf/IteratorAdaptors.h: * wtf/IteratorRange.h: * wtf/JSONValues.cpp: * wtf/JSValueMalloc.cpp: * wtf/LEBDecoder.h: * wtf/Language.cpp: * wtf/ListDump.h: * wtf/Lock.cpp: * wtf/Lock.h: * wtf/LockAlgorithm.h: * wtf/LockedPrintStream.cpp: * wtf/Locker.h: * wtf/MD5.cpp: * wtf/MD5.h: * wtf/MainThread.cpp: * wtf/MainThread.h: * wtf/MallocPtr.h: * wtf/MathExtras.h: * wtf/MediaTime.cpp: * wtf/MediaTime.h: * wtf/MemoryPressureHandler.cpp: * wtf/MessageQueue.h: * wtf/MetaAllocator.cpp: * wtf/MetaAllocator.h: * wtf/MetaAllocatorHandle.h: * wtf/MonotonicTime.cpp: * wtf/MonotonicTime.h: * wtf/NakedPtr.h: * wtf/NoLock.h: * wtf/NoTailCalls.h: * wtf/Noncopyable.h: * wtf/NumberOfCores.cpp: * wtf/NumberOfCores.h: * wtf/OSAllocator.h: * wtf/OSAllocatorPosix.cpp: * wtf/OSRandomSource.cpp: * wtf/OSRandomSource.h: * wtf/ObjcRuntimeExtras.h: * wtf/OrderMaker.h: * wtf/PackedIntVector.h: * wtf/PageAllocation.h: * wtf/PageBlock.cpp: * wtf/PageBlock.h: * wtf/PageReservation.h: * wtf/ParallelHelperPool.cpp: * wtf/ParallelHelperPool.h: * wtf/ParallelJobs.h: * wtf/ParallelJobsLibdispatch.h: * wtf/ParallelVectorIterator.h: * wtf/ParkingLot.cpp: * wtf/ParkingLot.h: * wtf/Platform.h: * wtf/PointerComparison.h: * wtf/Poisoned.cpp: * wtf/PrintStream.cpp: * wtf/PrintStream.h: * wtf/ProcessID.h: * wtf/ProcessPrivilege.cpp: * wtf/RAMSize.cpp: * wtf/RAMSize.h: * wtf/RandomDevice.cpp: * wtf/RandomNumber.cpp: * wtf/RandomNumber.h: * wtf/RandomNumberSeed.h: * wtf/RangeSet.h: * wtf/RawPointer.h: * wtf/ReadWriteLock.cpp: * wtf/RedBlackTree.h: * wtf/Ref.h: * wtf/RefCountedArray.h: * wtf/RefCountedLeakCounter.cpp: * wtf/RefCountedLeakCounter.h: * wtf/RefCounter.h: * wtf/RefPtr.h: * wtf/RetainPtr.h: * wtf/RunLoop.cpp: * wtf/RunLoop.h: * wtf/RunLoopTimer.h: * wtf/RunLoopTimerCF.cpp: * wtf/SHA1.cpp: * wtf/SHA1.h: * wtf/SaturatedArithmetic.h: (saturatedSubtraction): * wtf/SchedulePair.h: * wtf/SchedulePairCF.cpp: * wtf/SchedulePairMac.mm: * wtf/ScopedLambda.h: * wtf/Seconds.cpp: * wtf/Seconds.h: * wtf/SegmentedVector.h: * wtf/SentinelLinkedList.h: * wtf/SharedTask.h: * wtf/SimpleStats.h: * wtf/SingleRootGraph.h: * wtf/SinglyLinkedList.h: * wtf/SixCharacterHash.cpp: * wtf/SixCharacterHash.h: * wtf/SmallPtrSet.h: * wtf/Spectrum.h: * wtf/StackBounds.cpp: * wtf/StackBounds.h: * wtf/StackStats.cpp: * wtf/StackStats.h: * wtf/StackTrace.cpp: * wtf/StdLibExtras.h: * wtf/StreamBuffer.h: * wtf/StringHashDumpContext.h: * wtf/StringPrintStream.cpp: * wtf/StringPrintStream.h: * wtf/ThreadGroup.cpp: * wtf/ThreadMessage.cpp: * wtf/ThreadSpecific.h: * wtf/Threading.cpp: * wtf/Threading.h: * wtf/ThreadingPrimitives.h: * wtf/ThreadingPthreads.cpp: * wtf/TimeWithDynamicClockType.cpp: * wtf/TimeWithDynamicClockType.h: * wtf/TimingScope.cpp: * wtf/TinyLRUCache.h: * wtf/TinyPtrSet.h: * wtf/TriState.h: * wtf/TypeCasts.h: * wtf/UUID.cpp: * wtf/UnionFind.h: * wtf/VMTags.h: * wtf/ValueCheck.h: * wtf/Vector.h: * wtf/VectorTraits.h: * wtf/WallTime.cpp: * wtf/WallTime.h: * wtf/WeakPtr.h: * wtf/WeakRandom.h: * wtf/WordLock.cpp: * wtf/WordLock.h: * wtf/WorkQueue.cpp: * wtf/WorkQueue.h: * wtf/WorkerPool.cpp: * wtf/cf/LanguageCF.cpp: * wtf/cf/RunLoopCF.cpp: * wtf/cocoa/Entitlements.mm: * wtf/cocoa/MachSendRight.cpp: * wtf/cocoa/MainThreadCocoa.mm: * wtf/cocoa/MemoryFootprintCocoa.cpp: * wtf/cocoa/WorkQueueCocoa.cpp: * wtf/dtoa.cpp: * wtf/dtoa.h: * wtf/ios/WebCoreThread.cpp: * wtf/ios/WebCoreThread.h: * wtf/mac/AppKitCompatibilityDeclarations.h: * wtf/mac/DeprecatedSymbolsUsedBySafari.mm: * wtf/mbmalloc.cpp: * wtf/persistence/PersistentCoders.cpp: * wtf/persistence/PersistentDecoder.cpp: * wtf/persistence/PersistentEncoder.cpp: * wtf/spi/cf/CFBundleSPI.h: * wtf/spi/darwin/CommonCryptoSPI.h: * wtf/text/ASCIIFastPath.h: * wtf/text/ASCIILiteral.cpp: * wtf/text/AtomicString.cpp: * wtf/text/AtomicString.h: * wtf/text/AtomicStringHash.h: * wtf/text/AtomicStringImpl.cpp: * wtf/text/AtomicStringImpl.h: * wtf/text/AtomicStringTable.cpp: * wtf/text/AtomicStringTable.h: * wtf/text/Base64.cpp: * wtf/text/CString.cpp: * wtf/text/CString.h: * wtf/text/ConversionMode.h: * wtf/text/ExternalStringImpl.cpp: * wtf/text/IntegerToStringConversion.h: * wtf/text/LChar.h: * wtf/text/LineEnding.cpp: * wtf/text/StringBuffer.h: * wtf/text/StringBuilder.cpp: * wtf/text/StringBuilder.h: * wtf/text/StringBuilderJSON.cpp: * wtf/text/StringCommon.h: * wtf/text/StringConcatenate.h: * wtf/text/StringHash.h: * wtf/text/StringImpl.cpp: * wtf/text/StringImpl.h: * wtf/text/StringOperators.h: * wtf/text/StringView.cpp: * wtf/text/StringView.h: * wtf/text/SymbolImpl.cpp: * wtf/text/SymbolRegistry.cpp: * wtf/text/SymbolRegistry.h: * wtf/text/TextBreakIterator.cpp: * wtf/text/TextBreakIterator.h: * wtf/text/TextBreakIteratorInternalICU.h: * wtf/text/TextPosition.h: * wtf/text/TextStream.cpp: * wtf/text/UniquedStringImpl.h: * wtf/text/WTFString.cpp: * wtf/text/WTFString.h: * wtf/text/cocoa/StringCocoa.mm: * wtf/text/cocoa/StringViewCocoa.mm: * wtf/text/cocoa/TextBreakIteratorInternalICUCocoa.cpp: * wtf/text/icu/UTextProvider.cpp: * wtf/text/icu/UTextProvider.h: * wtf/text/icu/UTextProviderLatin1.cpp: * wtf/text/icu/UTextProviderLatin1.h: * wtf/text/icu/UTextProviderUTF16.cpp: * wtf/text/icu/UTextProviderUTF16.h: * wtf/threads/BinarySemaphore.cpp: * wtf/threads/BinarySemaphore.h: * wtf/threads/Signals.cpp: * wtf/unicode/CharacterNames.h: * wtf/unicode/Collator.h: * wtf/unicode/CollatorDefault.cpp: * wtf/unicode/UTF8.cpp: * wtf/unicode/UTF8.h: Tools: Put WorkQueue in namespace DRT so it does not conflict with WTF::WorkQueue. * DumpRenderTree/TestRunner.cpp: (TestRunner::queueLoadHTMLString): (TestRunner::queueLoadAlternateHTMLString): (TestRunner::queueBackNavigation): (TestRunner::queueForwardNavigation): (TestRunner::queueLoadingScript): (TestRunner::queueNonLoadingScript): (TestRunner::queueReload): * DumpRenderTree/WorkQueue.cpp: (WorkQueue::singleton): Deleted. (WorkQueue::WorkQueue): Deleted. (WorkQueue::queue): Deleted. (WorkQueue::dequeue): Deleted. (WorkQueue::count): Deleted. (WorkQueue::clear): Deleted. (WorkQueue::processWork): Deleted. * DumpRenderTree/WorkQueue.h: (WorkQueue::setFrozen): Deleted. * DumpRenderTree/WorkQueueItem.h: * DumpRenderTree/mac/DumpRenderTree.mm: (runTest): * DumpRenderTree/mac/FrameLoadDelegate.mm: (-[FrameLoadDelegate processWork:]): (-[FrameLoadDelegate webView:locationChangeDone:forDataSource:]): * DumpRenderTree/mac/TestRunnerMac.mm: (TestRunner::notifyDone): (TestRunner::forceImmediateCompletion): (TestRunner::queueLoad): * DumpRenderTree/win/DumpRenderTree.cpp: (runTest): * DumpRenderTree/win/FrameLoadDelegate.cpp: (FrameLoadDelegate::processWork): (FrameLoadDelegate::locationChangeDone): * DumpRenderTree/win/TestRunnerWin.cpp: (TestRunner::notifyDone): (TestRunner::forceImmediateCompletion): (TestRunner::queueLoad): Canonical link: https://commits.webkit.org/205473@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@237099 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2018-10-15 14:24:49 +00:00
#include <wtf/DataLog.h>
#include <wtf/HashFunctions.h>
#include <wtf/StringPrintStream.h>
#include <wtf/ThreadSpecific.h>
#include <wtf/Threading.h>
#include <wtf/Vector.h>
#include <wtf/WeakRandom.h>
#include <wtf/WordLock.h>
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
namespace WTF {
namespace {
static constexpr bool verbose = false;
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
struct ThreadData : public ThreadSafeRefCounted<ThreadData> {
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
WTF_MAKE_FAST_ALLOCATED;
public:
ThreadData();
~ThreadData();
[WTF] Introduce Thread class and use RefPtr<Thread> and align Windows Threading implementation semantics to Pthread one https://bugs.webkit.org/show_bug.cgi?id=170502 Reviewed by Mark Lam. Source/JavaScriptCore: * API/tests/CompareAndSwapTest.cpp: (testCompareAndSwap): * JavaScriptCore.xcodeproj/project.pbxproj: * b3/air/testair.cpp: * b3/testb3.cpp: (JSC::B3::run): * bytecode/SuperSampler.cpp: (JSC::initializeSuperSampler): * dfg/DFGWorklist.cpp: * disassembler/Disassembler.cpp: * heap/Heap.cpp: (JSC::Heap::lastChanceToFinalize): (JSC::Heap::notifyIsSafeToCollect): * heap/Heap.h: * heap/MachineStackMarker.cpp: (JSC::MachineThreads::~MachineThreads): (JSC::MachineThreads::addCurrentThread): (JSC::MachineThreads::removeThread): (JSC::MachineThreads::removeThreadIfFound): (JSC::MachineThreads::MachineThread::MachineThread): (JSC::MachineThreads::MachineThread::getRegisters): (JSC::MachineThreads::MachineThread::Registers::stackPointer): (JSC::MachineThreads::MachineThread::Registers::framePointer): (JSC::MachineThreads::MachineThread::Registers::instructionPointer): (JSC::MachineThreads::MachineThread::Registers::llintPC): (JSC::MachineThreads::MachineThread::captureStack): (JSC::MachineThreads::tryCopyOtherThreadStack): (JSC::MachineThreads::tryCopyOtherThreadStacks): (pthreadSignalHandlerSuspendResume): Deleted. (JSC::threadData): Deleted. (JSC::MachineThreads::Thread::Thread): Deleted. (JSC::MachineThreads::Thread::createForCurrentThread): Deleted. (JSC::MachineThreads::Thread::operator==): Deleted. (JSC::MachineThreads::machineThreadForCurrentThread): Deleted. (JSC::MachineThreads::ThreadData::ThreadData): Deleted. (JSC::MachineThreads::ThreadData::~ThreadData): Deleted. (JSC::MachineThreads::ThreadData::suspend): Deleted. (JSC::MachineThreads::ThreadData::resume): Deleted. (JSC::MachineThreads::ThreadData::getRegisters): Deleted. (JSC::MachineThreads::ThreadData::Registers::stackPointer): Deleted. (JSC::MachineThreads::ThreadData::Registers::framePointer): Deleted. (JSC::MachineThreads::ThreadData::Registers::instructionPointer): Deleted. (JSC::MachineThreads::ThreadData::Registers::llintPC): Deleted. (JSC::MachineThreads::ThreadData::freeRegisters): Deleted. (JSC::MachineThreads::ThreadData::captureStack): Deleted. * heap/MachineStackMarker.h: (JSC::MachineThreads::MachineThread::suspend): (JSC::MachineThreads::MachineThread::resume): (JSC::MachineThreads::MachineThread::threadID): (JSC::MachineThreads::MachineThread::stackBase): (JSC::MachineThreads::MachineThread::stackEnd): (JSC::MachineThreads::threadsListHead): (JSC::MachineThreads::Thread::operator!=): Deleted. (JSC::MachineThreads::Thread::suspend): Deleted. (JSC::MachineThreads::Thread::resume): Deleted. (JSC::MachineThreads::Thread::getRegisters): Deleted. (JSC::MachineThreads::Thread::freeRegisters): Deleted. (JSC::MachineThreads::Thread::captureStack): Deleted. (JSC::MachineThreads::Thread::platformThread): Deleted. (JSC::MachineThreads::Thread::stackBase): Deleted. (JSC::MachineThreads::Thread::stackEnd): Deleted. * jit/ICStats.cpp: (JSC::ICStats::ICStats): (JSC::ICStats::~ICStats): * jit/ICStats.h: * jsc.cpp: (functionDollarAgentStart): (startTimeoutThreadIfNeeded): * runtime/JSLock.cpp: (JSC::JSLock::lock): * runtime/JSLock.h: (JSC::JSLock::ownerThread): (JSC::JSLock::currentThreadIsHoldingLock): * runtime/SamplingProfiler.cpp: (JSC::FrameWalker::isValidFramePointer): (JSC::SamplingProfiler::SamplingProfiler): (JSC::SamplingProfiler::createThreadIfNecessary): (JSC::SamplingProfiler::takeSample): * runtime/SamplingProfiler.h: * runtime/VM.h: (JSC::VM::ownerThread): * runtime/VMTraps.cpp: (JSC::findActiveVMAndStackBounds): (JSC::VMTraps::SignalSender::send): (JSC::VMTraps::fireTrap): Source/WebCore: Mechanical change. Use Thread:: APIs. * Modules/indexeddb/server/IDBServer.cpp: (WebCore::IDBServer::IDBServer::IDBServer): * Modules/indexeddb/server/IDBServer.h: * Modules/webaudio/AsyncAudioDecoder.cpp: (WebCore::AsyncAudioDecoder::AsyncAudioDecoder): (WebCore::AsyncAudioDecoder::~AsyncAudioDecoder): (WebCore::AsyncAudioDecoder::runLoop): * Modules/webaudio/AsyncAudioDecoder.h: * Modules/webaudio/OfflineAudioDestinationNode.cpp: (WebCore::OfflineAudioDestinationNode::OfflineAudioDestinationNode): (WebCore::OfflineAudioDestinationNode::uninitialize): (WebCore::OfflineAudioDestinationNode::startRendering): * Modules/webaudio/OfflineAudioDestinationNode.h: * Modules/webdatabase/Database.cpp: (WebCore::Database::securityOrigin): * Modules/webdatabase/DatabaseThread.cpp: (WebCore::DatabaseThread::start): (WebCore::DatabaseThread::databaseThread): (WebCore::DatabaseThread::recordDatabaseOpen): (WebCore::DatabaseThread::recordDatabaseClosed): * Modules/webdatabase/DatabaseThread.h: (WebCore::DatabaseThread::getThreadID): * bindings/js/GCController.cpp: (WebCore::GCController::garbageCollectOnAlternateThreadForDebugging): * fileapi/AsyncFileStream.cpp: (WebCore::callOnFileThread): * loader/icon/IconDatabase.cpp: (WebCore::IconDatabase::open): (WebCore::IconDatabase::close): * loader/icon/IconDatabase.h: * page/ResourceUsageThread.cpp: (WebCore::ResourceUsageThread::createThreadIfNeeded): * page/ResourceUsageThread.h: * page/scrolling/ScrollingThread.cpp: (WebCore::ScrollingThread::ScrollingThread): (WebCore::ScrollingThread::isCurrentThread): (WebCore::ScrollingThread::createThreadIfNeeded): (WebCore::ScrollingThread::threadCallback): * page/scrolling/ScrollingThread.h: * platform/audio/HRTFDatabaseLoader.cpp: (WebCore::HRTFDatabaseLoader::HRTFDatabaseLoader): (WebCore::HRTFDatabaseLoader::loadAsynchronously): (WebCore::HRTFDatabaseLoader::waitForLoaderThreadCompletion): * platform/audio/HRTFDatabaseLoader.h: * platform/audio/ReverbConvolver.cpp: (WebCore::ReverbConvolver::ReverbConvolver): (WebCore::ReverbConvolver::~ReverbConvolver): * platform/audio/ReverbConvolver.h: * platform/audio/gstreamer/AudioFileReaderGStreamer.cpp: (WebCore::createBusFromAudioFile): (WebCore::createBusFromInMemoryAudioFile): * platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp: (ResourceHandleStreamingClient::ResourceHandleStreamingClient): (ResourceHandleStreamingClient::~ResourceHandleStreamingClient): * platform/network/cf/LoaderRunLoopCF.cpp: (WebCore::loaderRunLoop): * platform/network/curl/CurlDownload.cpp: (WebCore::CurlDownloadManager::startThreadIfNeeded): (WebCore::CurlDownloadManager::stopThread): * platform/network/curl/CurlDownload.h: * platform/network/curl/SocketStreamHandleImpl.h: * platform/network/curl/SocketStreamHandleImplCurl.cpp: (WebCore::SocketStreamHandleImpl::startThread): (WebCore::SocketStreamHandleImpl::stopThread): * workers/WorkerThread.cpp: (WebCore::WorkerThread::WorkerThread): (WebCore::WorkerThread::start): (WebCore::WorkerThread::workerThread): * workers/WorkerThread.h: (WebCore::WorkerThread::threadID): Source/WebKit: Mechanical change. Use Thread:: APIs. * Storage/StorageThread.cpp: (WebCore::StorageThread::StorageThread): (WebCore::StorageThread::~StorageThread): (WebCore::StorageThread::start): (WebCore::StorageThread::dispatch): (WebCore::StorageThread::terminate): * Storage/StorageThread.h: Source/WebKit2: Mechanical change. Use Thread:: APIs. * NetworkProcess/NetworkProcess.cpp: (WebKit::NetworkProcess::initializeNetworkProcess): * NetworkProcess/cache/NetworkCacheIOChannelSoup.cpp: (WebKit::NetworkCache::IOChannel::readSyncInThread): * Platform/IPC/Connection.cpp: (IPC::Connection::processIncomingMessage): * Shared/EntryPointUtilities/mac/XPCService/XPCServiceEntryPoint.h: (WebKit::XPCServiceInitializer): * UIProcess/linux/MemoryPressureMonitor.cpp: (WebKit::MemoryPressureMonitor::MemoryPressureMonitor): * WebProcess/WebProcess.cpp: (WebKit::WebProcess::initializeWebProcess): Source/WTF: This patch is refactoring of WTF Threading mechanism to merge JavaScriptCore's threading extension to WTF Threading. Previously, JavaScriptCore requires richer threading features (such as suspending and resuming threads), and they are implemented for PlatformThread in JavaScriptCore. But these features should be implemented in WTF Threading side instead of maintaining JSC's own threading features too. This patch removes these features from JSC and move it to WTF Threading. However, current WTF Threading has one problem: Windows version of WTF Threading has different semantics from Pthreads one. In Windows WTF Threading, we cannot perform any operation after the target thread is detached: WTF Threading stop tracking the state of the thread once the thread is detached. But this is not the same to Pthreads one. In Pthreads, pthread_detach just means that the resource of the thread will be destroyed automatically. While some operations like pthread_join will be rejected, some operations like pthread_kill will be accepted. The problem is that detached thread can be suspended and resumed in JSC. For example, in jsc.cpp, we start the worker thread and detach it immediately. In worker thread, we will create VM and thus concurrent GC will suspend and resume the detached thread. However, in Windows WTF Threading, we have no reference to the detached thread. Thus we cannot perform suspend and resume operations onto the detached thread. To solve the problem, we change Windows Threading mechanism drastically to align it to the Pthread semantics. In the new Threading, we have RefPtr<Thread> class. It holds a handle to a platform thread. We can perform threading operations with this class. For example, Thread::suspend is offered. And we use destructor of the thread local variable to release the resources held by RefPtr<Thread>. In Windows, Thread::detach does nothing because the resource will be destroyed automatically by RefPtr<Thread>. To do so, we introduce ThreadHolder for Windows. This is similar to the previous ThreadIdentifierData for Pthreads. It holds RefPtr<Thread> in the thread local storage (technically, it is Fiber Local Storage in Windows). Thread::current() will return this reference. The problematic situation is that the order of the deallocation of the thread local storage is not defined. So we should not touch thread local storage in the destructor of the thread local storage. To avoid such edge cases, we have currentThread() / Thread::currentID() APIs. They are safe to be called even in the destructor of the other thread local storage. And in Windows, in the FLS destructor, we will create the thread_local variable to defer the destruction of the ThreadHolder. We ensure that this destructor is called after the other FLS destructors are called in Windows 10. This patch is performance neutral. * WTF.xcodeproj/project.pbxproj: * benchmarks/ConditionSpeedTest.cpp: * benchmarks/LockFairnessTest.cpp: * benchmarks/LockSpeedTest.cpp: * wtf/AutomaticThread.cpp: (WTF::AutomaticThread::start): * wtf/CMakeLists.txt: * wtf/MainThread.h: * wtf/MemoryPressureHandler.h: * wtf/ParallelJobsGeneric.cpp: (WTF::ParallelEnvironment::ThreadPrivate::tryLockFor): (WTF::ParallelEnvironment::ThreadPrivate::workerThread): * wtf/ParallelJobsGeneric.h: (WTF::ParallelEnvironment::ThreadPrivate::ThreadPrivate): Deleted. * wtf/ParkingLot.cpp: (WTF::ParkingLot::forEachImpl): * wtf/ParkingLot.h: (WTF::ParkingLot::forEach): * wtf/PlatformRegisters.h: Renamed from Source/JavaScriptCore/runtime/PlatformThread.h. * wtf/RefPtr.h: (WTF::RefPtr::RefPtr): * wtf/ThreadFunctionInvocation.h: (WTF::ThreadFunctionInvocation::ThreadFunctionInvocation): * wtf/ThreadHolder.cpp: Added. (WTF::ThreadHolder::~ThreadHolder): (WTF::ThreadHolder::initialize): * wtf/ThreadHolder.h: Renamed from Source/WTF/wtf/ThreadIdentifierDataPthreads.h. (WTF::ThreadHolder::thread): (WTF::ThreadHolder::ThreadHolder): * wtf/ThreadHolderPthreads.cpp: Renamed from Source/WTF/wtf/ThreadIdentifierDataPthreads.cpp. (WTF::ThreadHolder::initializeOnce): (WTF::ThreadHolder::current): (WTF::ThreadHolder::destruct): * wtf/ThreadHolderWin.cpp: Added. (WTF::threadMapMutex): (WTF::threadMap): (WTF::ThreadHolder::initializeOnce): (WTF::ThreadHolder::current): (WTF::ThreadHolder::destruct): * wtf/ThreadSpecific.h: * wtf/Threading.cpp: (WTF::Thread::normalizeThreadName): (WTF::threadEntryPoint): (WTF::Thread::create): (WTF::Thread::setCurrentThreadIsUserInteractive): (WTF::Thread::setCurrentThreadIsUserInitiated): (WTF::Thread::setGlobalMaxQOSClass): (WTF::Thread::adjustedQOSClass): (WTF::Thread::dump): (WTF::initializeThreading): (WTF::normalizeThreadName): Deleted. (WTF::createThread): Deleted. (WTF::setCurrentThreadIsUserInteractive): Deleted. (WTF::setCurrentThreadIsUserInitiated): Deleted. (WTF::setGlobalMaxQOSClass): Deleted. (WTF::adjustedQOSClass): Deleted. * wtf/Threading.h: (WTF::Thread::id): (WTF::Thread::operator==): (WTF::Thread::operator!=): (WTF::Thread::joinableState): (WTF::Thread::didBecomeDetached): (WTF::Thread::didJoin): (WTF::Thread::hasExited): (WTF::currentThread): * wtf/ThreadingPthreads.cpp: (WTF::Thread::Thread): (WTF::Thread::~Thread): (WTF::Thread::signalHandlerSuspendResume): (WTF::Thread::initializePlatformThreading): (WTF::initializeCurrentThreadEvenIfNonWTFCreated): (WTF::wtfThreadEntryPoint): (WTF::Thread::createInternal): (WTF::Thread::initializeCurrentThreadInternal): (WTF::Thread::changePriority): (WTF::Thread::waitForCompletion): (WTF::Thread::detach): (WTF::Thread::current): (WTF::Thread::currentID): (WTF::Thread::signal): (WTF::Thread::resume): (WTF::Thread::getRegisters): (WTF::Thread::didExit): (WTF::Thread::establish): (WTF::PthreadState::PthreadState): Deleted. (WTF::PthreadState::joinableState): Deleted. (WTF::PthreadState::pthreadHandle): Deleted. (WTF::PthreadState::didBecomeDetached): Deleted. (WTF::PthreadState::didExit): Deleted. (WTF::PthreadState::didJoin): Deleted. (WTF::PthreadState::hasExited): Deleted. (WTF::threadMapMutex): Deleted. (WTF::initializeThreading): Deleted. (WTF::threadMap): Deleted. (WTF::identifierByPthreadHandle): Deleted. (WTF::establishIdentifierForPthreadHandle): Deleted. (WTF::pthreadHandleForIdentifierWithLockAlreadyHeld): Deleted. (WTF::createThreadInternal): Deleted. (WTF::initializeCurrentThreadInternal): Deleted. (WTF::changeThreadPriority): Deleted. (WTF::waitForThreadCompletion): Deleted. (WTF::detachThread): Deleted. (WTF::threadDidExit): Deleted. (WTF::currentThread): Deleted. (WTF::signalThread): Deleted. * wtf/ThreadingWin.cpp: (WTF::Thread::Thread): (WTF::Thread::~Thread): (WTF::Thread::initializeCurrentThreadInternal): (WTF::Thread::initializePlatformThreading): (WTF::wtfThreadEntryPoint): (WTF::Thread::createInternal): (WTF::Thread::changePriority): (WTF::Thread::waitForCompletion): (WTF::Thread::detach): (WTF::Thread::resume): (WTF::Thread::getRegisters): (WTF::Thread::current): (WTF::Thread::currentID): (WTF::Thread::didExit): (WTF::Thread::establish): (WTF::initializeCurrentThreadInternal): Deleted. (WTF::threadMapMutex): Deleted. (WTF::initializeThreading): Deleted. (WTF::threadMap): Deleted. (WTF::storeThreadHandleByIdentifier): Deleted. (WTF::threadHandleForIdentifier): Deleted. (WTF::clearThreadHandleForIdentifier): Deleted. (WTF::createThreadInternal): Deleted. (WTF::changeThreadPriority): Deleted. (WTF::waitForThreadCompletion): Deleted. (WTF::detachThread): Deleted. (WTF::currentThread): Deleted. * wtf/WorkQueue.cpp: (WTF::WorkQueue::concurrentApply): * wtf/WorkQueue.h: * wtf/cocoa/WorkQueueCocoa.cpp: (WTF::dispatchQOSClass): * wtf/generic/WorkQueueGeneric.cpp: (WorkQueue::platformInitialize): (WorkQueue::platformInvalidate): * wtf/linux/MemoryPressureHandlerLinux.cpp: (WTF::MemoryPressureHandler::EventFDPoller::EventFDPoller): (WTF::MemoryPressureHandler::EventFDPoller::~EventFDPoller): * wtf/win/MainThreadWin.cpp: (WTF::initializeMainThreadPlatform): Tools: Mechanical change. Use Thread:: APIs. * DumpRenderTree/JavaScriptThreading.cpp: (runJavaScriptThread): (startJavaScriptThreads): (stopJavaScriptThreads): * DumpRenderTree/mac/DumpRenderTree.mm: (testThreadIdentifierMap): * TestWebKitAPI/Tests/WTF/Condition.cpp: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::runLockTest): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Canonical link: https://commits.webkit.org/187690@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@215265 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-04-12 12:08:29 +00:00
Ref<Thread> thread;
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
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): Canonical link: https://commits.webkit.org/182152@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208415 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-11-05 03:02:39 +00:00
Mutex parkingLock;
ThreadCondition parkingCondition;
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
WTF::Lock should not suffer from the thundering herd https://bugs.webkit.org/show_bug.cgi?id=147947 Reviewed by Geoffrey Garen. Source/WTF: This changes Lock::unlockSlow() to use unparkOne() instead of unparkAll(). The problem with doing this is that it's not obvious after calling unparkOne() if there are any other threads that are still parked on the lock's queue. If we assume that there are and leave the hasParkedBit set, then future calls to unlock() will take the slow path. We don't want that if there aren't actually any threads parked. On the other hand, if we assume that there aren't any threads parked and clear the hasParkedBit, then if there actually were some threads parked, then they may never be awoken since future calls to unlock() won't take slow path and so won't call unparkOne(). In other words, we need a way to be very precise about when we clear the hasParkedBit and we need to do it in a race-free way: it can't be the case that we clear the bit just as some thread gets parked on the queue. A similar problem arises in futexes, and one of the solutions is to have a thread that acquires a lock after parking sets the hasParkedBit. This is what Rusty Russel's usersem does. It's a subtle algorithm. Also, it means that if a thread barges in before the unparked thread runs, then that barging thread will not know that there are threads parked. This could increase the severity of barging. Since ParkingLot is a user-level API, we don't have to worry about the kernel-user security issues and so we can expose callbacks while ParkingLot is holding its internal locks. This change does exactly that for unparkOne(). The new variant of unparkOne() will call a user function while the queue from which we are unparking is locked. The callback is told basic stats about the queue: did we unpark a thread this time, and could there be more threads to unpark in the future. The callback runs while it's impossible for the queue state to change, since the ParkingLot's internal locks for the queue is held. This means that Lock::unlockSlow() can either clear, or leave, the hasParkedBit while releasing the lock inside the callback from unparkOne(). This takes care of the thundering herd problem while also reducing the greed that arises from barging threads. This required some careful reworking of the ParkingLot algorithm. The first thing I noticed was that the ThreadData::shouldPark flag was useless, since it's set exactly when ThreadData::address is non-null. Then I had to make sure that dequeue() could lazily create both hashtables and buckets, since the "callback is called while queue is locked" invariant requires that we didn't exit early due to the hashtable or bucket not being present. Note that all of this is done in such a way that the old unparkOne() and unparkAll() don't have to create any buckets, though they now may create the hashtable. We don't care as much about the hashtable being created by unpark since it's just such an unlikely scenario and it would only happen once. This change reduces the kernel CPU usage of WTF::Lock for the long critical section test by about 8x and makes it always perform as well as WTF::WordLock and WTF::Mutex for that benchmark. * benchmarks/LockSpeedTest.cpp: * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): * wtf/Lock.h: (WTF::LockBase::isLocked): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: * wtf/WordLock.h: (WTF::WordLock::isLocked): (WTF::WordLock::isFullyReset): Tools: Add testing that checks that locks return to a pristine state after contention is over. * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::LockInspector::isFullyReset): (TestWebKitAPI::runLockTest): (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/166072@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188374 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 03:51:25 +00:00
const void* address { nullptr };
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
ThreadData* nextInQueue { nullptr };
WTF::Lock should be fair eventually https://bugs.webkit.org/show_bug.cgi?id=159384 Reviewed by Geoffrey Garen. Source/WTF: In https://webkit.org/blog/6161/locking-in-webkit/ we showed how relaxing the fairness of locks makes them fast. That post presented lock fairness as a trade-off between two extremes: - Barging. A barging lock, like WTF::Lock, releases the lock in unlock() even if there was a thread on the queue. If there was a thread on the queue, the lock is released and that thread is made runnable. That thread may then grab the lock, or some other thread may grab the lock first (it may barge). Usually, the barging thread is the thread that released the lock in the first place. This maximizes throughput but hurts fairness. There is no good theoretical bound on how unfair the lock may become, but empirical data suggests that it's fair enough for the cases we previously measured. - FIFO. A FIFO lock, like HandoffLock in ToyLocks.h, does not release the lock in unlock() if there is a thread waiting. If there is a thread waiting, unlock() will make that thread runnable and inform it that it now holds the lock. This ensures perfect round-robin fairness and allows us to reason theoretically about how long it may take for a thread to grab the lock. For example, if we know that only N threads are running and each one may contend on a critical section, and each one may hold the lock for at most S seconds, then the time it takes to grab the lock is N * S. Unfortunately, FIFO locks perform very badly in most cases. This is because for the common case of short critical sections, they force a context switch after each critical section if the lock is contended. This change makes WTF::Lock almost as fair as FIFO while still being as fast as barging. Thanks to this new algorithm, you can now have both of these things at the same time. This change makes WTF::Lock eventually fair. We can almost (more on the caveats below) guarantee that the time it takes to grab a lock is N * max(1ms, S). In other words, critical sections that are longer than 1ms are always fair. For shorter critical sections, the amount of time that any thread waits is 1ms times the number of threads. There are some caveats that arise from our use of randomness, but even then, in the limit as the critical section length goes to infinity, the lock becomes fair. The corner cases are unlikely to happen; our experiments show that the lock becomes exactly as fair as a FIFO lock for any critical section that is 1ms or longer. The fairness mechanism is broken into two parts. WTF::Lock can now choose to unlock a lock fairly or unfairly thanks to the new ParkingLot token mechanism. WTF::Lock knows when to use fair unlocking based on a timeout mechanism in ParkingLot called timeToBeFair. ParkingLot::unparkOne() and ParkingLot::parkConditionally() can now communicate with each other via a token. unparkOne() can pass a token, which parkConditionally() will return. This change also makes parkConditionally() a lot more precise about when it was unparked due to a call to unparkOne(). If unparkOne() is told that a thread was unparked then this thread is guaranteed to report that it was unparked rather than timing out, and that thread is guaranteed to get the token that unparkOne() passed. The token is an intptr_t. We use it as a boolean variable in WTF::Lock, but you could use it to pass arbitrary data structures. By default, the token is zero. WTF::Lock's unlock() will pass 1 as the token if it is doing fair unlocking. In that case, unlock() will not release the lock, and lock() will know that it holds the lock as soon as parkConditionally() returns. Note that this algorithm relies on unparkOne() invoking WTF::Lock's callback while the queue lock is held, so that WTF::Lock can make a decision about unlock strategy and inject a token while it has complete knowledge over the state of the queue. As such, it's not immediately obvious how to implement this algorithm on top of futexes. You really need ParkingLot! WTF::Lock does not use fair unlocking every time. We expose a new API, Lock::unlockFairly(), which forces the fair unlocking behavior. Additionally, ParkingLot now maintains a per-bucket stochastic fairness timeout. When the timeout fires, the unparkOne() callback sees UnparkResult::timeToBeFair = true. This timeout is set to be anywhere from 0ms to 1ms at random. When a dequeue happens and there are threads that actually get dequeued, we check if the time since the last unfair unlock (the last time timeToBeFair was set to true) is more than the timeout amount. If so, then we set timeToBeFair to true and reset the timeout. This means that in the absence of ParkingLot collisions, unfair unlocking is guaranteed to happen at least once per millisecond. It will happen at 2 KHz on average. If there are collisions, then each collision adds one millisecond to the worst case (and 0.5 ms to the average case). The reason why we don't just use a fixed 1ms timeout is that we want to avoid resonance. Imagine a program in which some thread acquires a lock at 1 KHz in-phase with the timeToBeFair timeout. Then this thread would be the benefactor of fairness to the detriment of everyone else. Randomness ensures that we aren't too fair to any one thread. Empirically, this is neutral on our major benchmarks like JetStream but it's an enormous improvement in LockFairnessTest. It's common for an unfair lock (either our BargingLock, the old WTF::Lock, any of the other futex-based locks that barge, or new os_unfair_lock) to allow only one thread to hold the lock during a whole second in which each thread is holding the lock for 1ms at a time. This is because in a barging lock, releasing a lock after holding it for 1ms and then reacquiring it immediately virtually ensures that none of the other threads can wake up in time to grab it before it's relocked. But the new WTF::Lock handles this case like a champ: each thread gets equal turns. Here's some data. If we launch 10 threads and have each of them run for 1 second while repeatedly holding a critical section for 1ms, then here's how many times each thread gets to hold the lock using the old WTF::Lock algorithm: 799, 6, 1, 1, 1, 1, 1, 1, 1, 1 One thread hogged the lock for almost the whole time! With the new WTF::Lock, the lock becomes totally fair: 80, 79, 79, 79, 79, 79, 79, 80, 80, 79 I don't know of anyone creating such an automatically-fair adaptive lock before, so I think that this is a pretty awesome advancement to the state of the art! This change is good for three reasons: - We do have long critical sections in WebKit and we don't want to have to worry about starvation. This reduces the likelihood that we will see starvation due to our lock strategy. - I was talking to ggaren about bmalloc's locking needs, and he wanted unlockFairly() or lockFairly() or some moral equivalent for the scavenger thread. - If we use a WTF::Lock to manage heap access in a multithreaded GC, we'll need the ability to unlock and relock without barging. * benchmarks/LockFairnessTest.cpp: (main): * benchmarks/ToyLocks.h: * wtf/Condition.h: (WTF::ConditionBase::waitUntil): (WTF::ConditionBase::notifyOne): * wtf/Lock.cpp: (WTF::LockBase::lockSlow): (WTF::LockBase::unlockSlow): (WTF::LockBase::unlockFairlySlow): (WTF::LockBase::unlockSlowImpl): * wtf/Lock.h: (WTF::LockBase::try_lock): (WTF::LockBase::unlock): (WTF::LockBase::unlockFairly): (WTF::LockBase::isHeld): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::compareAndPark): (WTF::ParkingLot::unparkOne): Tools: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Canonical link: https://commits.webkit.org/178039@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@203350 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-07-18 18:32:52 +00:00
intptr_t token { 0 };
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
};
enum class DequeueResult {
Ignore,
RemoveAndContinue,
RemoveAndStop
};
struct Bucket {
WTF_MAKE_FAST_ALLOCATED;
public:
WTF::Lock should be fair eventually https://bugs.webkit.org/show_bug.cgi?id=159384 Reviewed by Geoffrey Garen. Source/WTF: In https://webkit.org/blog/6161/locking-in-webkit/ we showed how relaxing the fairness of locks makes them fast. That post presented lock fairness as a trade-off between two extremes: - Barging. A barging lock, like WTF::Lock, releases the lock in unlock() even if there was a thread on the queue. If there was a thread on the queue, the lock is released and that thread is made runnable. That thread may then grab the lock, or some other thread may grab the lock first (it may barge). Usually, the barging thread is the thread that released the lock in the first place. This maximizes throughput but hurts fairness. There is no good theoretical bound on how unfair the lock may become, but empirical data suggests that it's fair enough for the cases we previously measured. - FIFO. A FIFO lock, like HandoffLock in ToyLocks.h, does not release the lock in unlock() if there is a thread waiting. If there is a thread waiting, unlock() will make that thread runnable and inform it that it now holds the lock. This ensures perfect round-robin fairness and allows us to reason theoretically about how long it may take for a thread to grab the lock. For example, if we know that only N threads are running and each one may contend on a critical section, and each one may hold the lock for at most S seconds, then the time it takes to grab the lock is N * S. Unfortunately, FIFO locks perform very badly in most cases. This is because for the common case of short critical sections, they force a context switch after each critical section if the lock is contended. This change makes WTF::Lock almost as fair as FIFO while still being as fast as barging. Thanks to this new algorithm, you can now have both of these things at the same time. This change makes WTF::Lock eventually fair. We can almost (more on the caveats below) guarantee that the time it takes to grab a lock is N * max(1ms, S). In other words, critical sections that are longer than 1ms are always fair. For shorter critical sections, the amount of time that any thread waits is 1ms times the number of threads. There are some caveats that arise from our use of randomness, but even then, in the limit as the critical section length goes to infinity, the lock becomes fair. The corner cases are unlikely to happen; our experiments show that the lock becomes exactly as fair as a FIFO lock for any critical section that is 1ms or longer. The fairness mechanism is broken into two parts. WTF::Lock can now choose to unlock a lock fairly or unfairly thanks to the new ParkingLot token mechanism. WTF::Lock knows when to use fair unlocking based on a timeout mechanism in ParkingLot called timeToBeFair. ParkingLot::unparkOne() and ParkingLot::parkConditionally() can now communicate with each other via a token. unparkOne() can pass a token, which parkConditionally() will return. This change also makes parkConditionally() a lot more precise about when it was unparked due to a call to unparkOne(). If unparkOne() is told that a thread was unparked then this thread is guaranteed to report that it was unparked rather than timing out, and that thread is guaranteed to get the token that unparkOne() passed. The token is an intptr_t. We use it as a boolean variable in WTF::Lock, but you could use it to pass arbitrary data structures. By default, the token is zero. WTF::Lock's unlock() will pass 1 as the token if it is doing fair unlocking. In that case, unlock() will not release the lock, and lock() will know that it holds the lock as soon as parkConditionally() returns. Note that this algorithm relies on unparkOne() invoking WTF::Lock's callback while the queue lock is held, so that WTF::Lock can make a decision about unlock strategy and inject a token while it has complete knowledge over the state of the queue. As such, it's not immediately obvious how to implement this algorithm on top of futexes. You really need ParkingLot! WTF::Lock does not use fair unlocking every time. We expose a new API, Lock::unlockFairly(), which forces the fair unlocking behavior. Additionally, ParkingLot now maintains a per-bucket stochastic fairness timeout. When the timeout fires, the unparkOne() callback sees UnparkResult::timeToBeFair = true. This timeout is set to be anywhere from 0ms to 1ms at random. When a dequeue happens and there are threads that actually get dequeued, we check if the time since the last unfair unlock (the last time timeToBeFair was set to true) is more than the timeout amount. If so, then we set timeToBeFair to true and reset the timeout. This means that in the absence of ParkingLot collisions, unfair unlocking is guaranteed to happen at least once per millisecond. It will happen at 2 KHz on average. If there are collisions, then each collision adds one millisecond to the worst case (and 0.5 ms to the average case). The reason why we don't just use a fixed 1ms timeout is that we want to avoid resonance. Imagine a program in which some thread acquires a lock at 1 KHz in-phase with the timeToBeFair timeout. Then this thread would be the benefactor of fairness to the detriment of everyone else. Randomness ensures that we aren't too fair to any one thread. Empirically, this is neutral on our major benchmarks like JetStream but it's an enormous improvement in LockFairnessTest. It's common for an unfair lock (either our BargingLock, the old WTF::Lock, any of the other futex-based locks that barge, or new os_unfair_lock) to allow only one thread to hold the lock during a whole second in which each thread is holding the lock for 1ms at a time. This is because in a barging lock, releasing a lock after holding it for 1ms and then reacquiring it immediately virtually ensures that none of the other threads can wake up in time to grab it before it's relocked. But the new WTF::Lock handles this case like a champ: each thread gets equal turns. Here's some data. If we launch 10 threads and have each of them run for 1 second while repeatedly holding a critical section for 1ms, then here's how many times each thread gets to hold the lock using the old WTF::Lock algorithm: 799, 6, 1, 1, 1, 1, 1, 1, 1, 1 One thread hogged the lock for almost the whole time! With the new WTF::Lock, the lock becomes totally fair: 80, 79, 79, 79, 79, 79, 79, 80, 80, 79 I don't know of anyone creating such an automatically-fair adaptive lock before, so I think that this is a pretty awesome advancement to the state of the art! This change is good for three reasons: - We do have long critical sections in WebKit and we don't want to have to worry about starvation. This reduces the likelihood that we will see starvation due to our lock strategy. - I was talking to ggaren about bmalloc's locking needs, and he wanted unlockFairly() or lockFairly() or some moral equivalent for the scavenger thread. - If we use a WTF::Lock to manage heap access in a multithreaded GC, we'll need the ability to unlock and relock without barging. * benchmarks/LockFairnessTest.cpp: (main): * benchmarks/ToyLocks.h: * wtf/Condition.h: (WTF::ConditionBase::waitUntil): (WTF::ConditionBase::notifyOne): * wtf/Lock.cpp: (WTF::LockBase::lockSlow): (WTF::LockBase::unlockSlow): (WTF::LockBase::unlockFairlySlow): (WTF::LockBase::unlockSlowImpl): * wtf/Lock.h: (WTF::LockBase::try_lock): (WTF::LockBase::unlock): (WTF::LockBase::unlockFairly): (WTF::LockBase::isHeld): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::compareAndPark): (WTF::ParkingLot::unparkOne): Tools: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Canonical link: https://commits.webkit.org/178039@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@203350 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-07-18 18:32:52 +00:00
Bucket()
: random(static_cast<unsigned>(bitwise_cast<intptr_t>(this))) // Cannot use default seed since that recurses into Lock.
{
}
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
void enqueue(ThreadData* data)
{
if (verbose)
WTF shouldn't have both Thread and ThreadIdentifier https://bugs.webkit.org/show_bug.cgi?id=180308 Reviewed by Darin Adler. Source/JavaScriptCore: * heap/MachineStackMarker.cpp: (JSC::MachineThreads::tryCopyOtherThreadStacks): * llint/LLIntSlowPaths.cpp: (JSC::LLInt::llint_trace_operand): (JSC::LLInt::llint_trace_value): (JSC::LLInt::LLINT_SLOW_PATH_DECL): (JSC::LLInt::traceFunctionPrologue): * runtime/ExceptionScope.cpp: (JSC::ExceptionScope::unexpectedExceptionMessage): * runtime/JSLock.h: (JSC::JSLock::currentThreadIsHoldingLock): * runtime/VM.cpp: (JSC::VM::throwException): * runtime/VM.h: (JSC::VM::throwingThread const): (JSC::VM::clearException): * tools/HeapVerifier.cpp: (JSC::HeapVerifier::printVerificationHeader): Source/WebCore: No behavior change. * Modules/indexeddb/IDBActiveDOMObject.h: (WebCore::IDBActiveDOMObject::originThread const): (WebCore::IDBActiveDOMObject::performCallbackOnOriginThread): (WebCore::IDBActiveDOMObject::callFunctionOnOriginThread): (WebCore::IDBActiveDOMObject::originThreadID const): Deleted. * Modules/indexeddb/IDBCursor.cpp: (WebCore::IDBCursor::IDBCursor): (WebCore::IDBCursor::~IDBCursor): (WebCore::IDBCursor::sourcesDeleted const): (WebCore::IDBCursor::transaction const): (WebCore::IDBCursor::update): (WebCore::IDBCursor::advance): (WebCore::IDBCursor::continueFunction): (WebCore::IDBCursor::uncheckedIterateCursor): (WebCore::IDBCursor::deleteFunction): (WebCore::IDBCursor::setGetResult): * Modules/indexeddb/IDBDatabase.cpp: (WebCore::IDBDatabase::~IDBDatabase): (WebCore::IDBDatabase::hasPendingActivity const): (WebCore::IDBDatabase::name const): (WebCore::IDBDatabase::version const): (WebCore::IDBDatabase::objectStoreNames const): (WebCore::IDBDatabase::renameObjectStore): (WebCore::IDBDatabase::renameIndex): (WebCore::IDBDatabase::createObjectStore): (WebCore::IDBDatabase::transaction): (WebCore::IDBDatabase::deleteObjectStore): (WebCore::IDBDatabase::close): (WebCore::IDBDatabase::connectionToServerLost): (WebCore::IDBDatabase::maybeCloseInServer): (WebCore::IDBDatabase::activeDOMObjectName const): (WebCore::IDBDatabase::canSuspendForDocumentSuspension const): (WebCore::IDBDatabase::stop): (WebCore::IDBDatabase::startVersionChangeTransaction): (WebCore::IDBDatabase::didStartTransaction): (WebCore::IDBDatabase::willCommitTransaction): (WebCore::IDBDatabase::didCommitTransaction): (WebCore::IDBDatabase::willAbortTransaction): (WebCore::IDBDatabase::didAbortTransaction): (WebCore::IDBDatabase::didCommitOrAbortTransaction): (WebCore::IDBDatabase::fireVersionChangeEvent): (WebCore::IDBDatabase::dispatchEvent): (WebCore::IDBDatabase::didCreateIndexInfo): (WebCore::IDBDatabase::didDeleteIndexInfo): * Modules/indexeddb/IDBIndex.cpp: (WebCore::IDBIndex::IDBIndex): (WebCore::IDBIndex::~IDBIndex): (WebCore::IDBIndex::name const): (WebCore::IDBIndex::setName): (WebCore::IDBIndex::objectStore): (WebCore::IDBIndex::keyPath const): (WebCore::IDBIndex::unique const): (WebCore::IDBIndex::multiEntry const): (WebCore::IDBIndex::rollbackInfoForVersionChangeAbort): (WebCore::IDBIndex::openCursor): (WebCore::IDBIndex::openKeyCursor): (WebCore::IDBIndex::doCount): (WebCore::IDBIndex::doGet): (WebCore::IDBIndex::doGetKey): (WebCore::IDBIndex::getAll): (WebCore::IDBIndex::getAllKeys): (WebCore::IDBIndex::markAsDeleted): * Modules/indexeddb/IDBObjectStore.cpp: (WebCore::IDBObjectStore::IDBObjectStore): (WebCore::IDBObjectStore::~IDBObjectStore): (WebCore::IDBObjectStore::name const): (WebCore::IDBObjectStore::setName): (WebCore::IDBObjectStore::keyPath const): (WebCore::IDBObjectStore::indexNames const): (WebCore::IDBObjectStore::transaction): (WebCore::IDBObjectStore::autoIncrement const): (WebCore::IDBObjectStore::openCursor): (WebCore::IDBObjectStore::openKeyCursor): (WebCore::IDBObjectStore::get): (WebCore::IDBObjectStore::getKey): (WebCore::IDBObjectStore::putOrAdd): (WebCore::IDBObjectStore::doDelete): (WebCore::IDBObjectStore::clear): (WebCore::IDBObjectStore::createIndex): (WebCore::IDBObjectStore::index): (WebCore::IDBObjectStore::deleteIndex): (WebCore::IDBObjectStore::doCount): (WebCore::IDBObjectStore::getAll): (WebCore::IDBObjectStore::getAllKeys): (WebCore::IDBObjectStore::markAsDeleted): (WebCore::IDBObjectStore::rollbackForVersionChangeAbort): * Modules/indexeddb/IDBOpenDBRequest.cpp: (WebCore::IDBOpenDBRequest::~IDBOpenDBRequest): (WebCore::IDBOpenDBRequest::onError): (WebCore::IDBOpenDBRequest::versionChangeTransactionDidFinish): (WebCore::IDBOpenDBRequest::fireSuccessAfterVersionChangeCommit): (WebCore::IDBOpenDBRequest::fireErrorAfterVersionChangeCompletion): (WebCore::IDBOpenDBRequest::dispatchEvent): (WebCore::IDBOpenDBRequest::onSuccess): (WebCore::IDBOpenDBRequest::onUpgradeNeeded): (WebCore::IDBOpenDBRequest::onDeleteDatabaseSuccess): (WebCore::IDBOpenDBRequest::requestCompleted): (WebCore::IDBOpenDBRequest::requestBlocked): * Modules/indexeddb/IDBRequest.cpp: (WebCore::IDBRequest::~IDBRequest): (WebCore:: const): (WebCore::IDBRequest::setSource): (WebCore::IDBRequest::setVersionChangeTransaction): (WebCore::IDBRequest::transaction const): (WebCore::IDBRequest::sourceObjectStoreIdentifier const): (WebCore::IDBRequest::sourceIndexIdentifier const): (WebCore::IDBRequest::requestedObjectStoreRecordType const): (WebCore::IDBRequest::requestedIndexRecordType const): (WebCore::IDBRequest::eventTargetInterface const): (WebCore::IDBRequest::activeDOMObjectName const): (WebCore::IDBRequest::canSuspendForDocumentSuspension const): (WebCore::IDBRequest::hasPendingActivity const): (WebCore::IDBRequest::stop): (WebCore::IDBRequest::enqueueEvent): (WebCore::IDBRequest::dispatchEvent): (WebCore::IDBRequest::uncaughtExceptionInEventHandler): (WebCore::IDBRequest::setResult): (WebCore::IDBRequest::setResultToStructuredClone): (WebCore::IDBRequest::setResultToUndefined): (WebCore::IDBRequest::resultCursor): (WebCore::IDBRequest::willIterateCursor): (WebCore::IDBRequest::didOpenOrIterateCursor): (WebCore::IDBRequest::completeRequestAndDispatchEvent): (WebCore::IDBRequest::onError): (WebCore::IDBRequest::onSuccess): * Modules/indexeddb/IDBTransaction.cpp: (WebCore::IDBTransaction::IDBTransaction): (WebCore::IDBTransaction::~IDBTransaction): (WebCore::IDBTransaction::objectStoreNames const): (WebCore::IDBTransaction::db): (WebCore::IDBTransaction::error const): (WebCore::IDBTransaction::objectStore): (WebCore::IDBTransaction::abortDueToFailedRequest): (WebCore::IDBTransaction::transitionedToFinishing): (WebCore::IDBTransaction::abort): (WebCore::IDBTransaction::internalAbort): (WebCore::IDBTransaction::abortOnServerAndCancelRequests): (WebCore::IDBTransaction::activeDOMObjectName const): (WebCore::IDBTransaction::canSuspendForDocumentSuspension const): (WebCore::IDBTransaction::hasPendingActivity const): (WebCore::IDBTransaction::stop): (WebCore::IDBTransaction::isActive const): (WebCore::IDBTransaction::isFinishedOrFinishing const): (WebCore::IDBTransaction::addRequest): (WebCore::IDBTransaction::removeRequest): (WebCore::IDBTransaction::scheduleOperation): (WebCore::IDBTransaction::schedulePendingOperationTimer): (WebCore::IDBTransaction::pendingOperationTimerFired): (WebCore::IDBTransaction::operationCompletedOnServer): (WebCore::IDBTransaction::scheduleCompletedOperationTimer): (WebCore::IDBTransaction::completedOperationTimerFired): (WebCore::IDBTransaction::commit): (WebCore::IDBTransaction::commitOnServer): (WebCore::IDBTransaction::finishAbortOrCommit): (WebCore::IDBTransaction::didStart): (WebCore::IDBTransaction::notifyDidAbort): (WebCore::IDBTransaction::didAbort): (WebCore::IDBTransaction::didCommit): (WebCore::IDBTransaction::fireOnComplete): (WebCore::IDBTransaction::fireOnAbort): (WebCore::IDBTransaction::enqueueEvent): (WebCore::IDBTransaction::dispatchEvent): (WebCore::IDBTransaction::createObjectStore): (WebCore::IDBTransaction::createObjectStoreOnServer): (WebCore::IDBTransaction::didCreateObjectStoreOnServer): (WebCore::IDBTransaction::renameObjectStore): (WebCore::IDBTransaction::renameObjectStoreOnServer): (WebCore::IDBTransaction::didRenameObjectStoreOnServer): (WebCore::IDBTransaction::createIndex): (WebCore::IDBTransaction::createIndexOnServer): (WebCore::IDBTransaction::didCreateIndexOnServer): (WebCore::IDBTransaction::renameIndex): (WebCore::IDBTransaction::renameIndexOnServer): (WebCore::IDBTransaction::didRenameIndexOnServer): (WebCore::IDBTransaction::requestOpenCursor): (WebCore::IDBTransaction::doRequestOpenCursor): (WebCore::IDBTransaction::openCursorOnServer): (WebCore::IDBTransaction::didOpenCursorOnServer): (WebCore::IDBTransaction::iterateCursor): (WebCore::IDBTransaction::iterateCursorOnServer): (WebCore::IDBTransaction::didIterateCursorOnServer): (WebCore::IDBTransaction::requestGetAllObjectStoreRecords): (WebCore::IDBTransaction::requestGetAllIndexRecords): (WebCore::IDBTransaction::getAllRecordsOnServer): (WebCore::IDBTransaction::didGetAllRecordsOnServer): (WebCore::IDBTransaction::requestGetRecord): (WebCore::IDBTransaction::requestGetValue): (WebCore::IDBTransaction::requestGetKey): (WebCore::IDBTransaction::requestIndexRecord): (WebCore::IDBTransaction::getRecordOnServer): (WebCore::IDBTransaction::didGetRecordOnServer): (WebCore::IDBTransaction::requestCount): (WebCore::IDBTransaction::getCountOnServer): (WebCore::IDBTransaction::didGetCountOnServer): (WebCore::IDBTransaction::requestDeleteRecord): (WebCore::IDBTransaction::deleteRecordOnServer): (WebCore::IDBTransaction::didDeleteRecordOnServer): (WebCore::IDBTransaction::requestClearObjectStore): (WebCore::IDBTransaction::clearObjectStoreOnServer): (WebCore::IDBTransaction::didClearObjectStoreOnServer): (WebCore::IDBTransaction::requestPutOrAdd): (WebCore::IDBTransaction::putOrAddOnServer): (WebCore::IDBTransaction::didPutOrAddOnServer): (WebCore::IDBTransaction::deleteObjectStore): (WebCore::IDBTransaction::deleteObjectStoreOnServer): (WebCore::IDBTransaction::didDeleteObjectStoreOnServer): (WebCore::IDBTransaction::deleteIndex): (WebCore::IDBTransaction::deleteIndexOnServer): (WebCore::IDBTransaction::didDeleteIndexOnServer): (WebCore::IDBTransaction::operationCompletedOnClient): (WebCore::IDBTransaction::establishOnServer): (WebCore::IDBTransaction::activate): (WebCore::IDBTransaction::deactivate): * Modules/indexeddb/client/IDBConnectionProxy.cpp: (WebCore::IDBClient::removeItemsMatchingCurrentThread): * Modules/indexeddb/client/TransactionOperation.h: (WebCore::IDBClient::TransactionOperation::~TransactionOperation): (WebCore::IDBClient::TransactionOperation::perform): (WebCore::IDBClient::TransactionOperation::transitionToCompleteOnThisThread): (WebCore::IDBClient::TransactionOperation::transitionToComplete): (WebCore::IDBClient::TransactionOperation::doComplete): (WebCore::IDBClient::TransactionOperation::originThread const): (WebCore::IDBClient::TransactionOperation::originThreadID const): Deleted. * Modules/webaudio/AudioContext.cpp: (WebCore::AudioContext::AudioContext): (WebCore::AudioContext::lock): (WebCore::AudioContext::tryLock): (WebCore::AudioContext::unlock): (WebCore::AudioContext::isAudioThread const): (WebCore::AudioContext::isGraphOwner const): * Modules/webaudio/AudioContext.h: (WebCore::AudioContext::setAudioThread): (WebCore::AudioContext::audioThread const): * Modules/webaudio/AudioDestinationNode.cpp: (WebCore::AudioDestinationNode::render): * Modules/webdatabase/Database.cpp: (WebCore::Database::performClose): (WebCore::Database::securityOrigin): * Modules/webdatabase/DatabaseDetails.h: (WebCore::DatabaseDetails::DatabaseDetails): (WebCore::DatabaseDetails::operator=): (WebCore::DatabaseDetails::thread const): (WebCore::DatabaseDetails::threadID const): Deleted. * Modules/webdatabase/DatabaseManager.cpp: (WebCore::DatabaseManager::detailsForNameAndOrigin): * Modules/webdatabase/DatabaseThread.cpp: (WebCore::DatabaseThread::databaseThread): (WebCore::DatabaseThread::recordDatabaseOpen): (WebCore::DatabaseThread::recordDatabaseClosed): * Modules/webdatabase/DatabaseThread.h: (WebCore::DatabaseThread::getThread): (WebCore::DatabaseThread::getThreadID): Deleted. * Modules/webdatabase/SQLTransaction.cpp: (WebCore::SQLTransaction::checkAndHandleClosedDatabase): * Modules/webdatabase/SQLTransactionBackend.cpp: (WebCore::SQLTransactionBackend::doCleanup): (WebCore::SQLTransactionBackend::notifyDatabaseThreadIsShuttingDown): * bindings/js/JSCallbackData.h: (WebCore::JSCallbackData::JSCallbackData): (WebCore::JSCallbackData::~JSCallbackData): * bindings/js/ScheduledAction.cpp: (WebCore::ScheduledAction::execute): * dom/ScriptExecutionContext.cpp: (WebCore::ScriptExecutionContext::createdMessagePort): (WebCore::ScriptExecutionContext::destroyedMessagePort): * page/ResourceUsageOverlay.h: * page/scrolling/ScrollingThread.cpp: (WebCore::ScrollingThread::isCurrentThread): * platform/Supplementable.h: (WebCore::Supplementable::provideSupplement): (WebCore::Supplementable::removeSupplement): (WebCore::Supplementable::requireSupplement): (WebCore::Supplementable::Supplementable): Deleted. * platform/Timer.cpp: (WebCore::TimerBase::TimerBase): (WebCore::TimerBase::start): (WebCore::TimerBase::stop): (WebCore::TimerBase::setNextFireTime): * platform/Timer.h: (WebCore::TimerBase::isActive const): * platform/graphics/cocoa/FontCacheCoreText.cpp: (WebCore::shouldAutoActivateFontIfNeeded): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.cpp: (WebCore::TextureMapperPlatformLayerProxy::activateOnCompositingThread): (WebCore::TextureMapperPlatformLayerProxy::invalidate): (WebCore::TextureMapperPlatformLayerProxy::getAvailableBuffer): (WebCore::TextureMapperPlatformLayerProxy::appendToUnusedBuffers): (WebCore::TextureMapperPlatformLayerProxy::swapBuffer): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.h: (): Deleted. * platform/ios/wak/WebCoreThread.mm: (RunWebThread): (StartWebThread): * platform/sql/SQLiteDatabase.cpp: (WebCore::SQLiteDatabase::open): (WebCore::SQLiteDatabase::close): * platform/sql/SQLiteDatabase.h: (WebCore::SQLiteDatabase::sqlite3Handle const): * workers/WorkerGlobalScope.cpp: (WebCore::WorkerGlobalScope::~WorkerGlobalScope): (WebCore::WorkerGlobalScope::isContextThread const): * workers/WorkerMessagingProxy.cpp: (WebCore::WorkerMessagingProxy::WorkerMessagingProxy): (WebCore::WorkerMessagingProxy::~WorkerMessagingProxy): * workers/WorkerRunLoop.cpp: (WebCore::WorkerRunLoop::runInMode): (WebCore::WorkerRunLoop::runCleanupTasks): * workers/WorkerThread.h: (WebCore::WorkerThread::thread const): (WebCore::WorkerThread::threadID const): Deleted. * workers/service/ServiceWorkerContainer.cpp: (WebCore::ServiceWorkerContainer::~ServiceWorkerContainer): (WebCore::ServiceWorkerContainer::scheduleJob): (WebCore::ServiceWorkerContainer::jobFailedWithException): (WebCore::ServiceWorkerContainer::scheduleTaskToFireUpdateFoundEvent): (WebCore::ServiceWorkerContainer::jobResolvedWithRegistration): (WebCore::ServiceWorkerContainer::jobResolvedWithUnregistrationResult): (WebCore::ServiceWorkerContainer::startScriptFetchForJob): (WebCore::ServiceWorkerContainer::jobFinishedLoadingScript): (WebCore::ServiceWorkerContainer::jobFailedLoadingScript): (WebCore::ServiceWorkerContainer::jobDidFinish): (WebCore::ServiceWorkerContainer::addRegistration): (WebCore::ServiceWorkerContainer::removeRegistration): (WebCore::ServiceWorkerContainer::scheduleTaskToFireControllerChangeEvent): (WebCore::ServiceWorkerContainer::contextIdentifier): * workers/service/ServiceWorkerContainer.h: * workers/service/ServiceWorkerJob.cpp: (WebCore::ServiceWorkerJob::~ServiceWorkerJob): (WebCore::ServiceWorkerJob::failedWithException): (WebCore::ServiceWorkerJob::resolvedWithRegistration): (WebCore::ServiceWorkerJob::resolvedWithUnregistrationResult): (WebCore::ServiceWorkerJob::startScriptFetch): (WebCore::ServiceWorkerJob::fetchScriptWithContext): (WebCore::ServiceWorkerJob::didReceiveResponse): (WebCore::ServiceWorkerJob::notifyFinished): * workers/service/ServiceWorkerJob.h: * xml/parser/XMLDocumentParserLibxml2.cpp: (WebCore::matchFunc): (WebCore::openFunc): (WebCore::initializeXMLParser): (WebCore::XMLParserContext::createStringParser): (WebCore::XMLParserContext::createMemoryParser): Source/WebKit: * UIProcess/API/glib/IconDatabase.cpp: * UIProcess/GenericCallback.h: (WebKit::GenericCallback::~GenericCallback): (WebKit::GenericCallback::performCallbackWithReturnValue): Source/WTF: We should use a pointer of WTF::Thread instead of ThreadIdentifier. One problem is that Windows support library uses WTF::createThread, which returns ThreadIdentifier. So we cannot drop ThreadIdentifier in Windows environment. This patch keeps ThreadIdentifier in Windows. * wtf/MainThread.cpp: (WTF::initializeMainThread): (WTF::isMainThread): (WTF::canAccessThreadLocalDataForThread): * wtf/MainThread.h: * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkCount): * wtf/RecursiveLockAdapter.h: (WTF::RecursiveLockAdapter::lock): (WTF::RecursiveLockAdapter::unlock): (WTF::RecursiveLockAdapter::tryLock): * wtf/Threading.cpp: (WTF::Thread::dump const): * wtf/Threading.h: (WTF::Thread::id const): (WTF::Thread::operator==): Deleted. (WTF::Thread::operator!=): Deleted. (WTF::currentThread): Deleted. * wtf/ThreadingPrimitives.h: * wtf/ThreadingPthreads.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::detach): (WTF::Thread::initializeCurrentTLS): (WTF::Thread::suspend): (WTF::Thread::establishPlatformSpecificHandle): (WTF::Thread::currentID): Deleted. * wtf/ThreadingWin.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::suspend): (WTF::Thread::currentDying): * wtf/mac/MainThreadMac.mm: (WTF::initializeApplicationUIThread): (WTF::initializeWebThreadPlatform): (WTF::canAccessThreadLocalDataForThread): (WTF::initializeApplicationUIThreadIdentifier): Deleted. (WTF::initializeWebThreadIdentifier): Deleted. Tools: * DumpRenderTree/mac/DumpRenderTree.mm: (dumpRenderTree): (runThread): Deleted. (runPthread): Deleted. (testThreadIdentifierMap): Deleted. * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: * TestWebKitAPI/Tests/WTF/Threading.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/196314@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@225470 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-12-04 06:13:05 +00:00
dataLog(toString(Thread::current(), ": enqueueing ", RawPointer(data), " with address = ", RawPointer(data->address), " onto ", RawPointer(this), "\n"));
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
ASSERT(data->address);
ASSERT(!data->nextInQueue);
if (queueTail) {
queueTail->nextInQueue = data;
queueTail = data;
return;
}
queueHead = data;
queueTail = data;
}
template<typename Functor>
void genericDequeue(const Functor& functor)
{
if (verbose)
WTF shouldn't have both Thread and ThreadIdentifier https://bugs.webkit.org/show_bug.cgi?id=180308 Reviewed by Darin Adler. Source/JavaScriptCore: * heap/MachineStackMarker.cpp: (JSC::MachineThreads::tryCopyOtherThreadStacks): * llint/LLIntSlowPaths.cpp: (JSC::LLInt::llint_trace_operand): (JSC::LLInt::llint_trace_value): (JSC::LLInt::LLINT_SLOW_PATH_DECL): (JSC::LLInt::traceFunctionPrologue): * runtime/ExceptionScope.cpp: (JSC::ExceptionScope::unexpectedExceptionMessage): * runtime/JSLock.h: (JSC::JSLock::currentThreadIsHoldingLock): * runtime/VM.cpp: (JSC::VM::throwException): * runtime/VM.h: (JSC::VM::throwingThread const): (JSC::VM::clearException): * tools/HeapVerifier.cpp: (JSC::HeapVerifier::printVerificationHeader): Source/WebCore: No behavior change. * Modules/indexeddb/IDBActiveDOMObject.h: (WebCore::IDBActiveDOMObject::originThread const): (WebCore::IDBActiveDOMObject::performCallbackOnOriginThread): (WebCore::IDBActiveDOMObject::callFunctionOnOriginThread): (WebCore::IDBActiveDOMObject::originThreadID const): Deleted. * Modules/indexeddb/IDBCursor.cpp: (WebCore::IDBCursor::IDBCursor): (WebCore::IDBCursor::~IDBCursor): (WebCore::IDBCursor::sourcesDeleted const): (WebCore::IDBCursor::transaction const): (WebCore::IDBCursor::update): (WebCore::IDBCursor::advance): (WebCore::IDBCursor::continueFunction): (WebCore::IDBCursor::uncheckedIterateCursor): (WebCore::IDBCursor::deleteFunction): (WebCore::IDBCursor::setGetResult): * Modules/indexeddb/IDBDatabase.cpp: (WebCore::IDBDatabase::~IDBDatabase): (WebCore::IDBDatabase::hasPendingActivity const): (WebCore::IDBDatabase::name const): (WebCore::IDBDatabase::version const): (WebCore::IDBDatabase::objectStoreNames const): (WebCore::IDBDatabase::renameObjectStore): (WebCore::IDBDatabase::renameIndex): (WebCore::IDBDatabase::createObjectStore): (WebCore::IDBDatabase::transaction): (WebCore::IDBDatabase::deleteObjectStore): (WebCore::IDBDatabase::close): (WebCore::IDBDatabase::connectionToServerLost): (WebCore::IDBDatabase::maybeCloseInServer): (WebCore::IDBDatabase::activeDOMObjectName const): (WebCore::IDBDatabase::canSuspendForDocumentSuspension const): (WebCore::IDBDatabase::stop): (WebCore::IDBDatabase::startVersionChangeTransaction): (WebCore::IDBDatabase::didStartTransaction): (WebCore::IDBDatabase::willCommitTransaction): (WebCore::IDBDatabase::didCommitTransaction): (WebCore::IDBDatabase::willAbortTransaction): (WebCore::IDBDatabase::didAbortTransaction): (WebCore::IDBDatabase::didCommitOrAbortTransaction): (WebCore::IDBDatabase::fireVersionChangeEvent): (WebCore::IDBDatabase::dispatchEvent): (WebCore::IDBDatabase::didCreateIndexInfo): (WebCore::IDBDatabase::didDeleteIndexInfo): * Modules/indexeddb/IDBIndex.cpp: (WebCore::IDBIndex::IDBIndex): (WebCore::IDBIndex::~IDBIndex): (WebCore::IDBIndex::name const): (WebCore::IDBIndex::setName): (WebCore::IDBIndex::objectStore): (WebCore::IDBIndex::keyPath const): (WebCore::IDBIndex::unique const): (WebCore::IDBIndex::multiEntry const): (WebCore::IDBIndex::rollbackInfoForVersionChangeAbort): (WebCore::IDBIndex::openCursor): (WebCore::IDBIndex::openKeyCursor): (WebCore::IDBIndex::doCount): (WebCore::IDBIndex::doGet): (WebCore::IDBIndex::doGetKey): (WebCore::IDBIndex::getAll): (WebCore::IDBIndex::getAllKeys): (WebCore::IDBIndex::markAsDeleted): * Modules/indexeddb/IDBObjectStore.cpp: (WebCore::IDBObjectStore::IDBObjectStore): (WebCore::IDBObjectStore::~IDBObjectStore): (WebCore::IDBObjectStore::name const): (WebCore::IDBObjectStore::setName): (WebCore::IDBObjectStore::keyPath const): (WebCore::IDBObjectStore::indexNames const): (WebCore::IDBObjectStore::transaction): (WebCore::IDBObjectStore::autoIncrement const): (WebCore::IDBObjectStore::openCursor): (WebCore::IDBObjectStore::openKeyCursor): (WebCore::IDBObjectStore::get): (WebCore::IDBObjectStore::getKey): (WebCore::IDBObjectStore::putOrAdd): (WebCore::IDBObjectStore::doDelete): (WebCore::IDBObjectStore::clear): (WebCore::IDBObjectStore::createIndex): (WebCore::IDBObjectStore::index): (WebCore::IDBObjectStore::deleteIndex): (WebCore::IDBObjectStore::doCount): (WebCore::IDBObjectStore::getAll): (WebCore::IDBObjectStore::getAllKeys): (WebCore::IDBObjectStore::markAsDeleted): (WebCore::IDBObjectStore::rollbackForVersionChangeAbort): * Modules/indexeddb/IDBOpenDBRequest.cpp: (WebCore::IDBOpenDBRequest::~IDBOpenDBRequest): (WebCore::IDBOpenDBRequest::onError): (WebCore::IDBOpenDBRequest::versionChangeTransactionDidFinish): (WebCore::IDBOpenDBRequest::fireSuccessAfterVersionChangeCommit): (WebCore::IDBOpenDBRequest::fireErrorAfterVersionChangeCompletion): (WebCore::IDBOpenDBRequest::dispatchEvent): (WebCore::IDBOpenDBRequest::onSuccess): (WebCore::IDBOpenDBRequest::onUpgradeNeeded): (WebCore::IDBOpenDBRequest::onDeleteDatabaseSuccess): (WebCore::IDBOpenDBRequest::requestCompleted): (WebCore::IDBOpenDBRequest::requestBlocked): * Modules/indexeddb/IDBRequest.cpp: (WebCore::IDBRequest::~IDBRequest): (WebCore:: const): (WebCore::IDBRequest::setSource): (WebCore::IDBRequest::setVersionChangeTransaction): (WebCore::IDBRequest::transaction const): (WebCore::IDBRequest::sourceObjectStoreIdentifier const): (WebCore::IDBRequest::sourceIndexIdentifier const): (WebCore::IDBRequest::requestedObjectStoreRecordType const): (WebCore::IDBRequest::requestedIndexRecordType const): (WebCore::IDBRequest::eventTargetInterface const): (WebCore::IDBRequest::activeDOMObjectName const): (WebCore::IDBRequest::canSuspendForDocumentSuspension const): (WebCore::IDBRequest::hasPendingActivity const): (WebCore::IDBRequest::stop): (WebCore::IDBRequest::enqueueEvent): (WebCore::IDBRequest::dispatchEvent): (WebCore::IDBRequest::uncaughtExceptionInEventHandler): (WebCore::IDBRequest::setResult): (WebCore::IDBRequest::setResultToStructuredClone): (WebCore::IDBRequest::setResultToUndefined): (WebCore::IDBRequest::resultCursor): (WebCore::IDBRequest::willIterateCursor): (WebCore::IDBRequest::didOpenOrIterateCursor): (WebCore::IDBRequest::completeRequestAndDispatchEvent): (WebCore::IDBRequest::onError): (WebCore::IDBRequest::onSuccess): * Modules/indexeddb/IDBTransaction.cpp: (WebCore::IDBTransaction::IDBTransaction): (WebCore::IDBTransaction::~IDBTransaction): (WebCore::IDBTransaction::objectStoreNames const): (WebCore::IDBTransaction::db): (WebCore::IDBTransaction::error const): (WebCore::IDBTransaction::objectStore): (WebCore::IDBTransaction::abortDueToFailedRequest): (WebCore::IDBTransaction::transitionedToFinishing): (WebCore::IDBTransaction::abort): (WebCore::IDBTransaction::internalAbort): (WebCore::IDBTransaction::abortOnServerAndCancelRequests): (WebCore::IDBTransaction::activeDOMObjectName const): (WebCore::IDBTransaction::canSuspendForDocumentSuspension const): (WebCore::IDBTransaction::hasPendingActivity const): (WebCore::IDBTransaction::stop): (WebCore::IDBTransaction::isActive const): (WebCore::IDBTransaction::isFinishedOrFinishing const): (WebCore::IDBTransaction::addRequest): (WebCore::IDBTransaction::removeRequest): (WebCore::IDBTransaction::scheduleOperation): (WebCore::IDBTransaction::schedulePendingOperationTimer): (WebCore::IDBTransaction::pendingOperationTimerFired): (WebCore::IDBTransaction::operationCompletedOnServer): (WebCore::IDBTransaction::scheduleCompletedOperationTimer): (WebCore::IDBTransaction::completedOperationTimerFired): (WebCore::IDBTransaction::commit): (WebCore::IDBTransaction::commitOnServer): (WebCore::IDBTransaction::finishAbortOrCommit): (WebCore::IDBTransaction::didStart): (WebCore::IDBTransaction::notifyDidAbort): (WebCore::IDBTransaction::didAbort): (WebCore::IDBTransaction::didCommit): (WebCore::IDBTransaction::fireOnComplete): (WebCore::IDBTransaction::fireOnAbort): (WebCore::IDBTransaction::enqueueEvent): (WebCore::IDBTransaction::dispatchEvent): (WebCore::IDBTransaction::createObjectStore): (WebCore::IDBTransaction::createObjectStoreOnServer): (WebCore::IDBTransaction::didCreateObjectStoreOnServer): (WebCore::IDBTransaction::renameObjectStore): (WebCore::IDBTransaction::renameObjectStoreOnServer): (WebCore::IDBTransaction::didRenameObjectStoreOnServer): (WebCore::IDBTransaction::createIndex): (WebCore::IDBTransaction::createIndexOnServer): (WebCore::IDBTransaction::didCreateIndexOnServer): (WebCore::IDBTransaction::renameIndex): (WebCore::IDBTransaction::renameIndexOnServer): (WebCore::IDBTransaction::didRenameIndexOnServer): (WebCore::IDBTransaction::requestOpenCursor): (WebCore::IDBTransaction::doRequestOpenCursor): (WebCore::IDBTransaction::openCursorOnServer): (WebCore::IDBTransaction::didOpenCursorOnServer): (WebCore::IDBTransaction::iterateCursor): (WebCore::IDBTransaction::iterateCursorOnServer): (WebCore::IDBTransaction::didIterateCursorOnServer): (WebCore::IDBTransaction::requestGetAllObjectStoreRecords): (WebCore::IDBTransaction::requestGetAllIndexRecords): (WebCore::IDBTransaction::getAllRecordsOnServer): (WebCore::IDBTransaction::didGetAllRecordsOnServer): (WebCore::IDBTransaction::requestGetRecord): (WebCore::IDBTransaction::requestGetValue): (WebCore::IDBTransaction::requestGetKey): (WebCore::IDBTransaction::requestIndexRecord): (WebCore::IDBTransaction::getRecordOnServer): (WebCore::IDBTransaction::didGetRecordOnServer): (WebCore::IDBTransaction::requestCount): (WebCore::IDBTransaction::getCountOnServer): (WebCore::IDBTransaction::didGetCountOnServer): (WebCore::IDBTransaction::requestDeleteRecord): (WebCore::IDBTransaction::deleteRecordOnServer): (WebCore::IDBTransaction::didDeleteRecordOnServer): (WebCore::IDBTransaction::requestClearObjectStore): (WebCore::IDBTransaction::clearObjectStoreOnServer): (WebCore::IDBTransaction::didClearObjectStoreOnServer): (WebCore::IDBTransaction::requestPutOrAdd): (WebCore::IDBTransaction::putOrAddOnServer): (WebCore::IDBTransaction::didPutOrAddOnServer): (WebCore::IDBTransaction::deleteObjectStore): (WebCore::IDBTransaction::deleteObjectStoreOnServer): (WebCore::IDBTransaction::didDeleteObjectStoreOnServer): (WebCore::IDBTransaction::deleteIndex): (WebCore::IDBTransaction::deleteIndexOnServer): (WebCore::IDBTransaction::didDeleteIndexOnServer): (WebCore::IDBTransaction::operationCompletedOnClient): (WebCore::IDBTransaction::establishOnServer): (WebCore::IDBTransaction::activate): (WebCore::IDBTransaction::deactivate): * Modules/indexeddb/client/IDBConnectionProxy.cpp: (WebCore::IDBClient::removeItemsMatchingCurrentThread): * Modules/indexeddb/client/TransactionOperation.h: (WebCore::IDBClient::TransactionOperation::~TransactionOperation): (WebCore::IDBClient::TransactionOperation::perform): (WebCore::IDBClient::TransactionOperation::transitionToCompleteOnThisThread): (WebCore::IDBClient::TransactionOperation::transitionToComplete): (WebCore::IDBClient::TransactionOperation::doComplete): (WebCore::IDBClient::TransactionOperation::originThread const): (WebCore::IDBClient::TransactionOperation::originThreadID const): Deleted. * Modules/webaudio/AudioContext.cpp: (WebCore::AudioContext::AudioContext): (WebCore::AudioContext::lock): (WebCore::AudioContext::tryLock): (WebCore::AudioContext::unlock): (WebCore::AudioContext::isAudioThread const): (WebCore::AudioContext::isGraphOwner const): * Modules/webaudio/AudioContext.h: (WebCore::AudioContext::setAudioThread): (WebCore::AudioContext::audioThread const): * Modules/webaudio/AudioDestinationNode.cpp: (WebCore::AudioDestinationNode::render): * Modules/webdatabase/Database.cpp: (WebCore::Database::performClose): (WebCore::Database::securityOrigin): * Modules/webdatabase/DatabaseDetails.h: (WebCore::DatabaseDetails::DatabaseDetails): (WebCore::DatabaseDetails::operator=): (WebCore::DatabaseDetails::thread const): (WebCore::DatabaseDetails::threadID const): Deleted. * Modules/webdatabase/DatabaseManager.cpp: (WebCore::DatabaseManager::detailsForNameAndOrigin): * Modules/webdatabase/DatabaseThread.cpp: (WebCore::DatabaseThread::databaseThread): (WebCore::DatabaseThread::recordDatabaseOpen): (WebCore::DatabaseThread::recordDatabaseClosed): * Modules/webdatabase/DatabaseThread.h: (WebCore::DatabaseThread::getThread): (WebCore::DatabaseThread::getThreadID): Deleted. * Modules/webdatabase/SQLTransaction.cpp: (WebCore::SQLTransaction::checkAndHandleClosedDatabase): * Modules/webdatabase/SQLTransactionBackend.cpp: (WebCore::SQLTransactionBackend::doCleanup): (WebCore::SQLTransactionBackend::notifyDatabaseThreadIsShuttingDown): * bindings/js/JSCallbackData.h: (WebCore::JSCallbackData::JSCallbackData): (WebCore::JSCallbackData::~JSCallbackData): * bindings/js/ScheduledAction.cpp: (WebCore::ScheduledAction::execute): * dom/ScriptExecutionContext.cpp: (WebCore::ScriptExecutionContext::createdMessagePort): (WebCore::ScriptExecutionContext::destroyedMessagePort): * page/ResourceUsageOverlay.h: * page/scrolling/ScrollingThread.cpp: (WebCore::ScrollingThread::isCurrentThread): * platform/Supplementable.h: (WebCore::Supplementable::provideSupplement): (WebCore::Supplementable::removeSupplement): (WebCore::Supplementable::requireSupplement): (WebCore::Supplementable::Supplementable): Deleted. * platform/Timer.cpp: (WebCore::TimerBase::TimerBase): (WebCore::TimerBase::start): (WebCore::TimerBase::stop): (WebCore::TimerBase::setNextFireTime): * platform/Timer.h: (WebCore::TimerBase::isActive const): * platform/graphics/cocoa/FontCacheCoreText.cpp: (WebCore::shouldAutoActivateFontIfNeeded): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.cpp: (WebCore::TextureMapperPlatformLayerProxy::activateOnCompositingThread): (WebCore::TextureMapperPlatformLayerProxy::invalidate): (WebCore::TextureMapperPlatformLayerProxy::getAvailableBuffer): (WebCore::TextureMapperPlatformLayerProxy::appendToUnusedBuffers): (WebCore::TextureMapperPlatformLayerProxy::swapBuffer): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.h: (): Deleted. * platform/ios/wak/WebCoreThread.mm: (RunWebThread): (StartWebThread): * platform/sql/SQLiteDatabase.cpp: (WebCore::SQLiteDatabase::open): (WebCore::SQLiteDatabase::close): * platform/sql/SQLiteDatabase.h: (WebCore::SQLiteDatabase::sqlite3Handle const): * workers/WorkerGlobalScope.cpp: (WebCore::WorkerGlobalScope::~WorkerGlobalScope): (WebCore::WorkerGlobalScope::isContextThread const): * workers/WorkerMessagingProxy.cpp: (WebCore::WorkerMessagingProxy::WorkerMessagingProxy): (WebCore::WorkerMessagingProxy::~WorkerMessagingProxy): * workers/WorkerRunLoop.cpp: (WebCore::WorkerRunLoop::runInMode): (WebCore::WorkerRunLoop::runCleanupTasks): * workers/WorkerThread.h: (WebCore::WorkerThread::thread const): (WebCore::WorkerThread::threadID const): Deleted. * workers/service/ServiceWorkerContainer.cpp: (WebCore::ServiceWorkerContainer::~ServiceWorkerContainer): (WebCore::ServiceWorkerContainer::scheduleJob): (WebCore::ServiceWorkerContainer::jobFailedWithException): (WebCore::ServiceWorkerContainer::scheduleTaskToFireUpdateFoundEvent): (WebCore::ServiceWorkerContainer::jobResolvedWithRegistration): (WebCore::ServiceWorkerContainer::jobResolvedWithUnregistrationResult): (WebCore::ServiceWorkerContainer::startScriptFetchForJob): (WebCore::ServiceWorkerContainer::jobFinishedLoadingScript): (WebCore::ServiceWorkerContainer::jobFailedLoadingScript): (WebCore::ServiceWorkerContainer::jobDidFinish): (WebCore::ServiceWorkerContainer::addRegistration): (WebCore::ServiceWorkerContainer::removeRegistration): (WebCore::ServiceWorkerContainer::scheduleTaskToFireControllerChangeEvent): (WebCore::ServiceWorkerContainer::contextIdentifier): * workers/service/ServiceWorkerContainer.h: * workers/service/ServiceWorkerJob.cpp: (WebCore::ServiceWorkerJob::~ServiceWorkerJob): (WebCore::ServiceWorkerJob::failedWithException): (WebCore::ServiceWorkerJob::resolvedWithRegistration): (WebCore::ServiceWorkerJob::resolvedWithUnregistrationResult): (WebCore::ServiceWorkerJob::startScriptFetch): (WebCore::ServiceWorkerJob::fetchScriptWithContext): (WebCore::ServiceWorkerJob::didReceiveResponse): (WebCore::ServiceWorkerJob::notifyFinished): * workers/service/ServiceWorkerJob.h: * xml/parser/XMLDocumentParserLibxml2.cpp: (WebCore::matchFunc): (WebCore::openFunc): (WebCore::initializeXMLParser): (WebCore::XMLParserContext::createStringParser): (WebCore::XMLParserContext::createMemoryParser): Source/WebKit: * UIProcess/API/glib/IconDatabase.cpp: * UIProcess/GenericCallback.h: (WebKit::GenericCallback::~GenericCallback): (WebKit::GenericCallback::performCallbackWithReturnValue): Source/WTF: We should use a pointer of WTF::Thread instead of ThreadIdentifier. One problem is that Windows support library uses WTF::createThread, which returns ThreadIdentifier. So we cannot drop ThreadIdentifier in Windows environment. This patch keeps ThreadIdentifier in Windows. * wtf/MainThread.cpp: (WTF::initializeMainThread): (WTF::isMainThread): (WTF::canAccessThreadLocalDataForThread): * wtf/MainThread.h: * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkCount): * wtf/RecursiveLockAdapter.h: (WTF::RecursiveLockAdapter::lock): (WTF::RecursiveLockAdapter::unlock): (WTF::RecursiveLockAdapter::tryLock): * wtf/Threading.cpp: (WTF::Thread::dump const): * wtf/Threading.h: (WTF::Thread::id const): (WTF::Thread::operator==): Deleted. (WTF::Thread::operator!=): Deleted. (WTF::currentThread): Deleted. * wtf/ThreadingPrimitives.h: * wtf/ThreadingPthreads.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::detach): (WTF::Thread::initializeCurrentTLS): (WTF::Thread::suspend): (WTF::Thread::establishPlatformSpecificHandle): (WTF::Thread::currentID): Deleted. * wtf/ThreadingWin.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::suspend): (WTF::Thread::currentDying): * wtf/mac/MainThreadMac.mm: (WTF::initializeApplicationUIThread): (WTF::initializeWebThreadPlatform): (WTF::canAccessThreadLocalDataForThread): (WTF::initializeApplicationUIThreadIdentifier): Deleted. (WTF::initializeWebThreadIdentifier): Deleted. Tools: * DumpRenderTree/mac/DumpRenderTree.mm: (dumpRenderTree): (runThread): Deleted. (runPthread): Deleted. (testThreadIdentifierMap): Deleted. * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: * TestWebKitAPI/Tests/WTF/Threading.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/196314@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@225470 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-12-04 06:13:05 +00:00
dataLog(toString(Thread::current(), ": dequeueing from bucket at ", RawPointer(this), "\n"));
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
if (!queueHead) {
if (verbose)
WTF shouldn't have both Thread and ThreadIdentifier https://bugs.webkit.org/show_bug.cgi?id=180308 Reviewed by Darin Adler. Source/JavaScriptCore: * heap/MachineStackMarker.cpp: (JSC::MachineThreads::tryCopyOtherThreadStacks): * llint/LLIntSlowPaths.cpp: (JSC::LLInt::llint_trace_operand): (JSC::LLInt::llint_trace_value): (JSC::LLInt::LLINT_SLOW_PATH_DECL): (JSC::LLInt::traceFunctionPrologue): * runtime/ExceptionScope.cpp: (JSC::ExceptionScope::unexpectedExceptionMessage): * runtime/JSLock.h: (JSC::JSLock::currentThreadIsHoldingLock): * runtime/VM.cpp: (JSC::VM::throwException): * runtime/VM.h: (JSC::VM::throwingThread const): (JSC::VM::clearException): * tools/HeapVerifier.cpp: (JSC::HeapVerifier::printVerificationHeader): Source/WebCore: No behavior change. * Modules/indexeddb/IDBActiveDOMObject.h: (WebCore::IDBActiveDOMObject::originThread const): (WebCore::IDBActiveDOMObject::performCallbackOnOriginThread): (WebCore::IDBActiveDOMObject::callFunctionOnOriginThread): (WebCore::IDBActiveDOMObject::originThreadID const): Deleted. * Modules/indexeddb/IDBCursor.cpp: (WebCore::IDBCursor::IDBCursor): (WebCore::IDBCursor::~IDBCursor): (WebCore::IDBCursor::sourcesDeleted const): (WebCore::IDBCursor::transaction const): (WebCore::IDBCursor::update): (WebCore::IDBCursor::advance): (WebCore::IDBCursor::continueFunction): (WebCore::IDBCursor::uncheckedIterateCursor): (WebCore::IDBCursor::deleteFunction): (WebCore::IDBCursor::setGetResult): * Modules/indexeddb/IDBDatabase.cpp: (WebCore::IDBDatabase::~IDBDatabase): (WebCore::IDBDatabase::hasPendingActivity const): (WebCore::IDBDatabase::name const): (WebCore::IDBDatabase::version const): (WebCore::IDBDatabase::objectStoreNames const): (WebCore::IDBDatabase::renameObjectStore): (WebCore::IDBDatabase::renameIndex): (WebCore::IDBDatabase::createObjectStore): (WebCore::IDBDatabase::transaction): (WebCore::IDBDatabase::deleteObjectStore): (WebCore::IDBDatabase::close): (WebCore::IDBDatabase::connectionToServerLost): (WebCore::IDBDatabase::maybeCloseInServer): (WebCore::IDBDatabase::activeDOMObjectName const): (WebCore::IDBDatabase::canSuspendForDocumentSuspension const): (WebCore::IDBDatabase::stop): (WebCore::IDBDatabase::startVersionChangeTransaction): (WebCore::IDBDatabase::didStartTransaction): (WebCore::IDBDatabase::willCommitTransaction): (WebCore::IDBDatabase::didCommitTransaction): (WebCore::IDBDatabase::willAbortTransaction): (WebCore::IDBDatabase::didAbortTransaction): (WebCore::IDBDatabase::didCommitOrAbortTransaction): (WebCore::IDBDatabase::fireVersionChangeEvent): (WebCore::IDBDatabase::dispatchEvent): (WebCore::IDBDatabase::didCreateIndexInfo): (WebCore::IDBDatabase::didDeleteIndexInfo): * Modules/indexeddb/IDBIndex.cpp: (WebCore::IDBIndex::IDBIndex): (WebCore::IDBIndex::~IDBIndex): (WebCore::IDBIndex::name const): (WebCore::IDBIndex::setName): (WebCore::IDBIndex::objectStore): (WebCore::IDBIndex::keyPath const): (WebCore::IDBIndex::unique const): (WebCore::IDBIndex::multiEntry const): (WebCore::IDBIndex::rollbackInfoForVersionChangeAbort): (WebCore::IDBIndex::openCursor): (WebCore::IDBIndex::openKeyCursor): (WebCore::IDBIndex::doCount): (WebCore::IDBIndex::doGet): (WebCore::IDBIndex::doGetKey): (WebCore::IDBIndex::getAll): (WebCore::IDBIndex::getAllKeys): (WebCore::IDBIndex::markAsDeleted): * Modules/indexeddb/IDBObjectStore.cpp: (WebCore::IDBObjectStore::IDBObjectStore): (WebCore::IDBObjectStore::~IDBObjectStore): (WebCore::IDBObjectStore::name const): (WebCore::IDBObjectStore::setName): (WebCore::IDBObjectStore::keyPath const): (WebCore::IDBObjectStore::indexNames const): (WebCore::IDBObjectStore::transaction): (WebCore::IDBObjectStore::autoIncrement const): (WebCore::IDBObjectStore::openCursor): (WebCore::IDBObjectStore::openKeyCursor): (WebCore::IDBObjectStore::get): (WebCore::IDBObjectStore::getKey): (WebCore::IDBObjectStore::putOrAdd): (WebCore::IDBObjectStore::doDelete): (WebCore::IDBObjectStore::clear): (WebCore::IDBObjectStore::createIndex): (WebCore::IDBObjectStore::index): (WebCore::IDBObjectStore::deleteIndex): (WebCore::IDBObjectStore::doCount): (WebCore::IDBObjectStore::getAll): (WebCore::IDBObjectStore::getAllKeys): (WebCore::IDBObjectStore::markAsDeleted): (WebCore::IDBObjectStore::rollbackForVersionChangeAbort): * Modules/indexeddb/IDBOpenDBRequest.cpp: (WebCore::IDBOpenDBRequest::~IDBOpenDBRequest): (WebCore::IDBOpenDBRequest::onError): (WebCore::IDBOpenDBRequest::versionChangeTransactionDidFinish): (WebCore::IDBOpenDBRequest::fireSuccessAfterVersionChangeCommit): (WebCore::IDBOpenDBRequest::fireErrorAfterVersionChangeCompletion): (WebCore::IDBOpenDBRequest::dispatchEvent): (WebCore::IDBOpenDBRequest::onSuccess): (WebCore::IDBOpenDBRequest::onUpgradeNeeded): (WebCore::IDBOpenDBRequest::onDeleteDatabaseSuccess): (WebCore::IDBOpenDBRequest::requestCompleted): (WebCore::IDBOpenDBRequest::requestBlocked): * Modules/indexeddb/IDBRequest.cpp: (WebCore::IDBRequest::~IDBRequest): (WebCore:: const): (WebCore::IDBRequest::setSource): (WebCore::IDBRequest::setVersionChangeTransaction): (WebCore::IDBRequest::transaction const): (WebCore::IDBRequest::sourceObjectStoreIdentifier const): (WebCore::IDBRequest::sourceIndexIdentifier const): (WebCore::IDBRequest::requestedObjectStoreRecordType const): (WebCore::IDBRequest::requestedIndexRecordType const): (WebCore::IDBRequest::eventTargetInterface const): (WebCore::IDBRequest::activeDOMObjectName const): (WebCore::IDBRequest::canSuspendForDocumentSuspension const): (WebCore::IDBRequest::hasPendingActivity const): (WebCore::IDBRequest::stop): (WebCore::IDBRequest::enqueueEvent): (WebCore::IDBRequest::dispatchEvent): (WebCore::IDBRequest::uncaughtExceptionInEventHandler): (WebCore::IDBRequest::setResult): (WebCore::IDBRequest::setResultToStructuredClone): (WebCore::IDBRequest::setResultToUndefined): (WebCore::IDBRequest::resultCursor): (WebCore::IDBRequest::willIterateCursor): (WebCore::IDBRequest::didOpenOrIterateCursor): (WebCore::IDBRequest::completeRequestAndDispatchEvent): (WebCore::IDBRequest::onError): (WebCore::IDBRequest::onSuccess): * Modules/indexeddb/IDBTransaction.cpp: (WebCore::IDBTransaction::IDBTransaction): (WebCore::IDBTransaction::~IDBTransaction): (WebCore::IDBTransaction::objectStoreNames const): (WebCore::IDBTransaction::db): (WebCore::IDBTransaction::error const): (WebCore::IDBTransaction::objectStore): (WebCore::IDBTransaction::abortDueToFailedRequest): (WebCore::IDBTransaction::transitionedToFinishing): (WebCore::IDBTransaction::abort): (WebCore::IDBTransaction::internalAbort): (WebCore::IDBTransaction::abortOnServerAndCancelRequests): (WebCore::IDBTransaction::activeDOMObjectName const): (WebCore::IDBTransaction::canSuspendForDocumentSuspension const): (WebCore::IDBTransaction::hasPendingActivity const): (WebCore::IDBTransaction::stop): (WebCore::IDBTransaction::isActive const): (WebCore::IDBTransaction::isFinishedOrFinishing const): (WebCore::IDBTransaction::addRequest): (WebCore::IDBTransaction::removeRequest): (WebCore::IDBTransaction::scheduleOperation): (WebCore::IDBTransaction::schedulePendingOperationTimer): (WebCore::IDBTransaction::pendingOperationTimerFired): (WebCore::IDBTransaction::operationCompletedOnServer): (WebCore::IDBTransaction::scheduleCompletedOperationTimer): (WebCore::IDBTransaction::completedOperationTimerFired): (WebCore::IDBTransaction::commit): (WebCore::IDBTransaction::commitOnServer): (WebCore::IDBTransaction::finishAbortOrCommit): (WebCore::IDBTransaction::didStart): (WebCore::IDBTransaction::notifyDidAbort): (WebCore::IDBTransaction::didAbort): (WebCore::IDBTransaction::didCommit): (WebCore::IDBTransaction::fireOnComplete): (WebCore::IDBTransaction::fireOnAbort): (WebCore::IDBTransaction::enqueueEvent): (WebCore::IDBTransaction::dispatchEvent): (WebCore::IDBTransaction::createObjectStore): (WebCore::IDBTransaction::createObjectStoreOnServer): (WebCore::IDBTransaction::didCreateObjectStoreOnServer): (WebCore::IDBTransaction::renameObjectStore): (WebCore::IDBTransaction::renameObjectStoreOnServer): (WebCore::IDBTransaction::didRenameObjectStoreOnServer): (WebCore::IDBTransaction::createIndex): (WebCore::IDBTransaction::createIndexOnServer): (WebCore::IDBTransaction::didCreateIndexOnServer): (WebCore::IDBTransaction::renameIndex): (WebCore::IDBTransaction::renameIndexOnServer): (WebCore::IDBTransaction::didRenameIndexOnServer): (WebCore::IDBTransaction::requestOpenCursor): (WebCore::IDBTransaction::doRequestOpenCursor): (WebCore::IDBTransaction::openCursorOnServer): (WebCore::IDBTransaction::didOpenCursorOnServer): (WebCore::IDBTransaction::iterateCursor): (WebCore::IDBTransaction::iterateCursorOnServer): (WebCore::IDBTransaction::didIterateCursorOnServer): (WebCore::IDBTransaction::requestGetAllObjectStoreRecords): (WebCore::IDBTransaction::requestGetAllIndexRecords): (WebCore::IDBTransaction::getAllRecordsOnServer): (WebCore::IDBTransaction::didGetAllRecordsOnServer): (WebCore::IDBTransaction::requestGetRecord): (WebCore::IDBTransaction::requestGetValue): (WebCore::IDBTransaction::requestGetKey): (WebCore::IDBTransaction::requestIndexRecord): (WebCore::IDBTransaction::getRecordOnServer): (WebCore::IDBTransaction::didGetRecordOnServer): (WebCore::IDBTransaction::requestCount): (WebCore::IDBTransaction::getCountOnServer): (WebCore::IDBTransaction::didGetCountOnServer): (WebCore::IDBTransaction::requestDeleteRecord): (WebCore::IDBTransaction::deleteRecordOnServer): (WebCore::IDBTransaction::didDeleteRecordOnServer): (WebCore::IDBTransaction::requestClearObjectStore): (WebCore::IDBTransaction::clearObjectStoreOnServer): (WebCore::IDBTransaction::didClearObjectStoreOnServer): (WebCore::IDBTransaction::requestPutOrAdd): (WebCore::IDBTransaction::putOrAddOnServer): (WebCore::IDBTransaction::didPutOrAddOnServer): (WebCore::IDBTransaction::deleteObjectStore): (WebCore::IDBTransaction::deleteObjectStoreOnServer): (WebCore::IDBTransaction::didDeleteObjectStoreOnServer): (WebCore::IDBTransaction::deleteIndex): (WebCore::IDBTransaction::deleteIndexOnServer): (WebCore::IDBTransaction::didDeleteIndexOnServer): (WebCore::IDBTransaction::operationCompletedOnClient): (WebCore::IDBTransaction::establishOnServer): (WebCore::IDBTransaction::activate): (WebCore::IDBTransaction::deactivate): * Modules/indexeddb/client/IDBConnectionProxy.cpp: (WebCore::IDBClient::removeItemsMatchingCurrentThread): * Modules/indexeddb/client/TransactionOperation.h: (WebCore::IDBClient::TransactionOperation::~TransactionOperation): (WebCore::IDBClient::TransactionOperation::perform): (WebCore::IDBClient::TransactionOperation::transitionToCompleteOnThisThread): (WebCore::IDBClient::TransactionOperation::transitionToComplete): (WebCore::IDBClient::TransactionOperation::doComplete): (WebCore::IDBClient::TransactionOperation::originThread const): (WebCore::IDBClient::TransactionOperation::originThreadID const): Deleted. * Modules/webaudio/AudioContext.cpp: (WebCore::AudioContext::AudioContext): (WebCore::AudioContext::lock): (WebCore::AudioContext::tryLock): (WebCore::AudioContext::unlock): (WebCore::AudioContext::isAudioThread const): (WebCore::AudioContext::isGraphOwner const): * Modules/webaudio/AudioContext.h: (WebCore::AudioContext::setAudioThread): (WebCore::AudioContext::audioThread const): * Modules/webaudio/AudioDestinationNode.cpp: (WebCore::AudioDestinationNode::render): * Modules/webdatabase/Database.cpp: (WebCore::Database::performClose): (WebCore::Database::securityOrigin): * Modules/webdatabase/DatabaseDetails.h: (WebCore::DatabaseDetails::DatabaseDetails): (WebCore::DatabaseDetails::operator=): (WebCore::DatabaseDetails::thread const): (WebCore::DatabaseDetails::threadID const): Deleted. * Modules/webdatabase/DatabaseManager.cpp: (WebCore::DatabaseManager::detailsForNameAndOrigin): * Modules/webdatabase/DatabaseThread.cpp: (WebCore::DatabaseThread::databaseThread): (WebCore::DatabaseThread::recordDatabaseOpen): (WebCore::DatabaseThread::recordDatabaseClosed): * Modules/webdatabase/DatabaseThread.h: (WebCore::DatabaseThread::getThread): (WebCore::DatabaseThread::getThreadID): Deleted. * Modules/webdatabase/SQLTransaction.cpp: (WebCore::SQLTransaction::checkAndHandleClosedDatabase): * Modules/webdatabase/SQLTransactionBackend.cpp: (WebCore::SQLTransactionBackend::doCleanup): (WebCore::SQLTransactionBackend::notifyDatabaseThreadIsShuttingDown): * bindings/js/JSCallbackData.h: (WebCore::JSCallbackData::JSCallbackData): (WebCore::JSCallbackData::~JSCallbackData): * bindings/js/ScheduledAction.cpp: (WebCore::ScheduledAction::execute): * dom/ScriptExecutionContext.cpp: (WebCore::ScriptExecutionContext::createdMessagePort): (WebCore::ScriptExecutionContext::destroyedMessagePort): * page/ResourceUsageOverlay.h: * page/scrolling/ScrollingThread.cpp: (WebCore::ScrollingThread::isCurrentThread): * platform/Supplementable.h: (WebCore::Supplementable::provideSupplement): (WebCore::Supplementable::removeSupplement): (WebCore::Supplementable::requireSupplement): (WebCore::Supplementable::Supplementable): Deleted. * platform/Timer.cpp: (WebCore::TimerBase::TimerBase): (WebCore::TimerBase::start): (WebCore::TimerBase::stop): (WebCore::TimerBase::setNextFireTime): * platform/Timer.h: (WebCore::TimerBase::isActive const): * platform/graphics/cocoa/FontCacheCoreText.cpp: (WebCore::shouldAutoActivateFontIfNeeded): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.cpp: (WebCore::TextureMapperPlatformLayerProxy::activateOnCompositingThread): (WebCore::TextureMapperPlatformLayerProxy::invalidate): (WebCore::TextureMapperPlatformLayerProxy::getAvailableBuffer): (WebCore::TextureMapperPlatformLayerProxy::appendToUnusedBuffers): (WebCore::TextureMapperPlatformLayerProxy::swapBuffer): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.h: (): Deleted. * platform/ios/wak/WebCoreThread.mm: (RunWebThread): (StartWebThread): * platform/sql/SQLiteDatabase.cpp: (WebCore::SQLiteDatabase::open): (WebCore::SQLiteDatabase::close): * platform/sql/SQLiteDatabase.h: (WebCore::SQLiteDatabase::sqlite3Handle const): * workers/WorkerGlobalScope.cpp: (WebCore::WorkerGlobalScope::~WorkerGlobalScope): (WebCore::WorkerGlobalScope::isContextThread const): * workers/WorkerMessagingProxy.cpp: (WebCore::WorkerMessagingProxy::WorkerMessagingProxy): (WebCore::WorkerMessagingProxy::~WorkerMessagingProxy): * workers/WorkerRunLoop.cpp: (WebCore::WorkerRunLoop::runInMode): (WebCore::WorkerRunLoop::runCleanupTasks): * workers/WorkerThread.h: (WebCore::WorkerThread::thread const): (WebCore::WorkerThread::threadID const): Deleted. * workers/service/ServiceWorkerContainer.cpp: (WebCore::ServiceWorkerContainer::~ServiceWorkerContainer): (WebCore::ServiceWorkerContainer::scheduleJob): (WebCore::ServiceWorkerContainer::jobFailedWithException): (WebCore::ServiceWorkerContainer::scheduleTaskToFireUpdateFoundEvent): (WebCore::ServiceWorkerContainer::jobResolvedWithRegistration): (WebCore::ServiceWorkerContainer::jobResolvedWithUnregistrationResult): (WebCore::ServiceWorkerContainer::startScriptFetchForJob): (WebCore::ServiceWorkerContainer::jobFinishedLoadingScript): (WebCore::ServiceWorkerContainer::jobFailedLoadingScript): (WebCore::ServiceWorkerContainer::jobDidFinish): (WebCore::ServiceWorkerContainer::addRegistration): (WebCore::ServiceWorkerContainer::removeRegistration): (WebCore::ServiceWorkerContainer::scheduleTaskToFireControllerChangeEvent): (WebCore::ServiceWorkerContainer::contextIdentifier): * workers/service/ServiceWorkerContainer.h: * workers/service/ServiceWorkerJob.cpp: (WebCore::ServiceWorkerJob::~ServiceWorkerJob): (WebCore::ServiceWorkerJob::failedWithException): (WebCore::ServiceWorkerJob::resolvedWithRegistration): (WebCore::ServiceWorkerJob::resolvedWithUnregistrationResult): (WebCore::ServiceWorkerJob::startScriptFetch): (WebCore::ServiceWorkerJob::fetchScriptWithContext): (WebCore::ServiceWorkerJob::didReceiveResponse): (WebCore::ServiceWorkerJob::notifyFinished): * workers/service/ServiceWorkerJob.h: * xml/parser/XMLDocumentParserLibxml2.cpp: (WebCore::matchFunc): (WebCore::openFunc): (WebCore::initializeXMLParser): (WebCore::XMLParserContext::createStringParser): (WebCore::XMLParserContext::createMemoryParser): Source/WebKit: * UIProcess/API/glib/IconDatabase.cpp: * UIProcess/GenericCallback.h: (WebKit::GenericCallback::~GenericCallback): (WebKit::GenericCallback::performCallbackWithReturnValue): Source/WTF: We should use a pointer of WTF::Thread instead of ThreadIdentifier. One problem is that Windows support library uses WTF::createThread, which returns ThreadIdentifier. So we cannot drop ThreadIdentifier in Windows environment. This patch keeps ThreadIdentifier in Windows. * wtf/MainThread.cpp: (WTF::initializeMainThread): (WTF::isMainThread): (WTF::canAccessThreadLocalDataForThread): * wtf/MainThread.h: * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkCount): * wtf/RecursiveLockAdapter.h: (WTF::RecursiveLockAdapter::lock): (WTF::RecursiveLockAdapter::unlock): (WTF::RecursiveLockAdapter::tryLock): * wtf/Threading.cpp: (WTF::Thread::dump const): * wtf/Threading.h: (WTF::Thread::id const): (WTF::Thread::operator==): Deleted. (WTF::Thread::operator!=): Deleted. (WTF::currentThread): Deleted. * wtf/ThreadingPrimitives.h: * wtf/ThreadingPthreads.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::detach): (WTF::Thread::initializeCurrentTLS): (WTF::Thread::suspend): (WTF::Thread::establishPlatformSpecificHandle): (WTF::Thread::currentID): Deleted. * wtf/ThreadingWin.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::suspend): (WTF::Thread::currentDying): * wtf/mac/MainThreadMac.mm: (WTF::initializeApplicationUIThread): (WTF::initializeWebThreadPlatform): (WTF::canAccessThreadLocalDataForThread): (WTF::initializeApplicationUIThreadIdentifier): Deleted. (WTF::initializeWebThreadIdentifier): Deleted. Tools: * DumpRenderTree/mac/DumpRenderTree.mm: (dumpRenderTree): (runThread): Deleted. (runPthread): Deleted. (testThreadIdentifierMap): Deleted. * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: * TestWebKitAPI/Tests/WTF/Threading.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/196314@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@225470 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-12-04 06:13:05 +00:00
dataLog(toString(Thread::current(), ": empty.\n"));
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
return;
}
// This loop is a very clever abomination. The induction variables are the pointer to the
// pointer to the current node, and the pointer to the previous node. This gives us everything
// we need to both proceed forward to the next node, and to remove nodes while maintaining the
// queueHead/queueTail and all of the nextInQueue links. For example, when we are at the head
// element, then removal means rewiring queueHead, and if it was also equal to queueTail, then
// we'd want queueTail to be set to nullptr. This works because:
//
// currentPtr == &queueHead
// previous == nullptr
//
// We remove by setting *currentPtr = (*currentPtr)->nextInQueue, i.e. changing the pointer
// that used to point to this node to instead point to this node's successor. Another example:
// if we were at the second node in the queue, then we'd have:
//
// currentPtr == &queueHead->nextInQueue
// previous == queueHead
//
// If this node is not equal to queueTail, then removing it simply means making
// queueHead->nextInQueue point to queueHead->nextInQueue->nextInQueue (which the algorithm
// achieves by mutating *currentPtr). If this node is equal to queueTail, then we want to set
// queueTail to previous, which in this case is queueHead - thus making the queue look like a
// proper one-element queue with queueHead == queueTail.
bool shouldContinue = true;
ThreadData** currentPtr = &queueHead;
ThreadData* previous = nullptr;
WTF::Lock should be fair eventually https://bugs.webkit.org/show_bug.cgi?id=159384 Reviewed by Geoffrey Garen. Source/WTF: In https://webkit.org/blog/6161/locking-in-webkit/ we showed how relaxing the fairness of locks makes them fast. That post presented lock fairness as a trade-off between two extremes: - Barging. A barging lock, like WTF::Lock, releases the lock in unlock() even if there was a thread on the queue. If there was a thread on the queue, the lock is released and that thread is made runnable. That thread may then grab the lock, or some other thread may grab the lock first (it may barge). Usually, the barging thread is the thread that released the lock in the first place. This maximizes throughput but hurts fairness. There is no good theoretical bound on how unfair the lock may become, but empirical data suggests that it's fair enough for the cases we previously measured. - FIFO. A FIFO lock, like HandoffLock in ToyLocks.h, does not release the lock in unlock() if there is a thread waiting. If there is a thread waiting, unlock() will make that thread runnable and inform it that it now holds the lock. This ensures perfect round-robin fairness and allows us to reason theoretically about how long it may take for a thread to grab the lock. For example, if we know that only N threads are running and each one may contend on a critical section, and each one may hold the lock for at most S seconds, then the time it takes to grab the lock is N * S. Unfortunately, FIFO locks perform very badly in most cases. This is because for the common case of short critical sections, they force a context switch after each critical section if the lock is contended. This change makes WTF::Lock almost as fair as FIFO while still being as fast as barging. Thanks to this new algorithm, you can now have both of these things at the same time. This change makes WTF::Lock eventually fair. We can almost (more on the caveats below) guarantee that the time it takes to grab a lock is N * max(1ms, S). In other words, critical sections that are longer than 1ms are always fair. For shorter critical sections, the amount of time that any thread waits is 1ms times the number of threads. There are some caveats that arise from our use of randomness, but even then, in the limit as the critical section length goes to infinity, the lock becomes fair. The corner cases are unlikely to happen; our experiments show that the lock becomes exactly as fair as a FIFO lock for any critical section that is 1ms or longer. The fairness mechanism is broken into two parts. WTF::Lock can now choose to unlock a lock fairly or unfairly thanks to the new ParkingLot token mechanism. WTF::Lock knows when to use fair unlocking based on a timeout mechanism in ParkingLot called timeToBeFair. ParkingLot::unparkOne() and ParkingLot::parkConditionally() can now communicate with each other via a token. unparkOne() can pass a token, which parkConditionally() will return. This change also makes parkConditionally() a lot more precise about when it was unparked due to a call to unparkOne(). If unparkOne() is told that a thread was unparked then this thread is guaranteed to report that it was unparked rather than timing out, and that thread is guaranteed to get the token that unparkOne() passed. The token is an intptr_t. We use it as a boolean variable in WTF::Lock, but you could use it to pass arbitrary data structures. By default, the token is zero. WTF::Lock's unlock() will pass 1 as the token if it is doing fair unlocking. In that case, unlock() will not release the lock, and lock() will know that it holds the lock as soon as parkConditionally() returns. Note that this algorithm relies on unparkOne() invoking WTF::Lock's callback while the queue lock is held, so that WTF::Lock can make a decision about unlock strategy and inject a token while it has complete knowledge over the state of the queue. As such, it's not immediately obvious how to implement this algorithm on top of futexes. You really need ParkingLot! WTF::Lock does not use fair unlocking every time. We expose a new API, Lock::unlockFairly(), which forces the fair unlocking behavior. Additionally, ParkingLot now maintains a per-bucket stochastic fairness timeout. When the timeout fires, the unparkOne() callback sees UnparkResult::timeToBeFair = true. This timeout is set to be anywhere from 0ms to 1ms at random. When a dequeue happens and there are threads that actually get dequeued, we check if the time since the last unfair unlock (the last time timeToBeFair was set to true) is more than the timeout amount. If so, then we set timeToBeFair to true and reset the timeout. This means that in the absence of ParkingLot collisions, unfair unlocking is guaranteed to happen at least once per millisecond. It will happen at 2 KHz on average. If there are collisions, then each collision adds one millisecond to the worst case (and 0.5 ms to the average case). The reason why we don't just use a fixed 1ms timeout is that we want to avoid resonance. Imagine a program in which some thread acquires a lock at 1 KHz in-phase with the timeToBeFair timeout. Then this thread would be the benefactor of fairness to the detriment of everyone else. Randomness ensures that we aren't too fair to any one thread. Empirically, this is neutral on our major benchmarks like JetStream but it's an enormous improvement in LockFairnessTest. It's common for an unfair lock (either our BargingLock, the old WTF::Lock, any of the other futex-based locks that barge, or new os_unfair_lock) to allow only one thread to hold the lock during a whole second in which each thread is holding the lock for 1ms at a time. This is because in a barging lock, releasing a lock after holding it for 1ms and then reacquiring it immediately virtually ensures that none of the other threads can wake up in time to grab it before it's relocked. But the new WTF::Lock handles this case like a champ: each thread gets equal turns. Here's some data. If we launch 10 threads and have each of them run for 1 second while repeatedly holding a critical section for 1ms, then here's how many times each thread gets to hold the lock using the old WTF::Lock algorithm: 799, 6, 1, 1, 1, 1, 1, 1, 1, 1 One thread hogged the lock for almost the whole time! With the new WTF::Lock, the lock becomes totally fair: 80, 79, 79, 79, 79, 79, 79, 80, 80, 79 I don't know of anyone creating such an automatically-fair adaptive lock before, so I think that this is a pretty awesome advancement to the state of the art! This change is good for three reasons: - We do have long critical sections in WebKit and we don't want to have to worry about starvation. This reduces the likelihood that we will see starvation due to our lock strategy. - I was talking to ggaren about bmalloc's locking needs, and he wanted unlockFairly() or lockFairly() or some moral equivalent for the scavenger thread. - If we use a WTF::Lock to manage heap access in a multithreaded GC, we'll need the ability to unlock and relock without barging. * benchmarks/LockFairnessTest.cpp: (main): * benchmarks/ToyLocks.h: * wtf/Condition.h: (WTF::ConditionBase::waitUntil): (WTF::ConditionBase::notifyOne): * wtf/Lock.cpp: (WTF::LockBase::lockSlow): (WTF::LockBase::unlockSlow): (WTF::LockBase::unlockFairlySlow): (WTF::LockBase::unlockSlowImpl): * wtf/Lock.h: (WTF::LockBase::try_lock): (WTF::LockBase::unlock): (WTF::LockBase::unlockFairly): (WTF::LockBase::isHeld): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::compareAndPark): (WTF::ParkingLot::unparkOne): Tools: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Canonical link: https://commits.webkit.org/178039@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@203350 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-07-18 18:32:52 +00:00
Remove monotonicallyIncreasingTime https://bugs.webkit.org/show_bug.cgi?id=182911 Reviewed by Michael Catanzaro. Source/JavaScriptCore: * debugger/Debugger.cpp: (JSC::Debugger::willEvaluateScript): (JSC::Debugger::didEvaluateScript): * debugger/Debugger.h: * debugger/ScriptProfilingScope.h: * inspector/agents/InspectorDebuggerAgent.cpp: (Inspector::InspectorDebuggerAgent::breakpointActionProbe): * inspector/agents/InspectorHeapAgent.cpp: (Inspector::InspectorHeapAgent::snapshot): (Inspector::InspectorHeapAgent::didGarbageCollect): (Inspector::InspectorHeapAgent::dispatchGarbageCollectedEvent): * inspector/agents/InspectorHeapAgent.h: * inspector/agents/InspectorScriptProfilerAgent.cpp: (Inspector::InspectorScriptProfilerAgent::startTracking): (Inspector::InspectorScriptProfilerAgent::willEvaluateScript): (Inspector::InspectorScriptProfilerAgent::didEvaluateScript): (Inspector::InspectorScriptProfilerAgent::addEvent): (Inspector::buildSamples): * inspector/agents/InspectorScriptProfilerAgent.h: * runtime/SamplingProfiler.cpp: (JSC::SamplingProfiler::takeSample): * runtime/SamplingProfiler.h: Source/WebCore: While generic code uses MonotonicTime, CAAnimation uses media time (CFTimeInterval). At this boundary, we convert MonotonicTime to media time, this is the same logic to the code before this patch. * Modules/gamepad/Gamepad.h: * Modules/mediasource/SourceBuffer.cpp: (WebCore::SourceBuffer::SourceBuffer): (WebCore::SourceBuffer::monitorBufferingRate): * Modules/mediasource/SourceBuffer.h: * Modules/speech/SpeechSynthesis.cpp: (WebCore::SpeechSynthesis::startSpeakingImmediately): (WebCore::SpeechSynthesis::fireEvent): * Modules/speech/SpeechSynthesisUtterance.h: * contentextensions/ContentExtensionCompiler.cpp: (WebCore::ContentExtensions::compileRuleList): * contentextensions/ContentExtensionParser.cpp: (WebCore::ContentExtensions::parseRuleList): * contentextensions/ContentExtensionsBackend.cpp: (WebCore::ContentExtensions::ContentExtensionsBackend::actionsForResourceLoad const): * dom/Element.cpp: (WebCore::Element::setActive): * history/CachedPage.cpp: (WebCore::CachedPage::CachedPage): (WebCore::CachedPage::hasExpired const): * history/CachedPage.h: * html/HTMLMediaElement.cpp: (WebCore::HTMLMediaElement::startProgressEventTimer): (WebCore::HTMLMediaElement::progressEventTimerFired): (WebCore::HTMLMediaElement::refreshCachedTime const): (WebCore::HTMLMediaElement::invalidateCachedTime const): (WebCore::HTMLMediaElement::currentMediaTime const): (WebCore::HTMLMediaElement::startPlaybackProgressTimer): * html/HTMLMediaElement.h: * html/MediaElementSession.cpp: (WebCore::MediaElementSession::removeBehaviorRestriction): (WebCore::MediaElementSession::mostRecentUserInteractionTime const): (WebCore::MediaElementSession::resetPlaybackSessionState): * html/MediaElementSession.h: * html/parser/HTMLParserScheduler.cpp: (WebCore::PumpSession::PumpSession): (WebCore::HTMLParserScheduler::HTMLParserScheduler): * html/parser/HTMLParserScheduler.h: (WebCore::HTMLParserScheduler::checkForYield): * inspector/InspectorCanvas.cpp: (WebCore::InspectorCanvas::recordAction): (WebCore::InspectorCanvas::finalizeFrame): * inspector/InspectorCanvas.h: * inspector/agents/InspectorMemoryAgent.cpp: (WebCore::InspectorMemoryAgent::startTracking): (WebCore::InspectorMemoryAgent::didHandleMemoryPressure): (WebCore::InspectorMemoryAgent::collectSample): * inspector/agents/InspectorNetworkAgent.cpp: (WebCore::InspectorNetworkAgent::buildObjectForTiming): (WebCore::InspectorNetworkAgent::timestamp): (WebCore::InspectorNetworkAgent::didFinishLoading): * inspector/agents/InspectorPageAgent.cpp: (WebCore::InspectorPageAgent::timestamp): * inspector/agents/InspectorTimelineAgent.cpp: (WebCore::InspectorTimelineAgent::timestamp): * inspector/agents/WebHeapAgent.cpp: (WebCore::WebHeapAgent::dispatchGarbageCollectedEvent): * inspector/agents/WebHeapAgent.h: * loader/cache/CachedCSSStyleSheet.cpp: (WebCore::CachedCSSStyleSheet::restoreParsedStyleSheet): * loader/cache/CachedImage.cpp: (WebCore::CachedImage::didDraw): * loader/cache/CachedResource.cpp: (WebCore::CachedResource::didAccessDecodedData): * loader/cache/CachedResource.h: * loader/cache/MemoryCache.cpp: (WebCore::MemoryCache::pruneLiveResourcesToSize): * page/EventHandler.cpp: (WebCore::MaximumDurationTracker::MaximumDurationTracker): (WebCore::MaximumDurationTracker::~MaximumDurationTracker): * page/FocusController.cpp: (WebCore::FocusController::setFocusedElement): (WebCore::FocusController::timeSinceFocusWasSet const): * page/FocusController.h: * page/FrameView.cpp: (WebCore::FrameView::reset): (WebCore::FrameView::willPaintContents): (WebCore::FrameView::didPaintContents): * page/FrameView.h: * page/animation/AnimationBase.cpp: (WebCore::AnimationBase::freezeAtTime): (WebCore::AnimationBase::beginAnimationUpdateTime const): * page/animation/AnimationBase.h: (WebCore::AnimationBase::onAnimationStartResponse): * page/animation/CSSAnimationController.cpp: (WebCore::CSSAnimationControllerPrivate::beginAnimationUpdateTime): (WebCore::CSSAnimationControllerPrivate::receivedStartTimeResponse): (WebCore::CSSAnimationControllerPrivate::startTimeResponse): (WebCore::CSSAnimationController::notifyAnimationStarted): * page/animation/CSSAnimationController.h: * page/animation/CSSAnimationControllerPrivate.h: * page/mac/WheelEventDeltaFilterMac.h: * page/mac/WheelEventDeltaFilterMac.mm: (WebCore::WheelEventDeltaFilterMac::beginFilteringDeltas): (WebCore::WheelEventDeltaFilterMac::updateFromDelta): (WebCore::WheelEventDeltaFilterMac::endFilteringDeltas): * platform/ControlStates.h: (WebCore::ControlStates::timeSinceControlWasFocused const): (WebCore::ControlStates::setTimeSinceControlWasFocused): * platform/PlatformSpeechSynthesisUtterance.h: (WebCore::PlatformSpeechSynthesisUtterance::startTime const): (WebCore::PlatformSpeechSynthesisUtterance::setStartTime): * platform/gamepad/PlatformGamepad.h: (WebCore::PlatformGamepad::lastUpdateTime const): (WebCore::PlatformGamepad::connectTime const): (WebCore::PlatformGamepad::PlatformGamepad): * platform/gamepad/cocoa/GameControllerGamepad.mm: (WebCore::GameControllerGamepad::setupAsExtendedGamepad): (WebCore::GameControllerGamepad::setupAsGamepad): * platform/gamepad/mac/HIDGamepad.cpp: (WebCore::HIDGamepad::HIDGamepad): (WebCore::HIDGamepad::valueChanged): * platform/graphics/GraphicsLayer.cpp: (WebCore::GraphicsLayer::suspendAnimations): * platform/graphics/GraphicsLayer.h: * platform/graphics/GraphicsLayerClient.h: (WebCore::GraphicsLayerClient::notifyAnimationStarted): * platform/graphics/avfoundation/cf/MediaPlayerPrivateAVFoundationCF.cpp: (WebCore::LayerClient::platformCALayerAnimationStarted): (WebCore::AVFWrapper::createImageForTimeInRect): * platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm: (WebCore::MediaPlayerPrivateAVFoundationObjC::createImageForTimeInRect): (WebCore::MediaPlayerPrivateAVFoundationObjC::updateLastImage): * platform/graphics/ca/GraphicsLayerCA.cpp: (WebCore::GraphicsLayerCA::addAnimation): (WebCore::GraphicsLayerCA::pauseAnimation): (WebCore::GraphicsLayerCA::platformCALayerAnimationStarted): (WebCore::GraphicsLayerCA::setAnimationOnLayer): (WebCore::GraphicsLayerCA::pauseCAAnimationOnLayer): (WebCore::GraphicsLayerCA::createAnimationFromKeyframes): (WebCore::GraphicsLayerCA::appendToUncommittedAnimations): (WebCore::GraphicsLayerCA::createTransformAnimationsFromKeyframes): * platform/graphics/ca/GraphicsLayerCA.h: (WebCore::GraphicsLayerCA::LayerPropertyAnimation::LayerPropertyAnimation): (WebCore::GraphicsLayerCA::AnimationProcessingAction::AnimationProcessingAction): * platform/graphics/ca/LayerPool.cpp: (WebCore::LayerPool::LayerPool): (WebCore::LayerPool::addLayer): (WebCore::LayerPool::decayedCapacity const): (WebCore::LayerPool::pruneTimerFired): * platform/graphics/ca/LayerPool.h: * platform/graphics/ca/PlatformCAAnimation.h: * platform/graphics/ca/PlatformCALayer.h: * platform/graphics/ca/PlatformCALayerClient.h: (WebCore::PlatformCALayerClient::platformCALayerAnimationStarted): * platform/graphics/ca/TileGrid.cpp: (WebCore::TileGrid::revalidateTiles): (WebCore::TileGrid::startedNewCohort): (WebCore::TileGrid::TileCohortInfo::timeUntilExpiration): (WebCore::TileGrid::cohortRemovalTimerFired): * platform/graphics/ca/TileGrid.h: (WebCore::TileGrid::TileCohortInfo::TileCohortInfo): * platform/graphics/ca/cocoa/PlatformCALayerCocoa.h: * platform/graphics/ca/cocoa/PlatformCALayerCocoa.mm: (mediaTimeToCurrentTime): (-[WebAnimationDelegate animationDidStart:]): (PlatformCALayerCocoa::animationStarted): * platform/graphics/ca/win/CACFLayerTreeHost.cpp: (WebCore::CACFLayerTreeHost::notifyAnimationsStarted): * platform/graphics/ca/win/PlatformCALayerWin.cpp: (PlatformCALayerWin::animationStarted): (PlatformCALayerWin::layerTreeAsString const): * platform/graphics/ca/win/PlatformCALayerWin.h: * platform/graphics/cocoa/WebCoreDecompressionSession.mm: (WebCore::WebCoreDecompressionSession::decodeSample): * platform/graphics/texmap/BitmapTexturePool.cpp: (WebCore::BitmapTexturePool::releaseUnusedTexturesTimerFired): * platform/graphics/texmap/BitmapTexturePool.h: (WebCore::BitmapTexturePool::Entry::markIsInUse): (WebCore::BitmapTexturePool::Entry::canBeReleased const): (): Deleted. * platform/graphics/texmap/GraphicsLayerTextureMapper.cpp: (WebCore::GraphicsLayerTextureMapper::GraphicsLayerTextureMapper): (WebCore::GraphicsLayerTextureMapper::addAnimation): (WebCore::GraphicsLayerTextureMapper::pauseAnimation): * platform/graphics/texmap/GraphicsLayerTextureMapper.h: * platform/graphics/texmap/TextureMapperAnimation.cpp: (WebCore::TextureMapperAnimation::TextureMapperAnimation): (WebCore::TextureMapperAnimation::apply): (WebCore::TextureMapperAnimation::pause): (WebCore::TextureMapperAnimation::resume): (WebCore::TextureMapperAnimation::computeTotalRunningTime): (WebCore::TextureMapperAnimations::pause): (WebCore::TextureMapperAnimations::suspend): * platform/graphics/texmap/TextureMapperAnimation.h: (WebCore::TextureMapperAnimation::startTime const): (WebCore::TextureMapperAnimation::pauseTime const): * platform/graphics/texmap/TextureMapperFPSCounter.cpp: (WebCore::TextureMapperFPSCounter::TextureMapperFPSCounter): (WebCore::TextureMapperFPSCounter::updateFPSAndDisplay): * platform/graphics/texmap/TextureMapperFPSCounter.h: * platform/graphics/texmap/TextureMapperPlatformLayerBuffer.h: (WebCore::TextureMapperPlatformLayerBuffer::markUsed): (WebCore::TextureMapperPlatformLayerBuffer::lastUsedTime const): (): Deleted. * platform/graphics/texmap/TextureMapperPlatformLayerProxy.cpp: (WebCore::TextureMapperPlatformLayerProxy::releaseUnusedBuffersTimerFired): * platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.cpp: (WebCore::CoordinatedGraphicsLayer::addAnimation): (WebCore::CoordinatedGraphicsLayer::pauseAnimation): (WebCore::CoordinatedGraphicsLayer::suspendAnimations): * platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.h: * platform/mediastream/RealtimeMediaSource.h: * platform/mediastream/RealtimeOutgoingVideoSource.cpp: (WebCore::RealtimeOutgoingVideoSource::sendFrame): * platform/mediastream/libwebrtc/LibWebRTCAudioModule.cpp: (WebCore::LibWebRTCAudioModule::StartPlayoutOnAudioThread): * platform/mediastream/mac/DisplayCaptureSourceCocoa.cpp: (WebCore::DisplayCaptureSourceCocoa::startProducingData): (WebCore::DisplayCaptureSourceCocoa::stopProducingData): (WebCore::DisplayCaptureSourceCocoa::elapsedTime): * platform/mediastream/mac/DisplayCaptureSourceCocoa.h: * platform/mediastream/mac/MockRealtimeAudioSourceMac.h: * platform/mediastream/mac/MockRealtimeAudioSourceMac.mm: (WebCore::MockRealtimeAudioSourceMac::render): * platform/mediastream/mac/MockRealtimeVideoSourceMac.mm: (WebCore::MockRealtimeVideoSourceMac::CMSampleBufferFromPixelBuffer): * platform/mediastream/mac/ScreenDisplayCaptureSourceMac.h: * platform/mediastream/mac/ScreenDisplayCaptureSourceMac.mm: (WebCore::ScreenDisplayCaptureSourceMac::sampleBufferFromPixelBuffer): (WebCore::ScreenDisplayCaptureSourceMac::frameAvailable): * platform/mock/MockRealtimeAudioSource.cpp: (WebCore::MockRealtimeAudioSource::startProducingData): (WebCore::MockRealtimeAudioSource::stopProducingData): (WebCore::MockRealtimeAudioSource::elapsedTime): (WebCore::MockRealtimeAudioSource::tick): (WebCore::MockRealtimeAudioSource::delaySamples): * platform/mock/MockRealtimeAudioSource.h: (WebCore::MockRealtimeAudioSource::render): * platform/mock/MockRealtimeVideoSource.cpp: (WebCore::MockRealtimeVideoSource::startProducingData): (WebCore::MockRealtimeVideoSource::stopProducingData): (WebCore::MockRealtimeVideoSource::elapsedTime): (WebCore::MockRealtimeVideoSource::drawText): (WebCore::MockRealtimeVideoSource::delaySamples): (WebCore::MockRealtimeVideoSource::generateFrame): * platform/mock/MockRealtimeVideoSource.h: * platform/network/DNSResolveQueue.cpp: (WebCore::DNSResolveQueue::DNSResolveQueue): (WebCore::DNSResolveQueue::isUsingProxy): * platform/network/DNSResolveQueue.h: * rendering/RenderBoxModelObject.cpp: (WebCore::RenderBoxModelObject::suspendAnimations): * rendering/RenderBoxModelObject.h: * rendering/RenderElement.cpp: (WebCore::RenderElement::paintFocusRing): * rendering/RenderImage.cpp: (WebCore::RenderImage::paintAreaElementFocusRing): * rendering/RenderLayerBacking.cpp: (WebCore::RenderLayerBacking::notifyAnimationStarted): (WebCore::RenderLayerBacking::suspendAnimations): * rendering/RenderLayerBacking.h: * rendering/RenderLayerCompositor.cpp: (WebCore::RenderLayerCompositor::didPaintBacking): * rendering/RenderProgress.cpp: (WebCore::RenderProgress::RenderProgress): (WebCore::RenderProgress::animationProgress const): (WebCore::RenderProgress::updateAnimationState): * rendering/RenderProgress.h: * rendering/RenderTheme.cpp: (WebCore::RenderTheme::animationDurationForProgressBar const): * rendering/RenderTheme.h: * rendering/RenderThemeGtk.cpp: (WebCore::RenderThemeGtk::animationDurationForProgressBar const): * rendering/RenderThemeGtk.h: * rendering/RenderThemeIOS.h: * rendering/RenderThemeIOS.mm: (WebCore::RenderThemeIOS::animationDurationForProgressBar const): * rendering/RenderThemeMac.h: * rendering/RenderThemeMac.mm: (WebCore::RenderThemeMac::animationDurationForProgressBar const): * svg/animation/SMILTimeContainer.cpp: (WebCore::SMILTimeContainer::SMILTimeContainer): (WebCore::SMILTimeContainer::elapsed const): (WebCore::SMILTimeContainer::isActive const): (WebCore::SMILTimeContainer::isPaused const): (WebCore::SMILTimeContainer::isStarted const): (WebCore::SMILTimeContainer::begin): (WebCore::SMILTimeContainer::pause): (WebCore::SMILTimeContainer::resume): (WebCore::SMILTimeContainer::setElapsed): (WebCore::SMILTimeContainer::timerFired): * svg/animation/SMILTimeContainer.h: * testing/Internals.cpp: (WebCore::Internals::delayMediaStreamTrackSamples): * testing/MockGamepad.cpp: (WebCore::MockGamepad::MockGamepad): (WebCore::MockGamepad::updateDetails): (WebCore::MockGamepad::setAxisValue): (WebCore::MockGamepad::setButtonValue): Source/WebCore/PAL: * pal/system/ClockGeneric.cpp: (PAL::ClockGeneric::currentTime const): (PAL::ClockGeneric::now const): * pal/system/ClockGeneric.h: Source/WebKit: * NetworkProcess/cache/CacheStorageEngineCache.cpp: (WebKit::CacheStorage::Cache::toRecordInformation): * Platform/IPC/ArgumentCoders.cpp: (IPC::ArgumentCoder<Seconds>::encode): (IPC::ArgumentCoder<Seconds>::decode): (IPC::ArgumentCoder<MonotonicTime>::encode): (IPC::ArgumentCoder<MonotonicTime>::decode): * Platform/IPC/ArgumentCoders.h: * Shared/Gamepad/GamepadData.cpp: (WebKit::GamepadData::GamepadData): * Shared/Gamepad/GamepadData.h: (WebKit::GamepadData::lastUpdateTime const): * Shared/WebCoreArgumentCoders.cpp: (IPC::ArgumentCoder<MonotonicTime>::encode): Deleted. (IPC::ArgumentCoder<MonotonicTime>::decode): Deleted. (IPC::ArgumentCoder<Seconds>::encode): Deleted. (IPC::ArgumentCoder<Seconds>::decode): Deleted. ArgumentCoders for MonotonicTime and Seconds are now used internally. Move them to Platform/IPC/ArgumentCoders.h. * Shared/WebCoreArgumentCoders.h: * UIProcess/API/glib/IconDatabase.cpp: (WebKit::IconDatabase::iconDatabaseSyncThread): * UIProcess/DrawingAreaProxyImpl.cpp: (WebKit::DrawingAreaProxyImpl::DrawingMonitor::start): (WebKit::DrawingAreaProxyImpl::DrawingMonitor::stop): (WebKit::DrawingAreaProxyImpl::DrawingMonitor::didDraw): * UIProcess/DrawingAreaProxyImpl.h: * UIProcess/Gamepad/UIGamepad.h: * UIProcess/RemoteLayerTree/RemoteLayerTreeDrawingAreaProxy.h: * UIProcess/RemoteLayerTree/RemoteLayerTreeDrawingAreaProxy.mm: (WebKit::RemoteLayerTreeDrawingAreaProxy::acceleratedAnimationDidStart): * UIProcess/RemoteLayerTree/RemoteLayerTreeHost.h: * UIProcess/RemoteLayerTree/RemoteLayerTreeHost.mm: (WebKit::RemoteLayerTreeHost::animationDidStart): * WebProcess/WebPage/DrawingArea.h: (WebKit::DrawingArea::acceleratedAnimationDidStart): * WebProcess/WebPage/DrawingArea.messages.in: * WebProcess/WebPage/RemoteLayerTree/PlatformCAAnimationRemote.h: * WebProcess/WebPage/RemoteLayerTree/PlatformCAAnimationRemote.mm: (mediaTimeToCurrentTime): (-[WKAnimationDelegate animationDidStart:]): * WebProcess/WebPage/RemoteLayerTree/PlatformCALayerRemote.cpp: (WebKit::PlatformCALayerRemote::animationStarted): This argument `beginTime` is not CFTimeInverval actually. We add currentTimeToMediaTime conversion here to fix this issue. * WebProcess/WebPage/RemoteLayerTree/PlatformCALayerRemote.h: * WebProcess/WebPage/RemoteLayerTree/RemoteLayerTreeContext.h: * WebProcess/WebPage/RemoteLayerTree/RemoteLayerTreeContext.mm: (WebKit::RemoteLayerTreeContext::animationDidStart): * WebProcess/WebPage/RemoteLayerTree/RemoteLayerTreeDrawingArea.h: * WebProcess/WebPage/RemoteLayerTree/RemoteLayerTreeDrawingArea.mm: (WebKit::RemoteLayerTreeDrawingArea::acceleratedAnimationDidStart): * WebProcess/cocoa/WebProcessCocoa.mm: (WebKit::WebProcess::destroyRenderingResources): Source/WebKitLegacy/win: * FullscreenVideoController.cpp: (FullscreenVideoController::LayerClient::platformCALayerAnimationStarted): * Plugins/PluginMessageThrottlerWin.cpp: (WebCore::PluginMessageThrottlerWin::PluginMessageThrottlerWin): (WebCore::PluginMessageThrottlerWin::appendMessage): * Plugins/PluginMessageThrottlerWin.h: * WebView.cpp: (WebView::notifyAnimationStarted): * WebView.h: Source/WTF: This patch drops monotonicallyIncreasingTime and monotonicallyIncreasingTimeMS. We have MonotonicTime API instead. This offers strongly typed MonotonicTime, Seconds etc. This reduces the chance of bugs mixing doubles which represent milliseconds and seconds. Large part of this patch is mechanical one: replacing monotonicallyIncreasingTime with MonotonicTime, using MonotonicTime and Seconds instead of raw doubles. But this patch actually finds some bugs (but it is a bit difficult to show it as a test). One is mixing media time (CACurrentMediaTime()) and MonotonicTime. Basically they are super close because both uses mach_absolute_time(). But they would be slightly different. So we should not mix them. The second bug is GraphicsLayer::suspendAnimations(double). While CA ports (Apple, AppleWin, iOS etc.) use this double as MonotonicTime, GTK and WPE use this double as Seconds (timeOffset). This patch fixes it and now the signature becomes GraphicsLayer::suspendAnimations(MonotonicTime). In this patch, we still uses bunch of double for Seconds. But fixing them at this patch increases the size of this larger and larger. So some of them remains double. This should be fixed in subsequent patches. * benchmarks/ConditionSpeedTest.cpp: * benchmarks/LockSpeedTest.cpp: * wtf/CurrentTime.cpp: (WTF::MonotonicTime::now): (WTF::monotonicallyIncreasingTime): Deleted. * wtf/CurrentTime.h: (WTF::monotonicallyIncreasingTimeMS): Deleted. * wtf/MemoryPressureHandler.h: * wtf/MonotonicTime.cpp: (WTF::MonotonicTime::now): Deleted. * wtf/MonotonicTime.h: * wtf/ParkingLot.cpp: * wtf/Seconds.h: (WTF::Seconds::nan): * wtf/Stopwatch.h: (WTF::Stopwatch::reset): (WTF::Stopwatch::start): (WTF::Stopwatch::stop): (WTF::Stopwatch::elapsedTime): (WTF::Stopwatch::elapsedTimeSince): * wtf/cocoa/MemoryPressureHandlerCocoa.mm: (WTF::MemoryPressureHandler::holdOff): (WTF::MemoryPressureHandler::respondToMemoryPressure): * wtf/linux/MemoryPressureHandlerLinux.cpp: (WTF::MemoryPressureHandler::EventFDPoller::EventFDPoller): (WTF::MemoryPressureHandler::holdOff): (WTF::MemoryPressureHandler::respondToMemoryPressure): * wtf/win/MemoryPressureHandlerWin.cpp: (WTF::MemoryPressureHandler::holdOff): Canonical link: https://commits.webkit.org/198957@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@229174 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2018-03-02 17:13:32 +00:00
MonotonicTime time = MonotonicTime::now();
WTF::Lock should be fair eventually https://bugs.webkit.org/show_bug.cgi?id=159384 Reviewed by Geoffrey Garen. Source/WTF: In https://webkit.org/blog/6161/locking-in-webkit/ we showed how relaxing the fairness of locks makes them fast. That post presented lock fairness as a trade-off between two extremes: - Barging. A barging lock, like WTF::Lock, releases the lock in unlock() even if there was a thread on the queue. If there was a thread on the queue, the lock is released and that thread is made runnable. That thread may then grab the lock, or some other thread may grab the lock first (it may barge). Usually, the barging thread is the thread that released the lock in the first place. This maximizes throughput but hurts fairness. There is no good theoretical bound on how unfair the lock may become, but empirical data suggests that it's fair enough for the cases we previously measured. - FIFO. A FIFO lock, like HandoffLock in ToyLocks.h, does not release the lock in unlock() if there is a thread waiting. If there is a thread waiting, unlock() will make that thread runnable and inform it that it now holds the lock. This ensures perfect round-robin fairness and allows us to reason theoretically about how long it may take for a thread to grab the lock. For example, if we know that only N threads are running and each one may contend on a critical section, and each one may hold the lock for at most S seconds, then the time it takes to grab the lock is N * S. Unfortunately, FIFO locks perform very badly in most cases. This is because for the common case of short critical sections, they force a context switch after each critical section if the lock is contended. This change makes WTF::Lock almost as fair as FIFO while still being as fast as barging. Thanks to this new algorithm, you can now have both of these things at the same time. This change makes WTF::Lock eventually fair. We can almost (more on the caveats below) guarantee that the time it takes to grab a lock is N * max(1ms, S). In other words, critical sections that are longer than 1ms are always fair. For shorter critical sections, the amount of time that any thread waits is 1ms times the number of threads. There are some caveats that arise from our use of randomness, but even then, in the limit as the critical section length goes to infinity, the lock becomes fair. The corner cases are unlikely to happen; our experiments show that the lock becomes exactly as fair as a FIFO lock for any critical section that is 1ms or longer. The fairness mechanism is broken into two parts. WTF::Lock can now choose to unlock a lock fairly or unfairly thanks to the new ParkingLot token mechanism. WTF::Lock knows when to use fair unlocking based on a timeout mechanism in ParkingLot called timeToBeFair. ParkingLot::unparkOne() and ParkingLot::parkConditionally() can now communicate with each other via a token. unparkOne() can pass a token, which parkConditionally() will return. This change also makes parkConditionally() a lot more precise about when it was unparked due to a call to unparkOne(). If unparkOne() is told that a thread was unparked then this thread is guaranteed to report that it was unparked rather than timing out, and that thread is guaranteed to get the token that unparkOne() passed. The token is an intptr_t. We use it as a boolean variable in WTF::Lock, but you could use it to pass arbitrary data structures. By default, the token is zero. WTF::Lock's unlock() will pass 1 as the token if it is doing fair unlocking. In that case, unlock() will not release the lock, and lock() will know that it holds the lock as soon as parkConditionally() returns. Note that this algorithm relies on unparkOne() invoking WTF::Lock's callback while the queue lock is held, so that WTF::Lock can make a decision about unlock strategy and inject a token while it has complete knowledge over the state of the queue. As such, it's not immediately obvious how to implement this algorithm on top of futexes. You really need ParkingLot! WTF::Lock does not use fair unlocking every time. We expose a new API, Lock::unlockFairly(), which forces the fair unlocking behavior. Additionally, ParkingLot now maintains a per-bucket stochastic fairness timeout. When the timeout fires, the unparkOne() callback sees UnparkResult::timeToBeFair = true. This timeout is set to be anywhere from 0ms to 1ms at random. When a dequeue happens and there are threads that actually get dequeued, we check if the time since the last unfair unlock (the last time timeToBeFair was set to true) is more than the timeout amount. If so, then we set timeToBeFair to true and reset the timeout. This means that in the absence of ParkingLot collisions, unfair unlocking is guaranteed to happen at least once per millisecond. It will happen at 2 KHz on average. If there are collisions, then each collision adds one millisecond to the worst case (and 0.5 ms to the average case). The reason why we don't just use a fixed 1ms timeout is that we want to avoid resonance. Imagine a program in which some thread acquires a lock at 1 KHz in-phase with the timeToBeFair timeout. Then this thread would be the benefactor of fairness to the detriment of everyone else. Randomness ensures that we aren't too fair to any one thread. Empirically, this is neutral on our major benchmarks like JetStream but it's an enormous improvement in LockFairnessTest. It's common for an unfair lock (either our BargingLock, the old WTF::Lock, any of the other futex-based locks that barge, or new os_unfair_lock) to allow only one thread to hold the lock during a whole second in which each thread is holding the lock for 1ms at a time. This is because in a barging lock, releasing a lock after holding it for 1ms and then reacquiring it immediately virtually ensures that none of the other threads can wake up in time to grab it before it's relocked. But the new WTF::Lock handles this case like a champ: each thread gets equal turns. Here's some data. If we launch 10 threads and have each of them run for 1 second while repeatedly holding a critical section for 1ms, then here's how many times each thread gets to hold the lock using the old WTF::Lock algorithm: 799, 6, 1, 1, 1, 1, 1, 1, 1, 1 One thread hogged the lock for almost the whole time! With the new WTF::Lock, the lock becomes totally fair: 80, 79, 79, 79, 79, 79, 79, 80, 80, 79 I don't know of anyone creating such an automatically-fair adaptive lock before, so I think that this is a pretty awesome advancement to the state of the art! This change is good for three reasons: - We do have long critical sections in WebKit and we don't want to have to worry about starvation. This reduces the likelihood that we will see starvation due to our lock strategy. - I was talking to ggaren about bmalloc's locking needs, and he wanted unlockFairly() or lockFairly() or some moral equivalent for the scavenger thread. - If we use a WTF::Lock to manage heap access in a multithreaded GC, we'll need the ability to unlock and relock without barging. * benchmarks/LockFairnessTest.cpp: (main): * benchmarks/ToyLocks.h: * wtf/Condition.h: (WTF::ConditionBase::waitUntil): (WTF::ConditionBase::notifyOne): * wtf/Lock.cpp: (WTF::LockBase::lockSlow): (WTF::LockBase::unlockSlow): (WTF::LockBase::unlockFairlySlow): (WTF::LockBase::unlockSlowImpl): * wtf/Lock.h: (WTF::LockBase::try_lock): (WTF::LockBase::unlock): (WTF::LockBase::unlockFairly): (WTF::LockBase::isHeld): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::compareAndPark): (WTF::ParkingLot::unparkOne): Tools: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Canonical link: https://commits.webkit.org/178039@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@203350 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-07-18 18:32:52 +00:00
bool timeToBeFair = false;
if (time > nextFairTime)
timeToBeFair = true;
bool didDequeue = false;
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
while (shouldContinue) {
ThreadData* current = *currentPtr;
if (verbose)
WTF shouldn't have both Thread and ThreadIdentifier https://bugs.webkit.org/show_bug.cgi?id=180308 Reviewed by Darin Adler. Source/JavaScriptCore: * heap/MachineStackMarker.cpp: (JSC::MachineThreads::tryCopyOtherThreadStacks): * llint/LLIntSlowPaths.cpp: (JSC::LLInt::llint_trace_operand): (JSC::LLInt::llint_trace_value): (JSC::LLInt::LLINT_SLOW_PATH_DECL): (JSC::LLInt::traceFunctionPrologue): * runtime/ExceptionScope.cpp: (JSC::ExceptionScope::unexpectedExceptionMessage): * runtime/JSLock.h: (JSC::JSLock::currentThreadIsHoldingLock): * runtime/VM.cpp: (JSC::VM::throwException): * runtime/VM.h: (JSC::VM::throwingThread const): (JSC::VM::clearException): * tools/HeapVerifier.cpp: (JSC::HeapVerifier::printVerificationHeader): Source/WebCore: No behavior change. * Modules/indexeddb/IDBActiveDOMObject.h: (WebCore::IDBActiveDOMObject::originThread const): (WebCore::IDBActiveDOMObject::performCallbackOnOriginThread): (WebCore::IDBActiveDOMObject::callFunctionOnOriginThread): (WebCore::IDBActiveDOMObject::originThreadID const): Deleted. * Modules/indexeddb/IDBCursor.cpp: (WebCore::IDBCursor::IDBCursor): (WebCore::IDBCursor::~IDBCursor): (WebCore::IDBCursor::sourcesDeleted const): (WebCore::IDBCursor::transaction const): (WebCore::IDBCursor::update): (WebCore::IDBCursor::advance): (WebCore::IDBCursor::continueFunction): (WebCore::IDBCursor::uncheckedIterateCursor): (WebCore::IDBCursor::deleteFunction): (WebCore::IDBCursor::setGetResult): * Modules/indexeddb/IDBDatabase.cpp: (WebCore::IDBDatabase::~IDBDatabase): (WebCore::IDBDatabase::hasPendingActivity const): (WebCore::IDBDatabase::name const): (WebCore::IDBDatabase::version const): (WebCore::IDBDatabase::objectStoreNames const): (WebCore::IDBDatabase::renameObjectStore): (WebCore::IDBDatabase::renameIndex): (WebCore::IDBDatabase::createObjectStore): (WebCore::IDBDatabase::transaction): (WebCore::IDBDatabase::deleteObjectStore): (WebCore::IDBDatabase::close): (WebCore::IDBDatabase::connectionToServerLost): (WebCore::IDBDatabase::maybeCloseInServer): (WebCore::IDBDatabase::activeDOMObjectName const): (WebCore::IDBDatabase::canSuspendForDocumentSuspension const): (WebCore::IDBDatabase::stop): (WebCore::IDBDatabase::startVersionChangeTransaction): (WebCore::IDBDatabase::didStartTransaction): (WebCore::IDBDatabase::willCommitTransaction): (WebCore::IDBDatabase::didCommitTransaction): (WebCore::IDBDatabase::willAbortTransaction): (WebCore::IDBDatabase::didAbortTransaction): (WebCore::IDBDatabase::didCommitOrAbortTransaction): (WebCore::IDBDatabase::fireVersionChangeEvent): (WebCore::IDBDatabase::dispatchEvent): (WebCore::IDBDatabase::didCreateIndexInfo): (WebCore::IDBDatabase::didDeleteIndexInfo): * Modules/indexeddb/IDBIndex.cpp: (WebCore::IDBIndex::IDBIndex): (WebCore::IDBIndex::~IDBIndex): (WebCore::IDBIndex::name const): (WebCore::IDBIndex::setName): (WebCore::IDBIndex::objectStore): (WebCore::IDBIndex::keyPath const): (WebCore::IDBIndex::unique const): (WebCore::IDBIndex::multiEntry const): (WebCore::IDBIndex::rollbackInfoForVersionChangeAbort): (WebCore::IDBIndex::openCursor): (WebCore::IDBIndex::openKeyCursor): (WebCore::IDBIndex::doCount): (WebCore::IDBIndex::doGet): (WebCore::IDBIndex::doGetKey): (WebCore::IDBIndex::getAll): (WebCore::IDBIndex::getAllKeys): (WebCore::IDBIndex::markAsDeleted): * Modules/indexeddb/IDBObjectStore.cpp: (WebCore::IDBObjectStore::IDBObjectStore): (WebCore::IDBObjectStore::~IDBObjectStore): (WebCore::IDBObjectStore::name const): (WebCore::IDBObjectStore::setName): (WebCore::IDBObjectStore::keyPath const): (WebCore::IDBObjectStore::indexNames const): (WebCore::IDBObjectStore::transaction): (WebCore::IDBObjectStore::autoIncrement const): (WebCore::IDBObjectStore::openCursor): (WebCore::IDBObjectStore::openKeyCursor): (WebCore::IDBObjectStore::get): (WebCore::IDBObjectStore::getKey): (WebCore::IDBObjectStore::putOrAdd): (WebCore::IDBObjectStore::doDelete): (WebCore::IDBObjectStore::clear): (WebCore::IDBObjectStore::createIndex): (WebCore::IDBObjectStore::index): (WebCore::IDBObjectStore::deleteIndex): (WebCore::IDBObjectStore::doCount): (WebCore::IDBObjectStore::getAll): (WebCore::IDBObjectStore::getAllKeys): (WebCore::IDBObjectStore::markAsDeleted): (WebCore::IDBObjectStore::rollbackForVersionChangeAbort): * Modules/indexeddb/IDBOpenDBRequest.cpp: (WebCore::IDBOpenDBRequest::~IDBOpenDBRequest): (WebCore::IDBOpenDBRequest::onError): (WebCore::IDBOpenDBRequest::versionChangeTransactionDidFinish): (WebCore::IDBOpenDBRequest::fireSuccessAfterVersionChangeCommit): (WebCore::IDBOpenDBRequest::fireErrorAfterVersionChangeCompletion): (WebCore::IDBOpenDBRequest::dispatchEvent): (WebCore::IDBOpenDBRequest::onSuccess): (WebCore::IDBOpenDBRequest::onUpgradeNeeded): (WebCore::IDBOpenDBRequest::onDeleteDatabaseSuccess): (WebCore::IDBOpenDBRequest::requestCompleted): (WebCore::IDBOpenDBRequest::requestBlocked): * Modules/indexeddb/IDBRequest.cpp: (WebCore::IDBRequest::~IDBRequest): (WebCore:: const): (WebCore::IDBRequest::setSource): (WebCore::IDBRequest::setVersionChangeTransaction): (WebCore::IDBRequest::transaction const): (WebCore::IDBRequest::sourceObjectStoreIdentifier const): (WebCore::IDBRequest::sourceIndexIdentifier const): (WebCore::IDBRequest::requestedObjectStoreRecordType const): (WebCore::IDBRequest::requestedIndexRecordType const): (WebCore::IDBRequest::eventTargetInterface const): (WebCore::IDBRequest::activeDOMObjectName const): (WebCore::IDBRequest::canSuspendForDocumentSuspension const): (WebCore::IDBRequest::hasPendingActivity const): (WebCore::IDBRequest::stop): (WebCore::IDBRequest::enqueueEvent): (WebCore::IDBRequest::dispatchEvent): (WebCore::IDBRequest::uncaughtExceptionInEventHandler): (WebCore::IDBRequest::setResult): (WebCore::IDBRequest::setResultToStructuredClone): (WebCore::IDBRequest::setResultToUndefined): (WebCore::IDBRequest::resultCursor): (WebCore::IDBRequest::willIterateCursor): (WebCore::IDBRequest::didOpenOrIterateCursor): (WebCore::IDBRequest::completeRequestAndDispatchEvent): (WebCore::IDBRequest::onError): (WebCore::IDBRequest::onSuccess): * Modules/indexeddb/IDBTransaction.cpp: (WebCore::IDBTransaction::IDBTransaction): (WebCore::IDBTransaction::~IDBTransaction): (WebCore::IDBTransaction::objectStoreNames const): (WebCore::IDBTransaction::db): (WebCore::IDBTransaction::error const): (WebCore::IDBTransaction::objectStore): (WebCore::IDBTransaction::abortDueToFailedRequest): (WebCore::IDBTransaction::transitionedToFinishing): (WebCore::IDBTransaction::abort): (WebCore::IDBTransaction::internalAbort): (WebCore::IDBTransaction::abortOnServerAndCancelRequests): (WebCore::IDBTransaction::activeDOMObjectName const): (WebCore::IDBTransaction::canSuspendForDocumentSuspension const): (WebCore::IDBTransaction::hasPendingActivity const): (WebCore::IDBTransaction::stop): (WebCore::IDBTransaction::isActive const): (WebCore::IDBTransaction::isFinishedOrFinishing const): (WebCore::IDBTransaction::addRequest): (WebCore::IDBTransaction::removeRequest): (WebCore::IDBTransaction::scheduleOperation): (WebCore::IDBTransaction::schedulePendingOperationTimer): (WebCore::IDBTransaction::pendingOperationTimerFired): (WebCore::IDBTransaction::operationCompletedOnServer): (WebCore::IDBTransaction::scheduleCompletedOperationTimer): (WebCore::IDBTransaction::completedOperationTimerFired): (WebCore::IDBTransaction::commit): (WebCore::IDBTransaction::commitOnServer): (WebCore::IDBTransaction::finishAbortOrCommit): (WebCore::IDBTransaction::didStart): (WebCore::IDBTransaction::notifyDidAbort): (WebCore::IDBTransaction::didAbort): (WebCore::IDBTransaction::didCommit): (WebCore::IDBTransaction::fireOnComplete): (WebCore::IDBTransaction::fireOnAbort): (WebCore::IDBTransaction::enqueueEvent): (WebCore::IDBTransaction::dispatchEvent): (WebCore::IDBTransaction::createObjectStore): (WebCore::IDBTransaction::createObjectStoreOnServer): (WebCore::IDBTransaction::didCreateObjectStoreOnServer): (WebCore::IDBTransaction::renameObjectStore): (WebCore::IDBTransaction::renameObjectStoreOnServer): (WebCore::IDBTransaction::didRenameObjectStoreOnServer): (WebCore::IDBTransaction::createIndex): (WebCore::IDBTransaction::createIndexOnServer): (WebCore::IDBTransaction::didCreateIndexOnServer): (WebCore::IDBTransaction::renameIndex): (WebCore::IDBTransaction::renameIndexOnServer): (WebCore::IDBTransaction::didRenameIndexOnServer): (WebCore::IDBTransaction::requestOpenCursor): (WebCore::IDBTransaction::doRequestOpenCursor): (WebCore::IDBTransaction::openCursorOnServer): (WebCore::IDBTransaction::didOpenCursorOnServer): (WebCore::IDBTransaction::iterateCursor): (WebCore::IDBTransaction::iterateCursorOnServer): (WebCore::IDBTransaction::didIterateCursorOnServer): (WebCore::IDBTransaction::requestGetAllObjectStoreRecords): (WebCore::IDBTransaction::requestGetAllIndexRecords): (WebCore::IDBTransaction::getAllRecordsOnServer): (WebCore::IDBTransaction::didGetAllRecordsOnServer): (WebCore::IDBTransaction::requestGetRecord): (WebCore::IDBTransaction::requestGetValue): (WebCore::IDBTransaction::requestGetKey): (WebCore::IDBTransaction::requestIndexRecord): (WebCore::IDBTransaction::getRecordOnServer): (WebCore::IDBTransaction::didGetRecordOnServer): (WebCore::IDBTransaction::requestCount): (WebCore::IDBTransaction::getCountOnServer): (WebCore::IDBTransaction::didGetCountOnServer): (WebCore::IDBTransaction::requestDeleteRecord): (WebCore::IDBTransaction::deleteRecordOnServer): (WebCore::IDBTransaction::didDeleteRecordOnServer): (WebCore::IDBTransaction::requestClearObjectStore): (WebCore::IDBTransaction::clearObjectStoreOnServer): (WebCore::IDBTransaction::didClearObjectStoreOnServer): (WebCore::IDBTransaction::requestPutOrAdd): (WebCore::IDBTransaction::putOrAddOnServer): (WebCore::IDBTransaction::didPutOrAddOnServer): (WebCore::IDBTransaction::deleteObjectStore): (WebCore::IDBTransaction::deleteObjectStoreOnServer): (WebCore::IDBTransaction::didDeleteObjectStoreOnServer): (WebCore::IDBTransaction::deleteIndex): (WebCore::IDBTransaction::deleteIndexOnServer): (WebCore::IDBTransaction::didDeleteIndexOnServer): (WebCore::IDBTransaction::operationCompletedOnClient): (WebCore::IDBTransaction::establishOnServer): (WebCore::IDBTransaction::activate): (WebCore::IDBTransaction::deactivate): * Modules/indexeddb/client/IDBConnectionProxy.cpp: (WebCore::IDBClient::removeItemsMatchingCurrentThread): * Modules/indexeddb/client/TransactionOperation.h: (WebCore::IDBClient::TransactionOperation::~TransactionOperation): (WebCore::IDBClient::TransactionOperation::perform): (WebCore::IDBClient::TransactionOperation::transitionToCompleteOnThisThread): (WebCore::IDBClient::TransactionOperation::transitionToComplete): (WebCore::IDBClient::TransactionOperation::doComplete): (WebCore::IDBClient::TransactionOperation::originThread const): (WebCore::IDBClient::TransactionOperation::originThreadID const): Deleted. * Modules/webaudio/AudioContext.cpp: (WebCore::AudioContext::AudioContext): (WebCore::AudioContext::lock): (WebCore::AudioContext::tryLock): (WebCore::AudioContext::unlock): (WebCore::AudioContext::isAudioThread const): (WebCore::AudioContext::isGraphOwner const): * Modules/webaudio/AudioContext.h: (WebCore::AudioContext::setAudioThread): (WebCore::AudioContext::audioThread const): * Modules/webaudio/AudioDestinationNode.cpp: (WebCore::AudioDestinationNode::render): * Modules/webdatabase/Database.cpp: (WebCore::Database::performClose): (WebCore::Database::securityOrigin): * Modules/webdatabase/DatabaseDetails.h: (WebCore::DatabaseDetails::DatabaseDetails): (WebCore::DatabaseDetails::operator=): (WebCore::DatabaseDetails::thread const): (WebCore::DatabaseDetails::threadID const): Deleted. * Modules/webdatabase/DatabaseManager.cpp: (WebCore::DatabaseManager::detailsForNameAndOrigin): * Modules/webdatabase/DatabaseThread.cpp: (WebCore::DatabaseThread::databaseThread): (WebCore::DatabaseThread::recordDatabaseOpen): (WebCore::DatabaseThread::recordDatabaseClosed): * Modules/webdatabase/DatabaseThread.h: (WebCore::DatabaseThread::getThread): (WebCore::DatabaseThread::getThreadID): Deleted. * Modules/webdatabase/SQLTransaction.cpp: (WebCore::SQLTransaction::checkAndHandleClosedDatabase): * Modules/webdatabase/SQLTransactionBackend.cpp: (WebCore::SQLTransactionBackend::doCleanup): (WebCore::SQLTransactionBackend::notifyDatabaseThreadIsShuttingDown): * bindings/js/JSCallbackData.h: (WebCore::JSCallbackData::JSCallbackData): (WebCore::JSCallbackData::~JSCallbackData): * bindings/js/ScheduledAction.cpp: (WebCore::ScheduledAction::execute): * dom/ScriptExecutionContext.cpp: (WebCore::ScriptExecutionContext::createdMessagePort): (WebCore::ScriptExecutionContext::destroyedMessagePort): * page/ResourceUsageOverlay.h: * page/scrolling/ScrollingThread.cpp: (WebCore::ScrollingThread::isCurrentThread): * platform/Supplementable.h: (WebCore::Supplementable::provideSupplement): (WebCore::Supplementable::removeSupplement): (WebCore::Supplementable::requireSupplement): (WebCore::Supplementable::Supplementable): Deleted. * platform/Timer.cpp: (WebCore::TimerBase::TimerBase): (WebCore::TimerBase::start): (WebCore::TimerBase::stop): (WebCore::TimerBase::setNextFireTime): * platform/Timer.h: (WebCore::TimerBase::isActive const): * platform/graphics/cocoa/FontCacheCoreText.cpp: (WebCore::shouldAutoActivateFontIfNeeded): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.cpp: (WebCore::TextureMapperPlatformLayerProxy::activateOnCompositingThread): (WebCore::TextureMapperPlatformLayerProxy::invalidate): (WebCore::TextureMapperPlatformLayerProxy::getAvailableBuffer): (WebCore::TextureMapperPlatformLayerProxy::appendToUnusedBuffers): (WebCore::TextureMapperPlatformLayerProxy::swapBuffer): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.h: (): Deleted. * platform/ios/wak/WebCoreThread.mm: (RunWebThread): (StartWebThread): * platform/sql/SQLiteDatabase.cpp: (WebCore::SQLiteDatabase::open): (WebCore::SQLiteDatabase::close): * platform/sql/SQLiteDatabase.h: (WebCore::SQLiteDatabase::sqlite3Handle const): * workers/WorkerGlobalScope.cpp: (WebCore::WorkerGlobalScope::~WorkerGlobalScope): (WebCore::WorkerGlobalScope::isContextThread const): * workers/WorkerMessagingProxy.cpp: (WebCore::WorkerMessagingProxy::WorkerMessagingProxy): (WebCore::WorkerMessagingProxy::~WorkerMessagingProxy): * workers/WorkerRunLoop.cpp: (WebCore::WorkerRunLoop::runInMode): (WebCore::WorkerRunLoop::runCleanupTasks): * workers/WorkerThread.h: (WebCore::WorkerThread::thread const): (WebCore::WorkerThread::threadID const): Deleted. * workers/service/ServiceWorkerContainer.cpp: (WebCore::ServiceWorkerContainer::~ServiceWorkerContainer): (WebCore::ServiceWorkerContainer::scheduleJob): (WebCore::ServiceWorkerContainer::jobFailedWithException): (WebCore::ServiceWorkerContainer::scheduleTaskToFireUpdateFoundEvent): (WebCore::ServiceWorkerContainer::jobResolvedWithRegistration): (WebCore::ServiceWorkerContainer::jobResolvedWithUnregistrationResult): (WebCore::ServiceWorkerContainer::startScriptFetchForJob): (WebCore::ServiceWorkerContainer::jobFinishedLoadingScript): (WebCore::ServiceWorkerContainer::jobFailedLoadingScript): (WebCore::ServiceWorkerContainer::jobDidFinish): (WebCore::ServiceWorkerContainer::addRegistration): (WebCore::ServiceWorkerContainer::removeRegistration): (WebCore::ServiceWorkerContainer::scheduleTaskToFireControllerChangeEvent): (WebCore::ServiceWorkerContainer::contextIdentifier): * workers/service/ServiceWorkerContainer.h: * workers/service/ServiceWorkerJob.cpp: (WebCore::ServiceWorkerJob::~ServiceWorkerJob): (WebCore::ServiceWorkerJob::failedWithException): (WebCore::ServiceWorkerJob::resolvedWithRegistration): (WebCore::ServiceWorkerJob::resolvedWithUnregistrationResult): (WebCore::ServiceWorkerJob::startScriptFetch): (WebCore::ServiceWorkerJob::fetchScriptWithContext): (WebCore::ServiceWorkerJob::didReceiveResponse): (WebCore::ServiceWorkerJob::notifyFinished): * workers/service/ServiceWorkerJob.h: * xml/parser/XMLDocumentParserLibxml2.cpp: (WebCore::matchFunc): (WebCore::openFunc): (WebCore::initializeXMLParser): (WebCore::XMLParserContext::createStringParser): (WebCore::XMLParserContext::createMemoryParser): Source/WebKit: * UIProcess/API/glib/IconDatabase.cpp: * UIProcess/GenericCallback.h: (WebKit::GenericCallback::~GenericCallback): (WebKit::GenericCallback::performCallbackWithReturnValue): Source/WTF: We should use a pointer of WTF::Thread instead of ThreadIdentifier. One problem is that Windows support library uses WTF::createThread, which returns ThreadIdentifier. So we cannot drop ThreadIdentifier in Windows environment. This patch keeps ThreadIdentifier in Windows. * wtf/MainThread.cpp: (WTF::initializeMainThread): (WTF::isMainThread): (WTF::canAccessThreadLocalDataForThread): * wtf/MainThread.h: * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkCount): * wtf/RecursiveLockAdapter.h: (WTF::RecursiveLockAdapter::lock): (WTF::RecursiveLockAdapter::unlock): (WTF::RecursiveLockAdapter::tryLock): * wtf/Threading.cpp: (WTF::Thread::dump const): * wtf/Threading.h: (WTF::Thread::id const): (WTF::Thread::operator==): Deleted. (WTF::Thread::operator!=): Deleted. (WTF::currentThread): Deleted. * wtf/ThreadingPrimitives.h: * wtf/ThreadingPthreads.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::detach): (WTF::Thread::initializeCurrentTLS): (WTF::Thread::suspend): (WTF::Thread::establishPlatformSpecificHandle): (WTF::Thread::currentID): Deleted. * wtf/ThreadingWin.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::suspend): (WTF::Thread::currentDying): * wtf/mac/MainThreadMac.mm: (WTF::initializeApplicationUIThread): (WTF::initializeWebThreadPlatform): (WTF::canAccessThreadLocalDataForThread): (WTF::initializeApplicationUIThreadIdentifier): Deleted. (WTF::initializeWebThreadIdentifier): Deleted. Tools: * DumpRenderTree/mac/DumpRenderTree.mm: (dumpRenderTree): (runThread): Deleted. (runPthread): Deleted. (testThreadIdentifierMap): Deleted. * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: * TestWebKitAPI/Tests/WTF/Threading.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/196314@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@225470 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-12-04 06:13:05 +00:00
dataLog(toString(Thread::current(), ": got thread ", RawPointer(current), "\n"));
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
if (!current)
break;
WTF::Lock should be fair eventually https://bugs.webkit.org/show_bug.cgi?id=159384 Reviewed by Geoffrey Garen. Source/WTF: In https://webkit.org/blog/6161/locking-in-webkit/ we showed how relaxing the fairness of locks makes them fast. That post presented lock fairness as a trade-off between two extremes: - Barging. A barging lock, like WTF::Lock, releases the lock in unlock() even if there was a thread on the queue. If there was a thread on the queue, the lock is released and that thread is made runnable. That thread may then grab the lock, or some other thread may grab the lock first (it may barge). Usually, the barging thread is the thread that released the lock in the first place. This maximizes throughput but hurts fairness. There is no good theoretical bound on how unfair the lock may become, but empirical data suggests that it's fair enough for the cases we previously measured. - FIFO. A FIFO lock, like HandoffLock in ToyLocks.h, does not release the lock in unlock() if there is a thread waiting. If there is a thread waiting, unlock() will make that thread runnable and inform it that it now holds the lock. This ensures perfect round-robin fairness and allows us to reason theoretically about how long it may take for a thread to grab the lock. For example, if we know that only N threads are running and each one may contend on a critical section, and each one may hold the lock for at most S seconds, then the time it takes to grab the lock is N * S. Unfortunately, FIFO locks perform very badly in most cases. This is because for the common case of short critical sections, they force a context switch after each critical section if the lock is contended. This change makes WTF::Lock almost as fair as FIFO while still being as fast as barging. Thanks to this new algorithm, you can now have both of these things at the same time. This change makes WTF::Lock eventually fair. We can almost (more on the caveats below) guarantee that the time it takes to grab a lock is N * max(1ms, S). In other words, critical sections that are longer than 1ms are always fair. For shorter critical sections, the amount of time that any thread waits is 1ms times the number of threads. There are some caveats that arise from our use of randomness, but even then, in the limit as the critical section length goes to infinity, the lock becomes fair. The corner cases are unlikely to happen; our experiments show that the lock becomes exactly as fair as a FIFO lock for any critical section that is 1ms or longer. The fairness mechanism is broken into two parts. WTF::Lock can now choose to unlock a lock fairly or unfairly thanks to the new ParkingLot token mechanism. WTF::Lock knows when to use fair unlocking based on a timeout mechanism in ParkingLot called timeToBeFair. ParkingLot::unparkOne() and ParkingLot::parkConditionally() can now communicate with each other via a token. unparkOne() can pass a token, which parkConditionally() will return. This change also makes parkConditionally() a lot more precise about when it was unparked due to a call to unparkOne(). If unparkOne() is told that a thread was unparked then this thread is guaranteed to report that it was unparked rather than timing out, and that thread is guaranteed to get the token that unparkOne() passed. The token is an intptr_t. We use it as a boolean variable in WTF::Lock, but you could use it to pass arbitrary data structures. By default, the token is zero. WTF::Lock's unlock() will pass 1 as the token if it is doing fair unlocking. In that case, unlock() will not release the lock, and lock() will know that it holds the lock as soon as parkConditionally() returns. Note that this algorithm relies on unparkOne() invoking WTF::Lock's callback while the queue lock is held, so that WTF::Lock can make a decision about unlock strategy and inject a token while it has complete knowledge over the state of the queue. As such, it's not immediately obvious how to implement this algorithm on top of futexes. You really need ParkingLot! WTF::Lock does not use fair unlocking every time. We expose a new API, Lock::unlockFairly(), which forces the fair unlocking behavior. Additionally, ParkingLot now maintains a per-bucket stochastic fairness timeout. When the timeout fires, the unparkOne() callback sees UnparkResult::timeToBeFair = true. This timeout is set to be anywhere from 0ms to 1ms at random. When a dequeue happens and there are threads that actually get dequeued, we check if the time since the last unfair unlock (the last time timeToBeFair was set to true) is more than the timeout amount. If so, then we set timeToBeFair to true and reset the timeout. This means that in the absence of ParkingLot collisions, unfair unlocking is guaranteed to happen at least once per millisecond. It will happen at 2 KHz on average. If there are collisions, then each collision adds one millisecond to the worst case (and 0.5 ms to the average case). The reason why we don't just use a fixed 1ms timeout is that we want to avoid resonance. Imagine a program in which some thread acquires a lock at 1 KHz in-phase with the timeToBeFair timeout. Then this thread would be the benefactor of fairness to the detriment of everyone else. Randomness ensures that we aren't too fair to any one thread. Empirically, this is neutral on our major benchmarks like JetStream but it's an enormous improvement in LockFairnessTest. It's common for an unfair lock (either our BargingLock, the old WTF::Lock, any of the other futex-based locks that barge, or new os_unfair_lock) to allow only one thread to hold the lock during a whole second in which each thread is holding the lock for 1ms at a time. This is because in a barging lock, releasing a lock after holding it for 1ms and then reacquiring it immediately virtually ensures that none of the other threads can wake up in time to grab it before it's relocked. But the new WTF::Lock handles this case like a champ: each thread gets equal turns. Here's some data. If we launch 10 threads and have each of them run for 1 second while repeatedly holding a critical section for 1ms, then here's how many times each thread gets to hold the lock using the old WTF::Lock algorithm: 799, 6, 1, 1, 1, 1, 1, 1, 1, 1 One thread hogged the lock for almost the whole time! With the new WTF::Lock, the lock becomes totally fair: 80, 79, 79, 79, 79, 79, 79, 80, 80, 79 I don't know of anyone creating such an automatically-fair adaptive lock before, so I think that this is a pretty awesome advancement to the state of the art! This change is good for three reasons: - We do have long critical sections in WebKit and we don't want to have to worry about starvation. This reduces the likelihood that we will see starvation due to our lock strategy. - I was talking to ggaren about bmalloc's locking needs, and he wanted unlockFairly() or lockFairly() or some moral equivalent for the scavenger thread. - If we use a WTF::Lock to manage heap access in a multithreaded GC, we'll need the ability to unlock and relock without barging. * benchmarks/LockFairnessTest.cpp: (main): * benchmarks/ToyLocks.h: * wtf/Condition.h: (WTF::ConditionBase::waitUntil): (WTF::ConditionBase::notifyOne): * wtf/Lock.cpp: (WTF::LockBase::lockSlow): (WTF::LockBase::unlockSlow): (WTF::LockBase::unlockFairlySlow): (WTF::LockBase::unlockSlowImpl): * wtf/Lock.h: (WTF::LockBase::try_lock): (WTF::LockBase::unlock): (WTF::LockBase::unlockFairly): (WTF::LockBase::isHeld): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::compareAndPark): (WTF::ParkingLot::unparkOne): Tools: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Canonical link: https://commits.webkit.org/178039@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@203350 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-07-18 18:32:52 +00:00
DequeueResult result = functor(current, timeToBeFair);
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
switch (result) {
case DequeueResult::Ignore:
if (verbose)
WTF shouldn't have both Thread and ThreadIdentifier https://bugs.webkit.org/show_bug.cgi?id=180308 Reviewed by Darin Adler. Source/JavaScriptCore: * heap/MachineStackMarker.cpp: (JSC::MachineThreads::tryCopyOtherThreadStacks): * llint/LLIntSlowPaths.cpp: (JSC::LLInt::llint_trace_operand): (JSC::LLInt::llint_trace_value): (JSC::LLInt::LLINT_SLOW_PATH_DECL): (JSC::LLInt::traceFunctionPrologue): * runtime/ExceptionScope.cpp: (JSC::ExceptionScope::unexpectedExceptionMessage): * runtime/JSLock.h: (JSC::JSLock::currentThreadIsHoldingLock): * runtime/VM.cpp: (JSC::VM::throwException): * runtime/VM.h: (JSC::VM::throwingThread const): (JSC::VM::clearException): * tools/HeapVerifier.cpp: (JSC::HeapVerifier::printVerificationHeader): Source/WebCore: No behavior change. * Modules/indexeddb/IDBActiveDOMObject.h: (WebCore::IDBActiveDOMObject::originThread const): (WebCore::IDBActiveDOMObject::performCallbackOnOriginThread): (WebCore::IDBActiveDOMObject::callFunctionOnOriginThread): (WebCore::IDBActiveDOMObject::originThreadID const): Deleted. * Modules/indexeddb/IDBCursor.cpp: (WebCore::IDBCursor::IDBCursor): (WebCore::IDBCursor::~IDBCursor): (WebCore::IDBCursor::sourcesDeleted const): (WebCore::IDBCursor::transaction const): (WebCore::IDBCursor::update): (WebCore::IDBCursor::advance): (WebCore::IDBCursor::continueFunction): (WebCore::IDBCursor::uncheckedIterateCursor): (WebCore::IDBCursor::deleteFunction): (WebCore::IDBCursor::setGetResult): * Modules/indexeddb/IDBDatabase.cpp: (WebCore::IDBDatabase::~IDBDatabase): (WebCore::IDBDatabase::hasPendingActivity const): (WebCore::IDBDatabase::name const): (WebCore::IDBDatabase::version const): (WebCore::IDBDatabase::objectStoreNames const): (WebCore::IDBDatabase::renameObjectStore): (WebCore::IDBDatabase::renameIndex): (WebCore::IDBDatabase::createObjectStore): (WebCore::IDBDatabase::transaction): (WebCore::IDBDatabase::deleteObjectStore): (WebCore::IDBDatabase::close): (WebCore::IDBDatabase::connectionToServerLost): (WebCore::IDBDatabase::maybeCloseInServer): (WebCore::IDBDatabase::activeDOMObjectName const): (WebCore::IDBDatabase::canSuspendForDocumentSuspension const): (WebCore::IDBDatabase::stop): (WebCore::IDBDatabase::startVersionChangeTransaction): (WebCore::IDBDatabase::didStartTransaction): (WebCore::IDBDatabase::willCommitTransaction): (WebCore::IDBDatabase::didCommitTransaction): (WebCore::IDBDatabase::willAbortTransaction): (WebCore::IDBDatabase::didAbortTransaction): (WebCore::IDBDatabase::didCommitOrAbortTransaction): (WebCore::IDBDatabase::fireVersionChangeEvent): (WebCore::IDBDatabase::dispatchEvent): (WebCore::IDBDatabase::didCreateIndexInfo): (WebCore::IDBDatabase::didDeleteIndexInfo): * Modules/indexeddb/IDBIndex.cpp: (WebCore::IDBIndex::IDBIndex): (WebCore::IDBIndex::~IDBIndex): (WebCore::IDBIndex::name const): (WebCore::IDBIndex::setName): (WebCore::IDBIndex::objectStore): (WebCore::IDBIndex::keyPath const): (WebCore::IDBIndex::unique const): (WebCore::IDBIndex::multiEntry const): (WebCore::IDBIndex::rollbackInfoForVersionChangeAbort): (WebCore::IDBIndex::openCursor): (WebCore::IDBIndex::openKeyCursor): (WebCore::IDBIndex::doCount): (WebCore::IDBIndex::doGet): (WebCore::IDBIndex::doGetKey): (WebCore::IDBIndex::getAll): (WebCore::IDBIndex::getAllKeys): (WebCore::IDBIndex::markAsDeleted): * Modules/indexeddb/IDBObjectStore.cpp: (WebCore::IDBObjectStore::IDBObjectStore): (WebCore::IDBObjectStore::~IDBObjectStore): (WebCore::IDBObjectStore::name const): (WebCore::IDBObjectStore::setName): (WebCore::IDBObjectStore::keyPath const): (WebCore::IDBObjectStore::indexNames const): (WebCore::IDBObjectStore::transaction): (WebCore::IDBObjectStore::autoIncrement const): (WebCore::IDBObjectStore::openCursor): (WebCore::IDBObjectStore::openKeyCursor): (WebCore::IDBObjectStore::get): (WebCore::IDBObjectStore::getKey): (WebCore::IDBObjectStore::putOrAdd): (WebCore::IDBObjectStore::doDelete): (WebCore::IDBObjectStore::clear): (WebCore::IDBObjectStore::createIndex): (WebCore::IDBObjectStore::index): (WebCore::IDBObjectStore::deleteIndex): (WebCore::IDBObjectStore::doCount): (WebCore::IDBObjectStore::getAll): (WebCore::IDBObjectStore::getAllKeys): (WebCore::IDBObjectStore::markAsDeleted): (WebCore::IDBObjectStore::rollbackForVersionChangeAbort): * Modules/indexeddb/IDBOpenDBRequest.cpp: (WebCore::IDBOpenDBRequest::~IDBOpenDBRequest): (WebCore::IDBOpenDBRequest::onError): (WebCore::IDBOpenDBRequest::versionChangeTransactionDidFinish): (WebCore::IDBOpenDBRequest::fireSuccessAfterVersionChangeCommit): (WebCore::IDBOpenDBRequest::fireErrorAfterVersionChangeCompletion): (WebCore::IDBOpenDBRequest::dispatchEvent): (WebCore::IDBOpenDBRequest::onSuccess): (WebCore::IDBOpenDBRequest::onUpgradeNeeded): (WebCore::IDBOpenDBRequest::onDeleteDatabaseSuccess): (WebCore::IDBOpenDBRequest::requestCompleted): (WebCore::IDBOpenDBRequest::requestBlocked): * Modules/indexeddb/IDBRequest.cpp: (WebCore::IDBRequest::~IDBRequest): (WebCore:: const): (WebCore::IDBRequest::setSource): (WebCore::IDBRequest::setVersionChangeTransaction): (WebCore::IDBRequest::transaction const): (WebCore::IDBRequest::sourceObjectStoreIdentifier const): (WebCore::IDBRequest::sourceIndexIdentifier const): (WebCore::IDBRequest::requestedObjectStoreRecordType const): (WebCore::IDBRequest::requestedIndexRecordType const): (WebCore::IDBRequest::eventTargetInterface const): (WebCore::IDBRequest::activeDOMObjectName const): (WebCore::IDBRequest::canSuspendForDocumentSuspension const): (WebCore::IDBRequest::hasPendingActivity const): (WebCore::IDBRequest::stop): (WebCore::IDBRequest::enqueueEvent): (WebCore::IDBRequest::dispatchEvent): (WebCore::IDBRequest::uncaughtExceptionInEventHandler): (WebCore::IDBRequest::setResult): (WebCore::IDBRequest::setResultToStructuredClone): (WebCore::IDBRequest::setResultToUndefined): (WebCore::IDBRequest::resultCursor): (WebCore::IDBRequest::willIterateCursor): (WebCore::IDBRequest::didOpenOrIterateCursor): (WebCore::IDBRequest::completeRequestAndDispatchEvent): (WebCore::IDBRequest::onError): (WebCore::IDBRequest::onSuccess): * Modules/indexeddb/IDBTransaction.cpp: (WebCore::IDBTransaction::IDBTransaction): (WebCore::IDBTransaction::~IDBTransaction): (WebCore::IDBTransaction::objectStoreNames const): (WebCore::IDBTransaction::db): (WebCore::IDBTransaction::error const): (WebCore::IDBTransaction::objectStore): (WebCore::IDBTransaction::abortDueToFailedRequest): (WebCore::IDBTransaction::transitionedToFinishing): (WebCore::IDBTransaction::abort): (WebCore::IDBTransaction::internalAbort): (WebCore::IDBTransaction::abortOnServerAndCancelRequests): (WebCore::IDBTransaction::activeDOMObjectName const): (WebCore::IDBTransaction::canSuspendForDocumentSuspension const): (WebCore::IDBTransaction::hasPendingActivity const): (WebCore::IDBTransaction::stop): (WebCore::IDBTransaction::isActive const): (WebCore::IDBTransaction::isFinishedOrFinishing const): (WebCore::IDBTransaction::addRequest): (WebCore::IDBTransaction::removeRequest): (WebCore::IDBTransaction::scheduleOperation): (WebCore::IDBTransaction::schedulePendingOperationTimer): (WebCore::IDBTransaction::pendingOperationTimerFired): (WebCore::IDBTransaction::operationCompletedOnServer): (WebCore::IDBTransaction::scheduleCompletedOperationTimer): (WebCore::IDBTransaction::completedOperationTimerFired): (WebCore::IDBTransaction::commit): (WebCore::IDBTransaction::commitOnServer): (WebCore::IDBTransaction::finishAbortOrCommit): (WebCore::IDBTransaction::didStart): (WebCore::IDBTransaction::notifyDidAbort): (WebCore::IDBTransaction::didAbort): (WebCore::IDBTransaction::didCommit): (WebCore::IDBTransaction::fireOnComplete): (WebCore::IDBTransaction::fireOnAbort): (WebCore::IDBTransaction::enqueueEvent): (WebCore::IDBTransaction::dispatchEvent): (WebCore::IDBTransaction::createObjectStore): (WebCore::IDBTransaction::createObjectStoreOnServer): (WebCore::IDBTransaction::didCreateObjectStoreOnServer): (WebCore::IDBTransaction::renameObjectStore): (WebCore::IDBTransaction::renameObjectStoreOnServer): (WebCore::IDBTransaction::didRenameObjectStoreOnServer): (WebCore::IDBTransaction::createIndex): (WebCore::IDBTransaction::createIndexOnServer): (WebCore::IDBTransaction::didCreateIndexOnServer): (WebCore::IDBTransaction::renameIndex): (WebCore::IDBTransaction::renameIndexOnServer): (WebCore::IDBTransaction::didRenameIndexOnServer): (WebCore::IDBTransaction::requestOpenCursor): (WebCore::IDBTransaction::doRequestOpenCursor): (WebCore::IDBTransaction::openCursorOnServer): (WebCore::IDBTransaction::didOpenCursorOnServer): (WebCore::IDBTransaction::iterateCursor): (WebCore::IDBTransaction::iterateCursorOnServer): (WebCore::IDBTransaction::didIterateCursorOnServer): (WebCore::IDBTransaction::requestGetAllObjectStoreRecords): (WebCore::IDBTransaction::requestGetAllIndexRecords): (WebCore::IDBTransaction::getAllRecordsOnServer): (WebCore::IDBTransaction::didGetAllRecordsOnServer): (WebCore::IDBTransaction::requestGetRecord): (WebCore::IDBTransaction::requestGetValue): (WebCore::IDBTransaction::requestGetKey): (WebCore::IDBTransaction::requestIndexRecord): (WebCore::IDBTransaction::getRecordOnServer): (WebCore::IDBTransaction::didGetRecordOnServer): (WebCore::IDBTransaction::requestCount): (WebCore::IDBTransaction::getCountOnServer): (WebCore::IDBTransaction::didGetCountOnServer): (WebCore::IDBTransaction::requestDeleteRecord): (WebCore::IDBTransaction::deleteRecordOnServer): (WebCore::IDBTransaction::didDeleteRecordOnServer): (WebCore::IDBTransaction::requestClearObjectStore): (WebCore::IDBTransaction::clearObjectStoreOnServer): (WebCore::IDBTransaction::didClearObjectStoreOnServer): (WebCore::IDBTransaction::requestPutOrAdd): (WebCore::IDBTransaction::putOrAddOnServer): (WebCore::IDBTransaction::didPutOrAddOnServer): (WebCore::IDBTransaction::deleteObjectStore): (WebCore::IDBTransaction::deleteObjectStoreOnServer): (WebCore::IDBTransaction::didDeleteObjectStoreOnServer): (WebCore::IDBTransaction::deleteIndex): (WebCore::IDBTransaction::deleteIndexOnServer): (WebCore::IDBTransaction::didDeleteIndexOnServer): (WebCore::IDBTransaction::operationCompletedOnClient): (WebCore::IDBTransaction::establishOnServer): (WebCore::IDBTransaction::activate): (WebCore::IDBTransaction::deactivate): * Modules/indexeddb/client/IDBConnectionProxy.cpp: (WebCore::IDBClient::removeItemsMatchingCurrentThread): * Modules/indexeddb/client/TransactionOperation.h: (WebCore::IDBClient::TransactionOperation::~TransactionOperation): (WebCore::IDBClient::TransactionOperation::perform): (WebCore::IDBClient::TransactionOperation::transitionToCompleteOnThisThread): (WebCore::IDBClient::TransactionOperation::transitionToComplete): (WebCore::IDBClient::TransactionOperation::doComplete): (WebCore::IDBClient::TransactionOperation::originThread const): (WebCore::IDBClient::TransactionOperation::originThreadID const): Deleted. * Modules/webaudio/AudioContext.cpp: (WebCore::AudioContext::AudioContext): (WebCore::AudioContext::lock): (WebCore::AudioContext::tryLock): (WebCore::AudioContext::unlock): (WebCore::AudioContext::isAudioThread const): (WebCore::AudioContext::isGraphOwner const): * Modules/webaudio/AudioContext.h: (WebCore::AudioContext::setAudioThread): (WebCore::AudioContext::audioThread const): * Modules/webaudio/AudioDestinationNode.cpp: (WebCore::AudioDestinationNode::render): * Modules/webdatabase/Database.cpp: (WebCore::Database::performClose): (WebCore::Database::securityOrigin): * Modules/webdatabase/DatabaseDetails.h: (WebCore::DatabaseDetails::DatabaseDetails): (WebCore::DatabaseDetails::operator=): (WebCore::DatabaseDetails::thread const): (WebCore::DatabaseDetails::threadID const): Deleted. * Modules/webdatabase/DatabaseManager.cpp: (WebCore::DatabaseManager::detailsForNameAndOrigin): * Modules/webdatabase/DatabaseThread.cpp: (WebCore::DatabaseThread::databaseThread): (WebCore::DatabaseThread::recordDatabaseOpen): (WebCore::DatabaseThread::recordDatabaseClosed): * Modules/webdatabase/DatabaseThread.h: (WebCore::DatabaseThread::getThread): (WebCore::DatabaseThread::getThreadID): Deleted. * Modules/webdatabase/SQLTransaction.cpp: (WebCore::SQLTransaction::checkAndHandleClosedDatabase): * Modules/webdatabase/SQLTransactionBackend.cpp: (WebCore::SQLTransactionBackend::doCleanup): (WebCore::SQLTransactionBackend::notifyDatabaseThreadIsShuttingDown): * bindings/js/JSCallbackData.h: (WebCore::JSCallbackData::JSCallbackData): (WebCore::JSCallbackData::~JSCallbackData): * bindings/js/ScheduledAction.cpp: (WebCore::ScheduledAction::execute): * dom/ScriptExecutionContext.cpp: (WebCore::ScriptExecutionContext::createdMessagePort): (WebCore::ScriptExecutionContext::destroyedMessagePort): * page/ResourceUsageOverlay.h: * page/scrolling/ScrollingThread.cpp: (WebCore::ScrollingThread::isCurrentThread): * platform/Supplementable.h: (WebCore::Supplementable::provideSupplement): (WebCore::Supplementable::removeSupplement): (WebCore::Supplementable::requireSupplement): (WebCore::Supplementable::Supplementable): Deleted. * platform/Timer.cpp: (WebCore::TimerBase::TimerBase): (WebCore::TimerBase::start): (WebCore::TimerBase::stop): (WebCore::TimerBase::setNextFireTime): * platform/Timer.h: (WebCore::TimerBase::isActive const): * platform/graphics/cocoa/FontCacheCoreText.cpp: (WebCore::shouldAutoActivateFontIfNeeded): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.cpp: (WebCore::TextureMapperPlatformLayerProxy::activateOnCompositingThread): (WebCore::TextureMapperPlatformLayerProxy::invalidate): (WebCore::TextureMapperPlatformLayerProxy::getAvailableBuffer): (WebCore::TextureMapperPlatformLayerProxy::appendToUnusedBuffers): (WebCore::TextureMapperPlatformLayerProxy::swapBuffer): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.h: (): Deleted. * platform/ios/wak/WebCoreThread.mm: (RunWebThread): (StartWebThread): * platform/sql/SQLiteDatabase.cpp: (WebCore::SQLiteDatabase::open): (WebCore::SQLiteDatabase::close): * platform/sql/SQLiteDatabase.h: (WebCore::SQLiteDatabase::sqlite3Handle const): * workers/WorkerGlobalScope.cpp: (WebCore::WorkerGlobalScope::~WorkerGlobalScope): (WebCore::WorkerGlobalScope::isContextThread const): * workers/WorkerMessagingProxy.cpp: (WebCore::WorkerMessagingProxy::WorkerMessagingProxy): (WebCore::WorkerMessagingProxy::~WorkerMessagingProxy): * workers/WorkerRunLoop.cpp: (WebCore::WorkerRunLoop::runInMode): (WebCore::WorkerRunLoop::runCleanupTasks): * workers/WorkerThread.h: (WebCore::WorkerThread::thread const): (WebCore::WorkerThread::threadID const): Deleted. * workers/service/ServiceWorkerContainer.cpp: (WebCore::ServiceWorkerContainer::~ServiceWorkerContainer): (WebCore::ServiceWorkerContainer::scheduleJob): (WebCore::ServiceWorkerContainer::jobFailedWithException): (WebCore::ServiceWorkerContainer::scheduleTaskToFireUpdateFoundEvent): (WebCore::ServiceWorkerContainer::jobResolvedWithRegistration): (WebCore::ServiceWorkerContainer::jobResolvedWithUnregistrationResult): (WebCore::ServiceWorkerContainer::startScriptFetchForJob): (WebCore::ServiceWorkerContainer::jobFinishedLoadingScript): (WebCore::ServiceWorkerContainer::jobFailedLoadingScript): (WebCore::ServiceWorkerContainer::jobDidFinish): (WebCore::ServiceWorkerContainer::addRegistration): (WebCore::ServiceWorkerContainer::removeRegistration): (WebCore::ServiceWorkerContainer::scheduleTaskToFireControllerChangeEvent): (WebCore::ServiceWorkerContainer::contextIdentifier): * workers/service/ServiceWorkerContainer.h: * workers/service/ServiceWorkerJob.cpp: (WebCore::ServiceWorkerJob::~ServiceWorkerJob): (WebCore::ServiceWorkerJob::failedWithException): (WebCore::ServiceWorkerJob::resolvedWithRegistration): (WebCore::ServiceWorkerJob::resolvedWithUnregistrationResult): (WebCore::ServiceWorkerJob::startScriptFetch): (WebCore::ServiceWorkerJob::fetchScriptWithContext): (WebCore::ServiceWorkerJob::didReceiveResponse): (WebCore::ServiceWorkerJob::notifyFinished): * workers/service/ServiceWorkerJob.h: * xml/parser/XMLDocumentParserLibxml2.cpp: (WebCore::matchFunc): (WebCore::openFunc): (WebCore::initializeXMLParser): (WebCore::XMLParserContext::createStringParser): (WebCore::XMLParserContext::createMemoryParser): Source/WebKit: * UIProcess/API/glib/IconDatabase.cpp: * UIProcess/GenericCallback.h: (WebKit::GenericCallback::~GenericCallback): (WebKit::GenericCallback::performCallbackWithReturnValue): Source/WTF: We should use a pointer of WTF::Thread instead of ThreadIdentifier. One problem is that Windows support library uses WTF::createThread, which returns ThreadIdentifier. So we cannot drop ThreadIdentifier in Windows environment. This patch keeps ThreadIdentifier in Windows. * wtf/MainThread.cpp: (WTF::initializeMainThread): (WTF::isMainThread): (WTF::canAccessThreadLocalDataForThread): * wtf/MainThread.h: * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkCount): * wtf/RecursiveLockAdapter.h: (WTF::RecursiveLockAdapter::lock): (WTF::RecursiveLockAdapter::unlock): (WTF::RecursiveLockAdapter::tryLock): * wtf/Threading.cpp: (WTF::Thread::dump const): * wtf/Threading.h: (WTF::Thread::id const): (WTF::Thread::operator==): Deleted. (WTF::Thread::operator!=): Deleted. (WTF::currentThread): Deleted. * wtf/ThreadingPrimitives.h: * wtf/ThreadingPthreads.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::detach): (WTF::Thread::initializeCurrentTLS): (WTF::Thread::suspend): (WTF::Thread::establishPlatformSpecificHandle): (WTF::Thread::currentID): Deleted. * wtf/ThreadingWin.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::suspend): (WTF::Thread::currentDying): * wtf/mac/MainThreadMac.mm: (WTF::initializeApplicationUIThread): (WTF::initializeWebThreadPlatform): (WTF::canAccessThreadLocalDataForThread): (WTF::initializeApplicationUIThreadIdentifier): Deleted. (WTF::initializeWebThreadIdentifier): Deleted. Tools: * DumpRenderTree/mac/DumpRenderTree.mm: (dumpRenderTree): (runThread): Deleted. (runPthread): Deleted. (testThreadIdentifierMap): Deleted. * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: * TestWebKitAPI/Tests/WTF/Threading.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/196314@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@225470 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-12-04 06:13:05 +00:00
dataLog(toString(Thread::current(), ": currentPtr = ", RawPointer(currentPtr), ", *currentPtr = ", RawPointer(*currentPtr), "\n"));
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
previous = current;
currentPtr = &(*currentPtr)->nextInQueue;
break;
case DequeueResult::RemoveAndStop:
shouldContinue = false;
FALLTHROUGH;
case DequeueResult::RemoveAndContinue:
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
if (verbose)
WTF shouldn't have both Thread and ThreadIdentifier https://bugs.webkit.org/show_bug.cgi?id=180308 Reviewed by Darin Adler. Source/JavaScriptCore: * heap/MachineStackMarker.cpp: (JSC::MachineThreads::tryCopyOtherThreadStacks): * llint/LLIntSlowPaths.cpp: (JSC::LLInt::llint_trace_operand): (JSC::LLInt::llint_trace_value): (JSC::LLInt::LLINT_SLOW_PATH_DECL): (JSC::LLInt::traceFunctionPrologue): * runtime/ExceptionScope.cpp: (JSC::ExceptionScope::unexpectedExceptionMessage): * runtime/JSLock.h: (JSC::JSLock::currentThreadIsHoldingLock): * runtime/VM.cpp: (JSC::VM::throwException): * runtime/VM.h: (JSC::VM::throwingThread const): (JSC::VM::clearException): * tools/HeapVerifier.cpp: (JSC::HeapVerifier::printVerificationHeader): Source/WebCore: No behavior change. * Modules/indexeddb/IDBActiveDOMObject.h: (WebCore::IDBActiveDOMObject::originThread const): (WebCore::IDBActiveDOMObject::performCallbackOnOriginThread): (WebCore::IDBActiveDOMObject::callFunctionOnOriginThread): (WebCore::IDBActiveDOMObject::originThreadID const): Deleted. * Modules/indexeddb/IDBCursor.cpp: (WebCore::IDBCursor::IDBCursor): (WebCore::IDBCursor::~IDBCursor): (WebCore::IDBCursor::sourcesDeleted const): (WebCore::IDBCursor::transaction const): (WebCore::IDBCursor::update): (WebCore::IDBCursor::advance): (WebCore::IDBCursor::continueFunction): (WebCore::IDBCursor::uncheckedIterateCursor): (WebCore::IDBCursor::deleteFunction): (WebCore::IDBCursor::setGetResult): * Modules/indexeddb/IDBDatabase.cpp: (WebCore::IDBDatabase::~IDBDatabase): (WebCore::IDBDatabase::hasPendingActivity const): (WebCore::IDBDatabase::name const): (WebCore::IDBDatabase::version const): (WebCore::IDBDatabase::objectStoreNames const): (WebCore::IDBDatabase::renameObjectStore): (WebCore::IDBDatabase::renameIndex): (WebCore::IDBDatabase::createObjectStore): (WebCore::IDBDatabase::transaction): (WebCore::IDBDatabase::deleteObjectStore): (WebCore::IDBDatabase::close): (WebCore::IDBDatabase::connectionToServerLost): (WebCore::IDBDatabase::maybeCloseInServer): (WebCore::IDBDatabase::activeDOMObjectName const): (WebCore::IDBDatabase::canSuspendForDocumentSuspension const): (WebCore::IDBDatabase::stop): (WebCore::IDBDatabase::startVersionChangeTransaction): (WebCore::IDBDatabase::didStartTransaction): (WebCore::IDBDatabase::willCommitTransaction): (WebCore::IDBDatabase::didCommitTransaction): (WebCore::IDBDatabase::willAbortTransaction): (WebCore::IDBDatabase::didAbortTransaction): (WebCore::IDBDatabase::didCommitOrAbortTransaction): (WebCore::IDBDatabase::fireVersionChangeEvent): (WebCore::IDBDatabase::dispatchEvent): (WebCore::IDBDatabase::didCreateIndexInfo): (WebCore::IDBDatabase::didDeleteIndexInfo): * Modules/indexeddb/IDBIndex.cpp: (WebCore::IDBIndex::IDBIndex): (WebCore::IDBIndex::~IDBIndex): (WebCore::IDBIndex::name const): (WebCore::IDBIndex::setName): (WebCore::IDBIndex::objectStore): (WebCore::IDBIndex::keyPath const): (WebCore::IDBIndex::unique const): (WebCore::IDBIndex::multiEntry const): (WebCore::IDBIndex::rollbackInfoForVersionChangeAbort): (WebCore::IDBIndex::openCursor): (WebCore::IDBIndex::openKeyCursor): (WebCore::IDBIndex::doCount): (WebCore::IDBIndex::doGet): (WebCore::IDBIndex::doGetKey): (WebCore::IDBIndex::getAll): (WebCore::IDBIndex::getAllKeys): (WebCore::IDBIndex::markAsDeleted): * Modules/indexeddb/IDBObjectStore.cpp: (WebCore::IDBObjectStore::IDBObjectStore): (WebCore::IDBObjectStore::~IDBObjectStore): (WebCore::IDBObjectStore::name const): (WebCore::IDBObjectStore::setName): (WebCore::IDBObjectStore::keyPath const): (WebCore::IDBObjectStore::indexNames const): (WebCore::IDBObjectStore::transaction): (WebCore::IDBObjectStore::autoIncrement const): (WebCore::IDBObjectStore::openCursor): (WebCore::IDBObjectStore::openKeyCursor): (WebCore::IDBObjectStore::get): (WebCore::IDBObjectStore::getKey): (WebCore::IDBObjectStore::putOrAdd): (WebCore::IDBObjectStore::doDelete): (WebCore::IDBObjectStore::clear): (WebCore::IDBObjectStore::createIndex): (WebCore::IDBObjectStore::index): (WebCore::IDBObjectStore::deleteIndex): (WebCore::IDBObjectStore::doCount): (WebCore::IDBObjectStore::getAll): (WebCore::IDBObjectStore::getAllKeys): (WebCore::IDBObjectStore::markAsDeleted): (WebCore::IDBObjectStore::rollbackForVersionChangeAbort): * Modules/indexeddb/IDBOpenDBRequest.cpp: (WebCore::IDBOpenDBRequest::~IDBOpenDBRequest): (WebCore::IDBOpenDBRequest::onError): (WebCore::IDBOpenDBRequest::versionChangeTransactionDidFinish): (WebCore::IDBOpenDBRequest::fireSuccessAfterVersionChangeCommit): (WebCore::IDBOpenDBRequest::fireErrorAfterVersionChangeCompletion): (WebCore::IDBOpenDBRequest::dispatchEvent): (WebCore::IDBOpenDBRequest::onSuccess): (WebCore::IDBOpenDBRequest::onUpgradeNeeded): (WebCore::IDBOpenDBRequest::onDeleteDatabaseSuccess): (WebCore::IDBOpenDBRequest::requestCompleted): (WebCore::IDBOpenDBRequest::requestBlocked): * Modules/indexeddb/IDBRequest.cpp: (WebCore::IDBRequest::~IDBRequest): (WebCore:: const): (WebCore::IDBRequest::setSource): (WebCore::IDBRequest::setVersionChangeTransaction): (WebCore::IDBRequest::transaction const): (WebCore::IDBRequest::sourceObjectStoreIdentifier const): (WebCore::IDBRequest::sourceIndexIdentifier const): (WebCore::IDBRequest::requestedObjectStoreRecordType const): (WebCore::IDBRequest::requestedIndexRecordType const): (WebCore::IDBRequest::eventTargetInterface const): (WebCore::IDBRequest::activeDOMObjectName const): (WebCore::IDBRequest::canSuspendForDocumentSuspension const): (WebCore::IDBRequest::hasPendingActivity const): (WebCore::IDBRequest::stop): (WebCore::IDBRequest::enqueueEvent): (WebCore::IDBRequest::dispatchEvent): (WebCore::IDBRequest::uncaughtExceptionInEventHandler): (WebCore::IDBRequest::setResult): (WebCore::IDBRequest::setResultToStructuredClone): (WebCore::IDBRequest::setResultToUndefined): (WebCore::IDBRequest::resultCursor): (WebCore::IDBRequest::willIterateCursor): (WebCore::IDBRequest::didOpenOrIterateCursor): (WebCore::IDBRequest::completeRequestAndDispatchEvent): (WebCore::IDBRequest::onError): (WebCore::IDBRequest::onSuccess): * Modules/indexeddb/IDBTransaction.cpp: (WebCore::IDBTransaction::IDBTransaction): (WebCore::IDBTransaction::~IDBTransaction): (WebCore::IDBTransaction::objectStoreNames const): (WebCore::IDBTransaction::db): (WebCore::IDBTransaction::error const): (WebCore::IDBTransaction::objectStore): (WebCore::IDBTransaction::abortDueToFailedRequest): (WebCore::IDBTransaction::transitionedToFinishing): (WebCore::IDBTransaction::abort): (WebCore::IDBTransaction::internalAbort): (WebCore::IDBTransaction::abortOnServerAndCancelRequests): (WebCore::IDBTransaction::activeDOMObjectName const): (WebCore::IDBTransaction::canSuspendForDocumentSuspension const): (WebCore::IDBTransaction::hasPendingActivity const): (WebCore::IDBTransaction::stop): (WebCore::IDBTransaction::isActive const): (WebCore::IDBTransaction::isFinishedOrFinishing const): (WebCore::IDBTransaction::addRequest): (WebCore::IDBTransaction::removeRequest): (WebCore::IDBTransaction::scheduleOperation): (WebCore::IDBTransaction::schedulePendingOperationTimer): (WebCore::IDBTransaction::pendingOperationTimerFired): (WebCore::IDBTransaction::operationCompletedOnServer): (WebCore::IDBTransaction::scheduleCompletedOperationTimer): (WebCore::IDBTransaction::completedOperationTimerFired): (WebCore::IDBTransaction::commit): (WebCore::IDBTransaction::commitOnServer): (WebCore::IDBTransaction::finishAbortOrCommit): (WebCore::IDBTransaction::didStart): (WebCore::IDBTransaction::notifyDidAbort): (WebCore::IDBTransaction::didAbort): (WebCore::IDBTransaction::didCommit): (WebCore::IDBTransaction::fireOnComplete): (WebCore::IDBTransaction::fireOnAbort): (WebCore::IDBTransaction::enqueueEvent): (WebCore::IDBTransaction::dispatchEvent): (WebCore::IDBTransaction::createObjectStore): (WebCore::IDBTransaction::createObjectStoreOnServer): (WebCore::IDBTransaction::didCreateObjectStoreOnServer): (WebCore::IDBTransaction::renameObjectStore): (WebCore::IDBTransaction::renameObjectStoreOnServer): (WebCore::IDBTransaction::didRenameObjectStoreOnServer): (WebCore::IDBTransaction::createIndex): (WebCore::IDBTransaction::createIndexOnServer): (WebCore::IDBTransaction::didCreateIndexOnServer): (WebCore::IDBTransaction::renameIndex): (WebCore::IDBTransaction::renameIndexOnServer): (WebCore::IDBTransaction::didRenameIndexOnServer): (WebCore::IDBTransaction::requestOpenCursor): (WebCore::IDBTransaction::doRequestOpenCursor): (WebCore::IDBTransaction::openCursorOnServer): (WebCore::IDBTransaction::didOpenCursorOnServer): (WebCore::IDBTransaction::iterateCursor): (WebCore::IDBTransaction::iterateCursorOnServer): (WebCore::IDBTransaction::didIterateCursorOnServer): (WebCore::IDBTransaction::requestGetAllObjectStoreRecords): (WebCore::IDBTransaction::requestGetAllIndexRecords): (WebCore::IDBTransaction::getAllRecordsOnServer): (WebCore::IDBTransaction::didGetAllRecordsOnServer): (WebCore::IDBTransaction::requestGetRecord): (WebCore::IDBTransaction::requestGetValue): (WebCore::IDBTransaction::requestGetKey): (WebCore::IDBTransaction::requestIndexRecord): (WebCore::IDBTransaction::getRecordOnServer): (WebCore::IDBTransaction::didGetRecordOnServer): (WebCore::IDBTransaction::requestCount): (WebCore::IDBTransaction::getCountOnServer): (WebCore::IDBTransaction::didGetCountOnServer): (WebCore::IDBTransaction::requestDeleteRecord): (WebCore::IDBTransaction::deleteRecordOnServer): (WebCore::IDBTransaction::didDeleteRecordOnServer): (WebCore::IDBTransaction::requestClearObjectStore): (WebCore::IDBTransaction::clearObjectStoreOnServer): (WebCore::IDBTransaction::didClearObjectStoreOnServer): (WebCore::IDBTransaction::requestPutOrAdd): (WebCore::IDBTransaction::putOrAddOnServer): (WebCore::IDBTransaction::didPutOrAddOnServer): (WebCore::IDBTransaction::deleteObjectStore): (WebCore::IDBTransaction::deleteObjectStoreOnServer): (WebCore::IDBTransaction::didDeleteObjectStoreOnServer): (WebCore::IDBTransaction::deleteIndex): (WebCore::IDBTransaction::deleteIndexOnServer): (WebCore::IDBTransaction::didDeleteIndexOnServer): (WebCore::IDBTransaction::operationCompletedOnClient): (WebCore::IDBTransaction::establishOnServer): (WebCore::IDBTransaction::activate): (WebCore::IDBTransaction::deactivate): * Modules/indexeddb/client/IDBConnectionProxy.cpp: (WebCore::IDBClient::removeItemsMatchingCurrentThread): * Modules/indexeddb/client/TransactionOperation.h: (WebCore::IDBClient::TransactionOperation::~TransactionOperation): (WebCore::IDBClient::TransactionOperation::perform): (WebCore::IDBClient::TransactionOperation::transitionToCompleteOnThisThread): (WebCore::IDBClient::TransactionOperation::transitionToComplete): (WebCore::IDBClient::TransactionOperation::doComplete): (WebCore::IDBClient::TransactionOperation::originThread const): (WebCore::IDBClient::TransactionOperation::originThreadID const): Deleted. * Modules/webaudio/AudioContext.cpp: (WebCore::AudioContext::AudioContext): (WebCore::AudioContext::lock): (WebCore::AudioContext::tryLock): (WebCore::AudioContext::unlock): (WebCore::AudioContext::isAudioThread const): (WebCore::AudioContext::isGraphOwner const): * Modules/webaudio/AudioContext.h: (WebCore::AudioContext::setAudioThread): (WebCore::AudioContext::audioThread const): * Modules/webaudio/AudioDestinationNode.cpp: (WebCore::AudioDestinationNode::render): * Modules/webdatabase/Database.cpp: (WebCore::Database::performClose): (WebCore::Database::securityOrigin): * Modules/webdatabase/DatabaseDetails.h: (WebCore::DatabaseDetails::DatabaseDetails): (WebCore::DatabaseDetails::operator=): (WebCore::DatabaseDetails::thread const): (WebCore::DatabaseDetails::threadID const): Deleted. * Modules/webdatabase/DatabaseManager.cpp: (WebCore::DatabaseManager::detailsForNameAndOrigin): * Modules/webdatabase/DatabaseThread.cpp: (WebCore::DatabaseThread::databaseThread): (WebCore::DatabaseThread::recordDatabaseOpen): (WebCore::DatabaseThread::recordDatabaseClosed): * Modules/webdatabase/DatabaseThread.h: (WebCore::DatabaseThread::getThread): (WebCore::DatabaseThread::getThreadID): Deleted. * Modules/webdatabase/SQLTransaction.cpp: (WebCore::SQLTransaction::checkAndHandleClosedDatabase): * Modules/webdatabase/SQLTransactionBackend.cpp: (WebCore::SQLTransactionBackend::doCleanup): (WebCore::SQLTransactionBackend::notifyDatabaseThreadIsShuttingDown): * bindings/js/JSCallbackData.h: (WebCore::JSCallbackData::JSCallbackData): (WebCore::JSCallbackData::~JSCallbackData): * bindings/js/ScheduledAction.cpp: (WebCore::ScheduledAction::execute): * dom/ScriptExecutionContext.cpp: (WebCore::ScriptExecutionContext::createdMessagePort): (WebCore::ScriptExecutionContext::destroyedMessagePort): * page/ResourceUsageOverlay.h: * page/scrolling/ScrollingThread.cpp: (WebCore::ScrollingThread::isCurrentThread): * platform/Supplementable.h: (WebCore::Supplementable::provideSupplement): (WebCore::Supplementable::removeSupplement): (WebCore::Supplementable::requireSupplement): (WebCore::Supplementable::Supplementable): Deleted. * platform/Timer.cpp: (WebCore::TimerBase::TimerBase): (WebCore::TimerBase::start): (WebCore::TimerBase::stop): (WebCore::TimerBase::setNextFireTime): * platform/Timer.h: (WebCore::TimerBase::isActive const): * platform/graphics/cocoa/FontCacheCoreText.cpp: (WebCore::shouldAutoActivateFontIfNeeded): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.cpp: (WebCore::TextureMapperPlatformLayerProxy::activateOnCompositingThread): (WebCore::TextureMapperPlatformLayerProxy::invalidate): (WebCore::TextureMapperPlatformLayerProxy::getAvailableBuffer): (WebCore::TextureMapperPlatformLayerProxy::appendToUnusedBuffers): (WebCore::TextureMapperPlatformLayerProxy::swapBuffer): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.h: (): Deleted. * platform/ios/wak/WebCoreThread.mm: (RunWebThread): (StartWebThread): * platform/sql/SQLiteDatabase.cpp: (WebCore::SQLiteDatabase::open): (WebCore::SQLiteDatabase::close): * platform/sql/SQLiteDatabase.h: (WebCore::SQLiteDatabase::sqlite3Handle const): * workers/WorkerGlobalScope.cpp: (WebCore::WorkerGlobalScope::~WorkerGlobalScope): (WebCore::WorkerGlobalScope::isContextThread const): * workers/WorkerMessagingProxy.cpp: (WebCore::WorkerMessagingProxy::WorkerMessagingProxy): (WebCore::WorkerMessagingProxy::~WorkerMessagingProxy): * workers/WorkerRunLoop.cpp: (WebCore::WorkerRunLoop::runInMode): (WebCore::WorkerRunLoop::runCleanupTasks): * workers/WorkerThread.h: (WebCore::WorkerThread::thread const): (WebCore::WorkerThread::threadID const): Deleted. * workers/service/ServiceWorkerContainer.cpp: (WebCore::ServiceWorkerContainer::~ServiceWorkerContainer): (WebCore::ServiceWorkerContainer::scheduleJob): (WebCore::ServiceWorkerContainer::jobFailedWithException): (WebCore::ServiceWorkerContainer::scheduleTaskToFireUpdateFoundEvent): (WebCore::ServiceWorkerContainer::jobResolvedWithRegistration): (WebCore::ServiceWorkerContainer::jobResolvedWithUnregistrationResult): (WebCore::ServiceWorkerContainer::startScriptFetchForJob): (WebCore::ServiceWorkerContainer::jobFinishedLoadingScript): (WebCore::ServiceWorkerContainer::jobFailedLoadingScript): (WebCore::ServiceWorkerContainer::jobDidFinish): (WebCore::ServiceWorkerContainer::addRegistration): (WebCore::ServiceWorkerContainer::removeRegistration): (WebCore::ServiceWorkerContainer::scheduleTaskToFireControllerChangeEvent): (WebCore::ServiceWorkerContainer::contextIdentifier): * workers/service/ServiceWorkerContainer.h: * workers/service/ServiceWorkerJob.cpp: (WebCore::ServiceWorkerJob::~ServiceWorkerJob): (WebCore::ServiceWorkerJob::failedWithException): (WebCore::ServiceWorkerJob::resolvedWithRegistration): (WebCore::ServiceWorkerJob::resolvedWithUnregistrationResult): (WebCore::ServiceWorkerJob::startScriptFetch): (WebCore::ServiceWorkerJob::fetchScriptWithContext): (WebCore::ServiceWorkerJob::didReceiveResponse): (WebCore::ServiceWorkerJob::notifyFinished): * workers/service/ServiceWorkerJob.h: * xml/parser/XMLDocumentParserLibxml2.cpp: (WebCore::matchFunc): (WebCore::openFunc): (WebCore::initializeXMLParser): (WebCore::XMLParserContext::createStringParser): (WebCore::XMLParserContext::createMemoryParser): Source/WebKit: * UIProcess/API/glib/IconDatabase.cpp: * UIProcess/GenericCallback.h: (WebKit::GenericCallback::~GenericCallback): (WebKit::GenericCallback::performCallbackWithReturnValue): Source/WTF: We should use a pointer of WTF::Thread instead of ThreadIdentifier. One problem is that Windows support library uses WTF::createThread, which returns ThreadIdentifier. So we cannot drop ThreadIdentifier in Windows environment. This patch keeps ThreadIdentifier in Windows. * wtf/MainThread.cpp: (WTF::initializeMainThread): (WTF::isMainThread): (WTF::canAccessThreadLocalDataForThread): * wtf/MainThread.h: * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkCount): * wtf/RecursiveLockAdapter.h: (WTF::RecursiveLockAdapter::lock): (WTF::RecursiveLockAdapter::unlock): (WTF::RecursiveLockAdapter::tryLock): * wtf/Threading.cpp: (WTF::Thread::dump const): * wtf/Threading.h: (WTF::Thread::id const): (WTF::Thread::operator==): Deleted. (WTF::Thread::operator!=): Deleted. (WTF::currentThread): Deleted. * wtf/ThreadingPrimitives.h: * wtf/ThreadingPthreads.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::detach): (WTF::Thread::initializeCurrentTLS): (WTF::Thread::suspend): (WTF::Thread::establishPlatformSpecificHandle): (WTF::Thread::currentID): Deleted. * wtf/ThreadingWin.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::suspend): (WTF::Thread::currentDying): * wtf/mac/MainThreadMac.mm: (WTF::initializeApplicationUIThread): (WTF::initializeWebThreadPlatform): (WTF::canAccessThreadLocalDataForThread): (WTF::initializeApplicationUIThreadIdentifier): Deleted. (WTF::initializeWebThreadIdentifier): Deleted. Tools: * DumpRenderTree/mac/DumpRenderTree.mm: (dumpRenderTree): (runThread): Deleted. (runPthread): Deleted. (testThreadIdentifierMap): Deleted. * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: * TestWebKitAPI/Tests/WTF/Threading.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/196314@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@225470 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-12-04 06:13:05 +00:00
dataLog(toString(Thread::current(), ": dequeueing ", RawPointer(current), " from ", RawPointer(this), "\n"));
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
if (current == queueTail)
queueTail = previous;
WTF::Lock should be fair eventually https://bugs.webkit.org/show_bug.cgi?id=159384 Reviewed by Geoffrey Garen. Source/WTF: In https://webkit.org/blog/6161/locking-in-webkit/ we showed how relaxing the fairness of locks makes them fast. That post presented lock fairness as a trade-off between two extremes: - Barging. A barging lock, like WTF::Lock, releases the lock in unlock() even if there was a thread on the queue. If there was a thread on the queue, the lock is released and that thread is made runnable. That thread may then grab the lock, or some other thread may grab the lock first (it may barge). Usually, the barging thread is the thread that released the lock in the first place. This maximizes throughput but hurts fairness. There is no good theoretical bound on how unfair the lock may become, but empirical data suggests that it's fair enough for the cases we previously measured. - FIFO. A FIFO lock, like HandoffLock in ToyLocks.h, does not release the lock in unlock() if there is a thread waiting. If there is a thread waiting, unlock() will make that thread runnable and inform it that it now holds the lock. This ensures perfect round-robin fairness and allows us to reason theoretically about how long it may take for a thread to grab the lock. For example, if we know that only N threads are running and each one may contend on a critical section, and each one may hold the lock for at most S seconds, then the time it takes to grab the lock is N * S. Unfortunately, FIFO locks perform very badly in most cases. This is because for the common case of short critical sections, they force a context switch after each critical section if the lock is contended. This change makes WTF::Lock almost as fair as FIFO while still being as fast as barging. Thanks to this new algorithm, you can now have both of these things at the same time. This change makes WTF::Lock eventually fair. We can almost (more on the caveats below) guarantee that the time it takes to grab a lock is N * max(1ms, S). In other words, critical sections that are longer than 1ms are always fair. For shorter critical sections, the amount of time that any thread waits is 1ms times the number of threads. There are some caveats that arise from our use of randomness, but even then, in the limit as the critical section length goes to infinity, the lock becomes fair. The corner cases are unlikely to happen; our experiments show that the lock becomes exactly as fair as a FIFO lock for any critical section that is 1ms or longer. The fairness mechanism is broken into two parts. WTF::Lock can now choose to unlock a lock fairly or unfairly thanks to the new ParkingLot token mechanism. WTF::Lock knows when to use fair unlocking based on a timeout mechanism in ParkingLot called timeToBeFair. ParkingLot::unparkOne() and ParkingLot::parkConditionally() can now communicate with each other via a token. unparkOne() can pass a token, which parkConditionally() will return. This change also makes parkConditionally() a lot more precise about when it was unparked due to a call to unparkOne(). If unparkOne() is told that a thread was unparked then this thread is guaranteed to report that it was unparked rather than timing out, and that thread is guaranteed to get the token that unparkOne() passed. The token is an intptr_t. We use it as a boolean variable in WTF::Lock, but you could use it to pass arbitrary data structures. By default, the token is zero. WTF::Lock's unlock() will pass 1 as the token if it is doing fair unlocking. In that case, unlock() will not release the lock, and lock() will know that it holds the lock as soon as parkConditionally() returns. Note that this algorithm relies on unparkOne() invoking WTF::Lock's callback while the queue lock is held, so that WTF::Lock can make a decision about unlock strategy and inject a token while it has complete knowledge over the state of the queue. As such, it's not immediately obvious how to implement this algorithm on top of futexes. You really need ParkingLot! WTF::Lock does not use fair unlocking every time. We expose a new API, Lock::unlockFairly(), which forces the fair unlocking behavior. Additionally, ParkingLot now maintains a per-bucket stochastic fairness timeout. When the timeout fires, the unparkOne() callback sees UnparkResult::timeToBeFair = true. This timeout is set to be anywhere from 0ms to 1ms at random. When a dequeue happens and there are threads that actually get dequeued, we check if the time since the last unfair unlock (the last time timeToBeFair was set to true) is more than the timeout amount. If so, then we set timeToBeFair to true and reset the timeout. This means that in the absence of ParkingLot collisions, unfair unlocking is guaranteed to happen at least once per millisecond. It will happen at 2 KHz on average. If there are collisions, then each collision adds one millisecond to the worst case (and 0.5 ms to the average case). The reason why we don't just use a fixed 1ms timeout is that we want to avoid resonance. Imagine a program in which some thread acquires a lock at 1 KHz in-phase with the timeToBeFair timeout. Then this thread would be the benefactor of fairness to the detriment of everyone else. Randomness ensures that we aren't too fair to any one thread. Empirically, this is neutral on our major benchmarks like JetStream but it's an enormous improvement in LockFairnessTest. It's common for an unfair lock (either our BargingLock, the old WTF::Lock, any of the other futex-based locks that barge, or new os_unfair_lock) to allow only one thread to hold the lock during a whole second in which each thread is holding the lock for 1ms at a time. This is because in a barging lock, releasing a lock after holding it for 1ms and then reacquiring it immediately virtually ensures that none of the other threads can wake up in time to grab it before it's relocked. But the new WTF::Lock handles this case like a champ: each thread gets equal turns. Here's some data. If we launch 10 threads and have each of them run for 1 second while repeatedly holding a critical section for 1ms, then here's how many times each thread gets to hold the lock using the old WTF::Lock algorithm: 799, 6, 1, 1, 1, 1, 1, 1, 1, 1 One thread hogged the lock for almost the whole time! With the new WTF::Lock, the lock becomes totally fair: 80, 79, 79, 79, 79, 79, 79, 80, 80, 79 I don't know of anyone creating such an automatically-fair adaptive lock before, so I think that this is a pretty awesome advancement to the state of the art! This change is good for three reasons: - We do have long critical sections in WebKit and we don't want to have to worry about starvation. This reduces the likelihood that we will see starvation due to our lock strategy. - I was talking to ggaren about bmalloc's locking needs, and he wanted unlockFairly() or lockFairly() or some moral equivalent for the scavenger thread. - If we use a WTF::Lock to manage heap access in a multithreaded GC, we'll need the ability to unlock and relock without barging. * benchmarks/LockFairnessTest.cpp: (main): * benchmarks/ToyLocks.h: * wtf/Condition.h: (WTF::ConditionBase::waitUntil): (WTF::ConditionBase::notifyOne): * wtf/Lock.cpp: (WTF::LockBase::lockSlow): (WTF::LockBase::unlockSlow): (WTF::LockBase::unlockFairlySlow): (WTF::LockBase::unlockSlowImpl): * wtf/Lock.h: (WTF::LockBase::try_lock): (WTF::LockBase::unlock): (WTF::LockBase::unlockFairly): (WTF::LockBase::isHeld): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::compareAndPark): (WTF::ParkingLot::unparkOne): Tools: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Canonical link: https://commits.webkit.org/178039@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@203350 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-07-18 18:32:52 +00:00
didDequeue = true;
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
*currentPtr = current->nextInQueue;
current->nextInQueue = nullptr;
break;
}
}
WTF::Lock should be fair eventually https://bugs.webkit.org/show_bug.cgi?id=159384 Reviewed by Geoffrey Garen. Source/WTF: In https://webkit.org/blog/6161/locking-in-webkit/ we showed how relaxing the fairness of locks makes them fast. That post presented lock fairness as a trade-off between two extremes: - Barging. A barging lock, like WTF::Lock, releases the lock in unlock() even if there was a thread on the queue. If there was a thread on the queue, the lock is released and that thread is made runnable. That thread may then grab the lock, or some other thread may grab the lock first (it may barge). Usually, the barging thread is the thread that released the lock in the first place. This maximizes throughput but hurts fairness. There is no good theoretical bound on how unfair the lock may become, but empirical data suggests that it's fair enough for the cases we previously measured. - FIFO. A FIFO lock, like HandoffLock in ToyLocks.h, does not release the lock in unlock() if there is a thread waiting. If there is a thread waiting, unlock() will make that thread runnable and inform it that it now holds the lock. This ensures perfect round-robin fairness and allows us to reason theoretically about how long it may take for a thread to grab the lock. For example, if we know that only N threads are running and each one may contend on a critical section, and each one may hold the lock for at most S seconds, then the time it takes to grab the lock is N * S. Unfortunately, FIFO locks perform very badly in most cases. This is because for the common case of short critical sections, they force a context switch after each critical section if the lock is contended. This change makes WTF::Lock almost as fair as FIFO while still being as fast as barging. Thanks to this new algorithm, you can now have both of these things at the same time. This change makes WTF::Lock eventually fair. We can almost (more on the caveats below) guarantee that the time it takes to grab a lock is N * max(1ms, S). In other words, critical sections that are longer than 1ms are always fair. For shorter critical sections, the amount of time that any thread waits is 1ms times the number of threads. There are some caveats that arise from our use of randomness, but even then, in the limit as the critical section length goes to infinity, the lock becomes fair. The corner cases are unlikely to happen; our experiments show that the lock becomes exactly as fair as a FIFO lock for any critical section that is 1ms or longer. The fairness mechanism is broken into two parts. WTF::Lock can now choose to unlock a lock fairly or unfairly thanks to the new ParkingLot token mechanism. WTF::Lock knows when to use fair unlocking based on a timeout mechanism in ParkingLot called timeToBeFair. ParkingLot::unparkOne() and ParkingLot::parkConditionally() can now communicate with each other via a token. unparkOne() can pass a token, which parkConditionally() will return. This change also makes parkConditionally() a lot more precise about when it was unparked due to a call to unparkOne(). If unparkOne() is told that a thread was unparked then this thread is guaranteed to report that it was unparked rather than timing out, and that thread is guaranteed to get the token that unparkOne() passed. The token is an intptr_t. We use it as a boolean variable in WTF::Lock, but you could use it to pass arbitrary data structures. By default, the token is zero. WTF::Lock's unlock() will pass 1 as the token if it is doing fair unlocking. In that case, unlock() will not release the lock, and lock() will know that it holds the lock as soon as parkConditionally() returns. Note that this algorithm relies on unparkOne() invoking WTF::Lock's callback while the queue lock is held, so that WTF::Lock can make a decision about unlock strategy and inject a token while it has complete knowledge over the state of the queue. As such, it's not immediately obvious how to implement this algorithm on top of futexes. You really need ParkingLot! WTF::Lock does not use fair unlocking every time. We expose a new API, Lock::unlockFairly(), which forces the fair unlocking behavior. Additionally, ParkingLot now maintains a per-bucket stochastic fairness timeout. When the timeout fires, the unparkOne() callback sees UnparkResult::timeToBeFair = true. This timeout is set to be anywhere from 0ms to 1ms at random. When a dequeue happens and there are threads that actually get dequeued, we check if the time since the last unfair unlock (the last time timeToBeFair was set to true) is more than the timeout amount. If so, then we set timeToBeFair to true and reset the timeout. This means that in the absence of ParkingLot collisions, unfair unlocking is guaranteed to happen at least once per millisecond. It will happen at 2 KHz on average. If there are collisions, then each collision adds one millisecond to the worst case (and 0.5 ms to the average case). The reason why we don't just use a fixed 1ms timeout is that we want to avoid resonance. Imagine a program in which some thread acquires a lock at 1 KHz in-phase with the timeToBeFair timeout. Then this thread would be the benefactor of fairness to the detriment of everyone else. Randomness ensures that we aren't too fair to any one thread. Empirically, this is neutral on our major benchmarks like JetStream but it's an enormous improvement in LockFairnessTest. It's common for an unfair lock (either our BargingLock, the old WTF::Lock, any of the other futex-based locks that barge, or new os_unfair_lock) to allow only one thread to hold the lock during a whole second in which each thread is holding the lock for 1ms at a time. This is because in a barging lock, releasing a lock after holding it for 1ms and then reacquiring it immediately virtually ensures that none of the other threads can wake up in time to grab it before it's relocked. But the new WTF::Lock handles this case like a champ: each thread gets equal turns. Here's some data. If we launch 10 threads and have each of them run for 1 second while repeatedly holding a critical section for 1ms, then here's how many times each thread gets to hold the lock using the old WTF::Lock algorithm: 799, 6, 1, 1, 1, 1, 1, 1, 1, 1 One thread hogged the lock for almost the whole time! With the new WTF::Lock, the lock becomes totally fair: 80, 79, 79, 79, 79, 79, 79, 80, 80, 79 I don't know of anyone creating such an automatically-fair adaptive lock before, so I think that this is a pretty awesome advancement to the state of the art! This change is good for three reasons: - We do have long critical sections in WebKit and we don't want to have to worry about starvation. This reduces the likelihood that we will see starvation due to our lock strategy. - I was talking to ggaren about bmalloc's locking needs, and he wanted unlockFairly() or lockFairly() or some moral equivalent for the scavenger thread. - If we use a WTF::Lock to manage heap access in a multithreaded GC, we'll need the ability to unlock and relock without barging. * benchmarks/LockFairnessTest.cpp: (main): * benchmarks/ToyLocks.h: * wtf/Condition.h: (WTF::ConditionBase::waitUntil): (WTF::ConditionBase::notifyOne): * wtf/Lock.cpp: (WTF::LockBase::lockSlow): (WTF::LockBase::unlockSlow): (WTF::LockBase::unlockFairlySlow): (WTF::LockBase::unlockSlowImpl): * wtf/Lock.h: (WTF::LockBase::try_lock): (WTF::LockBase::unlock): (WTF::LockBase::unlockFairly): (WTF::LockBase::isHeld): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::compareAndPark): (WTF::ParkingLot::unparkOne): Tools: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Canonical link: https://commits.webkit.org/178039@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@203350 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-07-18 18:32:52 +00:00
if (timeToBeFair && didDequeue)
Remove monotonicallyIncreasingTime https://bugs.webkit.org/show_bug.cgi?id=182911 Reviewed by Michael Catanzaro. Source/JavaScriptCore: * debugger/Debugger.cpp: (JSC::Debugger::willEvaluateScript): (JSC::Debugger::didEvaluateScript): * debugger/Debugger.h: * debugger/ScriptProfilingScope.h: * inspector/agents/InspectorDebuggerAgent.cpp: (Inspector::InspectorDebuggerAgent::breakpointActionProbe): * inspector/agents/InspectorHeapAgent.cpp: (Inspector::InspectorHeapAgent::snapshot): (Inspector::InspectorHeapAgent::didGarbageCollect): (Inspector::InspectorHeapAgent::dispatchGarbageCollectedEvent): * inspector/agents/InspectorHeapAgent.h: * inspector/agents/InspectorScriptProfilerAgent.cpp: (Inspector::InspectorScriptProfilerAgent::startTracking): (Inspector::InspectorScriptProfilerAgent::willEvaluateScript): (Inspector::InspectorScriptProfilerAgent::didEvaluateScript): (Inspector::InspectorScriptProfilerAgent::addEvent): (Inspector::buildSamples): * inspector/agents/InspectorScriptProfilerAgent.h: * runtime/SamplingProfiler.cpp: (JSC::SamplingProfiler::takeSample): * runtime/SamplingProfiler.h: Source/WebCore: While generic code uses MonotonicTime, CAAnimation uses media time (CFTimeInterval). At this boundary, we convert MonotonicTime to media time, this is the same logic to the code before this patch. * Modules/gamepad/Gamepad.h: * Modules/mediasource/SourceBuffer.cpp: (WebCore::SourceBuffer::SourceBuffer): (WebCore::SourceBuffer::monitorBufferingRate): * Modules/mediasource/SourceBuffer.h: * Modules/speech/SpeechSynthesis.cpp: (WebCore::SpeechSynthesis::startSpeakingImmediately): (WebCore::SpeechSynthesis::fireEvent): * Modules/speech/SpeechSynthesisUtterance.h: * contentextensions/ContentExtensionCompiler.cpp: (WebCore::ContentExtensions::compileRuleList): * contentextensions/ContentExtensionParser.cpp: (WebCore::ContentExtensions::parseRuleList): * contentextensions/ContentExtensionsBackend.cpp: (WebCore::ContentExtensions::ContentExtensionsBackend::actionsForResourceLoad const): * dom/Element.cpp: (WebCore::Element::setActive): * history/CachedPage.cpp: (WebCore::CachedPage::CachedPage): (WebCore::CachedPage::hasExpired const): * history/CachedPage.h: * html/HTMLMediaElement.cpp: (WebCore::HTMLMediaElement::startProgressEventTimer): (WebCore::HTMLMediaElement::progressEventTimerFired): (WebCore::HTMLMediaElement::refreshCachedTime const): (WebCore::HTMLMediaElement::invalidateCachedTime const): (WebCore::HTMLMediaElement::currentMediaTime const): (WebCore::HTMLMediaElement::startPlaybackProgressTimer): * html/HTMLMediaElement.h: * html/MediaElementSession.cpp: (WebCore::MediaElementSession::removeBehaviorRestriction): (WebCore::MediaElementSession::mostRecentUserInteractionTime const): (WebCore::MediaElementSession::resetPlaybackSessionState): * html/MediaElementSession.h: * html/parser/HTMLParserScheduler.cpp: (WebCore::PumpSession::PumpSession): (WebCore::HTMLParserScheduler::HTMLParserScheduler): * html/parser/HTMLParserScheduler.h: (WebCore::HTMLParserScheduler::checkForYield): * inspector/InspectorCanvas.cpp: (WebCore::InspectorCanvas::recordAction): (WebCore::InspectorCanvas::finalizeFrame): * inspector/InspectorCanvas.h: * inspector/agents/InspectorMemoryAgent.cpp: (WebCore::InspectorMemoryAgent::startTracking): (WebCore::InspectorMemoryAgent::didHandleMemoryPressure): (WebCore::InspectorMemoryAgent::collectSample): * inspector/agents/InspectorNetworkAgent.cpp: (WebCore::InspectorNetworkAgent::buildObjectForTiming): (WebCore::InspectorNetworkAgent::timestamp): (WebCore::InspectorNetworkAgent::didFinishLoading): * inspector/agents/InspectorPageAgent.cpp: (WebCore::InspectorPageAgent::timestamp): * inspector/agents/InspectorTimelineAgent.cpp: (WebCore::InspectorTimelineAgent::timestamp): * inspector/agents/WebHeapAgent.cpp: (WebCore::WebHeapAgent::dispatchGarbageCollectedEvent): * inspector/agents/WebHeapAgent.h: * loader/cache/CachedCSSStyleSheet.cpp: (WebCore::CachedCSSStyleSheet::restoreParsedStyleSheet): * loader/cache/CachedImage.cpp: (WebCore::CachedImage::didDraw): * loader/cache/CachedResource.cpp: (WebCore::CachedResource::didAccessDecodedData): * loader/cache/CachedResource.h: * loader/cache/MemoryCache.cpp: (WebCore::MemoryCache::pruneLiveResourcesToSize): * page/EventHandler.cpp: (WebCore::MaximumDurationTracker::MaximumDurationTracker): (WebCore::MaximumDurationTracker::~MaximumDurationTracker): * page/FocusController.cpp: (WebCore::FocusController::setFocusedElement): (WebCore::FocusController::timeSinceFocusWasSet const): * page/FocusController.h: * page/FrameView.cpp: (WebCore::FrameView::reset): (WebCore::FrameView::willPaintContents): (WebCore::FrameView::didPaintContents): * page/FrameView.h: * page/animation/AnimationBase.cpp: (WebCore::AnimationBase::freezeAtTime): (WebCore::AnimationBase::beginAnimationUpdateTime const): * page/animation/AnimationBase.h: (WebCore::AnimationBase::onAnimationStartResponse): * page/animation/CSSAnimationController.cpp: (WebCore::CSSAnimationControllerPrivate::beginAnimationUpdateTime): (WebCore::CSSAnimationControllerPrivate::receivedStartTimeResponse): (WebCore::CSSAnimationControllerPrivate::startTimeResponse): (WebCore::CSSAnimationController::notifyAnimationStarted): * page/animation/CSSAnimationController.h: * page/animation/CSSAnimationControllerPrivate.h: * page/mac/WheelEventDeltaFilterMac.h: * page/mac/WheelEventDeltaFilterMac.mm: (WebCore::WheelEventDeltaFilterMac::beginFilteringDeltas): (WebCore::WheelEventDeltaFilterMac::updateFromDelta): (WebCore::WheelEventDeltaFilterMac::endFilteringDeltas): * platform/ControlStates.h: (WebCore::ControlStates::timeSinceControlWasFocused const): (WebCore::ControlStates::setTimeSinceControlWasFocused): * platform/PlatformSpeechSynthesisUtterance.h: (WebCore::PlatformSpeechSynthesisUtterance::startTime const): (WebCore::PlatformSpeechSynthesisUtterance::setStartTime): * platform/gamepad/PlatformGamepad.h: (WebCore::PlatformGamepad::lastUpdateTime const): (WebCore::PlatformGamepad::connectTime const): (WebCore::PlatformGamepad::PlatformGamepad): * platform/gamepad/cocoa/GameControllerGamepad.mm: (WebCore::GameControllerGamepad::setupAsExtendedGamepad): (WebCore::GameControllerGamepad::setupAsGamepad): * platform/gamepad/mac/HIDGamepad.cpp: (WebCore::HIDGamepad::HIDGamepad): (WebCore::HIDGamepad::valueChanged): * platform/graphics/GraphicsLayer.cpp: (WebCore::GraphicsLayer::suspendAnimations): * platform/graphics/GraphicsLayer.h: * platform/graphics/GraphicsLayerClient.h: (WebCore::GraphicsLayerClient::notifyAnimationStarted): * platform/graphics/avfoundation/cf/MediaPlayerPrivateAVFoundationCF.cpp: (WebCore::LayerClient::platformCALayerAnimationStarted): (WebCore::AVFWrapper::createImageForTimeInRect): * platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm: (WebCore::MediaPlayerPrivateAVFoundationObjC::createImageForTimeInRect): (WebCore::MediaPlayerPrivateAVFoundationObjC::updateLastImage): * platform/graphics/ca/GraphicsLayerCA.cpp: (WebCore::GraphicsLayerCA::addAnimation): (WebCore::GraphicsLayerCA::pauseAnimation): (WebCore::GraphicsLayerCA::platformCALayerAnimationStarted): (WebCore::GraphicsLayerCA::setAnimationOnLayer): (WebCore::GraphicsLayerCA::pauseCAAnimationOnLayer): (WebCore::GraphicsLayerCA::createAnimationFromKeyframes): (WebCore::GraphicsLayerCA::appendToUncommittedAnimations): (WebCore::GraphicsLayerCA::createTransformAnimationsFromKeyframes): * platform/graphics/ca/GraphicsLayerCA.h: (WebCore::GraphicsLayerCA::LayerPropertyAnimation::LayerPropertyAnimation): (WebCore::GraphicsLayerCA::AnimationProcessingAction::AnimationProcessingAction): * platform/graphics/ca/LayerPool.cpp: (WebCore::LayerPool::LayerPool): (WebCore::LayerPool::addLayer): (WebCore::LayerPool::decayedCapacity const): (WebCore::LayerPool::pruneTimerFired): * platform/graphics/ca/LayerPool.h: * platform/graphics/ca/PlatformCAAnimation.h: * platform/graphics/ca/PlatformCALayer.h: * platform/graphics/ca/PlatformCALayerClient.h: (WebCore::PlatformCALayerClient::platformCALayerAnimationStarted): * platform/graphics/ca/TileGrid.cpp: (WebCore::TileGrid::revalidateTiles): (WebCore::TileGrid::startedNewCohort): (WebCore::TileGrid::TileCohortInfo::timeUntilExpiration): (WebCore::TileGrid::cohortRemovalTimerFired): * platform/graphics/ca/TileGrid.h: (WebCore::TileGrid::TileCohortInfo::TileCohortInfo): * platform/graphics/ca/cocoa/PlatformCALayerCocoa.h: * platform/graphics/ca/cocoa/PlatformCALayerCocoa.mm: (mediaTimeToCurrentTime): (-[WebAnimationDelegate animationDidStart:]): (PlatformCALayerCocoa::animationStarted): * platform/graphics/ca/win/CACFLayerTreeHost.cpp: (WebCore::CACFLayerTreeHost::notifyAnimationsStarted): * platform/graphics/ca/win/PlatformCALayerWin.cpp: (PlatformCALayerWin::animationStarted): (PlatformCALayerWin::layerTreeAsString const): * platform/graphics/ca/win/PlatformCALayerWin.h: * platform/graphics/cocoa/WebCoreDecompressionSession.mm: (WebCore::WebCoreDecompressionSession::decodeSample): * platform/graphics/texmap/BitmapTexturePool.cpp: (WebCore::BitmapTexturePool::releaseUnusedTexturesTimerFired): * platform/graphics/texmap/BitmapTexturePool.h: (WebCore::BitmapTexturePool::Entry::markIsInUse): (WebCore::BitmapTexturePool::Entry::canBeReleased const): (): Deleted. * platform/graphics/texmap/GraphicsLayerTextureMapper.cpp: (WebCore::GraphicsLayerTextureMapper::GraphicsLayerTextureMapper): (WebCore::GraphicsLayerTextureMapper::addAnimation): (WebCore::GraphicsLayerTextureMapper::pauseAnimation): * platform/graphics/texmap/GraphicsLayerTextureMapper.h: * platform/graphics/texmap/TextureMapperAnimation.cpp: (WebCore::TextureMapperAnimation::TextureMapperAnimation): (WebCore::TextureMapperAnimation::apply): (WebCore::TextureMapperAnimation::pause): (WebCore::TextureMapperAnimation::resume): (WebCore::TextureMapperAnimation::computeTotalRunningTime): (WebCore::TextureMapperAnimations::pause): (WebCore::TextureMapperAnimations::suspend): * platform/graphics/texmap/TextureMapperAnimation.h: (WebCore::TextureMapperAnimation::startTime const): (WebCore::TextureMapperAnimation::pauseTime const): * platform/graphics/texmap/TextureMapperFPSCounter.cpp: (WebCore::TextureMapperFPSCounter::TextureMapperFPSCounter): (WebCore::TextureMapperFPSCounter::updateFPSAndDisplay): * platform/graphics/texmap/TextureMapperFPSCounter.h: * platform/graphics/texmap/TextureMapperPlatformLayerBuffer.h: (WebCore::TextureMapperPlatformLayerBuffer::markUsed): (WebCore::TextureMapperPlatformLayerBuffer::lastUsedTime const): (): Deleted. * platform/graphics/texmap/TextureMapperPlatformLayerProxy.cpp: (WebCore::TextureMapperPlatformLayerProxy::releaseUnusedBuffersTimerFired): * platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.cpp: (WebCore::CoordinatedGraphicsLayer::addAnimation): (WebCore::CoordinatedGraphicsLayer::pauseAnimation): (WebCore::CoordinatedGraphicsLayer::suspendAnimations): * platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.h: * platform/mediastream/RealtimeMediaSource.h: * platform/mediastream/RealtimeOutgoingVideoSource.cpp: (WebCore::RealtimeOutgoingVideoSource::sendFrame): * platform/mediastream/libwebrtc/LibWebRTCAudioModule.cpp: (WebCore::LibWebRTCAudioModule::StartPlayoutOnAudioThread): * platform/mediastream/mac/DisplayCaptureSourceCocoa.cpp: (WebCore::DisplayCaptureSourceCocoa::startProducingData): (WebCore::DisplayCaptureSourceCocoa::stopProducingData): (WebCore::DisplayCaptureSourceCocoa::elapsedTime): * platform/mediastream/mac/DisplayCaptureSourceCocoa.h: * platform/mediastream/mac/MockRealtimeAudioSourceMac.h: * platform/mediastream/mac/MockRealtimeAudioSourceMac.mm: (WebCore::MockRealtimeAudioSourceMac::render): * platform/mediastream/mac/MockRealtimeVideoSourceMac.mm: (WebCore::MockRealtimeVideoSourceMac::CMSampleBufferFromPixelBuffer): * platform/mediastream/mac/ScreenDisplayCaptureSourceMac.h: * platform/mediastream/mac/ScreenDisplayCaptureSourceMac.mm: (WebCore::ScreenDisplayCaptureSourceMac::sampleBufferFromPixelBuffer): (WebCore::ScreenDisplayCaptureSourceMac::frameAvailable): * platform/mock/MockRealtimeAudioSource.cpp: (WebCore::MockRealtimeAudioSource::startProducingData): (WebCore::MockRealtimeAudioSource::stopProducingData): (WebCore::MockRealtimeAudioSource::elapsedTime): (WebCore::MockRealtimeAudioSource::tick): (WebCore::MockRealtimeAudioSource::delaySamples): * platform/mock/MockRealtimeAudioSource.h: (WebCore::MockRealtimeAudioSource::render): * platform/mock/MockRealtimeVideoSource.cpp: (WebCore::MockRealtimeVideoSource::startProducingData): (WebCore::MockRealtimeVideoSource::stopProducingData): (WebCore::MockRealtimeVideoSource::elapsedTime): (WebCore::MockRealtimeVideoSource::drawText): (WebCore::MockRealtimeVideoSource::delaySamples): (WebCore::MockRealtimeVideoSource::generateFrame): * platform/mock/MockRealtimeVideoSource.h: * platform/network/DNSResolveQueue.cpp: (WebCore::DNSResolveQueue::DNSResolveQueue): (WebCore::DNSResolveQueue::isUsingProxy): * platform/network/DNSResolveQueue.h: * rendering/RenderBoxModelObject.cpp: (WebCore::RenderBoxModelObject::suspendAnimations): * rendering/RenderBoxModelObject.h: * rendering/RenderElement.cpp: (WebCore::RenderElement::paintFocusRing): * rendering/RenderImage.cpp: (WebCore::RenderImage::paintAreaElementFocusRing): * rendering/RenderLayerBacking.cpp: (WebCore::RenderLayerBacking::notifyAnimationStarted): (WebCore::RenderLayerBacking::suspendAnimations): * rendering/RenderLayerBacking.h: * rendering/RenderLayerCompositor.cpp: (WebCore::RenderLayerCompositor::didPaintBacking): * rendering/RenderProgress.cpp: (WebCore::RenderProgress::RenderProgress): (WebCore::RenderProgress::animationProgress const): (WebCore::RenderProgress::updateAnimationState): * rendering/RenderProgress.h: * rendering/RenderTheme.cpp: (WebCore::RenderTheme::animationDurationForProgressBar const): * rendering/RenderTheme.h: * rendering/RenderThemeGtk.cpp: (WebCore::RenderThemeGtk::animationDurationForProgressBar const): * rendering/RenderThemeGtk.h: * rendering/RenderThemeIOS.h: * rendering/RenderThemeIOS.mm: (WebCore::RenderThemeIOS::animationDurationForProgressBar const): * rendering/RenderThemeMac.h: * rendering/RenderThemeMac.mm: (WebCore::RenderThemeMac::animationDurationForProgressBar const): * svg/animation/SMILTimeContainer.cpp: (WebCore::SMILTimeContainer::SMILTimeContainer): (WebCore::SMILTimeContainer::elapsed const): (WebCore::SMILTimeContainer::isActive const): (WebCore::SMILTimeContainer::isPaused const): (WebCore::SMILTimeContainer::isStarted const): (WebCore::SMILTimeContainer::begin): (WebCore::SMILTimeContainer::pause): (WebCore::SMILTimeContainer::resume): (WebCore::SMILTimeContainer::setElapsed): (WebCore::SMILTimeContainer::timerFired): * svg/animation/SMILTimeContainer.h: * testing/Internals.cpp: (WebCore::Internals::delayMediaStreamTrackSamples): * testing/MockGamepad.cpp: (WebCore::MockGamepad::MockGamepad): (WebCore::MockGamepad::updateDetails): (WebCore::MockGamepad::setAxisValue): (WebCore::MockGamepad::setButtonValue): Source/WebCore/PAL: * pal/system/ClockGeneric.cpp: (PAL::ClockGeneric::currentTime const): (PAL::ClockGeneric::now const): * pal/system/ClockGeneric.h: Source/WebKit: * NetworkProcess/cache/CacheStorageEngineCache.cpp: (WebKit::CacheStorage::Cache::toRecordInformation): * Platform/IPC/ArgumentCoders.cpp: (IPC::ArgumentCoder<Seconds>::encode): (IPC::ArgumentCoder<Seconds>::decode): (IPC::ArgumentCoder<MonotonicTime>::encode): (IPC::ArgumentCoder<MonotonicTime>::decode): * Platform/IPC/ArgumentCoders.h: * Shared/Gamepad/GamepadData.cpp: (WebKit::GamepadData::GamepadData): * Shared/Gamepad/GamepadData.h: (WebKit::GamepadData::lastUpdateTime const): * Shared/WebCoreArgumentCoders.cpp: (IPC::ArgumentCoder<MonotonicTime>::encode): Deleted. (IPC::ArgumentCoder<MonotonicTime>::decode): Deleted. (IPC::ArgumentCoder<Seconds>::encode): Deleted. (IPC::ArgumentCoder<Seconds>::decode): Deleted. ArgumentCoders for MonotonicTime and Seconds are now used internally. Move them to Platform/IPC/ArgumentCoders.h. * Shared/WebCoreArgumentCoders.h: * UIProcess/API/glib/IconDatabase.cpp: (WebKit::IconDatabase::iconDatabaseSyncThread): * UIProcess/DrawingAreaProxyImpl.cpp: (WebKit::DrawingAreaProxyImpl::DrawingMonitor::start): (WebKit::DrawingAreaProxyImpl::DrawingMonitor::stop): (WebKit::DrawingAreaProxyImpl::DrawingMonitor::didDraw): * UIProcess/DrawingAreaProxyImpl.h: * UIProcess/Gamepad/UIGamepad.h: * UIProcess/RemoteLayerTree/RemoteLayerTreeDrawingAreaProxy.h: * UIProcess/RemoteLayerTree/RemoteLayerTreeDrawingAreaProxy.mm: (WebKit::RemoteLayerTreeDrawingAreaProxy::acceleratedAnimationDidStart): * UIProcess/RemoteLayerTree/RemoteLayerTreeHost.h: * UIProcess/RemoteLayerTree/RemoteLayerTreeHost.mm: (WebKit::RemoteLayerTreeHost::animationDidStart): * WebProcess/WebPage/DrawingArea.h: (WebKit::DrawingArea::acceleratedAnimationDidStart): * WebProcess/WebPage/DrawingArea.messages.in: * WebProcess/WebPage/RemoteLayerTree/PlatformCAAnimationRemote.h: * WebProcess/WebPage/RemoteLayerTree/PlatformCAAnimationRemote.mm: (mediaTimeToCurrentTime): (-[WKAnimationDelegate animationDidStart:]): * WebProcess/WebPage/RemoteLayerTree/PlatformCALayerRemote.cpp: (WebKit::PlatformCALayerRemote::animationStarted): This argument `beginTime` is not CFTimeInverval actually. We add currentTimeToMediaTime conversion here to fix this issue. * WebProcess/WebPage/RemoteLayerTree/PlatformCALayerRemote.h: * WebProcess/WebPage/RemoteLayerTree/RemoteLayerTreeContext.h: * WebProcess/WebPage/RemoteLayerTree/RemoteLayerTreeContext.mm: (WebKit::RemoteLayerTreeContext::animationDidStart): * WebProcess/WebPage/RemoteLayerTree/RemoteLayerTreeDrawingArea.h: * WebProcess/WebPage/RemoteLayerTree/RemoteLayerTreeDrawingArea.mm: (WebKit::RemoteLayerTreeDrawingArea::acceleratedAnimationDidStart): * WebProcess/cocoa/WebProcessCocoa.mm: (WebKit::WebProcess::destroyRenderingResources): Source/WebKitLegacy/win: * FullscreenVideoController.cpp: (FullscreenVideoController::LayerClient::platformCALayerAnimationStarted): * Plugins/PluginMessageThrottlerWin.cpp: (WebCore::PluginMessageThrottlerWin::PluginMessageThrottlerWin): (WebCore::PluginMessageThrottlerWin::appendMessage): * Plugins/PluginMessageThrottlerWin.h: * WebView.cpp: (WebView::notifyAnimationStarted): * WebView.h: Source/WTF: This patch drops monotonicallyIncreasingTime and monotonicallyIncreasingTimeMS. We have MonotonicTime API instead. This offers strongly typed MonotonicTime, Seconds etc. This reduces the chance of bugs mixing doubles which represent milliseconds and seconds. Large part of this patch is mechanical one: replacing monotonicallyIncreasingTime with MonotonicTime, using MonotonicTime and Seconds instead of raw doubles. But this patch actually finds some bugs (but it is a bit difficult to show it as a test). One is mixing media time (CACurrentMediaTime()) and MonotonicTime. Basically they are super close because both uses mach_absolute_time(). But they would be slightly different. So we should not mix them. The second bug is GraphicsLayer::suspendAnimations(double). While CA ports (Apple, AppleWin, iOS etc.) use this double as MonotonicTime, GTK and WPE use this double as Seconds (timeOffset). This patch fixes it and now the signature becomes GraphicsLayer::suspendAnimations(MonotonicTime). In this patch, we still uses bunch of double for Seconds. But fixing them at this patch increases the size of this larger and larger. So some of them remains double. This should be fixed in subsequent patches. * benchmarks/ConditionSpeedTest.cpp: * benchmarks/LockSpeedTest.cpp: * wtf/CurrentTime.cpp: (WTF::MonotonicTime::now): (WTF::monotonicallyIncreasingTime): Deleted. * wtf/CurrentTime.h: (WTF::monotonicallyIncreasingTimeMS): Deleted. * wtf/MemoryPressureHandler.h: * wtf/MonotonicTime.cpp: (WTF::MonotonicTime::now): Deleted. * wtf/MonotonicTime.h: * wtf/ParkingLot.cpp: * wtf/Seconds.h: (WTF::Seconds::nan): * wtf/Stopwatch.h: (WTF::Stopwatch::reset): (WTF::Stopwatch::start): (WTF::Stopwatch::stop): (WTF::Stopwatch::elapsedTime): (WTF::Stopwatch::elapsedTimeSince): * wtf/cocoa/MemoryPressureHandlerCocoa.mm: (WTF::MemoryPressureHandler::holdOff): (WTF::MemoryPressureHandler::respondToMemoryPressure): * wtf/linux/MemoryPressureHandlerLinux.cpp: (WTF::MemoryPressureHandler::EventFDPoller::EventFDPoller): (WTF::MemoryPressureHandler::holdOff): (WTF::MemoryPressureHandler::respondToMemoryPressure): * wtf/win/MemoryPressureHandlerWin.cpp: (WTF::MemoryPressureHandler::holdOff): Canonical link: https://commits.webkit.org/198957@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@229174 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2018-03-02 17:13:32 +00:00
nextFairTime = time + Seconds::fromMilliseconds(random.get());
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
ASSERT(!!queueHead == !!queueTail);
}
ThreadData* dequeue()
{
ThreadData* result = nullptr;
genericDequeue(
WTF::Lock should be fair eventually https://bugs.webkit.org/show_bug.cgi?id=159384 Reviewed by Geoffrey Garen. Source/WTF: In https://webkit.org/blog/6161/locking-in-webkit/ we showed how relaxing the fairness of locks makes them fast. That post presented lock fairness as a trade-off between two extremes: - Barging. A barging lock, like WTF::Lock, releases the lock in unlock() even if there was a thread on the queue. If there was a thread on the queue, the lock is released and that thread is made runnable. That thread may then grab the lock, or some other thread may grab the lock first (it may barge). Usually, the barging thread is the thread that released the lock in the first place. This maximizes throughput but hurts fairness. There is no good theoretical bound on how unfair the lock may become, but empirical data suggests that it's fair enough for the cases we previously measured. - FIFO. A FIFO lock, like HandoffLock in ToyLocks.h, does not release the lock in unlock() if there is a thread waiting. If there is a thread waiting, unlock() will make that thread runnable and inform it that it now holds the lock. This ensures perfect round-robin fairness and allows us to reason theoretically about how long it may take for a thread to grab the lock. For example, if we know that only N threads are running and each one may contend on a critical section, and each one may hold the lock for at most S seconds, then the time it takes to grab the lock is N * S. Unfortunately, FIFO locks perform very badly in most cases. This is because for the common case of short critical sections, they force a context switch after each critical section if the lock is contended. This change makes WTF::Lock almost as fair as FIFO while still being as fast as barging. Thanks to this new algorithm, you can now have both of these things at the same time. This change makes WTF::Lock eventually fair. We can almost (more on the caveats below) guarantee that the time it takes to grab a lock is N * max(1ms, S). In other words, critical sections that are longer than 1ms are always fair. For shorter critical sections, the amount of time that any thread waits is 1ms times the number of threads. There are some caveats that arise from our use of randomness, but even then, in the limit as the critical section length goes to infinity, the lock becomes fair. The corner cases are unlikely to happen; our experiments show that the lock becomes exactly as fair as a FIFO lock for any critical section that is 1ms or longer. The fairness mechanism is broken into two parts. WTF::Lock can now choose to unlock a lock fairly or unfairly thanks to the new ParkingLot token mechanism. WTF::Lock knows when to use fair unlocking based on a timeout mechanism in ParkingLot called timeToBeFair. ParkingLot::unparkOne() and ParkingLot::parkConditionally() can now communicate with each other via a token. unparkOne() can pass a token, which parkConditionally() will return. This change also makes parkConditionally() a lot more precise about when it was unparked due to a call to unparkOne(). If unparkOne() is told that a thread was unparked then this thread is guaranteed to report that it was unparked rather than timing out, and that thread is guaranteed to get the token that unparkOne() passed. The token is an intptr_t. We use it as a boolean variable in WTF::Lock, but you could use it to pass arbitrary data structures. By default, the token is zero. WTF::Lock's unlock() will pass 1 as the token if it is doing fair unlocking. In that case, unlock() will not release the lock, and lock() will know that it holds the lock as soon as parkConditionally() returns. Note that this algorithm relies on unparkOne() invoking WTF::Lock's callback while the queue lock is held, so that WTF::Lock can make a decision about unlock strategy and inject a token while it has complete knowledge over the state of the queue. As such, it's not immediately obvious how to implement this algorithm on top of futexes. You really need ParkingLot! WTF::Lock does not use fair unlocking every time. We expose a new API, Lock::unlockFairly(), which forces the fair unlocking behavior. Additionally, ParkingLot now maintains a per-bucket stochastic fairness timeout. When the timeout fires, the unparkOne() callback sees UnparkResult::timeToBeFair = true. This timeout is set to be anywhere from 0ms to 1ms at random. When a dequeue happens and there are threads that actually get dequeued, we check if the time since the last unfair unlock (the last time timeToBeFair was set to true) is more than the timeout amount. If so, then we set timeToBeFair to true and reset the timeout. This means that in the absence of ParkingLot collisions, unfair unlocking is guaranteed to happen at least once per millisecond. It will happen at 2 KHz on average. If there are collisions, then each collision adds one millisecond to the worst case (and 0.5 ms to the average case). The reason why we don't just use a fixed 1ms timeout is that we want to avoid resonance. Imagine a program in which some thread acquires a lock at 1 KHz in-phase with the timeToBeFair timeout. Then this thread would be the benefactor of fairness to the detriment of everyone else. Randomness ensures that we aren't too fair to any one thread. Empirically, this is neutral on our major benchmarks like JetStream but it's an enormous improvement in LockFairnessTest. It's common for an unfair lock (either our BargingLock, the old WTF::Lock, any of the other futex-based locks that barge, or new os_unfair_lock) to allow only one thread to hold the lock during a whole second in which each thread is holding the lock for 1ms at a time. This is because in a barging lock, releasing a lock after holding it for 1ms and then reacquiring it immediately virtually ensures that none of the other threads can wake up in time to grab it before it's relocked. But the new WTF::Lock handles this case like a champ: each thread gets equal turns. Here's some data. If we launch 10 threads and have each of them run for 1 second while repeatedly holding a critical section for 1ms, then here's how many times each thread gets to hold the lock using the old WTF::Lock algorithm: 799, 6, 1, 1, 1, 1, 1, 1, 1, 1 One thread hogged the lock for almost the whole time! With the new WTF::Lock, the lock becomes totally fair: 80, 79, 79, 79, 79, 79, 79, 80, 80, 79 I don't know of anyone creating such an automatically-fair adaptive lock before, so I think that this is a pretty awesome advancement to the state of the art! This change is good for three reasons: - We do have long critical sections in WebKit and we don't want to have to worry about starvation. This reduces the likelihood that we will see starvation due to our lock strategy. - I was talking to ggaren about bmalloc's locking needs, and he wanted unlockFairly() or lockFairly() or some moral equivalent for the scavenger thread. - If we use a WTF::Lock to manage heap access in a multithreaded GC, we'll need the ability to unlock and relock without barging. * benchmarks/LockFairnessTest.cpp: (main): * benchmarks/ToyLocks.h: * wtf/Condition.h: (WTF::ConditionBase::waitUntil): (WTF::ConditionBase::notifyOne): * wtf/Lock.cpp: (WTF::LockBase::lockSlow): (WTF::LockBase::unlockSlow): (WTF::LockBase::unlockFairlySlow): (WTF::LockBase::unlockSlowImpl): * wtf/Lock.h: (WTF::LockBase::try_lock): (WTF::LockBase::unlock): (WTF::LockBase::unlockFairly): (WTF::LockBase::isHeld): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::compareAndPark): (WTF::ParkingLot::unparkOne): Tools: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Canonical link: https://commits.webkit.org/178039@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@203350 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-07-18 18:32:52 +00:00
[&] (ThreadData* element, bool) -> DequeueResult {
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
result = element;
return DequeueResult::RemoveAndStop;
});
return result;
}
ThreadData* queueHead { nullptr };
ThreadData* queueTail { nullptr };
// This lock protects the entire bucket. Thou shall not make changes to Bucket without holding
// this lock.
Always use a byte-sized lock implementation https://bugs.webkit.org/show_bug.cgi?id=147908 Reviewed by Geoffrey Garen. Source/JavaScriptCore: * runtime/ConcurrentJITLock.h: Lock is now byte-sized and ByteLock is gone, so use Lock. Source/WTF: At the start of my locking algorithm crusade, I implemented Lock, which is a sizeof(void*) lock implementation with some nice theoretical properties and good performance. Then I added the ParkingLot abstraction and ByteLock. ParkingLot uses Lock in its implementation. ByteLock uses ParkingLot to create a sizeof(char) lock implementation that performs like Lock. It turns out that ByteLock is always at least as good as Lock, and sometimes a lot better: it requires 8x less memory on 64-bit systems. It's hard to construct a benchmark where ByteLock is significantly slower than Lock, and when you do construct such a benchmark, tweaking it a bit can also create a scenario where ByteLock is significantly faster than Lock. So, the thing that we call "Lock" should really use ByteLock's algorithm, since it is more compact and just as fast. That's what this patch does. But we still need to keep the old Lock algorithm, because it's used to implement ParkingLot, which in turn is used to implement ByteLock. So this patch does this transformation: - Move the algorithm in Lock into files called WordLock.h|cpp. Make ParkingLot use WordLock. - Move the algorithm in ByteLock into Lock.h|cpp. Make everyone who used ByteLock use Lock instead. All other users of Lock now get the byte-sized lock implementation. - Remove the old ByteLock files. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/WordLock.cpp: Added. (WTF::WordLock::lockSlow): (WTF::WordLock::unlockSlow): * wtf/WordLock.h: Added. (WTF::WordLock::WordLock): (WTF::WordLock::lock): (WTF::WordLock::unlock): (WTF::WordLock::isHeld): (WTF::WordLock::isLocked): * wtf/ByteLock.cpp: Removed. * wtf/ByteLock.h: Removed. * wtf/CMakeLists.txt: * wtf/Lock.cpp: (WTF::LockBase::lockSlow): (WTF::LockBase::unlockSlow): * wtf/Lock.h: (WTF::LockBase::lock): (WTF::LockBase::unlock): (WTF::LockBase::isHeld): (WTF::LockBase::isLocked): (WTF::Lock::Lock): * wtf/ParkingLot.cpp: Tools: All previous tests of Lock are now tests of WordLock. All previous tests of ByteLock are now tests of Lock. * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::runLockTest): (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/166025@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188323 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-12 04:20:24 +00:00
WordLock lock;
WTF::Lock should be fair eventually https://bugs.webkit.org/show_bug.cgi?id=159384 Reviewed by Geoffrey Garen. Source/WTF: In https://webkit.org/blog/6161/locking-in-webkit/ we showed how relaxing the fairness of locks makes them fast. That post presented lock fairness as a trade-off between two extremes: - Barging. A barging lock, like WTF::Lock, releases the lock in unlock() even if there was a thread on the queue. If there was a thread on the queue, the lock is released and that thread is made runnable. That thread may then grab the lock, or some other thread may grab the lock first (it may barge). Usually, the barging thread is the thread that released the lock in the first place. This maximizes throughput but hurts fairness. There is no good theoretical bound on how unfair the lock may become, but empirical data suggests that it's fair enough for the cases we previously measured. - FIFO. A FIFO lock, like HandoffLock in ToyLocks.h, does not release the lock in unlock() if there is a thread waiting. If there is a thread waiting, unlock() will make that thread runnable and inform it that it now holds the lock. This ensures perfect round-robin fairness and allows us to reason theoretically about how long it may take for a thread to grab the lock. For example, if we know that only N threads are running and each one may contend on a critical section, and each one may hold the lock for at most S seconds, then the time it takes to grab the lock is N * S. Unfortunately, FIFO locks perform very badly in most cases. This is because for the common case of short critical sections, they force a context switch after each critical section if the lock is contended. This change makes WTF::Lock almost as fair as FIFO while still being as fast as barging. Thanks to this new algorithm, you can now have both of these things at the same time. This change makes WTF::Lock eventually fair. We can almost (more on the caveats below) guarantee that the time it takes to grab a lock is N * max(1ms, S). In other words, critical sections that are longer than 1ms are always fair. For shorter critical sections, the amount of time that any thread waits is 1ms times the number of threads. There are some caveats that arise from our use of randomness, but even then, in the limit as the critical section length goes to infinity, the lock becomes fair. The corner cases are unlikely to happen; our experiments show that the lock becomes exactly as fair as a FIFO lock for any critical section that is 1ms or longer. The fairness mechanism is broken into two parts. WTF::Lock can now choose to unlock a lock fairly or unfairly thanks to the new ParkingLot token mechanism. WTF::Lock knows when to use fair unlocking based on a timeout mechanism in ParkingLot called timeToBeFair. ParkingLot::unparkOne() and ParkingLot::parkConditionally() can now communicate with each other via a token. unparkOne() can pass a token, which parkConditionally() will return. This change also makes parkConditionally() a lot more precise about when it was unparked due to a call to unparkOne(). If unparkOne() is told that a thread was unparked then this thread is guaranteed to report that it was unparked rather than timing out, and that thread is guaranteed to get the token that unparkOne() passed. The token is an intptr_t. We use it as a boolean variable in WTF::Lock, but you could use it to pass arbitrary data structures. By default, the token is zero. WTF::Lock's unlock() will pass 1 as the token if it is doing fair unlocking. In that case, unlock() will not release the lock, and lock() will know that it holds the lock as soon as parkConditionally() returns. Note that this algorithm relies on unparkOne() invoking WTF::Lock's callback while the queue lock is held, so that WTF::Lock can make a decision about unlock strategy and inject a token while it has complete knowledge over the state of the queue. As such, it's not immediately obvious how to implement this algorithm on top of futexes. You really need ParkingLot! WTF::Lock does not use fair unlocking every time. We expose a new API, Lock::unlockFairly(), which forces the fair unlocking behavior. Additionally, ParkingLot now maintains a per-bucket stochastic fairness timeout. When the timeout fires, the unparkOne() callback sees UnparkResult::timeToBeFair = true. This timeout is set to be anywhere from 0ms to 1ms at random. When a dequeue happens and there are threads that actually get dequeued, we check if the time since the last unfair unlock (the last time timeToBeFair was set to true) is more than the timeout amount. If so, then we set timeToBeFair to true and reset the timeout. This means that in the absence of ParkingLot collisions, unfair unlocking is guaranteed to happen at least once per millisecond. It will happen at 2 KHz on average. If there are collisions, then each collision adds one millisecond to the worst case (and 0.5 ms to the average case). The reason why we don't just use a fixed 1ms timeout is that we want to avoid resonance. Imagine a program in which some thread acquires a lock at 1 KHz in-phase with the timeToBeFair timeout. Then this thread would be the benefactor of fairness to the detriment of everyone else. Randomness ensures that we aren't too fair to any one thread. Empirically, this is neutral on our major benchmarks like JetStream but it's an enormous improvement in LockFairnessTest. It's common for an unfair lock (either our BargingLock, the old WTF::Lock, any of the other futex-based locks that barge, or new os_unfair_lock) to allow only one thread to hold the lock during a whole second in which each thread is holding the lock for 1ms at a time. This is because in a barging lock, releasing a lock after holding it for 1ms and then reacquiring it immediately virtually ensures that none of the other threads can wake up in time to grab it before it's relocked. But the new WTF::Lock handles this case like a champ: each thread gets equal turns. Here's some data. If we launch 10 threads and have each of them run for 1 second while repeatedly holding a critical section for 1ms, then here's how many times each thread gets to hold the lock using the old WTF::Lock algorithm: 799, 6, 1, 1, 1, 1, 1, 1, 1, 1 One thread hogged the lock for almost the whole time! With the new WTF::Lock, the lock becomes totally fair: 80, 79, 79, 79, 79, 79, 79, 80, 80, 79 I don't know of anyone creating such an automatically-fair adaptive lock before, so I think that this is a pretty awesome advancement to the state of the art! This change is good for three reasons: - We do have long critical sections in WebKit and we don't want to have to worry about starvation. This reduces the likelihood that we will see starvation due to our lock strategy. - I was talking to ggaren about bmalloc's locking needs, and he wanted unlockFairly() or lockFairly() or some moral equivalent for the scavenger thread. - If we use a WTF::Lock to manage heap access in a multithreaded GC, we'll need the ability to unlock and relock without barging. * benchmarks/LockFairnessTest.cpp: (main): * benchmarks/ToyLocks.h: * wtf/Condition.h: (WTF::ConditionBase::waitUntil): (WTF::ConditionBase::notifyOne): * wtf/Lock.cpp: (WTF::LockBase::lockSlow): (WTF::LockBase::unlockSlow): (WTF::LockBase::unlockFairlySlow): (WTF::LockBase::unlockSlowImpl): * wtf/Lock.h: (WTF::LockBase::try_lock): (WTF::LockBase::unlock): (WTF::LockBase::unlockFairly): (WTF::LockBase::isHeld): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::compareAndPark): (WTF::ParkingLot::unparkOne): Tools: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Canonical link: https://commits.webkit.org/178039@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@203350 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-07-18 18:32:52 +00:00
Remove monotonicallyIncreasingTime https://bugs.webkit.org/show_bug.cgi?id=182911 Reviewed by Michael Catanzaro. Source/JavaScriptCore: * debugger/Debugger.cpp: (JSC::Debugger::willEvaluateScript): (JSC::Debugger::didEvaluateScript): * debugger/Debugger.h: * debugger/ScriptProfilingScope.h: * inspector/agents/InspectorDebuggerAgent.cpp: (Inspector::InspectorDebuggerAgent::breakpointActionProbe): * inspector/agents/InspectorHeapAgent.cpp: (Inspector::InspectorHeapAgent::snapshot): (Inspector::InspectorHeapAgent::didGarbageCollect): (Inspector::InspectorHeapAgent::dispatchGarbageCollectedEvent): * inspector/agents/InspectorHeapAgent.h: * inspector/agents/InspectorScriptProfilerAgent.cpp: (Inspector::InspectorScriptProfilerAgent::startTracking): (Inspector::InspectorScriptProfilerAgent::willEvaluateScript): (Inspector::InspectorScriptProfilerAgent::didEvaluateScript): (Inspector::InspectorScriptProfilerAgent::addEvent): (Inspector::buildSamples): * inspector/agents/InspectorScriptProfilerAgent.h: * runtime/SamplingProfiler.cpp: (JSC::SamplingProfiler::takeSample): * runtime/SamplingProfiler.h: Source/WebCore: While generic code uses MonotonicTime, CAAnimation uses media time (CFTimeInterval). At this boundary, we convert MonotonicTime to media time, this is the same logic to the code before this patch. * Modules/gamepad/Gamepad.h: * Modules/mediasource/SourceBuffer.cpp: (WebCore::SourceBuffer::SourceBuffer): (WebCore::SourceBuffer::monitorBufferingRate): * Modules/mediasource/SourceBuffer.h: * Modules/speech/SpeechSynthesis.cpp: (WebCore::SpeechSynthesis::startSpeakingImmediately): (WebCore::SpeechSynthesis::fireEvent): * Modules/speech/SpeechSynthesisUtterance.h: * contentextensions/ContentExtensionCompiler.cpp: (WebCore::ContentExtensions::compileRuleList): * contentextensions/ContentExtensionParser.cpp: (WebCore::ContentExtensions::parseRuleList): * contentextensions/ContentExtensionsBackend.cpp: (WebCore::ContentExtensions::ContentExtensionsBackend::actionsForResourceLoad const): * dom/Element.cpp: (WebCore::Element::setActive): * history/CachedPage.cpp: (WebCore::CachedPage::CachedPage): (WebCore::CachedPage::hasExpired const): * history/CachedPage.h: * html/HTMLMediaElement.cpp: (WebCore::HTMLMediaElement::startProgressEventTimer): (WebCore::HTMLMediaElement::progressEventTimerFired): (WebCore::HTMLMediaElement::refreshCachedTime const): (WebCore::HTMLMediaElement::invalidateCachedTime const): (WebCore::HTMLMediaElement::currentMediaTime const): (WebCore::HTMLMediaElement::startPlaybackProgressTimer): * html/HTMLMediaElement.h: * html/MediaElementSession.cpp: (WebCore::MediaElementSession::removeBehaviorRestriction): (WebCore::MediaElementSession::mostRecentUserInteractionTime const): (WebCore::MediaElementSession::resetPlaybackSessionState): * html/MediaElementSession.h: * html/parser/HTMLParserScheduler.cpp: (WebCore::PumpSession::PumpSession): (WebCore::HTMLParserScheduler::HTMLParserScheduler): * html/parser/HTMLParserScheduler.h: (WebCore::HTMLParserScheduler::checkForYield): * inspector/InspectorCanvas.cpp: (WebCore::InspectorCanvas::recordAction): (WebCore::InspectorCanvas::finalizeFrame): * inspector/InspectorCanvas.h: * inspector/agents/InspectorMemoryAgent.cpp: (WebCore::InspectorMemoryAgent::startTracking): (WebCore::InspectorMemoryAgent::didHandleMemoryPressure): (WebCore::InspectorMemoryAgent::collectSample): * inspector/agents/InspectorNetworkAgent.cpp: (WebCore::InspectorNetworkAgent::buildObjectForTiming): (WebCore::InspectorNetworkAgent::timestamp): (WebCore::InspectorNetworkAgent::didFinishLoading): * inspector/agents/InspectorPageAgent.cpp: (WebCore::InspectorPageAgent::timestamp): * inspector/agents/InspectorTimelineAgent.cpp: (WebCore::InspectorTimelineAgent::timestamp): * inspector/agents/WebHeapAgent.cpp: (WebCore::WebHeapAgent::dispatchGarbageCollectedEvent): * inspector/agents/WebHeapAgent.h: * loader/cache/CachedCSSStyleSheet.cpp: (WebCore::CachedCSSStyleSheet::restoreParsedStyleSheet): * loader/cache/CachedImage.cpp: (WebCore::CachedImage::didDraw): * loader/cache/CachedResource.cpp: (WebCore::CachedResource::didAccessDecodedData): * loader/cache/CachedResource.h: * loader/cache/MemoryCache.cpp: (WebCore::MemoryCache::pruneLiveResourcesToSize): * page/EventHandler.cpp: (WebCore::MaximumDurationTracker::MaximumDurationTracker): (WebCore::MaximumDurationTracker::~MaximumDurationTracker): * page/FocusController.cpp: (WebCore::FocusController::setFocusedElement): (WebCore::FocusController::timeSinceFocusWasSet const): * page/FocusController.h: * page/FrameView.cpp: (WebCore::FrameView::reset): (WebCore::FrameView::willPaintContents): (WebCore::FrameView::didPaintContents): * page/FrameView.h: * page/animation/AnimationBase.cpp: (WebCore::AnimationBase::freezeAtTime): (WebCore::AnimationBase::beginAnimationUpdateTime const): * page/animation/AnimationBase.h: (WebCore::AnimationBase::onAnimationStartResponse): * page/animation/CSSAnimationController.cpp: (WebCore::CSSAnimationControllerPrivate::beginAnimationUpdateTime): (WebCore::CSSAnimationControllerPrivate::receivedStartTimeResponse): (WebCore::CSSAnimationControllerPrivate::startTimeResponse): (WebCore::CSSAnimationController::notifyAnimationStarted): * page/animation/CSSAnimationController.h: * page/animation/CSSAnimationControllerPrivate.h: * page/mac/WheelEventDeltaFilterMac.h: * page/mac/WheelEventDeltaFilterMac.mm: (WebCore::WheelEventDeltaFilterMac::beginFilteringDeltas): (WebCore::WheelEventDeltaFilterMac::updateFromDelta): (WebCore::WheelEventDeltaFilterMac::endFilteringDeltas): * platform/ControlStates.h: (WebCore::ControlStates::timeSinceControlWasFocused const): (WebCore::ControlStates::setTimeSinceControlWasFocused): * platform/PlatformSpeechSynthesisUtterance.h: (WebCore::PlatformSpeechSynthesisUtterance::startTime const): (WebCore::PlatformSpeechSynthesisUtterance::setStartTime): * platform/gamepad/PlatformGamepad.h: (WebCore::PlatformGamepad::lastUpdateTime const): (WebCore::PlatformGamepad::connectTime const): (WebCore::PlatformGamepad::PlatformGamepad): * platform/gamepad/cocoa/GameControllerGamepad.mm: (WebCore::GameControllerGamepad::setupAsExtendedGamepad): (WebCore::GameControllerGamepad::setupAsGamepad): * platform/gamepad/mac/HIDGamepad.cpp: (WebCore::HIDGamepad::HIDGamepad): (WebCore::HIDGamepad::valueChanged): * platform/graphics/GraphicsLayer.cpp: (WebCore::GraphicsLayer::suspendAnimations): * platform/graphics/GraphicsLayer.h: * platform/graphics/GraphicsLayerClient.h: (WebCore::GraphicsLayerClient::notifyAnimationStarted): * platform/graphics/avfoundation/cf/MediaPlayerPrivateAVFoundationCF.cpp: (WebCore::LayerClient::platformCALayerAnimationStarted): (WebCore::AVFWrapper::createImageForTimeInRect): * platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm: (WebCore::MediaPlayerPrivateAVFoundationObjC::createImageForTimeInRect): (WebCore::MediaPlayerPrivateAVFoundationObjC::updateLastImage): * platform/graphics/ca/GraphicsLayerCA.cpp: (WebCore::GraphicsLayerCA::addAnimation): (WebCore::GraphicsLayerCA::pauseAnimation): (WebCore::GraphicsLayerCA::platformCALayerAnimationStarted): (WebCore::GraphicsLayerCA::setAnimationOnLayer): (WebCore::GraphicsLayerCA::pauseCAAnimationOnLayer): (WebCore::GraphicsLayerCA::createAnimationFromKeyframes): (WebCore::GraphicsLayerCA::appendToUncommittedAnimations): (WebCore::GraphicsLayerCA::createTransformAnimationsFromKeyframes): * platform/graphics/ca/GraphicsLayerCA.h: (WebCore::GraphicsLayerCA::LayerPropertyAnimation::LayerPropertyAnimation): (WebCore::GraphicsLayerCA::AnimationProcessingAction::AnimationProcessingAction): * platform/graphics/ca/LayerPool.cpp: (WebCore::LayerPool::LayerPool): (WebCore::LayerPool::addLayer): (WebCore::LayerPool::decayedCapacity const): (WebCore::LayerPool::pruneTimerFired): * platform/graphics/ca/LayerPool.h: * platform/graphics/ca/PlatformCAAnimation.h: * platform/graphics/ca/PlatformCALayer.h: * platform/graphics/ca/PlatformCALayerClient.h: (WebCore::PlatformCALayerClient::platformCALayerAnimationStarted): * platform/graphics/ca/TileGrid.cpp: (WebCore::TileGrid::revalidateTiles): (WebCore::TileGrid::startedNewCohort): (WebCore::TileGrid::TileCohortInfo::timeUntilExpiration): (WebCore::TileGrid::cohortRemovalTimerFired): * platform/graphics/ca/TileGrid.h: (WebCore::TileGrid::TileCohortInfo::TileCohortInfo): * platform/graphics/ca/cocoa/PlatformCALayerCocoa.h: * platform/graphics/ca/cocoa/PlatformCALayerCocoa.mm: (mediaTimeToCurrentTime): (-[WebAnimationDelegate animationDidStart:]): (PlatformCALayerCocoa::animationStarted): * platform/graphics/ca/win/CACFLayerTreeHost.cpp: (WebCore::CACFLayerTreeHost::notifyAnimationsStarted): * platform/graphics/ca/win/PlatformCALayerWin.cpp: (PlatformCALayerWin::animationStarted): (PlatformCALayerWin::layerTreeAsString const): * platform/graphics/ca/win/PlatformCALayerWin.h: * platform/graphics/cocoa/WebCoreDecompressionSession.mm: (WebCore::WebCoreDecompressionSession::decodeSample): * platform/graphics/texmap/BitmapTexturePool.cpp: (WebCore::BitmapTexturePool::releaseUnusedTexturesTimerFired): * platform/graphics/texmap/BitmapTexturePool.h: (WebCore::BitmapTexturePool::Entry::markIsInUse): (WebCore::BitmapTexturePool::Entry::canBeReleased const): (): Deleted. * platform/graphics/texmap/GraphicsLayerTextureMapper.cpp: (WebCore::GraphicsLayerTextureMapper::GraphicsLayerTextureMapper): (WebCore::GraphicsLayerTextureMapper::addAnimation): (WebCore::GraphicsLayerTextureMapper::pauseAnimation): * platform/graphics/texmap/GraphicsLayerTextureMapper.h: * platform/graphics/texmap/TextureMapperAnimation.cpp: (WebCore::TextureMapperAnimation::TextureMapperAnimation): (WebCore::TextureMapperAnimation::apply): (WebCore::TextureMapperAnimation::pause): (WebCore::TextureMapperAnimation::resume): (WebCore::TextureMapperAnimation::computeTotalRunningTime): (WebCore::TextureMapperAnimations::pause): (WebCore::TextureMapperAnimations::suspend): * platform/graphics/texmap/TextureMapperAnimation.h: (WebCore::TextureMapperAnimation::startTime const): (WebCore::TextureMapperAnimation::pauseTime const): * platform/graphics/texmap/TextureMapperFPSCounter.cpp: (WebCore::TextureMapperFPSCounter::TextureMapperFPSCounter): (WebCore::TextureMapperFPSCounter::updateFPSAndDisplay): * platform/graphics/texmap/TextureMapperFPSCounter.h: * platform/graphics/texmap/TextureMapperPlatformLayerBuffer.h: (WebCore::TextureMapperPlatformLayerBuffer::markUsed): (WebCore::TextureMapperPlatformLayerBuffer::lastUsedTime const): (): Deleted. * platform/graphics/texmap/TextureMapperPlatformLayerProxy.cpp: (WebCore::TextureMapperPlatformLayerProxy::releaseUnusedBuffersTimerFired): * platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.cpp: (WebCore::CoordinatedGraphicsLayer::addAnimation): (WebCore::CoordinatedGraphicsLayer::pauseAnimation): (WebCore::CoordinatedGraphicsLayer::suspendAnimations): * platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.h: * platform/mediastream/RealtimeMediaSource.h: * platform/mediastream/RealtimeOutgoingVideoSource.cpp: (WebCore::RealtimeOutgoingVideoSource::sendFrame): * platform/mediastream/libwebrtc/LibWebRTCAudioModule.cpp: (WebCore::LibWebRTCAudioModule::StartPlayoutOnAudioThread): * platform/mediastream/mac/DisplayCaptureSourceCocoa.cpp: (WebCore::DisplayCaptureSourceCocoa::startProducingData): (WebCore::DisplayCaptureSourceCocoa::stopProducingData): (WebCore::DisplayCaptureSourceCocoa::elapsedTime): * platform/mediastream/mac/DisplayCaptureSourceCocoa.h: * platform/mediastream/mac/MockRealtimeAudioSourceMac.h: * platform/mediastream/mac/MockRealtimeAudioSourceMac.mm: (WebCore::MockRealtimeAudioSourceMac::render): * platform/mediastream/mac/MockRealtimeVideoSourceMac.mm: (WebCore::MockRealtimeVideoSourceMac::CMSampleBufferFromPixelBuffer): * platform/mediastream/mac/ScreenDisplayCaptureSourceMac.h: * platform/mediastream/mac/ScreenDisplayCaptureSourceMac.mm: (WebCore::ScreenDisplayCaptureSourceMac::sampleBufferFromPixelBuffer): (WebCore::ScreenDisplayCaptureSourceMac::frameAvailable): * platform/mock/MockRealtimeAudioSource.cpp: (WebCore::MockRealtimeAudioSource::startProducingData): (WebCore::MockRealtimeAudioSource::stopProducingData): (WebCore::MockRealtimeAudioSource::elapsedTime): (WebCore::MockRealtimeAudioSource::tick): (WebCore::MockRealtimeAudioSource::delaySamples): * platform/mock/MockRealtimeAudioSource.h: (WebCore::MockRealtimeAudioSource::render): * platform/mock/MockRealtimeVideoSource.cpp: (WebCore::MockRealtimeVideoSource::startProducingData): (WebCore::MockRealtimeVideoSource::stopProducingData): (WebCore::MockRealtimeVideoSource::elapsedTime): (WebCore::MockRealtimeVideoSource::drawText): (WebCore::MockRealtimeVideoSource::delaySamples): (WebCore::MockRealtimeVideoSource::generateFrame): * platform/mock/MockRealtimeVideoSource.h: * platform/network/DNSResolveQueue.cpp: (WebCore::DNSResolveQueue::DNSResolveQueue): (WebCore::DNSResolveQueue::isUsingProxy): * platform/network/DNSResolveQueue.h: * rendering/RenderBoxModelObject.cpp: (WebCore::RenderBoxModelObject::suspendAnimations): * rendering/RenderBoxModelObject.h: * rendering/RenderElement.cpp: (WebCore::RenderElement::paintFocusRing): * rendering/RenderImage.cpp: (WebCore::RenderImage::paintAreaElementFocusRing): * rendering/RenderLayerBacking.cpp: (WebCore::RenderLayerBacking::notifyAnimationStarted): (WebCore::RenderLayerBacking::suspendAnimations): * rendering/RenderLayerBacking.h: * rendering/RenderLayerCompositor.cpp: (WebCore::RenderLayerCompositor::didPaintBacking): * rendering/RenderProgress.cpp: (WebCore::RenderProgress::RenderProgress): (WebCore::RenderProgress::animationProgress const): (WebCore::RenderProgress::updateAnimationState): * rendering/RenderProgress.h: * rendering/RenderTheme.cpp: (WebCore::RenderTheme::animationDurationForProgressBar const): * rendering/RenderTheme.h: * rendering/RenderThemeGtk.cpp: (WebCore::RenderThemeGtk::animationDurationForProgressBar const): * rendering/RenderThemeGtk.h: * rendering/RenderThemeIOS.h: * rendering/RenderThemeIOS.mm: (WebCore::RenderThemeIOS::animationDurationForProgressBar const): * rendering/RenderThemeMac.h: * rendering/RenderThemeMac.mm: (WebCore::RenderThemeMac::animationDurationForProgressBar const): * svg/animation/SMILTimeContainer.cpp: (WebCore::SMILTimeContainer::SMILTimeContainer): (WebCore::SMILTimeContainer::elapsed const): (WebCore::SMILTimeContainer::isActive const): (WebCore::SMILTimeContainer::isPaused const): (WebCore::SMILTimeContainer::isStarted const): (WebCore::SMILTimeContainer::begin): (WebCore::SMILTimeContainer::pause): (WebCore::SMILTimeContainer::resume): (WebCore::SMILTimeContainer::setElapsed): (WebCore::SMILTimeContainer::timerFired): * svg/animation/SMILTimeContainer.h: * testing/Internals.cpp: (WebCore::Internals::delayMediaStreamTrackSamples): * testing/MockGamepad.cpp: (WebCore::MockGamepad::MockGamepad): (WebCore::MockGamepad::updateDetails): (WebCore::MockGamepad::setAxisValue): (WebCore::MockGamepad::setButtonValue): Source/WebCore/PAL: * pal/system/ClockGeneric.cpp: (PAL::ClockGeneric::currentTime const): (PAL::ClockGeneric::now const): * pal/system/ClockGeneric.h: Source/WebKit: * NetworkProcess/cache/CacheStorageEngineCache.cpp: (WebKit::CacheStorage::Cache::toRecordInformation): * Platform/IPC/ArgumentCoders.cpp: (IPC::ArgumentCoder<Seconds>::encode): (IPC::ArgumentCoder<Seconds>::decode): (IPC::ArgumentCoder<MonotonicTime>::encode): (IPC::ArgumentCoder<MonotonicTime>::decode): * Platform/IPC/ArgumentCoders.h: * Shared/Gamepad/GamepadData.cpp: (WebKit::GamepadData::GamepadData): * Shared/Gamepad/GamepadData.h: (WebKit::GamepadData::lastUpdateTime const): * Shared/WebCoreArgumentCoders.cpp: (IPC::ArgumentCoder<MonotonicTime>::encode): Deleted. (IPC::ArgumentCoder<MonotonicTime>::decode): Deleted. (IPC::ArgumentCoder<Seconds>::encode): Deleted. (IPC::ArgumentCoder<Seconds>::decode): Deleted. ArgumentCoders for MonotonicTime and Seconds are now used internally. Move them to Platform/IPC/ArgumentCoders.h. * Shared/WebCoreArgumentCoders.h: * UIProcess/API/glib/IconDatabase.cpp: (WebKit::IconDatabase::iconDatabaseSyncThread): * UIProcess/DrawingAreaProxyImpl.cpp: (WebKit::DrawingAreaProxyImpl::DrawingMonitor::start): (WebKit::DrawingAreaProxyImpl::DrawingMonitor::stop): (WebKit::DrawingAreaProxyImpl::DrawingMonitor::didDraw): * UIProcess/DrawingAreaProxyImpl.h: * UIProcess/Gamepad/UIGamepad.h: * UIProcess/RemoteLayerTree/RemoteLayerTreeDrawingAreaProxy.h: * UIProcess/RemoteLayerTree/RemoteLayerTreeDrawingAreaProxy.mm: (WebKit::RemoteLayerTreeDrawingAreaProxy::acceleratedAnimationDidStart): * UIProcess/RemoteLayerTree/RemoteLayerTreeHost.h: * UIProcess/RemoteLayerTree/RemoteLayerTreeHost.mm: (WebKit::RemoteLayerTreeHost::animationDidStart): * WebProcess/WebPage/DrawingArea.h: (WebKit::DrawingArea::acceleratedAnimationDidStart): * WebProcess/WebPage/DrawingArea.messages.in: * WebProcess/WebPage/RemoteLayerTree/PlatformCAAnimationRemote.h: * WebProcess/WebPage/RemoteLayerTree/PlatformCAAnimationRemote.mm: (mediaTimeToCurrentTime): (-[WKAnimationDelegate animationDidStart:]): * WebProcess/WebPage/RemoteLayerTree/PlatformCALayerRemote.cpp: (WebKit::PlatformCALayerRemote::animationStarted): This argument `beginTime` is not CFTimeInverval actually. We add currentTimeToMediaTime conversion here to fix this issue. * WebProcess/WebPage/RemoteLayerTree/PlatformCALayerRemote.h: * WebProcess/WebPage/RemoteLayerTree/RemoteLayerTreeContext.h: * WebProcess/WebPage/RemoteLayerTree/RemoteLayerTreeContext.mm: (WebKit::RemoteLayerTreeContext::animationDidStart): * WebProcess/WebPage/RemoteLayerTree/RemoteLayerTreeDrawingArea.h: * WebProcess/WebPage/RemoteLayerTree/RemoteLayerTreeDrawingArea.mm: (WebKit::RemoteLayerTreeDrawingArea::acceleratedAnimationDidStart): * WebProcess/cocoa/WebProcessCocoa.mm: (WebKit::WebProcess::destroyRenderingResources): Source/WebKitLegacy/win: * FullscreenVideoController.cpp: (FullscreenVideoController::LayerClient::platformCALayerAnimationStarted): * Plugins/PluginMessageThrottlerWin.cpp: (WebCore::PluginMessageThrottlerWin::PluginMessageThrottlerWin): (WebCore::PluginMessageThrottlerWin::appendMessage): * Plugins/PluginMessageThrottlerWin.h: * WebView.cpp: (WebView::notifyAnimationStarted): * WebView.h: Source/WTF: This patch drops monotonicallyIncreasingTime and monotonicallyIncreasingTimeMS. We have MonotonicTime API instead. This offers strongly typed MonotonicTime, Seconds etc. This reduces the chance of bugs mixing doubles which represent milliseconds and seconds. Large part of this patch is mechanical one: replacing monotonicallyIncreasingTime with MonotonicTime, using MonotonicTime and Seconds instead of raw doubles. But this patch actually finds some bugs (but it is a bit difficult to show it as a test). One is mixing media time (CACurrentMediaTime()) and MonotonicTime. Basically they are super close because both uses mach_absolute_time(). But they would be slightly different. So we should not mix them. The second bug is GraphicsLayer::suspendAnimations(double). While CA ports (Apple, AppleWin, iOS etc.) use this double as MonotonicTime, GTK and WPE use this double as Seconds (timeOffset). This patch fixes it and now the signature becomes GraphicsLayer::suspendAnimations(MonotonicTime). In this patch, we still uses bunch of double for Seconds. But fixing them at this patch increases the size of this larger and larger. So some of them remains double. This should be fixed in subsequent patches. * benchmarks/ConditionSpeedTest.cpp: * benchmarks/LockSpeedTest.cpp: * wtf/CurrentTime.cpp: (WTF::MonotonicTime::now): (WTF::monotonicallyIncreasingTime): Deleted. * wtf/CurrentTime.h: (WTF::monotonicallyIncreasingTimeMS): Deleted. * wtf/MemoryPressureHandler.h: * wtf/MonotonicTime.cpp: (WTF::MonotonicTime::now): Deleted. * wtf/MonotonicTime.h: * wtf/ParkingLot.cpp: * wtf/Seconds.h: (WTF::Seconds::nan): * wtf/Stopwatch.h: (WTF::Stopwatch::reset): (WTF::Stopwatch::start): (WTF::Stopwatch::stop): (WTF::Stopwatch::elapsedTime): (WTF::Stopwatch::elapsedTimeSince): * wtf/cocoa/MemoryPressureHandlerCocoa.mm: (WTF::MemoryPressureHandler::holdOff): (WTF::MemoryPressureHandler::respondToMemoryPressure): * wtf/linux/MemoryPressureHandlerLinux.cpp: (WTF::MemoryPressureHandler::EventFDPoller::EventFDPoller): (WTF::MemoryPressureHandler::holdOff): (WTF::MemoryPressureHandler::respondToMemoryPressure): * wtf/win/MemoryPressureHandlerWin.cpp: (WTF::MemoryPressureHandler::holdOff): Canonical link: https://commits.webkit.org/198957@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@229174 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2018-03-02 17:13:32 +00:00
MonotonicTime nextFairTime;
WTF::Lock should be fair eventually https://bugs.webkit.org/show_bug.cgi?id=159384 Reviewed by Geoffrey Garen. Source/WTF: In https://webkit.org/blog/6161/locking-in-webkit/ we showed how relaxing the fairness of locks makes them fast. That post presented lock fairness as a trade-off between two extremes: - Barging. A barging lock, like WTF::Lock, releases the lock in unlock() even if there was a thread on the queue. If there was a thread on the queue, the lock is released and that thread is made runnable. That thread may then grab the lock, or some other thread may grab the lock first (it may barge). Usually, the barging thread is the thread that released the lock in the first place. This maximizes throughput but hurts fairness. There is no good theoretical bound on how unfair the lock may become, but empirical data suggests that it's fair enough for the cases we previously measured. - FIFO. A FIFO lock, like HandoffLock in ToyLocks.h, does not release the lock in unlock() if there is a thread waiting. If there is a thread waiting, unlock() will make that thread runnable and inform it that it now holds the lock. This ensures perfect round-robin fairness and allows us to reason theoretically about how long it may take for a thread to grab the lock. For example, if we know that only N threads are running and each one may contend on a critical section, and each one may hold the lock for at most S seconds, then the time it takes to grab the lock is N * S. Unfortunately, FIFO locks perform very badly in most cases. This is because for the common case of short critical sections, they force a context switch after each critical section if the lock is contended. This change makes WTF::Lock almost as fair as FIFO while still being as fast as barging. Thanks to this new algorithm, you can now have both of these things at the same time. This change makes WTF::Lock eventually fair. We can almost (more on the caveats below) guarantee that the time it takes to grab a lock is N * max(1ms, S). In other words, critical sections that are longer than 1ms are always fair. For shorter critical sections, the amount of time that any thread waits is 1ms times the number of threads. There are some caveats that arise from our use of randomness, but even then, in the limit as the critical section length goes to infinity, the lock becomes fair. The corner cases are unlikely to happen; our experiments show that the lock becomes exactly as fair as a FIFO lock for any critical section that is 1ms or longer. The fairness mechanism is broken into two parts. WTF::Lock can now choose to unlock a lock fairly or unfairly thanks to the new ParkingLot token mechanism. WTF::Lock knows when to use fair unlocking based on a timeout mechanism in ParkingLot called timeToBeFair. ParkingLot::unparkOne() and ParkingLot::parkConditionally() can now communicate with each other via a token. unparkOne() can pass a token, which parkConditionally() will return. This change also makes parkConditionally() a lot more precise about when it was unparked due to a call to unparkOne(). If unparkOne() is told that a thread was unparked then this thread is guaranteed to report that it was unparked rather than timing out, and that thread is guaranteed to get the token that unparkOne() passed. The token is an intptr_t. We use it as a boolean variable in WTF::Lock, but you could use it to pass arbitrary data structures. By default, the token is zero. WTF::Lock's unlock() will pass 1 as the token if it is doing fair unlocking. In that case, unlock() will not release the lock, and lock() will know that it holds the lock as soon as parkConditionally() returns. Note that this algorithm relies on unparkOne() invoking WTF::Lock's callback while the queue lock is held, so that WTF::Lock can make a decision about unlock strategy and inject a token while it has complete knowledge over the state of the queue. As such, it's not immediately obvious how to implement this algorithm on top of futexes. You really need ParkingLot! WTF::Lock does not use fair unlocking every time. We expose a new API, Lock::unlockFairly(), which forces the fair unlocking behavior. Additionally, ParkingLot now maintains a per-bucket stochastic fairness timeout. When the timeout fires, the unparkOne() callback sees UnparkResult::timeToBeFair = true. This timeout is set to be anywhere from 0ms to 1ms at random. When a dequeue happens and there are threads that actually get dequeued, we check if the time since the last unfair unlock (the last time timeToBeFair was set to true) is more than the timeout amount. If so, then we set timeToBeFair to true and reset the timeout. This means that in the absence of ParkingLot collisions, unfair unlocking is guaranteed to happen at least once per millisecond. It will happen at 2 KHz on average. If there are collisions, then each collision adds one millisecond to the worst case (and 0.5 ms to the average case). The reason why we don't just use a fixed 1ms timeout is that we want to avoid resonance. Imagine a program in which some thread acquires a lock at 1 KHz in-phase with the timeToBeFair timeout. Then this thread would be the benefactor of fairness to the detriment of everyone else. Randomness ensures that we aren't too fair to any one thread. Empirically, this is neutral on our major benchmarks like JetStream but it's an enormous improvement in LockFairnessTest. It's common for an unfair lock (either our BargingLock, the old WTF::Lock, any of the other futex-based locks that barge, or new os_unfair_lock) to allow only one thread to hold the lock during a whole second in which each thread is holding the lock for 1ms at a time. This is because in a barging lock, releasing a lock after holding it for 1ms and then reacquiring it immediately virtually ensures that none of the other threads can wake up in time to grab it before it's relocked. But the new WTF::Lock handles this case like a champ: each thread gets equal turns. Here's some data. If we launch 10 threads and have each of them run for 1 second while repeatedly holding a critical section for 1ms, then here's how many times each thread gets to hold the lock using the old WTF::Lock algorithm: 799, 6, 1, 1, 1, 1, 1, 1, 1, 1 One thread hogged the lock for almost the whole time! With the new WTF::Lock, the lock becomes totally fair: 80, 79, 79, 79, 79, 79, 79, 80, 80, 79 I don't know of anyone creating such an automatically-fair adaptive lock before, so I think that this is a pretty awesome advancement to the state of the art! This change is good for three reasons: - We do have long critical sections in WebKit and we don't want to have to worry about starvation. This reduces the likelihood that we will see starvation due to our lock strategy. - I was talking to ggaren about bmalloc's locking needs, and he wanted unlockFairly() or lockFairly() or some moral equivalent for the scavenger thread. - If we use a WTF::Lock to manage heap access in a multithreaded GC, we'll need the ability to unlock and relock without barging. * benchmarks/LockFairnessTest.cpp: (main): * benchmarks/ToyLocks.h: * wtf/Condition.h: (WTF::ConditionBase::waitUntil): (WTF::ConditionBase::notifyOne): * wtf/Lock.cpp: (WTF::LockBase::lockSlow): (WTF::LockBase::unlockSlow): (WTF::LockBase::unlockFairlySlow): (WTF::LockBase::unlockSlowImpl): * wtf/Lock.h: (WTF::LockBase::try_lock): (WTF::LockBase::unlock): (WTF::LockBase::unlockFairly): (WTF::LockBase::isHeld): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::compareAndPark): (WTF::ParkingLot::unparkOne): Tools: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Canonical link: https://commits.webkit.org/178039@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@203350 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-07-18 18:32:52 +00:00
WeakRandom random;
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
// Put some distane between buckets in memory. This is one of several mitigations against false
// sharing.
char padding[64];
};
Silence leaks in ParkingLot https://bugs.webkit.org/show_bug.cgi?id=155510 Reviewed by Alexey Proskuryakov. ParkingLot has a concurrent hashtable that it reallocates on demand. It will not reallocate it in steady state. The hashtable is sized to accommodate the high watermark of the number of active threads - so long as the program doesn't just keep starting an unbounded number of threads that are all active, the hashtable will stop resizing. Each resize operation is designed to stay out of the way of the data-access-parallel normal path, in which two threads operating on different lock addresses don't have to synchronize. To do this, it simply drops the old hashtable without deleting it, so that threads that were still using it don't crash. They will realize that they have the wrong hashtable before doing anything bad, but we don't have a way of proving when all of those threads are no longer going to read from the old hashtables. So, we just leak them. This is a bounded leak, since the hashtable resizes exponentially. Thus the total memory utilization of all hashtables, including the leaked ones, converges to a linear function of the current hashtable's size (it's 2 * size of current hashtable). But this leak is a problem for leaks tools, which will always report this leak. This is not useful. It's better to silence the leak. That's what this patch does by ensuring that all hashtables, including leaked ones, end up in a global vector. This is perf-neutral. This requires making a StaticWordLock variant of WordLock. That's probably the biggest part of this change. * wtf/ParkingLot.cpp: * wtf/WordLock.cpp: (WTF::WordLockBase::lockSlow): (WTF::WordLockBase::unlockSlow): (WTF::WordLock::lockSlow): Deleted. (WTF::WordLock::unlockSlow): Deleted. * wtf/WordLock.h: (WTF::WordLockBase::lock): (WTF::WordLockBase::isLocked): (WTF::WordLock::WordLock): (WTF::WordLock::lock): Deleted. (WTF::WordLock::isLocked): Deleted. Canonical link: https://commits.webkit.org/173707@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@198345 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-03-17 18:54:15 +00:00
struct Hashtable;
// We track all allocated hashtables so that hashtable resizing doesn't anger leak detectors.
Vector<Hashtable*>* hashtables;
[WTF] Remove StaticLock https://bugs.webkit.org/show_bug.cgi?id=184332 Reviewed by Mark Lam. Source/JavaScriptCore: * API/JSValue.mm: (handerForStructTag): * API/JSVirtualMachine.mm: (+[JSVMWrapperCache addWrapper:forJSContextGroupRef:]): (+[JSVMWrapperCache wrapperForJSContextGroupRef:]): * API/glib/JSCVirtualMachine.cpp: (addWrapper): (removeWrapper): * assembler/testmasm.cpp: * b3/air/testair.cpp: * b3/testb3.cpp: * bytecode/SuperSampler.cpp: * dfg/DFGCommon.cpp: * dfg/DFGCommonData.cpp: * dynbench.cpp: * heap/MachineStackMarker.cpp: (JSC::MachineThreads::tryCopyOtherThreadStacks): * inspector/remote/cocoa/RemoteConnectionToTargetCocoa.mm: (Inspector::RemoteTargetHandleRunSourceGlobal): (Inspector::RemoteTargetQueueTaskOnGlobalQueue): * interpreter/CLoopStack.cpp: * parser/SourceProvider.cpp: * profiler/ProfilerDatabase.cpp: * profiler/ProfilerUID.cpp: (JSC::Profiler::UID::create): * runtime/IntlObject.cpp: (JSC::numberingSystemsForLocale): * runtime/JSLock.cpp: * runtime/JSLock.h: * runtime/SamplingProfiler.cpp: (JSC::SamplingProfiler::registerForReportAtExit): * runtime/VM.cpp: * wasm/WasmFaultSignalHandler.cpp: Source/WebCore: No behavior change. * Modules/webdatabase/Database.cpp: (WebCore::Database::Database): (WebCore::Database::performOpenAndVerify): (WebCore::Database::closeDatabase): (WebCore::Database::getCachedVersion const): (WebCore::Database::setCachedVersion): * Modules/webdatabase/DatabaseTracker.cpp: (WebCore::DatabaseTracker::openDatabaseMutex): * Modules/webdatabase/DatabaseTracker.h: * Modules/websockets/WebSocket.cpp: (WebCore::WebSocket::allActiveWebSocketsMutex): * Modules/websockets/WebSocket.h: * bridge/objc/WebScriptObject.mm: * crypto/CryptoAlgorithmRegistry.cpp: (WebCore::CryptoAlgorithmRegistry::identifier): (WebCore::CryptoAlgorithmRegistry::name): (WebCore::CryptoAlgorithmRegistry::create): (WebCore::CryptoAlgorithmRegistry::registerAlgorithm): * dom/Node.cpp: * platform/URL.cpp: * platform/graphics/FontCache.cpp: * platform/graphics/MediaPlayer.cpp: * platform/ios/QuickLook.mm: * platform/ios/WebSQLiteDatabaseTrackerClient.mm: * platform/ios/wak/WebCoreThread.mm: * platform/ios/wak/WebCoreThreadRun.cpp: * platform/network/cf/LoaderRunLoopCF.cpp: (WebCore::loaderRunLoop): * platform/network/curl/CurlContext.cpp: (WebCore::CurlShareHandle::mutexFor): * platform/network/curl/CurlContext.h: * platform/sql/SQLiteDatabaseTracker.cpp: (WebCore::SQLiteDatabaseTracker::incrementTransactionInProgressCount): (WebCore::SQLiteDatabaseTracker::decrementTransactionInProgressCount): * platform/text/TextEncodingRegistry.cpp: (WebCore::buildBaseTextCodecMaps): (WebCore::newTextCodec): (WebCore::atomicCanonicalTextEncodingName): * workers/WorkerThread.cpp: (WebCore::WorkerThread::workerThreadCount): (WebCore::WorkerThread::WorkerThread): (WebCore::WorkerThread::~WorkerThread): (WebCore::WorkerThread::releaseFastMallocFreeMemoryInAllThreads): Source/WebKitLegacy/ios: * WebCoreSupport/WebFixedPositionContent.mm: Source/WebKitLegacy/mac: * DOM/DOMInternal.mm: (getDOMWrapper): (addDOMWrapper): (removeDOMWrapper): Source/WebKitLegacy/win: * WebKitQuartzCoreAdditions/CAView.cpp: (WKQCA::CAView::releaseAllD3DResources): * WebLocalizableStrings.cpp: Source/WTF: Now, WTF::StaticLock is `using StaticLock = Lock`. Lock just works in either static storage and dynamic storage. Remove StaticLock and always use Lock. We also remove StaticWordLock and StaticReadWriteLock. And we add WTF::RecursiveLock, which is RecursiveLockAdapter<Lock>. * wtf/HashTable.cpp: (WTF::HashTableStats::recordCollisionAtCount): (WTF::HashTableStats::dumpStats): * wtf/Language.cpp: (WTF::userPreferredLanguages): * wtf/Lock.h: * wtf/MainThread.cpp: (WTF::dispatchFunctionsFromMainThread): (WTF::callOnMainThread): * wtf/ParkingLot.cpp: * wtf/ReadWriteLock.h: * wtf/RecursiveLockAdapter.h: * wtf/StackStats.cpp: (WTF::StackStats::CheckPoint::CheckPoint): (WTF::StackStats::CheckPoint::~CheckPoint): (WTF::StackStats::probe): (WTF::StackStats::LayoutCheckPoint::LayoutCheckPoint): (WTF::StackStats::LayoutCheckPoint::~LayoutCheckPoint): * wtf/StackStats.h: * wtf/ThreadMessage.cpp: (WTF::sendMessageScoped): * wtf/ThreadingPthreads.cpp: * wtf/ThreadingWin.cpp: * wtf/WordLock.h: * wtf/cf/LanguageCF.cpp: (WTF::languagePreferencesDidChange): (WTF::platformUserPreferredLanguages): * wtf/dtoa.cpp: * wtf/text/AtomicStringImpl.cpp: * wtf/text/StringView.cpp: (WTF::StringView::invalidate): (WTF::StringView::adoptUnderlyingString): (WTF::StringView::setUnderlyingString): * wtf/unicode/icu/CollatorICU.cpp: (WTF::Collator::Collator): (WTF::Collator::~Collator): * wtf/win/LanguageWin.cpp: (WTF::platformLanguage): Tools: * DumpRenderTree/JavaScriptThreading.cpp: Canonical link: https://commits.webkit.org/199887@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@230303 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2018-04-05 17:22:21 +00:00
WordLock hashtablesLock;
Silence leaks in ParkingLot https://bugs.webkit.org/show_bug.cgi?id=155510 Reviewed by Alexey Proskuryakov. ParkingLot has a concurrent hashtable that it reallocates on demand. It will not reallocate it in steady state. The hashtable is sized to accommodate the high watermark of the number of active threads - so long as the program doesn't just keep starting an unbounded number of threads that are all active, the hashtable will stop resizing. Each resize operation is designed to stay out of the way of the data-access-parallel normal path, in which two threads operating on different lock addresses don't have to synchronize. To do this, it simply drops the old hashtable without deleting it, so that threads that were still using it don't crash. They will realize that they have the wrong hashtable before doing anything bad, but we don't have a way of proving when all of those threads are no longer going to read from the old hashtables. So, we just leak them. This is a bounded leak, since the hashtable resizes exponentially. Thus the total memory utilization of all hashtables, including the leaked ones, converges to a linear function of the current hashtable's size (it's 2 * size of current hashtable). But this leak is a problem for leaks tools, which will always report this leak. This is not useful. It's better to silence the leak. That's what this patch does by ensuring that all hashtables, including leaked ones, end up in a global vector. This is perf-neutral. This requires making a StaticWordLock variant of WordLock. That's probably the biggest part of this change. * wtf/ParkingLot.cpp: * wtf/WordLock.cpp: (WTF::WordLockBase::lockSlow): (WTF::WordLockBase::unlockSlow): (WTF::WordLock::lockSlow): Deleted. (WTF::WordLock::unlockSlow): Deleted. * wtf/WordLock.h: (WTF::WordLockBase::lock): (WTF::WordLockBase::isLocked): (WTF::WordLock::WordLock): (WTF::WordLock::lock): Deleted. (WTF::WordLock::isLocked): Deleted. Canonical link: https://commits.webkit.org/173707@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@198345 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-03-17 18:54:15 +00:00
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
struct Hashtable {
unsigned size;
Atomic<Bucket*> data[1];
static Hashtable* create(unsigned size)
{
ASSERT(size >= 1);
Hashtable* result = static_cast<Hashtable*>(
fastZeroedMalloc(sizeof(Hashtable) + sizeof(Atomic<Bucket*>) * (size - 1)));
result->size = size;
Silence leaks in ParkingLot https://bugs.webkit.org/show_bug.cgi?id=155510 Reviewed by Alexey Proskuryakov. ParkingLot has a concurrent hashtable that it reallocates on demand. It will not reallocate it in steady state. The hashtable is sized to accommodate the high watermark of the number of active threads - so long as the program doesn't just keep starting an unbounded number of threads that are all active, the hashtable will stop resizing. Each resize operation is designed to stay out of the way of the data-access-parallel normal path, in which two threads operating on different lock addresses don't have to synchronize. To do this, it simply drops the old hashtable without deleting it, so that threads that were still using it don't crash. They will realize that they have the wrong hashtable before doing anything bad, but we don't have a way of proving when all of those threads are no longer going to read from the old hashtables. So, we just leak them. This is a bounded leak, since the hashtable resizes exponentially. Thus the total memory utilization of all hashtables, including the leaked ones, converges to a linear function of the current hashtable's size (it's 2 * size of current hashtable). But this leak is a problem for leaks tools, which will always report this leak. This is not useful. It's better to silence the leak. That's what this patch does by ensuring that all hashtables, including leaked ones, end up in a global vector. This is perf-neutral. This requires making a StaticWordLock variant of WordLock. That's probably the biggest part of this change. * wtf/ParkingLot.cpp: * wtf/WordLock.cpp: (WTF::WordLockBase::lockSlow): (WTF::WordLockBase::unlockSlow): (WTF::WordLock::lockSlow): Deleted. (WTF::WordLock::unlockSlow): Deleted. * wtf/WordLock.h: (WTF::WordLockBase::lock): (WTF::WordLockBase::isLocked): (WTF::WordLock::WordLock): (WTF::WordLock::lock): Deleted. (WTF::WordLock::isLocked): Deleted. Canonical link: https://commits.webkit.org/173707@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@198345 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-03-17 18:54:15 +00:00
{
// This is not fast and it's not data-access parallel, but that's fine, because
// hashtable resizing is guaranteed to be rare and it will never happen in steady
// state.
WordLockHolder locker(hashtablesLock);
if (!hashtables)
hashtables = new Vector<Hashtable*>();
hashtables->append(result);
}
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
return result;
}
static void destroy(Hashtable* hashtable)
{
Silence leaks in ParkingLot https://bugs.webkit.org/show_bug.cgi?id=155510 Reviewed by Alexey Proskuryakov. ParkingLot has a concurrent hashtable that it reallocates on demand. It will not reallocate it in steady state. The hashtable is sized to accommodate the high watermark of the number of active threads - so long as the program doesn't just keep starting an unbounded number of threads that are all active, the hashtable will stop resizing. Each resize operation is designed to stay out of the way of the data-access-parallel normal path, in which two threads operating on different lock addresses don't have to synchronize. To do this, it simply drops the old hashtable without deleting it, so that threads that were still using it don't crash. They will realize that they have the wrong hashtable before doing anything bad, but we don't have a way of proving when all of those threads are no longer going to read from the old hashtables. So, we just leak them. This is a bounded leak, since the hashtable resizes exponentially. Thus the total memory utilization of all hashtables, including the leaked ones, converges to a linear function of the current hashtable's size (it's 2 * size of current hashtable). But this leak is a problem for leaks tools, which will always report this leak. This is not useful. It's better to silence the leak. That's what this patch does by ensuring that all hashtables, including leaked ones, end up in a global vector. This is perf-neutral. This requires making a StaticWordLock variant of WordLock. That's probably the biggest part of this change. * wtf/ParkingLot.cpp: * wtf/WordLock.cpp: (WTF::WordLockBase::lockSlow): (WTF::WordLockBase::unlockSlow): (WTF::WordLock::lockSlow): Deleted. (WTF::WordLock::unlockSlow): Deleted. * wtf/WordLock.h: (WTF::WordLockBase::lock): (WTF::WordLockBase::isLocked): (WTF::WordLock::WordLock): (WTF::WordLock::lock): Deleted. (WTF::WordLock::isLocked): Deleted. Canonical link: https://commits.webkit.org/173707@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@198345 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-03-17 18:54:15 +00:00
{
// This is not fast, but that's OK. See comment in create().
WordLockHolder locker(hashtablesLock);
hashtables->removeFirst(hashtable);
}
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
fastFree(hashtable);
}
};
Atomic<Hashtable*> hashtable;
Atomic<unsigned> numThreads;
// With 64 bytes of padding per bucket, assuming a hashtable is fully populated with buckets, the
// memory usage per thread will still be less than 1KB.
const unsigned maxLoadFactor = 3;
const unsigned growthFactor = 2;
unsigned hashAddress(const void* address)
{
return WTF::PtrHash<const void*>::hash(address);
}
WTF::Lock should not suffer from the thundering herd https://bugs.webkit.org/show_bug.cgi?id=147947 Reviewed by Geoffrey Garen. Source/WTF: This changes Lock::unlockSlow() to use unparkOne() instead of unparkAll(). The problem with doing this is that it's not obvious after calling unparkOne() if there are any other threads that are still parked on the lock's queue. If we assume that there are and leave the hasParkedBit set, then future calls to unlock() will take the slow path. We don't want that if there aren't actually any threads parked. On the other hand, if we assume that there aren't any threads parked and clear the hasParkedBit, then if there actually were some threads parked, then they may never be awoken since future calls to unlock() won't take slow path and so won't call unparkOne(). In other words, we need a way to be very precise about when we clear the hasParkedBit and we need to do it in a race-free way: it can't be the case that we clear the bit just as some thread gets parked on the queue. A similar problem arises in futexes, and one of the solutions is to have a thread that acquires a lock after parking sets the hasParkedBit. This is what Rusty Russel's usersem does. It's a subtle algorithm. Also, it means that if a thread barges in before the unparked thread runs, then that barging thread will not know that there are threads parked. This could increase the severity of barging. Since ParkingLot is a user-level API, we don't have to worry about the kernel-user security issues and so we can expose callbacks while ParkingLot is holding its internal locks. This change does exactly that for unparkOne(). The new variant of unparkOne() will call a user function while the queue from which we are unparking is locked. The callback is told basic stats about the queue: did we unpark a thread this time, and could there be more threads to unpark in the future. The callback runs while it's impossible for the queue state to change, since the ParkingLot's internal locks for the queue is held. This means that Lock::unlockSlow() can either clear, or leave, the hasParkedBit while releasing the lock inside the callback from unparkOne(). This takes care of the thundering herd problem while also reducing the greed that arises from barging threads. This required some careful reworking of the ParkingLot algorithm. The first thing I noticed was that the ThreadData::shouldPark flag was useless, since it's set exactly when ThreadData::address is non-null. Then I had to make sure that dequeue() could lazily create both hashtables and buckets, since the "callback is called while queue is locked" invariant requires that we didn't exit early due to the hashtable or bucket not being present. Note that all of this is done in such a way that the old unparkOne() and unparkAll() don't have to create any buckets, though they now may create the hashtable. We don't care as much about the hashtable being created by unpark since it's just such an unlikely scenario and it would only happen once. This change reduces the kernel CPU usage of WTF::Lock for the long critical section test by about 8x and makes it always perform as well as WTF::WordLock and WTF::Mutex for that benchmark. * benchmarks/LockSpeedTest.cpp: * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): * wtf/Lock.h: (WTF::LockBase::isLocked): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: * wtf/WordLock.h: (WTF::WordLock::isLocked): (WTF::WordLock::isFullyReset): Tools: Add testing that checks that locks return to a pristine state after contention is over. * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::LockInspector::isFullyReset): (TestWebKitAPI::runLockTest): (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/166072@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188374 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 03:51:25 +00:00
Hashtable* ensureHashtable()
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
{
for (;;) {
WTF::Lock should not suffer from the thundering herd https://bugs.webkit.org/show_bug.cgi?id=147947 Reviewed by Geoffrey Garen. Source/WTF: This changes Lock::unlockSlow() to use unparkOne() instead of unparkAll(). The problem with doing this is that it's not obvious after calling unparkOne() if there are any other threads that are still parked on the lock's queue. If we assume that there are and leave the hasParkedBit set, then future calls to unlock() will take the slow path. We don't want that if there aren't actually any threads parked. On the other hand, if we assume that there aren't any threads parked and clear the hasParkedBit, then if there actually were some threads parked, then they may never be awoken since future calls to unlock() won't take slow path and so won't call unparkOne(). In other words, we need a way to be very precise about when we clear the hasParkedBit and we need to do it in a race-free way: it can't be the case that we clear the bit just as some thread gets parked on the queue. A similar problem arises in futexes, and one of the solutions is to have a thread that acquires a lock after parking sets the hasParkedBit. This is what Rusty Russel's usersem does. It's a subtle algorithm. Also, it means that if a thread barges in before the unparked thread runs, then that barging thread will not know that there are threads parked. This could increase the severity of barging. Since ParkingLot is a user-level API, we don't have to worry about the kernel-user security issues and so we can expose callbacks while ParkingLot is holding its internal locks. This change does exactly that for unparkOne(). The new variant of unparkOne() will call a user function while the queue from which we are unparking is locked. The callback is told basic stats about the queue: did we unpark a thread this time, and could there be more threads to unpark in the future. The callback runs while it's impossible for the queue state to change, since the ParkingLot's internal locks for the queue is held. This means that Lock::unlockSlow() can either clear, or leave, the hasParkedBit while releasing the lock inside the callback from unparkOne(). This takes care of the thundering herd problem while also reducing the greed that arises from barging threads. This required some careful reworking of the ParkingLot algorithm. The first thing I noticed was that the ThreadData::shouldPark flag was useless, since it's set exactly when ThreadData::address is non-null. Then I had to make sure that dequeue() could lazily create both hashtables and buckets, since the "callback is called while queue is locked" invariant requires that we didn't exit early due to the hashtable or bucket not being present. Note that all of this is done in such a way that the old unparkOne() and unparkAll() don't have to create any buckets, though they now may create the hashtable. We don't care as much about the hashtable being created by unpark since it's just such an unlikely scenario and it would only happen once. This change reduces the kernel CPU usage of WTF::Lock for the long critical section test by about 8x and makes it always perform as well as WTF::WordLock and WTF::Mutex for that benchmark. * benchmarks/LockSpeedTest.cpp: * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): * wtf/Lock.h: (WTF::LockBase::isLocked): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: * wtf/WordLock.h: (WTF::WordLock::isLocked): (WTF::WordLock::isFullyReset): Tools: Add testing that checks that locks return to a pristine state after contention is over. * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::LockInspector::isFullyReset): (TestWebKitAPI::runLockTest): (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/166072@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188374 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 03:51:25 +00:00
Hashtable* currentHashtable = hashtable.load();
if (currentHashtable)
return currentHashtable;
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
if (!currentHashtable) {
currentHashtable = Hashtable::create(maxLoadFactor);
WTF::Lock should not suffer from the thundering herd https://bugs.webkit.org/show_bug.cgi?id=147947 Reviewed by Geoffrey Garen. Source/WTF: This changes Lock::unlockSlow() to use unparkOne() instead of unparkAll(). The problem with doing this is that it's not obvious after calling unparkOne() if there are any other threads that are still parked on the lock's queue. If we assume that there are and leave the hasParkedBit set, then future calls to unlock() will take the slow path. We don't want that if there aren't actually any threads parked. On the other hand, if we assume that there aren't any threads parked and clear the hasParkedBit, then if there actually were some threads parked, then they may never be awoken since future calls to unlock() won't take slow path and so won't call unparkOne(). In other words, we need a way to be very precise about when we clear the hasParkedBit and we need to do it in a race-free way: it can't be the case that we clear the bit just as some thread gets parked on the queue. A similar problem arises in futexes, and one of the solutions is to have a thread that acquires a lock after parking sets the hasParkedBit. This is what Rusty Russel's usersem does. It's a subtle algorithm. Also, it means that if a thread barges in before the unparked thread runs, then that barging thread will not know that there are threads parked. This could increase the severity of barging. Since ParkingLot is a user-level API, we don't have to worry about the kernel-user security issues and so we can expose callbacks while ParkingLot is holding its internal locks. This change does exactly that for unparkOne(). The new variant of unparkOne() will call a user function while the queue from which we are unparking is locked. The callback is told basic stats about the queue: did we unpark a thread this time, and could there be more threads to unpark in the future. The callback runs while it's impossible for the queue state to change, since the ParkingLot's internal locks for the queue is held. This means that Lock::unlockSlow() can either clear, or leave, the hasParkedBit while releasing the lock inside the callback from unparkOne(). This takes care of the thundering herd problem while also reducing the greed that arises from barging threads. This required some careful reworking of the ParkingLot algorithm. The first thing I noticed was that the ThreadData::shouldPark flag was useless, since it's set exactly when ThreadData::address is non-null. Then I had to make sure that dequeue() could lazily create both hashtables and buckets, since the "callback is called while queue is locked" invariant requires that we didn't exit early due to the hashtable or bucket not being present. Note that all of this is done in such a way that the old unparkOne() and unparkAll() don't have to create any buckets, though they now may create the hashtable. We don't care as much about the hashtable being created by unpark since it's just such an unlikely scenario and it would only happen once. This change reduces the kernel CPU usage of WTF::Lock for the long critical section test by about 8x and makes it always perform as well as WTF::WordLock and WTF::Mutex for that benchmark. * benchmarks/LockSpeedTest.cpp: * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): * wtf/Lock.h: (WTF::LockBase::isLocked): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: * wtf/WordLock.h: (WTF::WordLock::isLocked): (WTF::WordLock::isFullyReset): Tools: Add testing that checks that locks return to a pristine state after contention is over. * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::LockInspector::isFullyReset): (TestWebKitAPI::runLockTest): (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/166072@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188374 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 03:51:25 +00:00
if (hashtable.compareExchangeWeak(nullptr, currentHashtable)) {
if (verbose)
WTF shouldn't have both Thread and ThreadIdentifier https://bugs.webkit.org/show_bug.cgi?id=180308 Reviewed by Darin Adler. Source/JavaScriptCore: * heap/MachineStackMarker.cpp: (JSC::MachineThreads::tryCopyOtherThreadStacks): * llint/LLIntSlowPaths.cpp: (JSC::LLInt::llint_trace_operand): (JSC::LLInt::llint_trace_value): (JSC::LLInt::LLINT_SLOW_PATH_DECL): (JSC::LLInt::traceFunctionPrologue): * runtime/ExceptionScope.cpp: (JSC::ExceptionScope::unexpectedExceptionMessage): * runtime/JSLock.h: (JSC::JSLock::currentThreadIsHoldingLock): * runtime/VM.cpp: (JSC::VM::throwException): * runtime/VM.h: (JSC::VM::throwingThread const): (JSC::VM::clearException): * tools/HeapVerifier.cpp: (JSC::HeapVerifier::printVerificationHeader): Source/WebCore: No behavior change. * Modules/indexeddb/IDBActiveDOMObject.h: (WebCore::IDBActiveDOMObject::originThread const): (WebCore::IDBActiveDOMObject::performCallbackOnOriginThread): (WebCore::IDBActiveDOMObject::callFunctionOnOriginThread): (WebCore::IDBActiveDOMObject::originThreadID const): Deleted. * Modules/indexeddb/IDBCursor.cpp: (WebCore::IDBCursor::IDBCursor): (WebCore::IDBCursor::~IDBCursor): (WebCore::IDBCursor::sourcesDeleted const): (WebCore::IDBCursor::transaction const): (WebCore::IDBCursor::update): (WebCore::IDBCursor::advance): (WebCore::IDBCursor::continueFunction): (WebCore::IDBCursor::uncheckedIterateCursor): (WebCore::IDBCursor::deleteFunction): (WebCore::IDBCursor::setGetResult): * Modules/indexeddb/IDBDatabase.cpp: (WebCore::IDBDatabase::~IDBDatabase): (WebCore::IDBDatabase::hasPendingActivity const): (WebCore::IDBDatabase::name const): (WebCore::IDBDatabase::version const): (WebCore::IDBDatabase::objectStoreNames const): (WebCore::IDBDatabase::renameObjectStore): (WebCore::IDBDatabase::renameIndex): (WebCore::IDBDatabase::createObjectStore): (WebCore::IDBDatabase::transaction): (WebCore::IDBDatabase::deleteObjectStore): (WebCore::IDBDatabase::close): (WebCore::IDBDatabase::connectionToServerLost): (WebCore::IDBDatabase::maybeCloseInServer): (WebCore::IDBDatabase::activeDOMObjectName const): (WebCore::IDBDatabase::canSuspendForDocumentSuspension const): (WebCore::IDBDatabase::stop): (WebCore::IDBDatabase::startVersionChangeTransaction): (WebCore::IDBDatabase::didStartTransaction): (WebCore::IDBDatabase::willCommitTransaction): (WebCore::IDBDatabase::didCommitTransaction): (WebCore::IDBDatabase::willAbortTransaction): (WebCore::IDBDatabase::didAbortTransaction): (WebCore::IDBDatabase::didCommitOrAbortTransaction): (WebCore::IDBDatabase::fireVersionChangeEvent): (WebCore::IDBDatabase::dispatchEvent): (WebCore::IDBDatabase::didCreateIndexInfo): (WebCore::IDBDatabase::didDeleteIndexInfo): * Modules/indexeddb/IDBIndex.cpp: (WebCore::IDBIndex::IDBIndex): (WebCore::IDBIndex::~IDBIndex): (WebCore::IDBIndex::name const): (WebCore::IDBIndex::setName): (WebCore::IDBIndex::objectStore): (WebCore::IDBIndex::keyPath const): (WebCore::IDBIndex::unique const): (WebCore::IDBIndex::multiEntry const): (WebCore::IDBIndex::rollbackInfoForVersionChangeAbort): (WebCore::IDBIndex::openCursor): (WebCore::IDBIndex::openKeyCursor): (WebCore::IDBIndex::doCount): (WebCore::IDBIndex::doGet): (WebCore::IDBIndex::doGetKey): (WebCore::IDBIndex::getAll): (WebCore::IDBIndex::getAllKeys): (WebCore::IDBIndex::markAsDeleted): * Modules/indexeddb/IDBObjectStore.cpp: (WebCore::IDBObjectStore::IDBObjectStore): (WebCore::IDBObjectStore::~IDBObjectStore): (WebCore::IDBObjectStore::name const): (WebCore::IDBObjectStore::setName): (WebCore::IDBObjectStore::keyPath const): (WebCore::IDBObjectStore::indexNames const): (WebCore::IDBObjectStore::transaction): (WebCore::IDBObjectStore::autoIncrement const): (WebCore::IDBObjectStore::openCursor): (WebCore::IDBObjectStore::openKeyCursor): (WebCore::IDBObjectStore::get): (WebCore::IDBObjectStore::getKey): (WebCore::IDBObjectStore::putOrAdd): (WebCore::IDBObjectStore::doDelete): (WebCore::IDBObjectStore::clear): (WebCore::IDBObjectStore::createIndex): (WebCore::IDBObjectStore::index): (WebCore::IDBObjectStore::deleteIndex): (WebCore::IDBObjectStore::doCount): (WebCore::IDBObjectStore::getAll): (WebCore::IDBObjectStore::getAllKeys): (WebCore::IDBObjectStore::markAsDeleted): (WebCore::IDBObjectStore::rollbackForVersionChangeAbort): * Modules/indexeddb/IDBOpenDBRequest.cpp: (WebCore::IDBOpenDBRequest::~IDBOpenDBRequest): (WebCore::IDBOpenDBRequest::onError): (WebCore::IDBOpenDBRequest::versionChangeTransactionDidFinish): (WebCore::IDBOpenDBRequest::fireSuccessAfterVersionChangeCommit): (WebCore::IDBOpenDBRequest::fireErrorAfterVersionChangeCompletion): (WebCore::IDBOpenDBRequest::dispatchEvent): (WebCore::IDBOpenDBRequest::onSuccess): (WebCore::IDBOpenDBRequest::onUpgradeNeeded): (WebCore::IDBOpenDBRequest::onDeleteDatabaseSuccess): (WebCore::IDBOpenDBRequest::requestCompleted): (WebCore::IDBOpenDBRequest::requestBlocked): * Modules/indexeddb/IDBRequest.cpp: (WebCore::IDBRequest::~IDBRequest): (WebCore:: const): (WebCore::IDBRequest::setSource): (WebCore::IDBRequest::setVersionChangeTransaction): (WebCore::IDBRequest::transaction const): (WebCore::IDBRequest::sourceObjectStoreIdentifier const): (WebCore::IDBRequest::sourceIndexIdentifier const): (WebCore::IDBRequest::requestedObjectStoreRecordType const): (WebCore::IDBRequest::requestedIndexRecordType const): (WebCore::IDBRequest::eventTargetInterface const): (WebCore::IDBRequest::activeDOMObjectName const): (WebCore::IDBRequest::canSuspendForDocumentSuspension const): (WebCore::IDBRequest::hasPendingActivity const): (WebCore::IDBRequest::stop): (WebCore::IDBRequest::enqueueEvent): (WebCore::IDBRequest::dispatchEvent): (WebCore::IDBRequest::uncaughtExceptionInEventHandler): (WebCore::IDBRequest::setResult): (WebCore::IDBRequest::setResultToStructuredClone): (WebCore::IDBRequest::setResultToUndefined): (WebCore::IDBRequest::resultCursor): (WebCore::IDBRequest::willIterateCursor): (WebCore::IDBRequest::didOpenOrIterateCursor): (WebCore::IDBRequest::completeRequestAndDispatchEvent): (WebCore::IDBRequest::onError): (WebCore::IDBRequest::onSuccess): * Modules/indexeddb/IDBTransaction.cpp: (WebCore::IDBTransaction::IDBTransaction): (WebCore::IDBTransaction::~IDBTransaction): (WebCore::IDBTransaction::objectStoreNames const): (WebCore::IDBTransaction::db): (WebCore::IDBTransaction::error const): (WebCore::IDBTransaction::objectStore): (WebCore::IDBTransaction::abortDueToFailedRequest): (WebCore::IDBTransaction::transitionedToFinishing): (WebCore::IDBTransaction::abort): (WebCore::IDBTransaction::internalAbort): (WebCore::IDBTransaction::abortOnServerAndCancelRequests): (WebCore::IDBTransaction::activeDOMObjectName const): (WebCore::IDBTransaction::canSuspendForDocumentSuspension const): (WebCore::IDBTransaction::hasPendingActivity const): (WebCore::IDBTransaction::stop): (WebCore::IDBTransaction::isActive const): (WebCore::IDBTransaction::isFinishedOrFinishing const): (WebCore::IDBTransaction::addRequest): (WebCore::IDBTransaction::removeRequest): (WebCore::IDBTransaction::scheduleOperation): (WebCore::IDBTransaction::schedulePendingOperationTimer): (WebCore::IDBTransaction::pendingOperationTimerFired): (WebCore::IDBTransaction::operationCompletedOnServer): (WebCore::IDBTransaction::scheduleCompletedOperationTimer): (WebCore::IDBTransaction::completedOperationTimerFired): (WebCore::IDBTransaction::commit): (WebCore::IDBTransaction::commitOnServer): (WebCore::IDBTransaction::finishAbortOrCommit): (WebCore::IDBTransaction::didStart): (WebCore::IDBTransaction::notifyDidAbort): (WebCore::IDBTransaction::didAbort): (WebCore::IDBTransaction::didCommit): (WebCore::IDBTransaction::fireOnComplete): (WebCore::IDBTransaction::fireOnAbort): (WebCore::IDBTransaction::enqueueEvent): (WebCore::IDBTransaction::dispatchEvent): (WebCore::IDBTransaction::createObjectStore): (WebCore::IDBTransaction::createObjectStoreOnServer): (WebCore::IDBTransaction::didCreateObjectStoreOnServer): (WebCore::IDBTransaction::renameObjectStore): (WebCore::IDBTransaction::renameObjectStoreOnServer): (WebCore::IDBTransaction::didRenameObjectStoreOnServer): (WebCore::IDBTransaction::createIndex): (WebCore::IDBTransaction::createIndexOnServer): (WebCore::IDBTransaction::didCreateIndexOnServer): (WebCore::IDBTransaction::renameIndex): (WebCore::IDBTransaction::renameIndexOnServer): (WebCore::IDBTransaction::didRenameIndexOnServer): (WebCore::IDBTransaction::requestOpenCursor): (WebCore::IDBTransaction::doRequestOpenCursor): (WebCore::IDBTransaction::openCursorOnServer): (WebCore::IDBTransaction::didOpenCursorOnServer): (WebCore::IDBTransaction::iterateCursor): (WebCore::IDBTransaction::iterateCursorOnServer): (WebCore::IDBTransaction::didIterateCursorOnServer): (WebCore::IDBTransaction::requestGetAllObjectStoreRecords): (WebCore::IDBTransaction::requestGetAllIndexRecords): (WebCore::IDBTransaction::getAllRecordsOnServer): (WebCore::IDBTransaction::didGetAllRecordsOnServer): (WebCore::IDBTransaction::requestGetRecord): (WebCore::IDBTransaction::requestGetValue): (WebCore::IDBTransaction::requestGetKey): (WebCore::IDBTransaction::requestIndexRecord): (WebCore::IDBTransaction::getRecordOnServer): (WebCore::IDBTransaction::didGetRecordOnServer): (WebCore::IDBTransaction::requestCount): (WebCore::IDBTransaction::getCountOnServer): (WebCore::IDBTransaction::didGetCountOnServer): (WebCore::IDBTransaction::requestDeleteRecord): (WebCore::IDBTransaction::deleteRecordOnServer): (WebCore::IDBTransaction::didDeleteRecordOnServer): (WebCore::IDBTransaction::requestClearObjectStore): (WebCore::IDBTransaction::clearObjectStoreOnServer): (WebCore::IDBTransaction::didClearObjectStoreOnServer): (WebCore::IDBTransaction::requestPutOrAdd): (WebCore::IDBTransaction::putOrAddOnServer): (WebCore::IDBTransaction::didPutOrAddOnServer): (WebCore::IDBTransaction::deleteObjectStore): (WebCore::IDBTransaction::deleteObjectStoreOnServer): (WebCore::IDBTransaction::didDeleteObjectStoreOnServer): (WebCore::IDBTransaction::deleteIndex): (WebCore::IDBTransaction::deleteIndexOnServer): (WebCore::IDBTransaction::didDeleteIndexOnServer): (WebCore::IDBTransaction::operationCompletedOnClient): (WebCore::IDBTransaction::establishOnServer): (WebCore::IDBTransaction::activate): (WebCore::IDBTransaction::deactivate): * Modules/indexeddb/client/IDBConnectionProxy.cpp: (WebCore::IDBClient::removeItemsMatchingCurrentThread): * Modules/indexeddb/client/TransactionOperation.h: (WebCore::IDBClient::TransactionOperation::~TransactionOperation): (WebCore::IDBClient::TransactionOperation::perform): (WebCore::IDBClient::TransactionOperation::transitionToCompleteOnThisThread): (WebCore::IDBClient::TransactionOperation::transitionToComplete): (WebCore::IDBClient::TransactionOperation::doComplete): (WebCore::IDBClient::TransactionOperation::originThread const): (WebCore::IDBClient::TransactionOperation::originThreadID const): Deleted. * Modules/webaudio/AudioContext.cpp: (WebCore::AudioContext::AudioContext): (WebCore::AudioContext::lock): (WebCore::AudioContext::tryLock): (WebCore::AudioContext::unlock): (WebCore::AudioContext::isAudioThread const): (WebCore::AudioContext::isGraphOwner const): * Modules/webaudio/AudioContext.h: (WebCore::AudioContext::setAudioThread): (WebCore::AudioContext::audioThread const): * Modules/webaudio/AudioDestinationNode.cpp: (WebCore::AudioDestinationNode::render): * Modules/webdatabase/Database.cpp: (WebCore::Database::performClose): (WebCore::Database::securityOrigin): * Modules/webdatabase/DatabaseDetails.h: (WebCore::DatabaseDetails::DatabaseDetails): (WebCore::DatabaseDetails::operator=): (WebCore::DatabaseDetails::thread const): (WebCore::DatabaseDetails::threadID const): Deleted. * Modules/webdatabase/DatabaseManager.cpp: (WebCore::DatabaseManager::detailsForNameAndOrigin): * Modules/webdatabase/DatabaseThread.cpp: (WebCore::DatabaseThread::databaseThread): (WebCore::DatabaseThread::recordDatabaseOpen): (WebCore::DatabaseThread::recordDatabaseClosed): * Modules/webdatabase/DatabaseThread.h: (WebCore::DatabaseThread::getThread): (WebCore::DatabaseThread::getThreadID): Deleted. * Modules/webdatabase/SQLTransaction.cpp: (WebCore::SQLTransaction::checkAndHandleClosedDatabase): * Modules/webdatabase/SQLTransactionBackend.cpp: (WebCore::SQLTransactionBackend::doCleanup): (WebCore::SQLTransactionBackend::notifyDatabaseThreadIsShuttingDown): * bindings/js/JSCallbackData.h: (WebCore::JSCallbackData::JSCallbackData): (WebCore::JSCallbackData::~JSCallbackData): * bindings/js/ScheduledAction.cpp: (WebCore::ScheduledAction::execute): * dom/ScriptExecutionContext.cpp: (WebCore::ScriptExecutionContext::createdMessagePort): (WebCore::ScriptExecutionContext::destroyedMessagePort): * page/ResourceUsageOverlay.h: * page/scrolling/ScrollingThread.cpp: (WebCore::ScrollingThread::isCurrentThread): * platform/Supplementable.h: (WebCore::Supplementable::provideSupplement): (WebCore::Supplementable::removeSupplement): (WebCore::Supplementable::requireSupplement): (WebCore::Supplementable::Supplementable): Deleted. * platform/Timer.cpp: (WebCore::TimerBase::TimerBase): (WebCore::TimerBase::start): (WebCore::TimerBase::stop): (WebCore::TimerBase::setNextFireTime): * platform/Timer.h: (WebCore::TimerBase::isActive const): * platform/graphics/cocoa/FontCacheCoreText.cpp: (WebCore::shouldAutoActivateFontIfNeeded): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.cpp: (WebCore::TextureMapperPlatformLayerProxy::activateOnCompositingThread): (WebCore::TextureMapperPlatformLayerProxy::invalidate): (WebCore::TextureMapperPlatformLayerProxy::getAvailableBuffer): (WebCore::TextureMapperPlatformLayerProxy::appendToUnusedBuffers): (WebCore::TextureMapperPlatformLayerProxy::swapBuffer): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.h: (): Deleted. * platform/ios/wak/WebCoreThread.mm: (RunWebThread): (StartWebThread): * platform/sql/SQLiteDatabase.cpp: (WebCore::SQLiteDatabase::open): (WebCore::SQLiteDatabase::close): * platform/sql/SQLiteDatabase.h: (WebCore::SQLiteDatabase::sqlite3Handle const): * workers/WorkerGlobalScope.cpp: (WebCore::WorkerGlobalScope::~WorkerGlobalScope): (WebCore::WorkerGlobalScope::isContextThread const): * workers/WorkerMessagingProxy.cpp: (WebCore::WorkerMessagingProxy::WorkerMessagingProxy): (WebCore::WorkerMessagingProxy::~WorkerMessagingProxy): * workers/WorkerRunLoop.cpp: (WebCore::WorkerRunLoop::runInMode): (WebCore::WorkerRunLoop::runCleanupTasks): * workers/WorkerThread.h: (WebCore::WorkerThread::thread const): (WebCore::WorkerThread::threadID const): Deleted. * workers/service/ServiceWorkerContainer.cpp: (WebCore::ServiceWorkerContainer::~ServiceWorkerContainer): (WebCore::ServiceWorkerContainer::scheduleJob): (WebCore::ServiceWorkerContainer::jobFailedWithException): (WebCore::ServiceWorkerContainer::scheduleTaskToFireUpdateFoundEvent): (WebCore::ServiceWorkerContainer::jobResolvedWithRegistration): (WebCore::ServiceWorkerContainer::jobResolvedWithUnregistrationResult): (WebCore::ServiceWorkerContainer::startScriptFetchForJob): (WebCore::ServiceWorkerContainer::jobFinishedLoadingScript): (WebCore::ServiceWorkerContainer::jobFailedLoadingScript): (WebCore::ServiceWorkerContainer::jobDidFinish): (WebCore::ServiceWorkerContainer::addRegistration): (WebCore::ServiceWorkerContainer::removeRegistration): (WebCore::ServiceWorkerContainer::scheduleTaskToFireControllerChangeEvent): (WebCore::ServiceWorkerContainer::contextIdentifier): * workers/service/ServiceWorkerContainer.h: * workers/service/ServiceWorkerJob.cpp: (WebCore::ServiceWorkerJob::~ServiceWorkerJob): (WebCore::ServiceWorkerJob::failedWithException): (WebCore::ServiceWorkerJob::resolvedWithRegistration): (WebCore::ServiceWorkerJob::resolvedWithUnregistrationResult): (WebCore::ServiceWorkerJob::startScriptFetch): (WebCore::ServiceWorkerJob::fetchScriptWithContext): (WebCore::ServiceWorkerJob::didReceiveResponse): (WebCore::ServiceWorkerJob::notifyFinished): * workers/service/ServiceWorkerJob.h: * xml/parser/XMLDocumentParserLibxml2.cpp: (WebCore::matchFunc): (WebCore::openFunc): (WebCore::initializeXMLParser): (WebCore::XMLParserContext::createStringParser): (WebCore::XMLParserContext::createMemoryParser): Source/WebKit: * UIProcess/API/glib/IconDatabase.cpp: * UIProcess/GenericCallback.h: (WebKit::GenericCallback::~GenericCallback): (WebKit::GenericCallback::performCallbackWithReturnValue): Source/WTF: We should use a pointer of WTF::Thread instead of ThreadIdentifier. One problem is that Windows support library uses WTF::createThread, which returns ThreadIdentifier. So we cannot drop ThreadIdentifier in Windows environment. This patch keeps ThreadIdentifier in Windows. * wtf/MainThread.cpp: (WTF::initializeMainThread): (WTF::isMainThread): (WTF::canAccessThreadLocalDataForThread): * wtf/MainThread.h: * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkCount): * wtf/RecursiveLockAdapter.h: (WTF::RecursiveLockAdapter::lock): (WTF::RecursiveLockAdapter::unlock): (WTF::RecursiveLockAdapter::tryLock): * wtf/Threading.cpp: (WTF::Thread::dump const): * wtf/Threading.h: (WTF::Thread::id const): (WTF::Thread::operator==): Deleted. (WTF::Thread::operator!=): Deleted. (WTF::currentThread): Deleted. * wtf/ThreadingPrimitives.h: * wtf/ThreadingPthreads.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::detach): (WTF::Thread::initializeCurrentTLS): (WTF::Thread::suspend): (WTF::Thread::establishPlatformSpecificHandle): (WTF::Thread::currentID): Deleted. * wtf/ThreadingWin.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::suspend): (WTF::Thread::currentDying): * wtf/mac/MainThreadMac.mm: (WTF::initializeApplicationUIThread): (WTF::initializeWebThreadPlatform): (WTF::canAccessThreadLocalDataForThread): (WTF::initializeApplicationUIThreadIdentifier): Deleted. (WTF::initializeWebThreadIdentifier): Deleted. Tools: * DumpRenderTree/mac/DumpRenderTree.mm: (dumpRenderTree): (runThread): Deleted. (runPthread): Deleted. (testThreadIdentifierMap): Deleted. * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: * TestWebKitAPI/Tests/WTF/Threading.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/196314@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@225470 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-12-04 06:13:05 +00:00
dataLog(toString(Thread::current(), ": created initial hashtable ", RawPointer(currentHashtable), "\n"));
WTF::Lock should not suffer from the thundering herd https://bugs.webkit.org/show_bug.cgi?id=147947 Reviewed by Geoffrey Garen. Source/WTF: This changes Lock::unlockSlow() to use unparkOne() instead of unparkAll(). The problem with doing this is that it's not obvious after calling unparkOne() if there are any other threads that are still parked on the lock's queue. If we assume that there are and leave the hasParkedBit set, then future calls to unlock() will take the slow path. We don't want that if there aren't actually any threads parked. On the other hand, if we assume that there aren't any threads parked and clear the hasParkedBit, then if there actually were some threads parked, then they may never be awoken since future calls to unlock() won't take slow path and so won't call unparkOne(). In other words, we need a way to be very precise about when we clear the hasParkedBit and we need to do it in a race-free way: it can't be the case that we clear the bit just as some thread gets parked on the queue. A similar problem arises in futexes, and one of the solutions is to have a thread that acquires a lock after parking sets the hasParkedBit. This is what Rusty Russel's usersem does. It's a subtle algorithm. Also, it means that if a thread barges in before the unparked thread runs, then that barging thread will not know that there are threads parked. This could increase the severity of barging. Since ParkingLot is a user-level API, we don't have to worry about the kernel-user security issues and so we can expose callbacks while ParkingLot is holding its internal locks. This change does exactly that for unparkOne(). The new variant of unparkOne() will call a user function while the queue from which we are unparking is locked. The callback is told basic stats about the queue: did we unpark a thread this time, and could there be more threads to unpark in the future. The callback runs while it's impossible for the queue state to change, since the ParkingLot's internal locks for the queue is held. This means that Lock::unlockSlow() can either clear, or leave, the hasParkedBit while releasing the lock inside the callback from unparkOne(). This takes care of the thundering herd problem while also reducing the greed that arises from barging threads. This required some careful reworking of the ParkingLot algorithm. The first thing I noticed was that the ThreadData::shouldPark flag was useless, since it's set exactly when ThreadData::address is non-null. Then I had to make sure that dequeue() could lazily create both hashtables and buckets, since the "callback is called while queue is locked" invariant requires that we didn't exit early due to the hashtable or bucket not being present. Note that all of this is done in such a way that the old unparkOne() and unparkAll() don't have to create any buckets, though they now may create the hashtable. We don't care as much about the hashtable being created by unpark since it's just such an unlikely scenario and it would only happen once. This change reduces the kernel CPU usage of WTF::Lock for the long critical section test by about 8x and makes it always perform as well as WTF::WordLock and WTF::Mutex for that benchmark. * benchmarks/LockSpeedTest.cpp: * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): * wtf/Lock.h: (WTF::LockBase::isLocked): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: * wtf/WordLock.h: (WTF::WordLock::isLocked): (WTF::WordLock::isFullyReset): Tools: Add testing that checks that locks return to a pristine state after contention is over. * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::LockInspector::isFullyReset): (TestWebKitAPI::runLockTest): (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/166072@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188374 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 03:51:25 +00:00
return currentHashtable;
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
}
WTF::Lock should not suffer from the thundering herd https://bugs.webkit.org/show_bug.cgi?id=147947 Reviewed by Geoffrey Garen. Source/WTF: This changes Lock::unlockSlow() to use unparkOne() instead of unparkAll(). The problem with doing this is that it's not obvious after calling unparkOne() if there are any other threads that are still parked on the lock's queue. If we assume that there are and leave the hasParkedBit set, then future calls to unlock() will take the slow path. We don't want that if there aren't actually any threads parked. On the other hand, if we assume that there aren't any threads parked and clear the hasParkedBit, then if there actually were some threads parked, then they may never be awoken since future calls to unlock() won't take slow path and so won't call unparkOne(). In other words, we need a way to be very precise about when we clear the hasParkedBit and we need to do it in a race-free way: it can't be the case that we clear the bit just as some thread gets parked on the queue. A similar problem arises in futexes, and one of the solutions is to have a thread that acquires a lock after parking sets the hasParkedBit. This is what Rusty Russel's usersem does. It's a subtle algorithm. Also, it means that if a thread barges in before the unparked thread runs, then that barging thread will not know that there are threads parked. This could increase the severity of barging. Since ParkingLot is a user-level API, we don't have to worry about the kernel-user security issues and so we can expose callbacks while ParkingLot is holding its internal locks. This change does exactly that for unparkOne(). The new variant of unparkOne() will call a user function while the queue from which we are unparking is locked. The callback is told basic stats about the queue: did we unpark a thread this time, and could there be more threads to unpark in the future. The callback runs while it's impossible for the queue state to change, since the ParkingLot's internal locks for the queue is held. This means that Lock::unlockSlow() can either clear, or leave, the hasParkedBit while releasing the lock inside the callback from unparkOne(). This takes care of the thundering herd problem while also reducing the greed that arises from barging threads. This required some careful reworking of the ParkingLot algorithm. The first thing I noticed was that the ThreadData::shouldPark flag was useless, since it's set exactly when ThreadData::address is non-null. Then I had to make sure that dequeue() could lazily create both hashtables and buckets, since the "callback is called while queue is locked" invariant requires that we didn't exit early due to the hashtable or bucket not being present. Note that all of this is done in such a way that the old unparkOne() and unparkAll() don't have to create any buckets, though they now may create the hashtable. We don't care as much about the hashtable being created by unpark since it's just such an unlikely scenario and it would only happen once. This change reduces the kernel CPU usage of WTF::Lock for the long critical section test by about 8x and makes it always perform as well as WTF::WordLock and WTF::Mutex for that benchmark. * benchmarks/LockSpeedTest.cpp: * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): * wtf/Lock.h: (WTF::LockBase::isLocked): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: * wtf/WordLock.h: (WTF::WordLock::isLocked): (WTF::WordLock::isFullyReset): Tools: Add testing that checks that locks return to a pristine state after contention is over. * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::LockInspector::isFullyReset): (TestWebKitAPI::runLockTest): (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/166072@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188374 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 03:51:25 +00:00
Hashtable::destroy(currentHashtable);
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
}
WTF::Lock should not suffer from the thundering herd https://bugs.webkit.org/show_bug.cgi?id=147947 Reviewed by Geoffrey Garen. Source/WTF: This changes Lock::unlockSlow() to use unparkOne() instead of unparkAll(). The problem with doing this is that it's not obvious after calling unparkOne() if there are any other threads that are still parked on the lock's queue. If we assume that there are and leave the hasParkedBit set, then future calls to unlock() will take the slow path. We don't want that if there aren't actually any threads parked. On the other hand, if we assume that there aren't any threads parked and clear the hasParkedBit, then if there actually were some threads parked, then they may never be awoken since future calls to unlock() won't take slow path and so won't call unparkOne(). In other words, we need a way to be very precise about when we clear the hasParkedBit and we need to do it in a race-free way: it can't be the case that we clear the bit just as some thread gets parked on the queue. A similar problem arises in futexes, and one of the solutions is to have a thread that acquires a lock after parking sets the hasParkedBit. This is what Rusty Russel's usersem does. It's a subtle algorithm. Also, it means that if a thread barges in before the unparked thread runs, then that barging thread will not know that there are threads parked. This could increase the severity of barging. Since ParkingLot is a user-level API, we don't have to worry about the kernel-user security issues and so we can expose callbacks while ParkingLot is holding its internal locks. This change does exactly that for unparkOne(). The new variant of unparkOne() will call a user function while the queue from which we are unparking is locked. The callback is told basic stats about the queue: did we unpark a thread this time, and could there be more threads to unpark in the future. The callback runs while it's impossible for the queue state to change, since the ParkingLot's internal locks for the queue is held. This means that Lock::unlockSlow() can either clear, or leave, the hasParkedBit while releasing the lock inside the callback from unparkOne(). This takes care of the thundering herd problem while also reducing the greed that arises from barging threads. This required some careful reworking of the ParkingLot algorithm. The first thing I noticed was that the ThreadData::shouldPark flag was useless, since it's set exactly when ThreadData::address is non-null. Then I had to make sure that dequeue() could lazily create both hashtables and buckets, since the "callback is called while queue is locked" invariant requires that we didn't exit early due to the hashtable or bucket not being present. Note that all of this is done in such a way that the old unparkOne() and unparkAll() don't have to create any buckets, though they now may create the hashtable. We don't care as much about the hashtable being created by unpark since it's just such an unlikely scenario and it would only happen once. This change reduces the kernel CPU usage of WTF::Lock for the long critical section test by about 8x and makes it always perform as well as WTF::WordLock and WTF::Mutex for that benchmark. * benchmarks/LockSpeedTest.cpp: * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): * wtf/Lock.h: (WTF::LockBase::isLocked): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: * wtf/WordLock.h: (WTF::WordLock::isLocked): (WTF::WordLock::isFullyReset): Tools: Add testing that checks that locks return to a pristine state after contention is over. * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::LockInspector::isFullyReset): (TestWebKitAPI::runLockTest): (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/166072@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188374 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 03:51:25 +00:00
}
}
// Locks the hashtable. This reloops in case of rehashing, so the current hashtable may be different
// after this returns than when you called it. Guarantees that there is a hashtable. This is pretty
// slow and not scalable, so it's only used during thread creation and for debugging/testing.
Vector<Bucket*> lockHashtable()
{
for (;;) {
Hashtable* currentHashtable = ensureHashtable();
ASSERT(currentHashtable);
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
// Now find all of the buckets. This makes sure that the hashtable is full of buckets so that
// we can lock all of the buckets, not just the ones that are materialized.
Vector<Bucket*> buckets;
for (unsigned i = currentHashtable->size; i--;) {
Atomic<Bucket*>& bucketPointer = currentHashtable->data[i];
for (;;) {
Bucket* bucket = bucketPointer.load();
if (!bucket) {
bucket = new Bucket();
if (!bucketPointer.compareExchangeWeak(nullptr, bucket)) {
delete bucket;
continue;
}
}
buckets.append(bucket);
break;
}
}
// Now lock the buckets in the right order.
std::sort(buckets.begin(), buckets.end());
for (Bucket* bucket : buckets)
bucket->lock.lock();
// If the hashtable didn't change (wasn't rehashed) while we were locking it, then we own it
// now.
if (hashtable.load() == currentHashtable)
return buckets;
// The hashtable rehashed. Unlock everything and try again.
for (Bucket* bucket : buckets)
bucket->lock.unlock();
}
}
void unlockHashtable(const Vector<Bucket*>& buckets)
{
for (Bucket* bucket : buckets)
bucket->lock.unlock();
}
// Rehash the hashtable to handle numThreads threads.
void ensureHashtableSize(unsigned numThreads)
{
// We try to ensure that the size of the hashtable used for thread queues is always large enough
// to avoid collisions. So, since we started a new thread, we may need to increase the size of the
// hashtable. This does just that. Note that we never free the old spine, since we never lock
// around spine accesses (i.e. the "hashtable" global variable).
// First do a fast check to see if rehashing is needed.
Hashtable* oldHashtable = hashtable.load();
if (oldHashtable && static_cast<double>(oldHashtable->size) / static_cast<double>(numThreads) >= maxLoadFactor) {
if (verbose)
WTF shouldn't have both Thread and ThreadIdentifier https://bugs.webkit.org/show_bug.cgi?id=180308 Reviewed by Darin Adler. Source/JavaScriptCore: * heap/MachineStackMarker.cpp: (JSC::MachineThreads::tryCopyOtherThreadStacks): * llint/LLIntSlowPaths.cpp: (JSC::LLInt::llint_trace_operand): (JSC::LLInt::llint_trace_value): (JSC::LLInt::LLINT_SLOW_PATH_DECL): (JSC::LLInt::traceFunctionPrologue): * runtime/ExceptionScope.cpp: (JSC::ExceptionScope::unexpectedExceptionMessage): * runtime/JSLock.h: (JSC::JSLock::currentThreadIsHoldingLock): * runtime/VM.cpp: (JSC::VM::throwException): * runtime/VM.h: (JSC::VM::throwingThread const): (JSC::VM::clearException): * tools/HeapVerifier.cpp: (JSC::HeapVerifier::printVerificationHeader): Source/WebCore: No behavior change. * Modules/indexeddb/IDBActiveDOMObject.h: (WebCore::IDBActiveDOMObject::originThread const): (WebCore::IDBActiveDOMObject::performCallbackOnOriginThread): (WebCore::IDBActiveDOMObject::callFunctionOnOriginThread): (WebCore::IDBActiveDOMObject::originThreadID const): Deleted. * Modules/indexeddb/IDBCursor.cpp: (WebCore::IDBCursor::IDBCursor): (WebCore::IDBCursor::~IDBCursor): (WebCore::IDBCursor::sourcesDeleted const): (WebCore::IDBCursor::transaction const): (WebCore::IDBCursor::update): (WebCore::IDBCursor::advance): (WebCore::IDBCursor::continueFunction): (WebCore::IDBCursor::uncheckedIterateCursor): (WebCore::IDBCursor::deleteFunction): (WebCore::IDBCursor::setGetResult): * Modules/indexeddb/IDBDatabase.cpp: (WebCore::IDBDatabase::~IDBDatabase): (WebCore::IDBDatabase::hasPendingActivity const): (WebCore::IDBDatabase::name const): (WebCore::IDBDatabase::version const): (WebCore::IDBDatabase::objectStoreNames const): (WebCore::IDBDatabase::renameObjectStore): (WebCore::IDBDatabase::renameIndex): (WebCore::IDBDatabase::createObjectStore): (WebCore::IDBDatabase::transaction): (WebCore::IDBDatabase::deleteObjectStore): (WebCore::IDBDatabase::close): (WebCore::IDBDatabase::connectionToServerLost): (WebCore::IDBDatabase::maybeCloseInServer): (WebCore::IDBDatabase::activeDOMObjectName const): (WebCore::IDBDatabase::canSuspendForDocumentSuspension const): (WebCore::IDBDatabase::stop): (WebCore::IDBDatabase::startVersionChangeTransaction): (WebCore::IDBDatabase::didStartTransaction): (WebCore::IDBDatabase::willCommitTransaction): (WebCore::IDBDatabase::didCommitTransaction): (WebCore::IDBDatabase::willAbortTransaction): (WebCore::IDBDatabase::didAbortTransaction): (WebCore::IDBDatabase::didCommitOrAbortTransaction): (WebCore::IDBDatabase::fireVersionChangeEvent): (WebCore::IDBDatabase::dispatchEvent): (WebCore::IDBDatabase::didCreateIndexInfo): (WebCore::IDBDatabase::didDeleteIndexInfo): * Modules/indexeddb/IDBIndex.cpp: (WebCore::IDBIndex::IDBIndex): (WebCore::IDBIndex::~IDBIndex): (WebCore::IDBIndex::name const): (WebCore::IDBIndex::setName): (WebCore::IDBIndex::objectStore): (WebCore::IDBIndex::keyPath const): (WebCore::IDBIndex::unique const): (WebCore::IDBIndex::multiEntry const): (WebCore::IDBIndex::rollbackInfoForVersionChangeAbort): (WebCore::IDBIndex::openCursor): (WebCore::IDBIndex::openKeyCursor): (WebCore::IDBIndex::doCount): (WebCore::IDBIndex::doGet): (WebCore::IDBIndex::doGetKey): (WebCore::IDBIndex::getAll): (WebCore::IDBIndex::getAllKeys): (WebCore::IDBIndex::markAsDeleted): * Modules/indexeddb/IDBObjectStore.cpp: (WebCore::IDBObjectStore::IDBObjectStore): (WebCore::IDBObjectStore::~IDBObjectStore): (WebCore::IDBObjectStore::name const): (WebCore::IDBObjectStore::setName): (WebCore::IDBObjectStore::keyPath const): (WebCore::IDBObjectStore::indexNames const): (WebCore::IDBObjectStore::transaction): (WebCore::IDBObjectStore::autoIncrement const): (WebCore::IDBObjectStore::openCursor): (WebCore::IDBObjectStore::openKeyCursor): (WebCore::IDBObjectStore::get): (WebCore::IDBObjectStore::getKey): (WebCore::IDBObjectStore::putOrAdd): (WebCore::IDBObjectStore::doDelete): (WebCore::IDBObjectStore::clear): (WebCore::IDBObjectStore::createIndex): (WebCore::IDBObjectStore::index): (WebCore::IDBObjectStore::deleteIndex): (WebCore::IDBObjectStore::doCount): (WebCore::IDBObjectStore::getAll): (WebCore::IDBObjectStore::getAllKeys): (WebCore::IDBObjectStore::markAsDeleted): (WebCore::IDBObjectStore::rollbackForVersionChangeAbort): * Modules/indexeddb/IDBOpenDBRequest.cpp: (WebCore::IDBOpenDBRequest::~IDBOpenDBRequest): (WebCore::IDBOpenDBRequest::onError): (WebCore::IDBOpenDBRequest::versionChangeTransactionDidFinish): (WebCore::IDBOpenDBRequest::fireSuccessAfterVersionChangeCommit): (WebCore::IDBOpenDBRequest::fireErrorAfterVersionChangeCompletion): (WebCore::IDBOpenDBRequest::dispatchEvent): (WebCore::IDBOpenDBRequest::onSuccess): (WebCore::IDBOpenDBRequest::onUpgradeNeeded): (WebCore::IDBOpenDBRequest::onDeleteDatabaseSuccess): (WebCore::IDBOpenDBRequest::requestCompleted): (WebCore::IDBOpenDBRequest::requestBlocked): * Modules/indexeddb/IDBRequest.cpp: (WebCore::IDBRequest::~IDBRequest): (WebCore:: const): (WebCore::IDBRequest::setSource): (WebCore::IDBRequest::setVersionChangeTransaction): (WebCore::IDBRequest::transaction const): (WebCore::IDBRequest::sourceObjectStoreIdentifier const): (WebCore::IDBRequest::sourceIndexIdentifier const): (WebCore::IDBRequest::requestedObjectStoreRecordType const): (WebCore::IDBRequest::requestedIndexRecordType const): (WebCore::IDBRequest::eventTargetInterface const): (WebCore::IDBRequest::activeDOMObjectName const): (WebCore::IDBRequest::canSuspendForDocumentSuspension const): (WebCore::IDBRequest::hasPendingActivity const): (WebCore::IDBRequest::stop): (WebCore::IDBRequest::enqueueEvent): (WebCore::IDBRequest::dispatchEvent): (WebCore::IDBRequest::uncaughtExceptionInEventHandler): (WebCore::IDBRequest::setResult): (WebCore::IDBRequest::setResultToStructuredClone): (WebCore::IDBRequest::setResultToUndefined): (WebCore::IDBRequest::resultCursor): (WebCore::IDBRequest::willIterateCursor): (WebCore::IDBRequest::didOpenOrIterateCursor): (WebCore::IDBRequest::completeRequestAndDispatchEvent): (WebCore::IDBRequest::onError): (WebCore::IDBRequest::onSuccess): * Modules/indexeddb/IDBTransaction.cpp: (WebCore::IDBTransaction::IDBTransaction): (WebCore::IDBTransaction::~IDBTransaction): (WebCore::IDBTransaction::objectStoreNames const): (WebCore::IDBTransaction::db): (WebCore::IDBTransaction::error const): (WebCore::IDBTransaction::objectStore): (WebCore::IDBTransaction::abortDueToFailedRequest): (WebCore::IDBTransaction::transitionedToFinishing): (WebCore::IDBTransaction::abort): (WebCore::IDBTransaction::internalAbort): (WebCore::IDBTransaction::abortOnServerAndCancelRequests): (WebCore::IDBTransaction::activeDOMObjectName const): (WebCore::IDBTransaction::canSuspendForDocumentSuspension const): (WebCore::IDBTransaction::hasPendingActivity const): (WebCore::IDBTransaction::stop): (WebCore::IDBTransaction::isActive const): (WebCore::IDBTransaction::isFinishedOrFinishing const): (WebCore::IDBTransaction::addRequest): (WebCore::IDBTransaction::removeRequest): (WebCore::IDBTransaction::scheduleOperation): (WebCore::IDBTransaction::schedulePendingOperationTimer): (WebCore::IDBTransaction::pendingOperationTimerFired): (WebCore::IDBTransaction::operationCompletedOnServer): (WebCore::IDBTransaction::scheduleCompletedOperationTimer): (WebCore::IDBTransaction::completedOperationTimerFired): (WebCore::IDBTransaction::commit): (WebCore::IDBTransaction::commitOnServer): (WebCore::IDBTransaction::finishAbortOrCommit): (WebCore::IDBTransaction::didStart): (WebCore::IDBTransaction::notifyDidAbort): (WebCore::IDBTransaction::didAbort): (WebCore::IDBTransaction::didCommit): (WebCore::IDBTransaction::fireOnComplete): (WebCore::IDBTransaction::fireOnAbort): (WebCore::IDBTransaction::enqueueEvent): (WebCore::IDBTransaction::dispatchEvent): (WebCore::IDBTransaction::createObjectStore): (WebCore::IDBTransaction::createObjectStoreOnServer): (WebCore::IDBTransaction::didCreateObjectStoreOnServer): (WebCore::IDBTransaction::renameObjectStore): (WebCore::IDBTransaction::renameObjectStoreOnServer): (WebCore::IDBTransaction::didRenameObjectStoreOnServer): (WebCore::IDBTransaction::createIndex): (WebCore::IDBTransaction::createIndexOnServer): (WebCore::IDBTransaction::didCreateIndexOnServer): (WebCore::IDBTransaction::renameIndex): (WebCore::IDBTransaction::renameIndexOnServer): (WebCore::IDBTransaction::didRenameIndexOnServer): (WebCore::IDBTransaction::requestOpenCursor): (WebCore::IDBTransaction::doRequestOpenCursor): (WebCore::IDBTransaction::openCursorOnServer): (WebCore::IDBTransaction::didOpenCursorOnServer): (WebCore::IDBTransaction::iterateCursor): (WebCore::IDBTransaction::iterateCursorOnServer): (WebCore::IDBTransaction::didIterateCursorOnServer): (WebCore::IDBTransaction::requestGetAllObjectStoreRecords): (WebCore::IDBTransaction::requestGetAllIndexRecords): (WebCore::IDBTransaction::getAllRecordsOnServer): (WebCore::IDBTransaction::didGetAllRecordsOnServer): (WebCore::IDBTransaction::requestGetRecord): (WebCore::IDBTransaction::requestGetValue): (WebCore::IDBTransaction::requestGetKey): (WebCore::IDBTransaction::requestIndexRecord): (WebCore::IDBTransaction::getRecordOnServer): (WebCore::IDBTransaction::didGetRecordOnServer): (WebCore::IDBTransaction::requestCount): (WebCore::IDBTransaction::getCountOnServer): (WebCore::IDBTransaction::didGetCountOnServer): (WebCore::IDBTransaction::requestDeleteRecord): (WebCore::IDBTransaction::deleteRecordOnServer): (WebCore::IDBTransaction::didDeleteRecordOnServer): (WebCore::IDBTransaction::requestClearObjectStore): (WebCore::IDBTransaction::clearObjectStoreOnServer): (WebCore::IDBTransaction::didClearObjectStoreOnServer): (WebCore::IDBTransaction::requestPutOrAdd): (WebCore::IDBTransaction::putOrAddOnServer): (WebCore::IDBTransaction::didPutOrAddOnServer): (WebCore::IDBTransaction::deleteObjectStore): (WebCore::IDBTransaction::deleteObjectStoreOnServer): (WebCore::IDBTransaction::didDeleteObjectStoreOnServer): (WebCore::IDBTransaction::deleteIndex): (WebCore::IDBTransaction::deleteIndexOnServer): (WebCore::IDBTransaction::didDeleteIndexOnServer): (WebCore::IDBTransaction::operationCompletedOnClient): (WebCore::IDBTransaction::establishOnServer): (WebCore::IDBTransaction::activate): (WebCore::IDBTransaction::deactivate): * Modules/indexeddb/client/IDBConnectionProxy.cpp: (WebCore::IDBClient::removeItemsMatchingCurrentThread): * Modules/indexeddb/client/TransactionOperation.h: (WebCore::IDBClient::TransactionOperation::~TransactionOperation): (WebCore::IDBClient::TransactionOperation::perform): (WebCore::IDBClient::TransactionOperation::transitionToCompleteOnThisThread): (WebCore::IDBClient::TransactionOperation::transitionToComplete): (WebCore::IDBClient::TransactionOperation::doComplete): (WebCore::IDBClient::TransactionOperation::originThread const): (WebCore::IDBClient::TransactionOperation::originThreadID const): Deleted. * Modules/webaudio/AudioContext.cpp: (WebCore::AudioContext::AudioContext): (WebCore::AudioContext::lock): (WebCore::AudioContext::tryLock): (WebCore::AudioContext::unlock): (WebCore::AudioContext::isAudioThread const): (WebCore::AudioContext::isGraphOwner const): * Modules/webaudio/AudioContext.h: (WebCore::AudioContext::setAudioThread): (WebCore::AudioContext::audioThread const): * Modules/webaudio/AudioDestinationNode.cpp: (WebCore::AudioDestinationNode::render): * Modules/webdatabase/Database.cpp: (WebCore::Database::performClose): (WebCore::Database::securityOrigin): * Modules/webdatabase/DatabaseDetails.h: (WebCore::DatabaseDetails::DatabaseDetails): (WebCore::DatabaseDetails::operator=): (WebCore::DatabaseDetails::thread const): (WebCore::DatabaseDetails::threadID const): Deleted. * Modules/webdatabase/DatabaseManager.cpp: (WebCore::DatabaseManager::detailsForNameAndOrigin): * Modules/webdatabase/DatabaseThread.cpp: (WebCore::DatabaseThread::databaseThread): (WebCore::DatabaseThread::recordDatabaseOpen): (WebCore::DatabaseThread::recordDatabaseClosed): * Modules/webdatabase/DatabaseThread.h: (WebCore::DatabaseThread::getThread): (WebCore::DatabaseThread::getThreadID): Deleted. * Modules/webdatabase/SQLTransaction.cpp: (WebCore::SQLTransaction::checkAndHandleClosedDatabase): * Modules/webdatabase/SQLTransactionBackend.cpp: (WebCore::SQLTransactionBackend::doCleanup): (WebCore::SQLTransactionBackend::notifyDatabaseThreadIsShuttingDown): * bindings/js/JSCallbackData.h: (WebCore::JSCallbackData::JSCallbackData): (WebCore::JSCallbackData::~JSCallbackData): * bindings/js/ScheduledAction.cpp: (WebCore::ScheduledAction::execute): * dom/ScriptExecutionContext.cpp: (WebCore::ScriptExecutionContext::createdMessagePort): (WebCore::ScriptExecutionContext::destroyedMessagePort): * page/ResourceUsageOverlay.h: * page/scrolling/ScrollingThread.cpp: (WebCore::ScrollingThread::isCurrentThread): * platform/Supplementable.h: (WebCore::Supplementable::provideSupplement): (WebCore::Supplementable::removeSupplement): (WebCore::Supplementable::requireSupplement): (WebCore::Supplementable::Supplementable): Deleted. * platform/Timer.cpp: (WebCore::TimerBase::TimerBase): (WebCore::TimerBase::start): (WebCore::TimerBase::stop): (WebCore::TimerBase::setNextFireTime): * platform/Timer.h: (WebCore::TimerBase::isActive const): * platform/graphics/cocoa/FontCacheCoreText.cpp: (WebCore::shouldAutoActivateFontIfNeeded): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.cpp: (WebCore::TextureMapperPlatformLayerProxy::activateOnCompositingThread): (WebCore::TextureMapperPlatformLayerProxy::invalidate): (WebCore::TextureMapperPlatformLayerProxy::getAvailableBuffer): (WebCore::TextureMapperPlatformLayerProxy::appendToUnusedBuffers): (WebCore::TextureMapperPlatformLayerProxy::swapBuffer): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.h: (): Deleted. * platform/ios/wak/WebCoreThread.mm: (RunWebThread): (StartWebThread): * platform/sql/SQLiteDatabase.cpp: (WebCore::SQLiteDatabase::open): (WebCore::SQLiteDatabase::close): * platform/sql/SQLiteDatabase.h: (WebCore::SQLiteDatabase::sqlite3Handle const): * workers/WorkerGlobalScope.cpp: (WebCore::WorkerGlobalScope::~WorkerGlobalScope): (WebCore::WorkerGlobalScope::isContextThread const): * workers/WorkerMessagingProxy.cpp: (WebCore::WorkerMessagingProxy::WorkerMessagingProxy): (WebCore::WorkerMessagingProxy::~WorkerMessagingProxy): * workers/WorkerRunLoop.cpp: (WebCore::WorkerRunLoop::runInMode): (WebCore::WorkerRunLoop::runCleanupTasks): * workers/WorkerThread.h: (WebCore::WorkerThread::thread const): (WebCore::WorkerThread::threadID const): Deleted. * workers/service/ServiceWorkerContainer.cpp: (WebCore::ServiceWorkerContainer::~ServiceWorkerContainer): (WebCore::ServiceWorkerContainer::scheduleJob): (WebCore::ServiceWorkerContainer::jobFailedWithException): (WebCore::ServiceWorkerContainer::scheduleTaskToFireUpdateFoundEvent): (WebCore::ServiceWorkerContainer::jobResolvedWithRegistration): (WebCore::ServiceWorkerContainer::jobResolvedWithUnregistrationResult): (WebCore::ServiceWorkerContainer::startScriptFetchForJob): (WebCore::ServiceWorkerContainer::jobFinishedLoadingScript): (WebCore::ServiceWorkerContainer::jobFailedLoadingScript): (WebCore::ServiceWorkerContainer::jobDidFinish): (WebCore::ServiceWorkerContainer::addRegistration): (WebCore::ServiceWorkerContainer::removeRegistration): (WebCore::ServiceWorkerContainer::scheduleTaskToFireControllerChangeEvent): (WebCore::ServiceWorkerContainer::contextIdentifier): * workers/service/ServiceWorkerContainer.h: * workers/service/ServiceWorkerJob.cpp: (WebCore::ServiceWorkerJob::~ServiceWorkerJob): (WebCore::ServiceWorkerJob::failedWithException): (WebCore::ServiceWorkerJob::resolvedWithRegistration): (WebCore::ServiceWorkerJob::resolvedWithUnregistrationResult): (WebCore::ServiceWorkerJob::startScriptFetch): (WebCore::ServiceWorkerJob::fetchScriptWithContext): (WebCore::ServiceWorkerJob::didReceiveResponse): (WebCore::ServiceWorkerJob::notifyFinished): * workers/service/ServiceWorkerJob.h: * xml/parser/XMLDocumentParserLibxml2.cpp: (WebCore::matchFunc): (WebCore::openFunc): (WebCore::initializeXMLParser): (WebCore::XMLParserContext::createStringParser): (WebCore::XMLParserContext::createMemoryParser): Source/WebKit: * UIProcess/API/glib/IconDatabase.cpp: * UIProcess/GenericCallback.h: (WebKit::GenericCallback::~GenericCallback): (WebKit::GenericCallback::performCallbackWithReturnValue): Source/WTF: We should use a pointer of WTF::Thread instead of ThreadIdentifier. One problem is that Windows support library uses WTF::createThread, which returns ThreadIdentifier. So we cannot drop ThreadIdentifier in Windows environment. This patch keeps ThreadIdentifier in Windows. * wtf/MainThread.cpp: (WTF::initializeMainThread): (WTF::isMainThread): (WTF::canAccessThreadLocalDataForThread): * wtf/MainThread.h: * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkCount): * wtf/RecursiveLockAdapter.h: (WTF::RecursiveLockAdapter::lock): (WTF::RecursiveLockAdapter::unlock): (WTF::RecursiveLockAdapter::tryLock): * wtf/Threading.cpp: (WTF::Thread::dump const): * wtf/Threading.h: (WTF::Thread::id const): (WTF::Thread::operator==): Deleted. (WTF::Thread::operator!=): Deleted. (WTF::currentThread): Deleted. * wtf/ThreadingPrimitives.h: * wtf/ThreadingPthreads.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::detach): (WTF::Thread::initializeCurrentTLS): (WTF::Thread::suspend): (WTF::Thread::establishPlatformSpecificHandle): (WTF::Thread::currentID): Deleted. * wtf/ThreadingWin.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::suspend): (WTF::Thread::currentDying): * wtf/mac/MainThreadMac.mm: (WTF::initializeApplicationUIThread): (WTF::initializeWebThreadPlatform): (WTF::canAccessThreadLocalDataForThread): (WTF::initializeApplicationUIThreadIdentifier): Deleted. (WTF::initializeWebThreadIdentifier): Deleted. Tools: * DumpRenderTree/mac/DumpRenderTree.mm: (dumpRenderTree): (runThread): Deleted. (runPthread): Deleted. (testThreadIdentifierMap): Deleted. * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: * TestWebKitAPI/Tests/WTF/Threading.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/196314@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@225470 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-12-04 06:13:05 +00:00
dataLog(toString(Thread::current(), ": no need to rehash because ", oldHashtable->size, " / ", numThreads, " >= ", maxLoadFactor, "\n"));
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
return;
}
// Seems like we *might* have to rehash, so lock the hashtable and try again.
Vector<Bucket*> bucketsToUnlock = lockHashtable();
// Check again, since the hashtable could have rehashed while we were locking it. Also,
// lockHashtable() creates an initial hashtable for us.
oldHashtable = hashtable.load();
RELEASE_ASSERT(oldHashtable);
if (static_cast<double>(oldHashtable->size) / static_cast<double>(numThreads) >= maxLoadFactor) {
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
if (verbose)
WTF shouldn't have both Thread and ThreadIdentifier https://bugs.webkit.org/show_bug.cgi?id=180308 Reviewed by Darin Adler. Source/JavaScriptCore: * heap/MachineStackMarker.cpp: (JSC::MachineThreads::tryCopyOtherThreadStacks): * llint/LLIntSlowPaths.cpp: (JSC::LLInt::llint_trace_operand): (JSC::LLInt::llint_trace_value): (JSC::LLInt::LLINT_SLOW_PATH_DECL): (JSC::LLInt::traceFunctionPrologue): * runtime/ExceptionScope.cpp: (JSC::ExceptionScope::unexpectedExceptionMessage): * runtime/JSLock.h: (JSC::JSLock::currentThreadIsHoldingLock): * runtime/VM.cpp: (JSC::VM::throwException): * runtime/VM.h: (JSC::VM::throwingThread const): (JSC::VM::clearException): * tools/HeapVerifier.cpp: (JSC::HeapVerifier::printVerificationHeader): Source/WebCore: No behavior change. * Modules/indexeddb/IDBActiveDOMObject.h: (WebCore::IDBActiveDOMObject::originThread const): (WebCore::IDBActiveDOMObject::performCallbackOnOriginThread): (WebCore::IDBActiveDOMObject::callFunctionOnOriginThread): (WebCore::IDBActiveDOMObject::originThreadID const): Deleted. * Modules/indexeddb/IDBCursor.cpp: (WebCore::IDBCursor::IDBCursor): (WebCore::IDBCursor::~IDBCursor): (WebCore::IDBCursor::sourcesDeleted const): (WebCore::IDBCursor::transaction const): (WebCore::IDBCursor::update): (WebCore::IDBCursor::advance): (WebCore::IDBCursor::continueFunction): (WebCore::IDBCursor::uncheckedIterateCursor): (WebCore::IDBCursor::deleteFunction): (WebCore::IDBCursor::setGetResult): * Modules/indexeddb/IDBDatabase.cpp: (WebCore::IDBDatabase::~IDBDatabase): (WebCore::IDBDatabase::hasPendingActivity const): (WebCore::IDBDatabase::name const): (WebCore::IDBDatabase::version const): (WebCore::IDBDatabase::objectStoreNames const): (WebCore::IDBDatabase::renameObjectStore): (WebCore::IDBDatabase::renameIndex): (WebCore::IDBDatabase::createObjectStore): (WebCore::IDBDatabase::transaction): (WebCore::IDBDatabase::deleteObjectStore): (WebCore::IDBDatabase::close): (WebCore::IDBDatabase::connectionToServerLost): (WebCore::IDBDatabase::maybeCloseInServer): (WebCore::IDBDatabase::activeDOMObjectName const): (WebCore::IDBDatabase::canSuspendForDocumentSuspension const): (WebCore::IDBDatabase::stop): (WebCore::IDBDatabase::startVersionChangeTransaction): (WebCore::IDBDatabase::didStartTransaction): (WebCore::IDBDatabase::willCommitTransaction): (WebCore::IDBDatabase::didCommitTransaction): (WebCore::IDBDatabase::willAbortTransaction): (WebCore::IDBDatabase::didAbortTransaction): (WebCore::IDBDatabase::didCommitOrAbortTransaction): (WebCore::IDBDatabase::fireVersionChangeEvent): (WebCore::IDBDatabase::dispatchEvent): (WebCore::IDBDatabase::didCreateIndexInfo): (WebCore::IDBDatabase::didDeleteIndexInfo): * Modules/indexeddb/IDBIndex.cpp: (WebCore::IDBIndex::IDBIndex): (WebCore::IDBIndex::~IDBIndex): (WebCore::IDBIndex::name const): (WebCore::IDBIndex::setName): (WebCore::IDBIndex::objectStore): (WebCore::IDBIndex::keyPath const): (WebCore::IDBIndex::unique const): (WebCore::IDBIndex::multiEntry const): (WebCore::IDBIndex::rollbackInfoForVersionChangeAbort): (WebCore::IDBIndex::openCursor): (WebCore::IDBIndex::openKeyCursor): (WebCore::IDBIndex::doCount): (WebCore::IDBIndex::doGet): (WebCore::IDBIndex::doGetKey): (WebCore::IDBIndex::getAll): (WebCore::IDBIndex::getAllKeys): (WebCore::IDBIndex::markAsDeleted): * Modules/indexeddb/IDBObjectStore.cpp: (WebCore::IDBObjectStore::IDBObjectStore): (WebCore::IDBObjectStore::~IDBObjectStore): (WebCore::IDBObjectStore::name const): (WebCore::IDBObjectStore::setName): (WebCore::IDBObjectStore::keyPath const): (WebCore::IDBObjectStore::indexNames const): (WebCore::IDBObjectStore::transaction): (WebCore::IDBObjectStore::autoIncrement const): (WebCore::IDBObjectStore::openCursor): (WebCore::IDBObjectStore::openKeyCursor): (WebCore::IDBObjectStore::get): (WebCore::IDBObjectStore::getKey): (WebCore::IDBObjectStore::putOrAdd): (WebCore::IDBObjectStore::doDelete): (WebCore::IDBObjectStore::clear): (WebCore::IDBObjectStore::createIndex): (WebCore::IDBObjectStore::index): (WebCore::IDBObjectStore::deleteIndex): (WebCore::IDBObjectStore::doCount): (WebCore::IDBObjectStore::getAll): (WebCore::IDBObjectStore::getAllKeys): (WebCore::IDBObjectStore::markAsDeleted): (WebCore::IDBObjectStore::rollbackForVersionChangeAbort): * Modules/indexeddb/IDBOpenDBRequest.cpp: (WebCore::IDBOpenDBRequest::~IDBOpenDBRequest): (WebCore::IDBOpenDBRequest::onError): (WebCore::IDBOpenDBRequest::versionChangeTransactionDidFinish): (WebCore::IDBOpenDBRequest::fireSuccessAfterVersionChangeCommit): (WebCore::IDBOpenDBRequest::fireErrorAfterVersionChangeCompletion): (WebCore::IDBOpenDBRequest::dispatchEvent): (WebCore::IDBOpenDBRequest::onSuccess): (WebCore::IDBOpenDBRequest::onUpgradeNeeded): (WebCore::IDBOpenDBRequest::onDeleteDatabaseSuccess): (WebCore::IDBOpenDBRequest::requestCompleted): (WebCore::IDBOpenDBRequest::requestBlocked): * Modules/indexeddb/IDBRequest.cpp: (WebCore::IDBRequest::~IDBRequest): (WebCore:: const): (WebCore::IDBRequest::setSource): (WebCore::IDBRequest::setVersionChangeTransaction): (WebCore::IDBRequest::transaction const): (WebCore::IDBRequest::sourceObjectStoreIdentifier const): (WebCore::IDBRequest::sourceIndexIdentifier const): (WebCore::IDBRequest::requestedObjectStoreRecordType const): (WebCore::IDBRequest::requestedIndexRecordType const): (WebCore::IDBRequest::eventTargetInterface const): (WebCore::IDBRequest::activeDOMObjectName const): (WebCore::IDBRequest::canSuspendForDocumentSuspension const): (WebCore::IDBRequest::hasPendingActivity const): (WebCore::IDBRequest::stop): (WebCore::IDBRequest::enqueueEvent): (WebCore::IDBRequest::dispatchEvent): (WebCore::IDBRequest::uncaughtExceptionInEventHandler): (WebCore::IDBRequest::setResult): (WebCore::IDBRequest::setResultToStructuredClone): (WebCore::IDBRequest::setResultToUndefined): (WebCore::IDBRequest::resultCursor): (WebCore::IDBRequest::willIterateCursor): (WebCore::IDBRequest::didOpenOrIterateCursor): (WebCore::IDBRequest::completeRequestAndDispatchEvent): (WebCore::IDBRequest::onError): (WebCore::IDBRequest::onSuccess): * Modules/indexeddb/IDBTransaction.cpp: (WebCore::IDBTransaction::IDBTransaction): (WebCore::IDBTransaction::~IDBTransaction): (WebCore::IDBTransaction::objectStoreNames const): (WebCore::IDBTransaction::db): (WebCore::IDBTransaction::error const): (WebCore::IDBTransaction::objectStore): (WebCore::IDBTransaction::abortDueToFailedRequest): (WebCore::IDBTransaction::transitionedToFinishing): (WebCore::IDBTransaction::abort): (WebCore::IDBTransaction::internalAbort): (WebCore::IDBTransaction::abortOnServerAndCancelRequests): (WebCore::IDBTransaction::activeDOMObjectName const): (WebCore::IDBTransaction::canSuspendForDocumentSuspension const): (WebCore::IDBTransaction::hasPendingActivity const): (WebCore::IDBTransaction::stop): (WebCore::IDBTransaction::isActive const): (WebCore::IDBTransaction::isFinishedOrFinishing const): (WebCore::IDBTransaction::addRequest): (WebCore::IDBTransaction::removeRequest): (WebCore::IDBTransaction::scheduleOperation): (WebCore::IDBTransaction::schedulePendingOperationTimer): (WebCore::IDBTransaction::pendingOperationTimerFired): (WebCore::IDBTransaction::operationCompletedOnServer): (WebCore::IDBTransaction::scheduleCompletedOperationTimer): (WebCore::IDBTransaction::completedOperationTimerFired): (WebCore::IDBTransaction::commit): (WebCore::IDBTransaction::commitOnServer): (WebCore::IDBTransaction::finishAbortOrCommit): (WebCore::IDBTransaction::didStart): (WebCore::IDBTransaction::notifyDidAbort): (WebCore::IDBTransaction::didAbort): (WebCore::IDBTransaction::didCommit): (WebCore::IDBTransaction::fireOnComplete): (WebCore::IDBTransaction::fireOnAbort): (WebCore::IDBTransaction::enqueueEvent): (WebCore::IDBTransaction::dispatchEvent): (WebCore::IDBTransaction::createObjectStore): (WebCore::IDBTransaction::createObjectStoreOnServer): (WebCore::IDBTransaction::didCreateObjectStoreOnServer): (WebCore::IDBTransaction::renameObjectStore): (WebCore::IDBTransaction::renameObjectStoreOnServer): (WebCore::IDBTransaction::didRenameObjectStoreOnServer): (WebCore::IDBTransaction::createIndex): (WebCore::IDBTransaction::createIndexOnServer): (WebCore::IDBTransaction::didCreateIndexOnServer): (WebCore::IDBTransaction::renameIndex): (WebCore::IDBTransaction::renameIndexOnServer): (WebCore::IDBTransaction::didRenameIndexOnServer): (WebCore::IDBTransaction::requestOpenCursor): (WebCore::IDBTransaction::doRequestOpenCursor): (WebCore::IDBTransaction::openCursorOnServer): (WebCore::IDBTransaction::didOpenCursorOnServer): (WebCore::IDBTransaction::iterateCursor): (WebCore::IDBTransaction::iterateCursorOnServer): (WebCore::IDBTransaction::didIterateCursorOnServer): (WebCore::IDBTransaction::requestGetAllObjectStoreRecords): (WebCore::IDBTransaction::requestGetAllIndexRecords): (WebCore::IDBTransaction::getAllRecordsOnServer): (WebCore::IDBTransaction::didGetAllRecordsOnServer): (WebCore::IDBTransaction::requestGetRecord): (WebCore::IDBTransaction::requestGetValue): (WebCore::IDBTransaction::requestGetKey): (WebCore::IDBTransaction::requestIndexRecord): (WebCore::IDBTransaction::getRecordOnServer): (WebCore::IDBTransaction::didGetRecordOnServer): (WebCore::IDBTransaction::requestCount): (WebCore::IDBTransaction::getCountOnServer): (WebCore::IDBTransaction::didGetCountOnServer): (WebCore::IDBTransaction::requestDeleteRecord): (WebCore::IDBTransaction::deleteRecordOnServer): (WebCore::IDBTransaction::didDeleteRecordOnServer): (WebCore::IDBTransaction::requestClearObjectStore): (WebCore::IDBTransaction::clearObjectStoreOnServer): (WebCore::IDBTransaction::didClearObjectStoreOnServer): (WebCore::IDBTransaction::requestPutOrAdd): (WebCore::IDBTransaction::putOrAddOnServer): (WebCore::IDBTransaction::didPutOrAddOnServer): (WebCore::IDBTransaction::deleteObjectStore): (WebCore::IDBTransaction::deleteObjectStoreOnServer): (WebCore::IDBTransaction::didDeleteObjectStoreOnServer): (WebCore::IDBTransaction::deleteIndex): (WebCore::IDBTransaction::deleteIndexOnServer): (WebCore::IDBTransaction::didDeleteIndexOnServer): (WebCore::IDBTransaction::operationCompletedOnClient): (WebCore::IDBTransaction::establishOnServer): (WebCore::IDBTransaction::activate): (WebCore::IDBTransaction::deactivate): * Modules/indexeddb/client/IDBConnectionProxy.cpp: (WebCore::IDBClient::removeItemsMatchingCurrentThread): * Modules/indexeddb/client/TransactionOperation.h: (WebCore::IDBClient::TransactionOperation::~TransactionOperation): (WebCore::IDBClient::TransactionOperation::perform): (WebCore::IDBClient::TransactionOperation::transitionToCompleteOnThisThread): (WebCore::IDBClient::TransactionOperation::transitionToComplete): (WebCore::IDBClient::TransactionOperation::doComplete): (WebCore::IDBClient::TransactionOperation::originThread const): (WebCore::IDBClient::TransactionOperation::originThreadID const): Deleted. * Modules/webaudio/AudioContext.cpp: (WebCore::AudioContext::AudioContext): (WebCore::AudioContext::lock): (WebCore::AudioContext::tryLock): (WebCore::AudioContext::unlock): (WebCore::AudioContext::isAudioThread const): (WebCore::AudioContext::isGraphOwner const): * Modules/webaudio/AudioContext.h: (WebCore::AudioContext::setAudioThread): (WebCore::AudioContext::audioThread const): * Modules/webaudio/AudioDestinationNode.cpp: (WebCore::AudioDestinationNode::render): * Modules/webdatabase/Database.cpp: (WebCore::Database::performClose): (WebCore::Database::securityOrigin): * Modules/webdatabase/DatabaseDetails.h: (WebCore::DatabaseDetails::DatabaseDetails): (WebCore::DatabaseDetails::operator=): (WebCore::DatabaseDetails::thread const): (WebCore::DatabaseDetails::threadID const): Deleted. * Modules/webdatabase/DatabaseManager.cpp: (WebCore::DatabaseManager::detailsForNameAndOrigin): * Modules/webdatabase/DatabaseThread.cpp: (WebCore::DatabaseThread::databaseThread): (WebCore::DatabaseThread::recordDatabaseOpen): (WebCore::DatabaseThread::recordDatabaseClosed): * Modules/webdatabase/DatabaseThread.h: (WebCore::DatabaseThread::getThread): (WebCore::DatabaseThread::getThreadID): Deleted. * Modules/webdatabase/SQLTransaction.cpp: (WebCore::SQLTransaction::checkAndHandleClosedDatabase): * Modules/webdatabase/SQLTransactionBackend.cpp: (WebCore::SQLTransactionBackend::doCleanup): (WebCore::SQLTransactionBackend::notifyDatabaseThreadIsShuttingDown): * bindings/js/JSCallbackData.h: (WebCore::JSCallbackData::JSCallbackData): (WebCore::JSCallbackData::~JSCallbackData): * bindings/js/ScheduledAction.cpp: (WebCore::ScheduledAction::execute): * dom/ScriptExecutionContext.cpp: (WebCore::ScriptExecutionContext::createdMessagePort): (WebCore::ScriptExecutionContext::destroyedMessagePort): * page/ResourceUsageOverlay.h: * page/scrolling/ScrollingThread.cpp: (WebCore::ScrollingThread::isCurrentThread): * platform/Supplementable.h: (WebCore::Supplementable::provideSupplement): (WebCore::Supplementable::removeSupplement): (WebCore::Supplementable::requireSupplement): (WebCore::Supplementable::Supplementable): Deleted. * platform/Timer.cpp: (WebCore::TimerBase::TimerBase): (WebCore::TimerBase::start): (WebCore::TimerBase::stop): (WebCore::TimerBase::setNextFireTime): * platform/Timer.h: (WebCore::TimerBase::isActive const): * platform/graphics/cocoa/FontCacheCoreText.cpp: (WebCore::shouldAutoActivateFontIfNeeded): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.cpp: (WebCore::TextureMapperPlatformLayerProxy::activateOnCompositingThread): (WebCore::TextureMapperPlatformLayerProxy::invalidate): (WebCore::TextureMapperPlatformLayerProxy::getAvailableBuffer): (WebCore::TextureMapperPlatformLayerProxy::appendToUnusedBuffers): (WebCore::TextureMapperPlatformLayerProxy::swapBuffer): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.h: (): Deleted. * platform/ios/wak/WebCoreThread.mm: (RunWebThread): (StartWebThread): * platform/sql/SQLiteDatabase.cpp: (WebCore::SQLiteDatabase::open): (WebCore::SQLiteDatabase::close): * platform/sql/SQLiteDatabase.h: (WebCore::SQLiteDatabase::sqlite3Handle const): * workers/WorkerGlobalScope.cpp: (WebCore::WorkerGlobalScope::~WorkerGlobalScope): (WebCore::WorkerGlobalScope::isContextThread const): * workers/WorkerMessagingProxy.cpp: (WebCore::WorkerMessagingProxy::WorkerMessagingProxy): (WebCore::WorkerMessagingProxy::~WorkerMessagingProxy): * workers/WorkerRunLoop.cpp: (WebCore::WorkerRunLoop::runInMode): (WebCore::WorkerRunLoop::runCleanupTasks): * workers/WorkerThread.h: (WebCore::WorkerThread::thread const): (WebCore::WorkerThread::threadID const): Deleted. * workers/service/ServiceWorkerContainer.cpp: (WebCore::ServiceWorkerContainer::~ServiceWorkerContainer): (WebCore::ServiceWorkerContainer::scheduleJob): (WebCore::ServiceWorkerContainer::jobFailedWithException): (WebCore::ServiceWorkerContainer::scheduleTaskToFireUpdateFoundEvent): (WebCore::ServiceWorkerContainer::jobResolvedWithRegistration): (WebCore::ServiceWorkerContainer::jobResolvedWithUnregistrationResult): (WebCore::ServiceWorkerContainer::startScriptFetchForJob): (WebCore::ServiceWorkerContainer::jobFinishedLoadingScript): (WebCore::ServiceWorkerContainer::jobFailedLoadingScript): (WebCore::ServiceWorkerContainer::jobDidFinish): (WebCore::ServiceWorkerContainer::addRegistration): (WebCore::ServiceWorkerContainer::removeRegistration): (WebCore::ServiceWorkerContainer::scheduleTaskToFireControllerChangeEvent): (WebCore::ServiceWorkerContainer::contextIdentifier): * workers/service/ServiceWorkerContainer.h: * workers/service/ServiceWorkerJob.cpp: (WebCore::ServiceWorkerJob::~ServiceWorkerJob): (WebCore::ServiceWorkerJob::failedWithException): (WebCore::ServiceWorkerJob::resolvedWithRegistration): (WebCore::ServiceWorkerJob::resolvedWithUnregistrationResult): (WebCore::ServiceWorkerJob::startScriptFetch): (WebCore::ServiceWorkerJob::fetchScriptWithContext): (WebCore::ServiceWorkerJob::didReceiveResponse): (WebCore::ServiceWorkerJob::notifyFinished): * workers/service/ServiceWorkerJob.h: * xml/parser/XMLDocumentParserLibxml2.cpp: (WebCore::matchFunc): (WebCore::openFunc): (WebCore::initializeXMLParser): (WebCore::XMLParserContext::createStringParser): (WebCore::XMLParserContext::createMemoryParser): Source/WebKit: * UIProcess/API/glib/IconDatabase.cpp: * UIProcess/GenericCallback.h: (WebKit::GenericCallback::~GenericCallback): (WebKit::GenericCallback::performCallbackWithReturnValue): Source/WTF: We should use a pointer of WTF::Thread instead of ThreadIdentifier. One problem is that Windows support library uses WTF::createThread, which returns ThreadIdentifier. So we cannot drop ThreadIdentifier in Windows environment. This patch keeps ThreadIdentifier in Windows. * wtf/MainThread.cpp: (WTF::initializeMainThread): (WTF::isMainThread): (WTF::canAccessThreadLocalDataForThread): * wtf/MainThread.h: * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkCount): * wtf/RecursiveLockAdapter.h: (WTF::RecursiveLockAdapter::lock): (WTF::RecursiveLockAdapter::unlock): (WTF::RecursiveLockAdapter::tryLock): * wtf/Threading.cpp: (WTF::Thread::dump const): * wtf/Threading.h: (WTF::Thread::id const): (WTF::Thread::operator==): Deleted. (WTF::Thread::operator!=): Deleted. (WTF::currentThread): Deleted. * wtf/ThreadingPrimitives.h: * wtf/ThreadingPthreads.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::detach): (WTF::Thread::initializeCurrentTLS): (WTF::Thread::suspend): (WTF::Thread::establishPlatformSpecificHandle): (WTF::Thread::currentID): Deleted. * wtf/ThreadingWin.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::suspend): (WTF::Thread::currentDying): * wtf/mac/MainThreadMac.mm: (WTF::initializeApplicationUIThread): (WTF::initializeWebThreadPlatform): (WTF::canAccessThreadLocalDataForThread): (WTF::initializeApplicationUIThreadIdentifier): Deleted. (WTF::initializeWebThreadIdentifier): Deleted. Tools: * DumpRenderTree/mac/DumpRenderTree.mm: (dumpRenderTree): (runThread): Deleted. (runPthread): Deleted. (testThreadIdentifierMap): Deleted. * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: * TestWebKitAPI/Tests/WTF/Threading.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/196314@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@225470 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-12-04 06:13:05 +00:00
dataLog(toString(Thread::current(), ": after locking, no need to rehash because ", oldHashtable->size, " / ", numThreads, " >= ", maxLoadFactor, "\n"));
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
unlockHashtable(bucketsToUnlock);
return;
}
Vector<Bucket*> reusableBuckets = bucketsToUnlock;
// OK, now we resize. First we gather all thread datas from the old hashtable. These thread datas
// are placed into the vector in queue order.
Vector<ThreadData*> threadDatas;
for (Bucket* bucket : reusableBuckets) {
while (ThreadData* threadData = bucket->dequeue())
threadDatas.append(threadData);
}
unsigned newSize = numThreads * growthFactor * maxLoadFactor;
RELEASE_ASSERT(newSize > oldHashtable->size);
Hashtable* newHashtable = Hashtable::create(newSize);
if (verbose)
WTF shouldn't have both Thread and ThreadIdentifier https://bugs.webkit.org/show_bug.cgi?id=180308 Reviewed by Darin Adler. Source/JavaScriptCore: * heap/MachineStackMarker.cpp: (JSC::MachineThreads::tryCopyOtherThreadStacks): * llint/LLIntSlowPaths.cpp: (JSC::LLInt::llint_trace_operand): (JSC::LLInt::llint_trace_value): (JSC::LLInt::LLINT_SLOW_PATH_DECL): (JSC::LLInt::traceFunctionPrologue): * runtime/ExceptionScope.cpp: (JSC::ExceptionScope::unexpectedExceptionMessage): * runtime/JSLock.h: (JSC::JSLock::currentThreadIsHoldingLock): * runtime/VM.cpp: (JSC::VM::throwException): * runtime/VM.h: (JSC::VM::throwingThread const): (JSC::VM::clearException): * tools/HeapVerifier.cpp: (JSC::HeapVerifier::printVerificationHeader): Source/WebCore: No behavior change. * Modules/indexeddb/IDBActiveDOMObject.h: (WebCore::IDBActiveDOMObject::originThread const): (WebCore::IDBActiveDOMObject::performCallbackOnOriginThread): (WebCore::IDBActiveDOMObject::callFunctionOnOriginThread): (WebCore::IDBActiveDOMObject::originThreadID const): Deleted. * Modules/indexeddb/IDBCursor.cpp: (WebCore::IDBCursor::IDBCursor): (WebCore::IDBCursor::~IDBCursor): (WebCore::IDBCursor::sourcesDeleted const): (WebCore::IDBCursor::transaction const): (WebCore::IDBCursor::update): (WebCore::IDBCursor::advance): (WebCore::IDBCursor::continueFunction): (WebCore::IDBCursor::uncheckedIterateCursor): (WebCore::IDBCursor::deleteFunction): (WebCore::IDBCursor::setGetResult): * Modules/indexeddb/IDBDatabase.cpp: (WebCore::IDBDatabase::~IDBDatabase): (WebCore::IDBDatabase::hasPendingActivity const): (WebCore::IDBDatabase::name const): (WebCore::IDBDatabase::version const): (WebCore::IDBDatabase::objectStoreNames const): (WebCore::IDBDatabase::renameObjectStore): (WebCore::IDBDatabase::renameIndex): (WebCore::IDBDatabase::createObjectStore): (WebCore::IDBDatabase::transaction): (WebCore::IDBDatabase::deleteObjectStore): (WebCore::IDBDatabase::close): (WebCore::IDBDatabase::connectionToServerLost): (WebCore::IDBDatabase::maybeCloseInServer): (WebCore::IDBDatabase::activeDOMObjectName const): (WebCore::IDBDatabase::canSuspendForDocumentSuspension const): (WebCore::IDBDatabase::stop): (WebCore::IDBDatabase::startVersionChangeTransaction): (WebCore::IDBDatabase::didStartTransaction): (WebCore::IDBDatabase::willCommitTransaction): (WebCore::IDBDatabase::didCommitTransaction): (WebCore::IDBDatabase::willAbortTransaction): (WebCore::IDBDatabase::didAbortTransaction): (WebCore::IDBDatabase::didCommitOrAbortTransaction): (WebCore::IDBDatabase::fireVersionChangeEvent): (WebCore::IDBDatabase::dispatchEvent): (WebCore::IDBDatabase::didCreateIndexInfo): (WebCore::IDBDatabase::didDeleteIndexInfo): * Modules/indexeddb/IDBIndex.cpp: (WebCore::IDBIndex::IDBIndex): (WebCore::IDBIndex::~IDBIndex): (WebCore::IDBIndex::name const): (WebCore::IDBIndex::setName): (WebCore::IDBIndex::objectStore): (WebCore::IDBIndex::keyPath const): (WebCore::IDBIndex::unique const): (WebCore::IDBIndex::multiEntry const): (WebCore::IDBIndex::rollbackInfoForVersionChangeAbort): (WebCore::IDBIndex::openCursor): (WebCore::IDBIndex::openKeyCursor): (WebCore::IDBIndex::doCount): (WebCore::IDBIndex::doGet): (WebCore::IDBIndex::doGetKey): (WebCore::IDBIndex::getAll): (WebCore::IDBIndex::getAllKeys): (WebCore::IDBIndex::markAsDeleted): * Modules/indexeddb/IDBObjectStore.cpp: (WebCore::IDBObjectStore::IDBObjectStore): (WebCore::IDBObjectStore::~IDBObjectStore): (WebCore::IDBObjectStore::name const): (WebCore::IDBObjectStore::setName): (WebCore::IDBObjectStore::keyPath const): (WebCore::IDBObjectStore::indexNames const): (WebCore::IDBObjectStore::transaction): (WebCore::IDBObjectStore::autoIncrement const): (WebCore::IDBObjectStore::openCursor): (WebCore::IDBObjectStore::openKeyCursor): (WebCore::IDBObjectStore::get): (WebCore::IDBObjectStore::getKey): (WebCore::IDBObjectStore::putOrAdd): (WebCore::IDBObjectStore::doDelete): (WebCore::IDBObjectStore::clear): (WebCore::IDBObjectStore::createIndex): (WebCore::IDBObjectStore::index): (WebCore::IDBObjectStore::deleteIndex): (WebCore::IDBObjectStore::doCount): (WebCore::IDBObjectStore::getAll): (WebCore::IDBObjectStore::getAllKeys): (WebCore::IDBObjectStore::markAsDeleted): (WebCore::IDBObjectStore::rollbackForVersionChangeAbort): * Modules/indexeddb/IDBOpenDBRequest.cpp: (WebCore::IDBOpenDBRequest::~IDBOpenDBRequest): (WebCore::IDBOpenDBRequest::onError): (WebCore::IDBOpenDBRequest::versionChangeTransactionDidFinish): (WebCore::IDBOpenDBRequest::fireSuccessAfterVersionChangeCommit): (WebCore::IDBOpenDBRequest::fireErrorAfterVersionChangeCompletion): (WebCore::IDBOpenDBRequest::dispatchEvent): (WebCore::IDBOpenDBRequest::onSuccess): (WebCore::IDBOpenDBRequest::onUpgradeNeeded): (WebCore::IDBOpenDBRequest::onDeleteDatabaseSuccess): (WebCore::IDBOpenDBRequest::requestCompleted): (WebCore::IDBOpenDBRequest::requestBlocked): * Modules/indexeddb/IDBRequest.cpp: (WebCore::IDBRequest::~IDBRequest): (WebCore:: const): (WebCore::IDBRequest::setSource): (WebCore::IDBRequest::setVersionChangeTransaction): (WebCore::IDBRequest::transaction const): (WebCore::IDBRequest::sourceObjectStoreIdentifier const): (WebCore::IDBRequest::sourceIndexIdentifier const): (WebCore::IDBRequest::requestedObjectStoreRecordType const): (WebCore::IDBRequest::requestedIndexRecordType const): (WebCore::IDBRequest::eventTargetInterface const): (WebCore::IDBRequest::activeDOMObjectName const): (WebCore::IDBRequest::canSuspendForDocumentSuspension const): (WebCore::IDBRequest::hasPendingActivity const): (WebCore::IDBRequest::stop): (WebCore::IDBRequest::enqueueEvent): (WebCore::IDBRequest::dispatchEvent): (WebCore::IDBRequest::uncaughtExceptionInEventHandler): (WebCore::IDBRequest::setResult): (WebCore::IDBRequest::setResultToStructuredClone): (WebCore::IDBRequest::setResultToUndefined): (WebCore::IDBRequest::resultCursor): (WebCore::IDBRequest::willIterateCursor): (WebCore::IDBRequest::didOpenOrIterateCursor): (WebCore::IDBRequest::completeRequestAndDispatchEvent): (WebCore::IDBRequest::onError): (WebCore::IDBRequest::onSuccess): * Modules/indexeddb/IDBTransaction.cpp: (WebCore::IDBTransaction::IDBTransaction): (WebCore::IDBTransaction::~IDBTransaction): (WebCore::IDBTransaction::objectStoreNames const): (WebCore::IDBTransaction::db): (WebCore::IDBTransaction::error const): (WebCore::IDBTransaction::objectStore): (WebCore::IDBTransaction::abortDueToFailedRequest): (WebCore::IDBTransaction::transitionedToFinishing): (WebCore::IDBTransaction::abort): (WebCore::IDBTransaction::internalAbort): (WebCore::IDBTransaction::abortOnServerAndCancelRequests): (WebCore::IDBTransaction::activeDOMObjectName const): (WebCore::IDBTransaction::canSuspendForDocumentSuspension const): (WebCore::IDBTransaction::hasPendingActivity const): (WebCore::IDBTransaction::stop): (WebCore::IDBTransaction::isActive const): (WebCore::IDBTransaction::isFinishedOrFinishing const): (WebCore::IDBTransaction::addRequest): (WebCore::IDBTransaction::removeRequest): (WebCore::IDBTransaction::scheduleOperation): (WebCore::IDBTransaction::schedulePendingOperationTimer): (WebCore::IDBTransaction::pendingOperationTimerFired): (WebCore::IDBTransaction::operationCompletedOnServer): (WebCore::IDBTransaction::scheduleCompletedOperationTimer): (WebCore::IDBTransaction::completedOperationTimerFired): (WebCore::IDBTransaction::commit): (WebCore::IDBTransaction::commitOnServer): (WebCore::IDBTransaction::finishAbortOrCommit): (WebCore::IDBTransaction::didStart): (WebCore::IDBTransaction::notifyDidAbort): (WebCore::IDBTransaction::didAbort): (WebCore::IDBTransaction::didCommit): (WebCore::IDBTransaction::fireOnComplete): (WebCore::IDBTransaction::fireOnAbort): (WebCore::IDBTransaction::enqueueEvent): (WebCore::IDBTransaction::dispatchEvent): (WebCore::IDBTransaction::createObjectStore): (WebCore::IDBTransaction::createObjectStoreOnServer): (WebCore::IDBTransaction::didCreateObjectStoreOnServer): (WebCore::IDBTransaction::renameObjectStore): (WebCore::IDBTransaction::renameObjectStoreOnServer): (WebCore::IDBTransaction::didRenameObjectStoreOnServer): (WebCore::IDBTransaction::createIndex): (WebCore::IDBTransaction::createIndexOnServer): (WebCore::IDBTransaction::didCreateIndexOnServer): (WebCore::IDBTransaction::renameIndex): (WebCore::IDBTransaction::renameIndexOnServer): (WebCore::IDBTransaction::didRenameIndexOnServer): (WebCore::IDBTransaction::requestOpenCursor): (WebCore::IDBTransaction::doRequestOpenCursor): (WebCore::IDBTransaction::openCursorOnServer): (WebCore::IDBTransaction::didOpenCursorOnServer): (WebCore::IDBTransaction::iterateCursor): (WebCore::IDBTransaction::iterateCursorOnServer): (WebCore::IDBTransaction::didIterateCursorOnServer): (WebCore::IDBTransaction::requestGetAllObjectStoreRecords): (WebCore::IDBTransaction::requestGetAllIndexRecords): (WebCore::IDBTransaction::getAllRecordsOnServer): (WebCore::IDBTransaction::didGetAllRecordsOnServer): (WebCore::IDBTransaction::requestGetRecord): (WebCore::IDBTransaction::requestGetValue): (WebCore::IDBTransaction::requestGetKey): (WebCore::IDBTransaction::requestIndexRecord): (WebCore::IDBTransaction::getRecordOnServer): (WebCore::IDBTransaction::didGetRecordOnServer): (WebCore::IDBTransaction::requestCount): (WebCore::IDBTransaction::getCountOnServer): (WebCore::IDBTransaction::didGetCountOnServer): (WebCore::IDBTransaction::requestDeleteRecord): (WebCore::IDBTransaction::deleteRecordOnServer): (WebCore::IDBTransaction::didDeleteRecordOnServer): (WebCore::IDBTransaction::requestClearObjectStore): (WebCore::IDBTransaction::clearObjectStoreOnServer): (WebCore::IDBTransaction::didClearObjectStoreOnServer): (WebCore::IDBTransaction::requestPutOrAdd): (WebCore::IDBTransaction::putOrAddOnServer): (WebCore::IDBTransaction::didPutOrAddOnServer): (WebCore::IDBTransaction::deleteObjectStore): (WebCore::IDBTransaction::deleteObjectStoreOnServer): (WebCore::IDBTransaction::didDeleteObjectStoreOnServer): (WebCore::IDBTransaction::deleteIndex): (WebCore::IDBTransaction::deleteIndexOnServer): (WebCore::IDBTransaction::didDeleteIndexOnServer): (WebCore::IDBTransaction::operationCompletedOnClient): (WebCore::IDBTransaction::establishOnServer): (WebCore::IDBTransaction::activate): (WebCore::IDBTransaction::deactivate): * Modules/indexeddb/client/IDBConnectionProxy.cpp: (WebCore::IDBClient::removeItemsMatchingCurrentThread): * Modules/indexeddb/client/TransactionOperation.h: (WebCore::IDBClient::TransactionOperation::~TransactionOperation): (WebCore::IDBClient::TransactionOperation::perform): (WebCore::IDBClient::TransactionOperation::transitionToCompleteOnThisThread): (WebCore::IDBClient::TransactionOperation::transitionToComplete): (WebCore::IDBClient::TransactionOperation::doComplete): (WebCore::IDBClient::TransactionOperation::originThread const): (WebCore::IDBClient::TransactionOperation::originThreadID const): Deleted. * Modules/webaudio/AudioContext.cpp: (WebCore::AudioContext::AudioContext): (WebCore::AudioContext::lock): (WebCore::AudioContext::tryLock): (WebCore::AudioContext::unlock): (WebCore::AudioContext::isAudioThread const): (WebCore::AudioContext::isGraphOwner const): * Modules/webaudio/AudioContext.h: (WebCore::AudioContext::setAudioThread): (WebCore::AudioContext::audioThread const): * Modules/webaudio/AudioDestinationNode.cpp: (WebCore::AudioDestinationNode::render): * Modules/webdatabase/Database.cpp: (WebCore::Database::performClose): (WebCore::Database::securityOrigin): * Modules/webdatabase/DatabaseDetails.h: (WebCore::DatabaseDetails::DatabaseDetails): (WebCore::DatabaseDetails::operator=): (WebCore::DatabaseDetails::thread const): (WebCore::DatabaseDetails::threadID const): Deleted. * Modules/webdatabase/DatabaseManager.cpp: (WebCore::DatabaseManager::detailsForNameAndOrigin): * Modules/webdatabase/DatabaseThread.cpp: (WebCore::DatabaseThread::databaseThread): (WebCore::DatabaseThread::recordDatabaseOpen): (WebCore::DatabaseThread::recordDatabaseClosed): * Modules/webdatabase/DatabaseThread.h: (WebCore::DatabaseThread::getThread): (WebCore::DatabaseThread::getThreadID): Deleted. * Modules/webdatabase/SQLTransaction.cpp: (WebCore::SQLTransaction::checkAndHandleClosedDatabase): * Modules/webdatabase/SQLTransactionBackend.cpp: (WebCore::SQLTransactionBackend::doCleanup): (WebCore::SQLTransactionBackend::notifyDatabaseThreadIsShuttingDown): * bindings/js/JSCallbackData.h: (WebCore::JSCallbackData::JSCallbackData): (WebCore::JSCallbackData::~JSCallbackData): * bindings/js/ScheduledAction.cpp: (WebCore::ScheduledAction::execute): * dom/ScriptExecutionContext.cpp: (WebCore::ScriptExecutionContext::createdMessagePort): (WebCore::ScriptExecutionContext::destroyedMessagePort): * page/ResourceUsageOverlay.h: * page/scrolling/ScrollingThread.cpp: (WebCore::ScrollingThread::isCurrentThread): * platform/Supplementable.h: (WebCore::Supplementable::provideSupplement): (WebCore::Supplementable::removeSupplement): (WebCore::Supplementable::requireSupplement): (WebCore::Supplementable::Supplementable): Deleted. * platform/Timer.cpp: (WebCore::TimerBase::TimerBase): (WebCore::TimerBase::start): (WebCore::TimerBase::stop): (WebCore::TimerBase::setNextFireTime): * platform/Timer.h: (WebCore::TimerBase::isActive const): * platform/graphics/cocoa/FontCacheCoreText.cpp: (WebCore::shouldAutoActivateFontIfNeeded): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.cpp: (WebCore::TextureMapperPlatformLayerProxy::activateOnCompositingThread): (WebCore::TextureMapperPlatformLayerProxy::invalidate): (WebCore::TextureMapperPlatformLayerProxy::getAvailableBuffer): (WebCore::TextureMapperPlatformLayerProxy::appendToUnusedBuffers): (WebCore::TextureMapperPlatformLayerProxy::swapBuffer): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.h: (): Deleted. * platform/ios/wak/WebCoreThread.mm: (RunWebThread): (StartWebThread): * platform/sql/SQLiteDatabase.cpp: (WebCore::SQLiteDatabase::open): (WebCore::SQLiteDatabase::close): * platform/sql/SQLiteDatabase.h: (WebCore::SQLiteDatabase::sqlite3Handle const): * workers/WorkerGlobalScope.cpp: (WebCore::WorkerGlobalScope::~WorkerGlobalScope): (WebCore::WorkerGlobalScope::isContextThread const): * workers/WorkerMessagingProxy.cpp: (WebCore::WorkerMessagingProxy::WorkerMessagingProxy): (WebCore::WorkerMessagingProxy::~WorkerMessagingProxy): * workers/WorkerRunLoop.cpp: (WebCore::WorkerRunLoop::runInMode): (WebCore::WorkerRunLoop::runCleanupTasks): * workers/WorkerThread.h: (WebCore::WorkerThread::thread const): (WebCore::WorkerThread::threadID const): Deleted. * workers/service/ServiceWorkerContainer.cpp: (WebCore::ServiceWorkerContainer::~ServiceWorkerContainer): (WebCore::ServiceWorkerContainer::scheduleJob): (WebCore::ServiceWorkerContainer::jobFailedWithException): (WebCore::ServiceWorkerContainer::scheduleTaskToFireUpdateFoundEvent): (WebCore::ServiceWorkerContainer::jobResolvedWithRegistration): (WebCore::ServiceWorkerContainer::jobResolvedWithUnregistrationResult): (WebCore::ServiceWorkerContainer::startScriptFetchForJob): (WebCore::ServiceWorkerContainer::jobFinishedLoadingScript): (WebCore::ServiceWorkerContainer::jobFailedLoadingScript): (WebCore::ServiceWorkerContainer::jobDidFinish): (WebCore::ServiceWorkerContainer::addRegistration): (WebCore::ServiceWorkerContainer::removeRegistration): (WebCore::ServiceWorkerContainer::scheduleTaskToFireControllerChangeEvent): (WebCore::ServiceWorkerContainer::contextIdentifier): * workers/service/ServiceWorkerContainer.h: * workers/service/ServiceWorkerJob.cpp: (WebCore::ServiceWorkerJob::~ServiceWorkerJob): (WebCore::ServiceWorkerJob::failedWithException): (WebCore::ServiceWorkerJob::resolvedWithRegistration): (WebCore::ServiceWorkerJob::resolvedWithUnregistrationResult): (WebCore::ServiceWorkerJob::startScriptFetch): (WebCore::ServiceWorkerJob::fetchScriptWithContext): (WebCore::ServiceWorkerJob::didReceiveResponse): (WebCore::ServiceWorkerJob::notifyFinished): * workers/service/ServiceWorkerJob.h: * xml/parser/XMLDocumentParserLibxml2.cpp: (WebCore::matchFunc): (WebCore::openFunc): (WebCore::initializeXMLParser): (WebCore::XMLParserContext::createStringParser): (WebCore::XMLParserContext::createMemoryParser): Source/WebKit: * UIProcess/API/glib/IconDatabase.cpp: * UIProcess/GenericCallback.h: (WebKit::GenericCallback::~GenericCallback): (WebKit::GenericCallback::performCallbackWithReturnValue): Source/WTF: We should use a pointer of WTF::Thread instead of ThreadIdentifier. One problem is that Windows support library uses WTF::createThread, which returns ThreadIdentifier. So we cannot drop ThreadIdentifier in Windows environment. This patch keeps ThreadIdentifier in Windows. * wtf/MainThread.cpp: (WTF::initializeMainThread): (WTF::isMainThread): (WTF::canAccessThreadLocalDataForThread): * wtf/MainThread.h: * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkCount): * wtf/RecursiveLockAdapter.h: (WTF::RecursiveLockAdapter::lock): (WTF::RecursiveLockAdapter::unlock): (WTF::RecursiveLockAdapter::tryLock): * wtf/Threading.cpp: (WTF::Thread::dump const): * wtf/Threading.h: (WTF::Thread::id const): (WTF::Thread::operator==): Deleted. (WTF::Thread::operator!=): Deleted. (WTF::currentThread): Deleted. * wtf/ThreadingPrimitives.h: * wtf/ThreadingPthreads.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::detach): (WTF::Thread::initializeCurrentTLS): (WTF::Thread::suspend): (WTF::Thread::establishPlatformSpecificHandle): (WTF::Thread::currentID): Deleted. * wtf/ThreadingWin.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::suspend): (WTF::Thread::currentDying): * wtf/mac/MainThreadMac.mm: (WTF::initializeApplicationUIThread): (WTF::initializeWebThreadPlatform): (WTF::canAccessThreadLocalDataForThread): (WTF::initializeApplicationUIThreadIdentifier): Deleted. (WTF::initializeWebThreadIdentifier): Deleted. Tools: * DumpRenderTree/mac/DumpRenderTree.mm: (dumpRenderTree): (runThread): Deleted. (runPthread): Deleted. (testThreadIdentifierMap): Deleted. * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: * TestWebKitAPI/Tests/WTF/Threading.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/196314@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@225470 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-12-04 06:13:05 +00:00
dataLog(toString(Thread::current(), ": created new hashtable: ", RawPointer(newHashtable), "\n"));
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
for (ThreadData* threadData : threadDatas) {
if (verbose)
WTF shouldn't have both Thread and ThreadIdentifier https://bugs.webkit.org/show_bug.cgi?id=180308 Reviewed by Darin Adler. Source/JavaScriptCore: * heap/MachineStackMarker.cpp: (JSC::MachineThreads::tryCopyOtherThreadStacks): * llint/LLIntSlowPaths.cpp: (JSC::LLInt::llint_trace_operand): (JSC::LLInt::llint_trace_value): (JSC::LLInt::LLINT_SLOW_PATH_DECL): (JSC::LLInt::traceFunctionPrologue): * runtime/ExceptionScope.cpp: (JSC::ExceptionScope::unexpectedExceptionMessage): * runtime/JSLock.h: (JSC::JSLock::currentThreadIsHoldingLock): * runtime/VM.cpp: (JSC::VM::throwException): * runtime/VM.h: (JSC::VM::throwingThread const): (JSC::VM::clearException): * tools/HeapVerifier.cpp: (JSC::HeapVerifier::printVerificationHeader): Source/WebCore: No behavior change. * Modules/indexeddb/IDBActiveDOMObject.h: (WebCore::IDBActiveDOMObject::originThread const): (WebCore::IDBActiveDOMObject::performCallbackOnOriginThread): (WebCore::IDBActiveDOMObject::callFunctionOnOriginThread): (WebCore::IDBActiveDOMObject::originThreadID const): Deleted. * Modules/indexeddb/IDBCursor.cpp: (WebCore::IDBCursor::IDBCursor): (WebCore::IDBCursor::~IDBCursor): (WebCore::IDBCursor::sourcesDeleted const): (WebCore::IDBCursor::transaction const): (WebCore::IDBCursor::update): (WebCore::IDBCursor::advance): (WebCore::IDBCursor::continueFunction): (WebCore::IDBCursor::uncheckedIterateCursor): (WebCore::IDBCursor::deleteFunction): (WebCore::IDBCursor::setGetResult): * Modules/indexeddb/IDBDatabase.cpp: (WebCore::IDBDatabase::~IDBDatabase): (WebCore::IDBDatabase::hasPendingActivity const): (WebCore::IDBDatabase::name const): (WebCore::IDBDatabase::version const): (WebCore::IDBDatabase::objectStoreNames const): (WebCore::IDBDatabase::renameObjectStore): (WebCore::IDBDatabase::renameIndex): (WebCore::IDBDatabase::createObjectStore): (WebCore::IDBDatabase::transaction): (WebCore::IDBDatabase::deleteObjectStore): (WebCore::IDBDatabase::close): (WebCore::IDBDatabase::connectionToServerLost): (WebCore::IDBDatabase::maybeCloseInServer): (WebCore::IDBDatabase::activeDOMObjectName const): (WebCore::IDBDatabase::canSuspendForDocumentSuspension const): (WebCore::IDBDatabase::stop): (WebCore::IDBDatabase::startVersionChangeTransaction): (WebCore::IDBDatabase::didStartTransaction): (WebCore::IDBDatabase::willCommitTransaction): (WebCore::IDBDatabase::didCommitTransaction): (WebCore::IDBDatabase::willAbortTransaction): (WebCore::IDBDatabase::didAbortTransaction): (WebCore::IDBDatabase::didCommitOrAbortTransaction): (WebCore::IDBDatabase::fireVersionChangeEvent): (WebCore::IDBDatabase::dispatchEvent): (WebCore::IDBDatabase::didCreateIndexInfo): (WebCore::IDBDatabase::didDeleteIndexInfo): * Modules/indexeddb/IDBIndex.cpp: (WebCore::IDBIndex::IDBIndex): (WebCore::IDBIndex::~IDBIndex): (WebCore::IDBIndex::name const): (WebCore::IDBIndex::setName): (WebCore::IDBIndex::objectStore): (WebCore::IDBIndex::keyPath const): (WebCore::IDBIndex::unique const): (WebCore::IDBIndex::multiEntry const): (WebCore::IDBIndex::rollbackInfoForVersionChangeAbort): (WebCore::IDBIndex::openCursor): (WebCore::IDBIndex::openKeyCursor): (WebCore::IDBIndex::doCount): (WebCore::IDBIndex::doGet): (WebCore::IDBIndex::doGetKey): (WebCore::IDBIndex::getAll): (WebCore::IDBIndex::getAllKeys): (WebCore::IDBIndex::markAsDeleted): * Modules/indexeddb/IDBObjectStore.cpp: (WebCore::IDBObjectStore::IDBObjectStore): (WebCore::IDBObjectStore::~IDBObjectStore): (WebCore::IDBObjectStore::name const): (WebCore::IDBObjectStore::setName): (WebCore::IDBObjectStore::keyPath const): (WebCore::IDBObjectStore::indexNames const): (WebCore::IDBObjectStore::transaction): (WebCore::IDBObjectStore::autoIncrement const): (WebCore::IDBObjectStore::openCursor): (WebCore::IDBObjectStore::openKeyCursor): (WebCore::IDBObjectStore::get): (WebCore::IDBObjectStore::getKey): (WebCore::IDBObjectStore::putOrAdd): (WebCore::IDBObjectStore::doDelete): (WebCore::IDBObjectStore::clear): (WebCore::IDBObjectStore::createIndex): (WebCore::IDBObjectStore::index): (WebCore::IDBObjectStore::deleteIndex): (WebCore::IDBObjectStore::doCount): (WebCore::IDBObjectStore::getAll): (WebCore::IDBObjectStore::getAllKeys): (WebCore::IDBObjectStore::markAsDeleted): (WebCore::IDBObjectStore::rollbackForVersionChangeAbort): * Modules/indexeddb/IDBOpenDBRequest.cpp: (WebCore::IDBOpenDBRequest::~IDBOpenDBRequest): (WebCore::IDBOpenDBRequest::onError): (WebCore::IDBOpenDBRequest::versionChangeTransactionDidFinish): (WebCore::IDBOpenDBRequest::fireSuccessAfterVersionChangeCommit): (WebCore::IDBOpenDBRequest::fireErrorAfterVersionChangeCompletion): (WebCore::IDBOpenDBRequest::dispatchEvent): (WebCore::IDBOpenDBRequest::onSuccess): (WebCore::IDBOpenDBRequest::onUpgradeNeeded): (WebCore::IDBOpenDBRequest::onDeleteDatabaseSuccess): (WebCore::IDBOpenDBRequest::requestCompleted): (WebCore::IDBOpenDBRequest::requestBlocked): * Modules/indexeddb/IDBRequest.cpp: (WebCore::IDBRequest::~IDBRequest): (WebCore:: const): (WebCore::IDBRequest::setSource): (WebCore::IDBRequest::setVersionChangeTransaction): (WebCore::IDBRequest::transaction const): (WebCore::IDBRequest::sourceObjectStoreIdentifier const): (WebCore::IDBRequest::sourceIndexIdentifier const): (WebCore::IDBRequest::requestedObjectStoreRecordType const): (WebCore::IDBRequest::requestedIndexRecordType const): (WebCore::IDBRequest::eventTargetInterface const): (WebCore::IDBRequest::activeDOMObjectName const): (WebCore::IDBRequest::canSuspendForDocumentSuspension const): (WebCore::IDBRequest::hasPendingActivity const): (WebCore::IDBRequest::stop): (WebCore::IDBRequest::enqueueEvent): (WebCore::IDBRequest::dispatchEvent): (WebCore::IDBRequest::uncaughtExceptionInEventHandler): (WebCore::IDBRequest::setResult): (WebCore::IDBRequest::setResultToStructuredClone): (WebCore::IDBRequest::setResultToUndefined): (WebCore::IDBRequest::resultCursor): (WebCore::IDBRequest::willIterateCursor): (WebCore::IDBRequest::didOpenOrIterateCursor): (WebCore::IDBRequest::completeRequestAndDispatchEvent): (WebCore::IDBRequest::onError): (WebCore::IDBRequest::onSuccess): * Modules/indexeddb/IDBTransaction.cpp: (WebCore::IDBTransaction::IDBTransaction): (WebCore::IDBTransaction::~IDBTransaction): (WebCore::IDBTransaction::objectStoreNames const): (WebCore::IDBTransaction::db): (WebCore::IDBTransaction::error const): (WebCore::IDBTransaction::objectStore): (WebCore::IDBTransaction::abortDueToFailedRequest): (WebCore::IDBTransaction::transitionedToFinishing): (WebCore::IDBTransaction::abort): (WebCore::IDBTransaction::internalAbort): (WebCore::IDBTransaction::abortOnServerAndCancelRequests): (WebCore::IDBTransaction::activeDOMObjectName const): (WebCore::IDBTransaction::canSuspendForDocumentSuspension const): (WebCore::IDBTransaction::hasPendingActivity const): (WebCore::IDBTransaction::stop): (WebCore::IDBTransaction::isActive const): (WebCore::IDBTransaction::isFinishedOrFinishing const): (WebCore::IDBTransaction::addRequest): (WebCore::IDBTransaction::removeRequest): (WebCore::IDBTransaction::scheduleOperation): (WebCore::IDBTransaction::schedulePendingOperationTimer): (WebCore::IDBTransaction::pendingOperationTimerFired): (WebCore::IDBTransaction::operationCompletedOnServer): (WebCore::IDBTransaction::scheduleCompletedOperationTimer): (WebCore::IDBTransaction::completedOperationTimerFired): (WebCore::IDBTransaction::commit): (WebCore::IDBTransaction::commitOnServer): (WebCore::IDBTransaction::finishAbortOrCommit): (WebCore::IDBTransaction::didStart): (WebCore::IDBTransaction::notifyDidAbort): (WebCore::IDBTransaction::didAbort): (WebCore::IDBTransaction::didCommit): (WebCore::IDBTransaction::fireOnComplete): (WebCore::IDBTransaction::fireOnAbort): (WebCore::IDBTransaction::enqueueEvent): (WebCore::IDBTransaction::dispatchEvent): (WebCore::IDBTransaction::createObjectStore): (WebCore::IDBTransaction::createObjectStoreOnServer): (WebCore::IDBTransaction::didCreateObjectStoreOnServer): (WebCore::IDBTransaction::renameObjectStore): (WebCore::IDBTransaction::renameObjectStoreOnServer): (WebCore::IDBTransaction::didRenameObjectStoreOnServer): (WebCore::IDBTransaction::createIndex): (WebCore::IDBTransaction::createIndexOnServer): (WebCore::IDBTransaction::didCreateIndexOnServer): (WebCore::IDBTransaction::renameIndex): (WebCore::IDBTransaction::renameIndexOnServer): (WebCore::IDBTransaction::didRenameIndexOnServer): (WebCore::IDBTransaction::requestOpenCursor): (WebCore::IDBTransaction::doRequestOpenCursor): (WebCore::IDBTransaction::openCursorOnServer): (WebCore::IDBTransaction::didOpenCursorOnServer): (WebCore::IDBTransaction::iterateCursor): (WebCore::IDBTransaction::iterateCursorOnServer): (WebCore::IDBTransaction::didIterateCursorOnServer): (WebCore::IDBTransaction::requestGetAllObjectStoreRecords): (WebCore::IDBTransaction::requestGetAllIndexRecords): (WebCore::IDBTransaction::getAllRecordsOnServer): (WebCore::IDBTransaction::didGetAllRecordsOnServer): (WebCore::IDBTransaction::requestGetRecord): (WebCore::IDBTransaction::requestGetValue): (WebCore::IDBTransaction::requestGetKey): (WebCore::IDBTransaction::requestIndexRecord): (WebCore::IDBTransaction::getRecordOnServer): (WebCore::IDBTransaction::didGetRecordOnServer): (WebCore::IDBTransaction::requestCount): (WebCore::IDBTransaction::getCountOnServer): (WebCore::IDBTransaction::didGetCountOnServer): (WebCore::IDBTransaction::requestDeleteRecord): (WebCore::IDBTransaction::deleteRecordOnServer): (WebCore::IDBTransaction::didDeleteRecordOnServer): (WebCore::IDBTransaction::requestClearObjectStore): (WebCore::IDBTransaction::clearObjectStoreOnServer): (WebCore::IDBTransaction::didClearObjectStoreOnServer): (WebCore::IDBTransaction::requestPutOrAdd): (WebCore::IDBTransaction::putOrAddOnServer): (WebCore::IDBTransaction::didPutOrAddOnServer): (WebCore::IDBTransaction::deleteObjectStore): (WebCore::IDBTransaction::deleteObjectStoreOnServer): (WebCore::IDBTransaction::didDeleteObjectStoreOnServer): (WebCore::IDBTransaction::deleteIndex): (WebCore::IDBTransaction::deleteIndexOnServer): (WebCore::IDBTransaction::didDeleteIndexOnServer): (WebCore::IDBTransaction::operationCompletedOnClient): (WebCore::IDBTransaction::establishOnServer): (WebCore::IDBTransaction::activate): (WebCore::IDBTransaction::deactivate): * Modules/indexeddb/client/IDBConnectionProxy.cpp: (WebCore::IDBClient::removeItemsMatchingCurrentThread): * Modules/indexeddb/client/TransactionOperation.h: (WebCore::IDBClient::TransactionOperation::~TransactionOperation): (WebCore::IDBClient::TransactionOperation::perform): (WebCore::IDBClient::TransactionOperation::transitionToCompleteOnThisThread): (WebCore::IDBClient::TransactionOperation::transitionToComplete): (WebCore::IDBClient::TransactionOperation::doComplete): (WebCore::IDBClient::TransactionOperation::originThread const): (WebCore::IDBClient::TransactionOperation::originThreadID const): Deleted. * Modules/webaudio/AudioContext.cpp: (WebCore::AudioContext::AudioContext): (WebCore::AudioContext::lock): (WebCore::AudioContext::tryLock): (WebCore::AudioContext::unlock): (WebCore::AudioContext::isAudioThread const): (WebCore::AudioContext::isGraphOwner const): * Modules/webaudio/AudioContext.h: (WebCore::AudioContext::setAudioThread): (WebCore::AudioContext::audioThread const): * Modules/webaudio/AudioDestinationNode.cpp: (WebCore::AudioDestinationNode::render): * Modules/webdatabase/Database.cpp: (WebCore::Database::performClose): (WebCore::Database::securityOrigin): * Modules/webdatabase/DatabaseDetails.h: (WebCore::DatabaseDetails::DatabaseDetails): (WebCore::DatabaseDetails::operator=): (WebCore::DatabaseDetails::thread const): (WebCore::DatabaseDetails::threadID const): Deleted. * Modules/webdatabase/DatabaseManager.cpp: (WebCore::DatabaseManager::detailsForNameAndOrigin): * Modules/webdatabase/DatabaseThread.cpp: (WebCore::DatabaseThread::databaseThread): (WebCore::DatabaseThread::recordDatabaseOpen): (WebCore::DatabaseThread::recordDatabaseClosed): * Modules/webdatabase/DatabaseThread.h: (WebCore::DatabaseThread::getThread): (WebCore::DatabaseThread::getThreadID): Deleted. * Modules/webdatabase/SQLTransaction.cpp: (WebCore::SQLTransaction::checkAndHandleClosedDatabase): * Modules/webdatabase/SQLTransactionBackend.cpp: (WebCore::SQLTransactionBackend::doCleanup): (WebCore::SQLTransactionBackend::notifyDatabaseThreadIsShuttingDown): * bindings/js/JSCallbackData.h: (WebCore::JSCallbackData::JSCallbackData): (WebCore::JSCallbackData::~JSCallbackData): * bindings/js/ScheduledAction.cpp: (WebCore::ScheduledAction::execute): * dom/ScriptExecutionContext.cpp: (WebCore::ScriptExecutionContext::createdMessagePort): (WebCore::ScriptExecutionContext::destroyedMessagePort): * page/ResourceUsageOverlay.h: * page/scrolling/ScrollingThread.cpp: (WebCore::ScrollingThread::isCurrentThread): * platform/Supplementable.h: (WebCore::Supplementable::provideSupplement): (WebCore::Supplementable::removeSupplement): (WebCore::Supplementable::requireSupplement): (WebCore::Supplementable::Supplementable): Deleted. * platform/Timer.cpp: (WebCore::TimerBase::TimerBase): (WebCore::TimerBase::start): (WebCore::TimerBase::stop): (WebCore::TimerBase::setNextFireTime): * platform/Timer.h: (WebCore::TimerBase::isActive const): * platform/graphics/cocoa/FontCacheCoreText.cpp: (WebCore::shouldAutoActivateFontIfNeeded): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.cpp: (WebCore::TextureMapperPlatformLayerProxy::activateOnCompositingThread): (WebCore::TextureMapperPlatformLayerProxy::invalidate): (WebCore::TextureMapperPlatformLayerProxy::getAvailableBuffer): (WebCore::TextureMapperPlatformLayerProxy::appendToUnusedBuffers): (WebCore::TextureMapperPlatformLayerProxy::swapBuffer): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.h: (): Deleted. * platform/ios/wak/WebCoreThread.mm: (RunWebThread): (StartWebThread): * platform/sql/SQLiteDatabase.cpp: (WebCore::SQLiteDatabase::open): (WebCore::SQLiteDatabase::close): * platform/sql/SQLiteDatabase.h: (WebCore::SQLiteDatabase::sqlite3Handle const): * workers/WorkerGlobalScope.cpp: (WebCore::WorkerGlobalScope::~WorkerGlobalScope): (WebCore::WorkerGlobalScope::isContextThread const): * workers/WorkerMessagingProxy.cpp: (WebCore::WorkerMessagingProxy::WorkerMessagingProxy): (WebCore::WorkerMessagingProxy::~WorkerMessagingProxy): * workers/WorkerRunLoop.cpp: (WebCore::WorkerRunLoop::runInMode): (WebCore::WorkerRunLoop::runCleanupTasks): * workers/WorkerThread.h: (WebCore::WorkerThread::thread const): (WebCore::WorkerThread::threadID const): Deleted. * workers/service/ServiceWorkerContainer.cpp: (WebCore::ServiceWorkerContainer::~ServiceWorkerContainer): (WebCore::ServiceWorkerContainer::scheduleJob): (WebCore::ServiceWorkerContainer::jobFailedWithException): (WebCore::ServiceWorkerContainer::scheduleTaskToFireUpdateFoundEvent): (WebCore::ServiceWorkerContainer::jobResolvedWithRegistration): (WebCore::ServiceWorkerContainer::jobResolvedWithUnregistrationResult): (WebCore::ServiceWorkerContainer::startScriptFetchForJob): (WebCore::ServiceWorkerContainer::jobFinishedLoadingScript): (WebCore::ServiceWorkerContainer::jobFailedLoadingScript): (WebCore::ServiceWorkerContainer::jobDidFinish): (WebCore::ServiceWorkerContainer::addRegistration): (WebCore::ServiceWorkerContainer::removeRegistration): (WebCore::ServiceWorkerContainer::scheduleTaskToFireControllerChangeEvent): (WebCore::ServiceWorkerContainer::contextIdentifier): * workers/service/ServiceWorkerContainer.h: * workers/service/ServiceWorkerJob.cpp: (WebCore::ServiceWorkerJob::~ServiceWorkerJob): (WebCore::ServiceWorkerJob::failedWithException): (WebCore::ServiceWorkerJob::resolvedWithRegistration): (WebCore::ServiceWorkerJob::resolvedWithUnregistrationResult): (WebCore::ServiceWorkerJob::startScriptFetch): (WebCore::ServiceWorkerJob::fetchScriptWithContext): (WebCore::ServiceWorkerJob::didReceiveResponse): (WebCore::ServiceWorkerJob::notifyFinished): * workers/service/ServiceWorkerJob.h: * xml/parser/XMLDocumentParserLibxml2.cpp: (WebCore::matchFunc): (WebCore::openFunc): (WebCore::initializeXMLParser): (WebCore::XMLParserContext::createStringParser): (WebCore::XMLParserContext::createMemoryParser): Source/WebKit: * UIProcess/API/glib/IconDatabase.cpp: * UIProcess/GenericCallback.h: (WebKit::GenericCallback::~GenericCallback): (WebKit::GenericCallback::performCallbackWithReturnValue): Source/WTF: We should use a pointer of WTF::Thread instead of ThreadIdentifier. One problem is that Windows support library uses WTF::createThread, which returns ThreadIdentifier. So we cannot drop ThreadIdentifier in Windows environment. This patch keeps ThreadIdentifier in Windows. * wtf/MainThread.cpp: (WTF::initializeMainThread): (WTF::isMainThread): (WTF::canAccessThreadLocalDataForThread): * wtf/MainThread.h: * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkCount): * wtf/RecursiveLockAdapter.h: (WTF::RecursiveLockAdapter::lock): (WTF::RecursiveLockAdapter::unlock): (WTF::RecursiveLockAdapter::tryLock): * wtf/Threading.cpp: (WTF::Thread::dump const): * wtf/Threading.h: (WTF::Thread::id const): (WTF::Thread::operator==): Deleted. (WTF::Thread::operator!=): Deleted. (WTF::currentThread): Deleted. * wtf/ThreadingPrimitives.h: * wtf/ThreadingPthreads.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::detach): (WTF::Thread::initializeCurrentTLS): (WTF::Thread::suspend): (WTF::Thread::establishPlatformSpecificHandle): (WTF::Thread::currentID): Deleted. * wtf/ThreadingWin.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::suspend): (WTF::Thread::currentDying): * wtf/mac/MainThreadMac.mm: (WTF::initializeApplicationUIThread): (WTF::initializeWebThreadPlatform): (WTF::canAccessThreadLocalDataForThread): (WTF::initializeApplicationUIThreadIdentifier): Deleted. (WTF::initializeWebThreadIdentifier): Deleted. Tools: * DumpRenderTree/mac/DumpRenderTree.mm: (dumpRenderTree): (runThread): Deleted. (runPthread): Deleted. (testThreadIdentifierMap): Deleted. * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: * TestWebKitAPI/Tests/WTF/Threading.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/196314@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@225470 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-12-04 06:13:05 +00:00
dataLog(toString(Thread::current(), ": rehashing thread data ", RawPointer(threadData), " with address = ", RawPointer(threadData->address), "\n"));
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
unsigned hash = hashAddress(threadData->address);
unsigned index = hash % newHashtable->size;
if (verbose)
WTF shouldn't have both Thread and ThreadIdentifier https://bugs.webkit.org/show_bug.cgi?id=180308 Reviewed by Darin Adler. Source/JavaScriptCore: * heap/MachineStackMarker.cpp: (JSC::MachineThreads::tryCopyOtherThreadStacks): * llint/LLIntSlowPaths.cpp: (JSC::LLInt::llint_trace_operand): (JSC::LLInt::llint_trace_value): (JSC::LLInt::LLINT_SLOW_PATH_DECL): (JSC::LLInt::traceFunctionPrologue): * runtime/ExceptionScope.cpp: (JSC::ExceptionScope::unexpectedExceptionMessage): * runtime/JSLock.h: (JSC::JSLock::currentThreadIsHoldingLock): * runtime/VM.cpp: (JSC::VM::throwException): * runtime/VM.h: (JSC::VM::throwingThread const): (JSC::VM::clearException): * tools/HeapVerifier.cpp: (JSC::HeapVerifier::printVerificationHeader): Source/WebCore: No behavior change. * Modules/indexeddb/IDBActiveDOMObject.h: (WebCore::IDBActiveDOMObject::originThread const): (WebCore::IDBActiveDOMObject::performCallbackOnOriginThread): (WebCore::IDBActiveDOMObject::callFunctionOnOriginThread): (WebCore::IDBActiveDOMObject::originThreadID const): Deleted. * Modules/indexeddb/IDBCursor.cpp: (WebCore::IDBCursor::IDBCursor): (WebCore::IDBCursor::~IDBCursor): (WebCore::IDBCursor::sourcesDeleted const): (WebCore::IDBCursor::transaction const): (WebCore::IDBCursor::update): (WebCore::IDBCursor::advance): (WebCore::IDBCursor::continueFunction): (WebCore::IDBCursor::uncheckedIterateCursor): (WebCore::IDBCursor::deleteFunction): (WebCore::IDBCursor::setGetResult): * Modules/indexeddb/IDBDatabase.cpp: (WebCore::IDBDatabase::~IDBDatabase): (WebCore::IDBDatabase::hasPendingActivity const): (WebCore::IDBDatabase::name const): (WebCore::IDBDatabase::version const): (WebCore::IDBDatabase::objectStoreNames const): (WebCore::IDBDatabase::renameObjectStore): (WebCore::IDBDatabase::renameIndex): (WebCore::IDBDatabase::createObjectStore): (WebCore::IDBDatabase::transaction): (WebCore::IDBDatabase::deleteObjectStore): (WebCore::IDBDatabase::close): (WebCore::IDBDatabase::connectionToServerLost): (WebCore::IDBDatabase::maybeCloseInServer): (WebCore::IDBDatabase::activeDOMObjectName const): (WebCore::IDBDatabase::canSuspendForDocumentSuspension const): (WebCore::IDBDatabase::stop): (WebCore::IDBDatabase::startVersionChangeTransaction): (WebCore::IDBDatabase::didStartTransaction): (WebCore::IDBDatabase::willCommitTransaction): (WebCore::IDBDatabase::didCommitTransaction): (WebCore::IDBDatabase::willAbortTransaction): (WebCore::IDBDatabase::didAbortTransaction): (WebCore::IDBDatabase::didCommitOrAbortTransaction): (WebCore::IDBDatabase::fireVersionChangeEvent): (WebCore::IDBDatabase::dispatchEvent): (WebCore::IDBDatabase::didCreateIndexInfo): (WebCore::IDBDatabase::didDeleteIndexInfo): * Modules/indexeddb/IDBIndex.cpp: (WebCore::IDBIndex::IDBIndex): (WebCore::IDBIndex::~IDBIndex): (WebCore::IDBIndex::name const): (WebCore::IDBIndex::setName): (WebCore::IDBIndex::objectStore): (WebCore::IDBIndex::keyPath const): (WebCore::IDBIndex::unique const): (WebCore::IDBIndex::multiEntry const): (WebCore::IDBIndex::rollbackInfoForVersionChangeAbort): (WebCore::IDBIndex::openCursor): (WebCore::IDBIndex::openKeyCursor): (WebCore::IDBIndex::doCount): (WebCore::IDBIndex::doGet): (WebCore::IDBIndex::doGetKey): (WebCore::IDBIndex::getAll): (WebCore::IDBIndex::getAllKeys): (WebCore::IDBIndex::markAsDeleted): * Modules/indexeddb/IDBObjectStore.cpp: (WebCore::IDBObjectStore::IDBObjectStore): (WebCore::IDBObjectStore::~IDBObjectStore): (WebCore::IDBObjectStore::name const): (WebCore::IDBObjectStore::setName): (WebCore::IDBObjectStore::keyPath const): (WebCore::IDBObjectStore::indexNames const): (WebCore::IDBObjectStore::transaction): (WebCore::IDBObjectStore::autoIncrement const): (WebCore::IDBObjectStore::openCursor): (WebCore::IDBObjectStore::openKeyCursor): (WebCore::IDBObjectStore::get): (WebCore::IDBObjectStore::getKey): (WebCore::IDBObjectStore::putOrAdd): (WebCore::IDBObjectStore::doDelete): (WebCore::IDBObjectStore::clear): (WebCore::IDBObjectStore::createIndex): (WebCore::IDBObjectStore::index): (WebCore::IDBObjectStore::deleteIndex): (WebCore::IDBObjectStore::doCount): (WebCore::IDBObjectStore::getAll): (WebCore::IDBObjectStore::getAllKeys): (WebCore::IDBObjectStore::markAsDeleted): (WebCore::IDBObjectStore::rollbackForVersionChangeAbort): * Modules/indexeddb/IDBOpenDBRequest.cpp: (WebCore::IDBOpenDBRequest::~IDBOpenDBRequest): (WebCore::IDBOpenDBRequest::onError): (WebCore::IDBOpenDBRequest::versionChangeTransactionDidFinish): (WebCore::IDBOpenDBRequest::fireSuccessAfterVersionChangeCommit): (WebCore::IDBOpenDBRequest::fireErrorAfterVersionChangeCompletion): (WebCore::IDBOpenDBRequest::dispatchEvent): (WebCore::IDBOpenDBRequest::onSuccess): (WebCore::IDBOpenDBRequest::onUpgradeNeeded): (WebCore::IDBOpenDBRequest::onDeleteDatabaseSuccess): (WebCore::IDBOpenDBRequest::requestCompleted): (WebCore::IDBOpenDBRequest::requestBlocked): * Modules/indexeddb/IDBRequest.cpp: (WebCore::IDBRequest::~IDBRequest): (WebCore:: const): (WebCore::IDBRequest::setSource): (WebCore::IDBRequest::setVersionChangeTransaction): (WebCore::IDBRequest::transaction const): (WebCore::IDBRequest::sourceObjectStoreIdentifier const): (WebCore::IDBRequest::sourceIndexIdentifier const): (WebCore::IDBRequest::requestedObjectStoreRecordType const): (WebCore::IDBRequest::requestedIndexRecordType const): (WebCore::IDBRequest::eventTargetInterface const): (WebCore::IDBRequest::activeDOMObjectName const): (WebCore::IDBRequest::canSuspendForDocumentSuspension const): (WebCore::IDBRequest::hasPendingActivity const): (WebCore::IDBRequest::stop): (WebCore::IDBRequest::enqueueEvent): (WebCore::IDBRequest::dispatchEvent): (WebCore::IDBRequest::uncaughtExceptionInEventHandler): (WebCore::IDBRequest::setResult): (WebCore::IDBRequest::setResultToStructuredClone): (WebCore::IDBRequest::setResultToUndefined): (WebCore::IDBRequest::resultCursor): (WebCore::IDBRequest::willIterateCursor): (WebCore::IDBRequest::didOpenOrIterateCursor): (WebCore::IDBRequest::completeRequestAndDispatchEvent): (WebCore::IDBRequest::onError): (WebCore::IDBRequest::onSuccess): * Modules/indexeddb/IDBTransaction.cpp: (WebCore::IDBTransaction::IDBTransaction): (WebCore::IDBTransaction::~IDBTransaction): (WebCore::IDBTransaction::objectStoreNames const): (WebCore::IDBTransaction::db): (WebCore::IDBTransaction::error const): (WebCore::IDBTransaction::objectStore): (WebCore::IDBTransaction::abortDueToFailedRequest): (WebCore::IDBTransaction::transitionedToFinishing): (WebCore::IDBTransaction::abort): (WebCore::IDBTransaction::internalAbort): (WebCore::IDBTransaction::abortOnServerAndCancelRequests): (WebCore::IDBTransaction::activeDOMObjectName const): (WebCore::IDBTransaction::canSuspendForDocumentSuspension const): (WebCore::IDBTransaction::hasPendingActivity const): (WebCore::IDBTransaction::stop): (WebCore::IDBTransaction::isActive const): (WebCore::IDBTransaction::isFinishedOrFinishing const): (WebCore::IDBTransaction::addRequest): (WebCore::IDBTransaction::removeRequest): (WebCore::IDBTransaction::scheduleOperation): (WebCore::IDBTransaction::schedulePendingOperationTimer): (WebCore::IDBTransaction::pendingOperationTimerFired): (WebCore::IDBTransaction::operationCompletedOnServer): (WebCore::IDBTransaction::scheduleCompletedOperationTimer): (WebCore::IDBTransaction::completedOperationTimerFired): (WebCore::IDBTransaction::commit): (WebCore::IDBTransaction::commitOnServer): (WebCore::IDBTransaction::finishAbortOrCommit): (WebCore::IDBTransaction::didStart): (WebCore::IDBTransaction::notifyDidAbort): (WebCore::IDBTransaction::didAbort): (WebCore::IDBTransaction::didCommit): (WebCore::IDBTransaction::fireOnComplete): (WebCore::IDBTransaction::fireOnAbort): (WebCore::IDBTransaction::enqueueEvent): (WebCore::IDBTransaction::dispatchEvent): (WebCore::IDBTransaction::createObjectStore): (WebCore::IDBTransaction::createObjectStoreOnServer): (WebCore::IDBTransaction::didCreateObjectStoreOnServer): (WebCore::IDBTransaction::renameObjectStore): (WebCore::IDBTransaction::renameObjectStoreOnServer): (WebCore::IDBTransaction::didRenameObjectStoreOnServer): (WebCore::IDBTransaction::createIndex): (WebCore::IDBTransaction::createIndexOnServer): (WebCore::IDBTransaction::didCreateIndexOnServer): (WebCore::IDBTransaction::renameIndex): (WebCore::IDBTransaction::renameIndexOnServer): (WebCore::IDBTransaction::didRenameIndexOnServer): (WebCore::IDBTransaction::requestOpenCursor): (WebCore::IDBTransaction::doRequestOpenCursor): (WebCore::IDBTransaction::openCursorOnServer): (WebCore::IDBTransaction::didOpenCursorOnServer): (WebCore::IDBTransaction::iterateCursor): (WebCore::IDBTransaction::iterateCursorOnServer): (WebCore::IDBTransaction::didIterateCursorOnServer): (WebCore::IDBTransaction::requestGetAllObjectStoreRecords): (WebCore::IDBTransaction::requestGetAllIndexRecords): (WebCore::IDBTransaction::getAllRecordsOnServer): (WebCore::IDBTransaction::didGetAllRecordsOnServer): (WebCore::IDBTransaction::requestGetRecord): (WebCore::IDBTransaction::requestGetValue): (WebCore::IDBTransaction::requestGetKey): (WebCore::IDBTransaction::requestIndexRecord): (WebCore::IDBTransaction::getRecordOnServer): (WebCore::IDBTransaction::didGetRecordOnServer): (WebCore::IDBTransaction::requestCount): (WebCore::IDBTransaction::getCountOnServer): (WebCore::IDBTransaction::didGetCountOnServer): (WebCore::IDBTransaction::requestDeleteRecord): (WebCore::IDBTransaction::deleteRecordOnServer): (WebCore::IDBTransaction::didDeleteRecordOnServer): (WebCore::IDBTransaction::requestClearObjectStore): (WebCore::IDBTransaction::clearObjectStoreOnServer): (WebCore::IDBTransaction::didClearObjectStoreOnServer): (WebCore::IDBTransaction::requestPutOrAdd): (WebCore::IDBTransaction::putOrAddOnServer): (WebCore::IDBTransaction::didPutOrAddOnServer): (WebCore::IDBTransaction::deleteObjectStore): (WebCore::IDBTransaction::deleteObjectStoreOnServer): (WebCore::IDBTransaction::didDeleteObjectStoreOnServer): (WebCore::IDBTransaction::deleteIndex): (WebCore::IDBTransaction::deleteIndexOnServer): (WebCore::IDBTransaction::didDeleteIndexOnServer): (WebCore::IDBTransaction::operationCompletedOnClient): (WebCore::IDBTransaction::establishOnServer): (WebCore::IDBTransaction::activate): (WebCore::IDBTransaction::deactivate): * Modules/indexeddb/client/IDBConnectionProxy.cpp: (WebCore::IDBClient::removeItemsMatchingCurrentThread): * Modules/indexeddb/client/TransactionOperation.h: (WebCore::IDBClient::TransactionOperation::~TransactionOperation): (WebCore::IDBClient::TransactionOperation::perform): (WebCore::IDBClient::TransactionOperation::transitionToCompleteOnThisThread): (WebCore::IDBClient::TransactionOperation::transitionToComplete): (WebCore::IDBClient::TransactionOperation::doComplete): (WebCore::IDBClient::TransactionOperation::originThread const): (WebCore::IDBClient::TransactionOperation::originThreadID const): Deleted. * Modules/webaudio/AudioContext.cpp: (WebCore::AudioContext::AudioContext): (WebCore::AudioContext::lock): (WebCore::AudioContext::tryLock): (WebCore::AudioContext::unlock): (WebCore::AudioContext::isAudioThread const): (WebCore::AudioContext::isGraphOwner const): * Modules/webaudio/AudioContext.h: (WebCore::AudioContext::setAudioThread): (WebCore::AudioContext::audioThread const): * Modules/webaudio/AudioDestinationNode.cpp: (WebCore::AudioDestinationNode::render): * Modules/webdatabase/Database.cpp: (WebCore::Database::performClose): (WebCore::Database::securityOrigin): * Modules/webdatabase/DatabaseDetails.h: (WebCore::DatabaseDetails::DatabaseDetails): (WebCore::DatabaseDetails::operator=): (WebCore::DatabaseDetails::thread const): (WebCore::DatabaseDetails::threadID const): Deleted. * Modules/webdatabase/DatabaseManager.cpp: (WebCore::DatabaseManager::detailsForNameAndOrigin): * Modules/webdatabase/DatabaseThread.cpp: (WebCore::DatabaseThread::databaseThread): (WebCore::DatabaseThread::recordDatabaseOpen): (WebCore::DatabaseThread::recordDatabaseClosed): * Modules/webdatabase/DatabaseThread.h: (WebCore::DatabaseThread::getThread): (WebCore::DatabaseThread::getThreadID): Deleted. * Modules/webdatabase/SQLTransaction.cpp: (WebCore::SQLTransaction::checkAndHandleClosedDatabase): * Modules/webdatabase/SQLTransactionBackend.cpp: (WebCore::SQLTransactionBackend::doCleanup): (WebCore::SQLTransactionBackend::notifyDatabaseThreadIsShuttingDown): * bindings/js/JSCallbackData.h: (WebCore::JSCallbackData::JSCallbackData): (WebCore::JSCallbackData::~JSCallbackData): * bindings/js/ScheduledAction.cpp: (WebCore::ScheduledAction::execute): * dom/ScriptExecutionContext.cpp: (WebCore::ScriptExecutionContext::createdMessagePort): (WebCore::ScriptExecutionContext::destroyedMessagePort): * page/ResourceUsageOverlay.h: * page/scrolling/ScrollingThread.cpp: (WebCore::ScrollingThread::isCurrentThread): * platform/Supplementable.h: (WebCore::Supplementable::provideSupplement): (WebCore::Supplementable::removeSupplement): (WebCore::Supplementable::requireSupplement): (WebCore::Supplementable::Supplementable): Deleted. * platform/Timer.cpp: (WebCore::TimerBase::TimerBase): (WebCore::TimerBase::start): (WebCore::TimerBase::stop): (WebCore::TimerBase::setNextFireTime): * platform/Timer.h: (WebCore::TimerBase::isActive const): * platform/graphics/cocoa/FontCacheCoreText.cpp: (WebCore::shouldAutoActivateFontIfNeeded): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.cpp: (WebCore::TextureMapperPlatformLayerProxy::activateOnCompositingThread): (WebCore::TextureMapperPlatformLayerProxy::invalidate): (WebCore::TextureMapperPlatformLayerProxy::getAvailableBuffer): (WebCore::TextureMapperPlatformLayerProxy::appendToUnusedBuffers): (WebCore::TextureMapperPlatformLayerProxy::swapBuffer): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.h: (): Deleted. * platform/ios/wak/WebCoreThread.mm: (RunWebThread): (StartWebThread): * platform/sql/SQLiteDatabase.cpp: (WebCore::SQLiteDatabase::open): (WebCore::SQLiteDatabase::close): * platform/sql/SQLiteDatabase.h: (WebCore::SQLiteDatabase::sqlite3Handle const): * workers/WorkerGlobalScope.cpp: (WebCore::WorkerGlobalScope::~WorkerGlobalScope): (WebCore::WorkerGlobalScope::isContextThread const): * workers/WorkerMessagingProxy.cpp: (WebCore::WorkerMessagingProxy::WorkerMessagingProxy): (WebCore::WorkerMessagingProxy::~WorkerMessagingProxy): * workers/WorkerRunLoop.cpp: (WebCore::WorkerRunLoop::runInMode): (WebCore::WorkerRunLoop::runCleanupTasks): * workers/WorkerThread.h: (WebCore::WorkerThread::thread const): (WebCore::WorkerThread::threadID const): Deleted. * workers/service/ServiceWorkerContainer.cpp: (WebCore::ServiceWorkerContainer::~ServiceWorkerContainer): (WebCore::ServiceWorkerContainer::scheduleJob): (WebCore::ServiceWorkerContainer::jobFailedWithException): (WebCore::ServiceWorkerContainer::scheduleTaskToFireUpdateFoundEvent): (WebCore::ServiceWorkerContainer::jobResolvedWithRegistration): (WebCore::ServiceWorkerContainer::jobResolvedWithUnregistrationResult): (WebCore::ServiceWorkerContainer::startScriptFetchForJob): (WebCore::ServiceWorkerContainer::jobFinishedLoadingScript): (WebCore::ServiceWorkerContainer::jobFailedLoadingScript): (WebCore::ServiceWorkerContainer::jobDidFinish): (WebCore::ServiceWorkerContainer::addRegistration): (WebCore::ServiceWorkerContainer::removeRegistration): (WebCore::ServiceWorkerContainer::scheduleTaskToFireControllerChangeEvent): (WebCore::ServiceWorkerContainer::contextIdentifier): * workers/service/ServiceWorkerContainer.h: * workers/service/ServiceWorkerJob.cpp: (WebCore::ServiceWorkerJob::~ServiceWorkerJob): (WebCore::ServiceWorkerJob::failedWithException): (WebCore::ServiceWorkerJob::resolvedWithRegistration): (WebCore::ServiceWorkerJob::resolvedWithUnregistrationResult): (WebCore::ServiceWorkerJob::startScriptFetch): (WebCore::ServiceWorkerJob::fetchScriptWithContext): (WebCore::ServiceWorkerJob::didReceiveResponse): (WebCore::ServiceWorkerJob::notifyFinished): * workers/service/ServiceWorkerJob.h: * xml/parser/XMLDocumentParserLibxml2.cpp: (WebCore::matchFunc): (WebCore::openFunc): (WebCore::initializeXMLParser): (WebCore::XMLParserContext::createStringParser): (WebCore::XMLParserContext::createMemoryParser): Source/WebKit: * UIProcess/API/glib/IconDatabase.cpp: * UIProcess/GenericCallback.h: (WebKit::GenericCallback::~GenericCallback): (WebKit::GenericCallback::performCallbackWithReturnValue): Source/WTF: We should use a pointer of WTF::Thread instead of ThreadIdentifier. One problem is that Windows support library uses WTF::createThread, which returns ThreadIdentifier. So we cannot drop ThreadIdentifier in Windows environment. This patch keeps ThreadIdentifier in Windows. * wtf/MainThread.cpp: (WTF::initializeMainThread): (WTF::isMainThread): (WTF::canAccessThreadLocalDataForThread): * wtf/MainThread.h: * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkCount): * wtf/RecursiveLockAdapter.h: (WTF::RecursiveLockAdapter::lock): (WTF::RecursiveLockAdapter::unlock): (WTF::RecursiveLockAdapter::tryLock): * wtf/Threading.cpp: (WTF::Thread::dump const): * wtf/Threading.h: (WTF::Thread::id const): (WTF::Thread::operator==): Deleted. (WTF::Thread::operator!=): Deleted. (WTF::currentThread): Deleted. * wtf/ThreadingPrimitives.h: * wtf/ThreadingPthreads.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::detach): (WTF::Thread::initializeCurrentTLS): (WTF::Thread::suspend): (WTF::Thread::establishPlatformSpecificHandle): (WTF::Thread::currentID): Deleted. * wtf/ThreadingWin.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::suspend): (WTF::Thread::currentDying): * wtf/mac/MainThreadMac.mm: (WTF::initializeApplicationUIThread): (WTF::initializeWebThreadPlatform): (WTF::canAccessThreadLocalDataForThread): (WTF::initializeApplicationUIThreadIdentifier): Deleted. (WTF::initializeWebThreadIdentifier): Deleted. Tools: * DumpRenderTree/mac/DumpRenderTree.mm: (dumpRenderTree): (runThread): Deleted. (runPthread): Deleted. (testThreadIdentifierMap): Deleted. * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: * TestWebKitAPI/Tests/WTF/Threading.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/196314@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@225470 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-12-04 06:13:05 +00:00
dataLog(toString(Thread::current(), ": index = ", index, "\n"));
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
Bucket* bucket = newHashtable->data[index].load();
if (!bucket) {
if (reusableBuckets.isEmpty())
bucket = new Bucket();
else
bucket = reusableBuckets.takeLast();
newHashtable->data[index].store(bucket);
}
bucket->enqueue(threadData);
}
// At this point there may be some buckets left unreused. This could easily happen if the
// number of enqueued threads right now is low but the high watermark of the number of threads
// enqueued was high. We place these buckets into the hashtable basically at random, just to
// make sure we don't leak them.
for (unsigned i = 0; i < newHashtable->size && !reusableBuckets.isEmpty(); ++i) {
Atomic<Bucket*>& bucketPtr = newHashtable->data[i];
if (bucketPtr.load())
continue;
bucketPtr.store(reusableBuckets.takeLast());
}
// Since we increased the size of the hashtable, we should have exhausted our preallocated
// buckets by now.
ASSERT(reusableBuckets.isEmpty());
// OK, right now the old hashtable is locked up and the new hashtable is ready to rock and
// roll. After we install the new hashtable, we can release all bucket locks.
JSC should support SharedArrayBuffer https://bugs.webkit.org/show_bug.cgi?id=163986 Reviewed by Keith Miller. JSTests: This adds our own test for the various corner cases of SharedArrayBuffer. This test is meant to check all of the things that don't require concurrency. * stress/SharedArrayBuffer.js: Added. (checkAtomics): (shouldFail): (Symbol): (runAtomic): Source/JavaScriptCore: This implements https://tc39.github.io/ecmascript_sharedmem/shmem.html. There is now a new SharedArrayBuffer type. In the JS runtime, which includes typed array types, the SharedArrayBuffer is a drop-in replacement for ArrayBuffer, even though they are distinct types (new SharedArrayBuffer() instanceof ArrayBuffer == false and vice versa). The DOM will not recognize SharedArrayBuffer, or any typed array that wraps it, to ensure safety. This matches what other browsers intend to do, see https://github.com/tc39/ecmascript_sharedmem/issues/38. API is provided for the DOM to opt into SharedArrayBuffer. One notable place is postMessage, which will share the SharedArrayBuffer's underlying data storage with other workers. This creates a pool of shared memory that the workers can use to talk to each other. There is also an Atomics object in global scope, which exposes sequentially consistent atomic operations: add, and, compareExchange, exchange, load, or, store, sub, and xor. Additionally it exposes a Atomics.isLockFree utility, which takes a byte amount and returns true or false. Also there is Atomics.wake/wait, which neatly map to ParkingLot. Accesses to typed arrays that wrap SharedArrayBuffer are optimized by JSC the same way as always. I believe that DFG and B3 already obey the following memory model, which I believe is a bit weaker than Cambridge and a bit stronger than what is being proposed for SharedArrayBuffer. To predict a program's behavior under the B3 memory model, imagine the space of all possible programs that would result from running an optimizer that adversarially follows B3's transformation rules. B3 transformations are correct if the newly created program is equivalent to the old one, assuming that any opaque effect in IR (like the reads and writes of a patchpoint/call/fence) could perform any load/store that satisfies the B3::Effects summary. Opaque effects are a way of describing an infinite set of programs: any program that only does the effects summarized in B3::Effects belongs to the set. For example, this prevents motion of operations across fences since fences are summarized as opaque effects that could read or write memory. This rule alone is not enough, because it leaves the door open for turning an atomic operation (like a load) into a non-atomic one (like a load followed by a store of the same value back to the same location or multiple loads). This is not an optimization that either our compiler or the CPU would want to do. One way to think of what exactly is forbidden is that B3 transformations that mess with memory accesses can only reorder them or remove them. This means that for any execution of the untransformed program, the corresponding execution of the transformed program (i.e. with the same input arguments and the same programs filled in for the opaque effects) must have the same loads and stores, with some removed and some reordered. This is a fairly simple mental model that B3 and DFG already follow and it's based on existing abstractions for the infinite set of programs inside an opaque effect (DFG's AbstractHeaps and B3's Effects). This patch makes all atomics operations intrinsic, but the DFG doesn't know about any of them yet. That's covered by bug 164108. This ought to be perf-neutral, but I am still running tests to confirm this. I'm also still writing new tests to cover all of the Atomics functionality and the behavior of SAB objects. * API/JSTypedArray.cpp: (JSObjectGetTypedArrayBytesPtr): (JSObjectGetTypedArrayBuffer): (JSObjectMakeArrayBufferWithBytesNoCopy): * API/tests/CompareAndSwapTest.cpp: (Bitmap::concurrentTestAndSet): * CMakeLists.txt: * JavaScriptCore.xcodeproj/project.pbxproj: * dfg/DFGDesiredWatchpoints.cpp: (JSC::DFG::ArrayBufferViewWatchpointAdaptor::add): * heap/Heap.cpp: (JSC::Heap::reportExtraMemoryVisited): (JSC::Heap::reportExternalMemoryVisited): * jsc.cpp: (functionTransferArrayBuffer): * runtime/ArrayBuffer.cpp: (JSC::SharedArrayBufferContents::SharedArrayBufferContents): (JSC::SharedArrayBufferContents::~SharedArrayBufferContents): (JSC::ArrayBufferContents::ArrayBufferContents): (JSC::ArrayBufferContents::operator=): (JSC::ArrayBufferContents::~ArrayBufferContents): (JSC::ArrayBufferContents::clear): (JSC::ArrayBufferContents::destroy): (JSC::ArrayBufferContents::reset): (JSC::ArrayBufferContents::tryAllocate): (JSC::ArrayBufferContents::makeShared): (JSC::ArrayBufferContents::transferTo): (JSC::ArrayBufferContents::copyTo): (JSC::ArrayBufferContents::shareWith): (JSC::ArrayBuffer::create): (JSC::ArrayBuffer::createAdopted): (JSC::ArrayBuffer::createFromBytes): (JSC::ArrayBuffer::tryCreate): (JSC::ArrayBuffer::createUninitialized): (JSC::ArrayBuffer::tryCreateUninitialized): (JSC::ArrayBuffer::createInternal): (JSC::ArrayBuffer::ArrayBuffer): (JSC::ArrayBuffer::slice): (JSC::ArrayBuffer::sliceImpl): (JSC::ArrayBuffer::makeShared): (JSC::ArrayBuffer::setSharingMode): (JSC::ArrayBuffer::transferTo): (JSC::ArrayBuffer::transfer): Deleted. * runtime/ArrayBuffer.h: (JSC::arrayBufferSharingModeName): (JSC::SharedArrayBufferContents::data): (JSC::ArrayBufferContents::data): (JSC::ArrayBufferContents::sizeInBytes): (JSC::ArrayBufferContents::isShared): (JSC::ArrayBuffer::sharingMode): (JSC::ArrayBuffer::isShared): (JSC::ArrayBuffer::gcSizeEstimateInBytes): (JSC::arrayBufferDestructorNull): Deleted. (JSC::arrayBufferDestructorDefault): Deleted. (JSC::ArrayBufferContents::ArrayBufferContents): Deleted. (JSC::ArrayBufferContents::transfer): Deleted. (JSC::ArrayBufferContents::copyTo): Deleted. (JSC::ArrayBuffer::create): Deleted. (JSC::ArrayBuffer::createAdopted): Deleted. (JSC::ArrayBuffer::createFromBytes): Deleted. (JSC::ArrayBuffer::tryCreate): Deleted. (JSC::ArrayBuffer::createUninitialized): Deleted. (JSC::ArrayBuffer::tryCreateUninitialized): Deleted. (JSC::ArrayBuffer::createInternal): Deleted. (JSC::ArrayBuffer::ArrayBuffer): Deleted. (JSC::ArrayBuffer::slice): Deleted. (JSC::ArrayBuffer::sliceImpl): Deleted. (JSC::ArrayBufferContents::tryAllocate): Deleted. (JSC::ArrayBufferContents::~ArrayBufferContents): Deleted. * runtime/ArrayBufferSharingMode.h: Added. * runtime/ArrayBufferView.h: (JSC::ArrayBufferView::possiblySharedBuffer): (JSC::ArrayBufferView::unsharedBuffer): (JSC::ArrayBufferView::isShared): (JSC::ArrayBufferView::buffer): Deleted. * runtime/AtomicsObject.cpp: Added. (JSC::AtomicsObject::AtomicsObject): (JSC::AtomicsObject::create): (JSC::AtomicsObject::createStructure): (JSC::AtomicsObject::finishCreation): (JSC::atomicsFuncAdd): (JSC::atomicsFuncAnd): (JSC::atomicsFuncCompareExchange): (JSC::atomicsFuncExchange): (JSC::atomicsFuncIsLockFree): (JSC::atomicsFuncLoad): (JSC::atomicsFuncOr): (JSC::atomicsFuncStore): (JSC::atomicsFuncSub): (JSC::atomicsFuncWait): (JSC::atomicsFuncWake): (JSC::atomicsFuncXor): * runtime/AtomicsObject.h: Added. * runtime/CommonIdentifiers.h: * runtime/DataView.cpp: (JSC::DataView::wrap): * runtime/GenericTypedArrayViewInlines.h: (JSC::GenericTypedArrayView<Adaptor>::subarray): * runtime/Intrinsic.h: * runtime/JSArrayBuffer.cpp: (JSC::JSArrayBuffer::finishCreation): (JSC::JSArrayBuffer::isShared): (JSC::JSArrayBuffer::sharingMode): * runtime/JSArrayBuffer.h: (JSC::toPossiblySharedArrayBuffer): (JSC::toUnsharedArrayBuffer): (JSC::JSArrayBuffer::toWrapped): (JSC::toArrayBuffer): Deleted. * runtime/JSArrayBufferConstructor.cpp: (JSC::JSArrayBufferConstructor::JSArrayBufferConstructor): (JSC::JSArrayBufferConstructor::finishCreation): (JSC::JSArrayBufferConstructor::create): (JSC::constructArrayBuffer): * runtime/JSArrayBufferConstructor.h: (JSC::JSArrayBufferConstructor::sharingMode): * runtime/JSArrayBufferPrototype.cpp: (JSC::arrayBufferProtoFuncSlice): (JSC::JSArrayBufferPrototype::JSArrayBufferPrototype): (JSC::JSArrayBufferPrototype::finishCreation): (JSC::JSArrayBufferPrototype::create): * runtime/JSArrayBufferPrototype.h: * runtime/JSArrayBufferView.cpp: (JSC::JSArrayBufferView::finishCreation): (JSC::JSArrayBufferView::visitChildren): (JSC::JSArrayBufferView::unsharedBuffer): (JSC::JSArrayBufferView::unsharedJSBuffer): (JSC::JSArrayBufferView::possiblySharedJSBuffer): (JSC::JSArrayBufferView::neuter): (JSC::JSArrayBufferView::toWrapped): Deleted. * runtime/JSArrayBufferView.h: (JSC::JSArrayBufferView::jsBuffer): Deleted. * runtime/JSArrayBufferViewInlines.h: (JSC::JSArrayBufferView::isShared): (JSC::JSArrayBufferView::possiblySharedBuffer): (JSC::JSArrayBufferView::possiblySharedImpl): (JSC::JSArrayBufferView::unsharedImpl): (JSC::JSArrayBufferView::byteOffset): (JSC::JSArrayBufferView::toWrapped): (JSC::JSArrayBufferView::buffer): Deleted. (JSC::JSArrayBufferView::impl): Deleted. (JSC::JSArrayBufferView::neuter): Deleted. * runtime/JSDataView.cpp: (JSC::JSDataView::possiblySharedTypedImpl): (JSC::JSDataView::unsharedTypedImpl): (JSC::JSDataView::getTypedArrayImpl): (JSC::JSDataView::typedImpl): Deleted. * runtime/JSDataView.h: (JSC::JSDataView::possiblySharedBuffer): (JSC::JSDataView::unsharedBuffer): (JSC::JSDataView::buffer): Deleted. * runtime/JSDataViewPrototype.cpp: (JSC::dataViewProtoGetterBuffer): * runtime/JSGenericTypedArrayView.h: (JSC::toPossiblySharedNativeTypedView): (JSC::toUnsharedNativeTypedView): (JSC::JSGenericTypedArrayView<Adaptor>::toWrapped): (JSC::JSGenericTypedArrayView::typedImpl): Deleted. (JSC::toNativeTypedView): Deleted. * runtime/JSGenericTypedArrayViewInlines.h: (JSC::JSGenericTypedArrayView<Adaptor>::create): (JSC::JSGenericTypedArrayView<Adaptor>::possiblySharedTypedImpl): (JSC::JSGenericTypedArrayView<Adaptor>::unsharedTypedImpl): (JSC::JSGenericTypedArrayView<Adaptor>::getTypedArrayImpl): * runtime/JSGenericTypedArrayViewPrototypeFunctions.h: (JSC::genericTypedArrayViewProtoGetterFuncBuffer): (JSC::genericTypedArrayViewPrivateFuncSubarrayCreate): * runtime/JSGlobalObject.cpp: (JSC::createAtomicsProperty): (JSC::JSGlobalObject::init): (JSC::JSGlobalObject::visitChildren): * runtime/JSGlobalObject.h: (JSC::JSGlobalObject::arrayBufferPrototype): (JSC::JSGlobalObject::arrayBufferStructure): * runtime/MathObject.cpp: * runtime/RuntimeFlags.h: * runtime/SimpleTypedArrayController.cpp: (JSC::SimpleTypedArrayController::toJS): * runtime/TypedArrayType.h: (JSC::typedArrayTypeForType): Source/WebCore: New tests added in the LayoutTests/workers/sab directory. This teaches WebCore that a typed array could be shared or not. By default, WebCore will reject shared typed arrays as if they were not typed arrays. This ensures that we don't get race conditions in code that can't handle it. If you postMessage a SharedArrayBuffer or something that wraps it, you will send the shared memory to the other worker. * Modules/encryptedmedia/CDMSessionClearKey.cpp: (WebCore::CDMSessionClearKey::cachedKeyForKeyID): * Modules/fetch/FetchBody.cpp: (WebCore::FetchBody::extract): * Modules/mediastream/RTCDataChannel.cpp: (WebCore::RTCDataChannel::send): * Modules/webaudio/AudioBuffer.cpp: (WebCore::AudioBuffer::getChannelData): * Modules/websockets/WebSocket.cpp: (WebCore::WebSocket::send): * bindings/js/JSBlobCustom.cpp: (WebCore::constructJSBlob): * bindings/js/JSCryptoAlgorithmDictionary.cpp: (WebCore::createRsaKeyGenParams): * bindings/js/JSCryptoCustom.cpp: (WebCore::JSCrypto::getRandomValues): * bindings/js/JSCryptoOperationData.cpp: (WebCore::cryptoOperationDataFromJSValue): * bindings/js/JSDOMBinding.h: (WebCore::toJS): (WebCore::toPossiblySharedArrayBufferView): (WebCore::toUnsharedArrayBufferView): (WebCore::toPossiblySharedInt8Array): (WebCore::toPossiblySharedInt16Array): (WebCore::toPossiblySharedInt32Array): (WebCore::toPossiblySharedUint8Array): (WebCore::toPossiblySharedUint8ClampedArray): (WebCore::toPossiblySharedUint16Array): (WebCore::toPossiblySharedUint32Array): (WebCore::toPossiblySharedFloat32Array): (WebCore::toPossiblySharedFloat64Array): (WebCore::toUnsharedInt8Array): (WebCore::toUnsharedInt16Array): (WebCore::toUnsharedInt32Array): (WebCore::toUnsharedUint8Array): (WebCore::toUnsharedUint8ClampedArray): (WebCore::toUnsharedUint16Array): (WebCore::toUnsharedUint32Array): (WebCore::toUnsharedFloat32Array): (WebCore::toUnsharedFloat64Array): (WebCore::toArrayBufferView): Deleted. (WebCore::toInt8Array): Deleted. (WebCore::toInt16Array): Deleted. (WebCore::toInt32Array): Deleted. (WebCore::toUint8Array): Deleted. (WebCore::toUint8ClampedArray): Deleted. (WebCore::toUint16Array): Deleted. (WebCore::toUint32Array): Deleted. (WebCore::toFloat32Array): Deleted. (WebCore::toFloat64Array): Deleted. * bindings/js/JSDataCueCustom.cpp: (WebCore::constructJSDataCue): * bindings/js/JSDictionary.cpp: (WebCore::JSDictionary::convertValue): * bindings/js/JSFileCustom.cpp: (WebCore::constructJSFile): * bindings/js/JSMessagePortCustom.cpp: (WebCore::extractTransferables): * bindings/js/JSWebGLRenderingContextBaseCustom.cpp: (WebCore::dataFunctionf): (WebCore::dataFunctioni): (WebCore::dataFunctionMatrix): * bindings/js/JSXMLHttpRequestCustom.cpp: (WebCore::JSXMLHttpRequest::send): * bindings/js/SerializedScriptValue.cpp: (WebCore::CloneSerializer::dumpArrayBufferView): (WebCore::CloneSerializer::dumpIfTerminal): (WebCore::CloneDeserializer::readArrayBufferView): (WebCore::CloneDeserializer::readTerminal): (WebCore::SerializedScriptValue::transferArrayBuffers): * bindings/js/StructuredClone.cpp: (WebCore::structuredCloneArrayBuffer): (WebCore::structuredCloneArrayBufferView): * bindings/scripts/CodeGeneratorJS.pm: (JSValueToNative): * css/FontFace.cpp: (WebCore::FontFace::create): * html/canvas/WebGL2RenderingContext.cpp: (WebCore::WebGL2RenderingContext::bufferData): (WebCore::WebGL2RenderingContext::bufferSubData): * platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp: (WebCore::MediaPlayerPrivateAVFoundation::extractKeyURIKeyIDAndCertificateFromInitData): Source/WebKit/mac: Support the RuntimeFlag. * WebView/WebPreferencesPrivate.h: Source/WebKit/win: Support the RuntimeFlag. * Interfaces/IWebPreferencesPrivate.idl: Source/WebKit2: Adds some small things we need for SharedArrayBuffer. * UIProcess/API/C/WKPreferencesRefPrivate.h: * UIProcess/API/Cocoa/WKPreferencesPrivate.h: * WebProcess/InjectedBundle/InjectedBundle.cpp: (WebKit::InjectedBundle::createWebDataFromUint8Array): Source/WTF: Adds some small things we need for SharedArrayBuffer. * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeakRelaxed): (WTF::Atomic::exchangeAdd): (WTF::Atomic::exchangeAnd): (WTF::Atomic::exchangeOr): (WTF::Atomic::exchangeSub): (WTF::Atomic::exchangeXor): (WTF::atomicLoad): (WTF::atomicStore): (WTF::atomicCompareExchangeWeak): (WTF::atomicCompareExchangeWeakRelaxed): (WTF::atomicCompareExchangeStrong): (WTF::atomicExchangeAdd): (WTF::atomicExchangeAnd): (WTF::atomicExchangeOr): (WTF::atomicExchangeSub): (WTF::atomicExchangeXor): (WTF::atomicExchange): (WTF::Atomic::exchangeAndAdd): Deleted. (WTF::weakCompareAndSwap): Deleted. We need to be able to do atomics operations on naked pointers. We also need to be able to do all of the things that std::atomic does. This adds those things and renames weakCompareAndSwap to atomicCompareExchangeWeakRelaxed so that we're using consistent terminology. * wtf/Bitmap.h: (WTF::WordType>::concurrentTestAndSet): Renamed weakCompareAndSwap. (WTF::WordType>::concurrentTestAndClear): Renamed weakCompareAndSwap. * wtf/FastBitVector.h: (WTF::FastBitVector::atomicSetAndCheck): Renamed weakCompareAndSwap. * wtf/ParkingLot.cpp: (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkCount): * wtf/ParkingLot.h: Added unparkCount(), which lets you unpark some bounded number of threads and returns the number of threads unparked. This is just a modest extension of unparkAll(). unparkAll() now just calls unparkCount(ptr, UINT_MAX). Tools: Use the right kind of typed array API. * DumpRenderTree/TestRunner.cpp: (setAudioResultCallback): LayoutTests: Adding tests. This is a work in progress. * workers/sab: Added. * workers/sab/simple-worker-1.js: Added. (onmessage): * workers/sab/simple-worker-2.js: Added. (onmessage): * workers/sab/simple.html: Added. Canonical link: https://commits.webkit.org/181984@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208209 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-11-01 03:10:00 +00:00
bool result = hashtable.compareExchangeStrong(oldHashtable, newHashtable) == oldHashtable;
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
RELEASE_ASSERT(result);
unlockHashtable(bucketsToUnlock);
}
ThreadData::ThreadData()
[WTF] Introduce Thread class and use RefPtr<Thread> and align Windows Threading implementation semantics to Pthread one https://bugs.webkit.org/show_bug.cgi?id=170502 Reviewed by Mark Lam. Source/JavaScriptCore: * API/tests/CompareAndSwapTest.cpp: (testCompareAndSwap): * JavaScriptCore.xcodeproj/project.pbxproj: * b3/air/testair.cpp: * b3/testb3.cpp: (JSC::B3::run): * bytecode/SuperSampler.cpp: (JSC::initializeSuperSampler): * dfg/DFGWorklist.cpp: * disassembler/Disassembler.cpp: * heap/Heap.cpp: (JSC::Heap::lastChanceToFinalize): (JSC::Heap::notifyIsSafeToCollect): * heap/Heap.h: * heap/MachineStackMarker.cpp: (JSC::MachineThreads::~MachineThreads): (JSC::MachineThreads::addCurrentThread): (JSC::MachineThreads::removeThread): (JSC::MachineThreads::removeThreadIfFound): (JSC::MachineThreads::MachineThread::MachineThread): (JSC::MachineThreads::MachineThread::getRegisters): (JSC::MachineThreads::MachineThread::Registers::stackPointer): (JSC::MachineThreads::MachineThread::Registers::framePointer): (JSC::MachineThreads::MachineThread::Registers::instructionPointer): (JSC::MachineThreads::MachineThread::Registers::llintPC): (JSC::MachineThreads::MachineThread::captureStack): (JSC::MachineThreads::tryCopyOtherThreadStack): (JSC::MachineThreads::tryCopyOtherThreadStacks): (pthreadSignalHandlerSuspendResume): Deleted. (JSC::threadData): Deleted. (JSC::MachineThreads::Thread::Thread): Deleted. (JSC::MachineThreads::Thread::createForCurrentThread): Deleted. (JSC::MachineThreads::Thread::operator==): Deleted. (JSC::MachineThreads::machineThreadForCurrentThread): Deleted. (JSC::MachineThreads::ThreadData::ThreadData): Deleted. (JSC::MachineThreads::ThreadData::~ThreadData): Deleted. (JSC::MachineThreads::ThreadData::suspend): Deleted. (JSC::MachineThreads::ThreadData::resume): Deleted. (JSC::MachineThreads::ThreadData::getRegisters): Deleted. (JSC::MachineThreads::ThreadData::Registers::stackPointer): Deleted. (JSC::MachineThreads::ThreadData::Registers::framePointer): Deleted. (JSC::MachineThreads::ThreadData::Registers::instructionPointer): Deleted. (JSC::MachineThreads::ThreadData::Registers::llintPC): Deleted. (JSC::MachineThreads::ThreadData::freeRegisters): Deleted. (JSC::MachineThreads::ThreadData::captureStack): Deleted. * heap/MachineStackMarker.h: (JSC::MachineThreads::MachineThread::suspend): (JSC::MachineThreads::MachineThread::resume): (JSC::MachineThreads::MachineThread::threadID): (JSC::MachineThreads::MachineThread::stackBase): (JSC::MachineThreads::MachineThread::stackEnd): (JSC::MachineThreads::threadsListHead): (JSC::MachineThreads::Thread::operator!=): Deleted. (JSC::MachineThreads::Thread::suspend): Deleted. (JSC::MachineThreads::Thread::resume): Deleted. (JSC::MachineThreads::Thread::getRegisters): Deleted. (JSC::MachineThreads::Thread::freeRegisters): Deleted. (JSC::MachineThreads::Thread::captureStack): Deleted. (JSC::MachineThreads::Thread::platformThread): Deleted. (JSC::MachineThreads::Thread::stackBase): Deleted. (JSC::MachineThreads::Thread::stackEnd): Deleted. * jit/ICStats.cpp: (JSC::ICStats::ICStats): (JSC::ICStats::~ICStats): * jit/ICStats.h: * jsc.cpp: (functionDollarAgentStart): (startTimeoutThreadIfNeeded): * runtime/JSLock.cpp: (JSC::JSLock::lock): * runtime/JSLock.h: (JSC::JSLock::ownerThread): (JSC::JSLock::currentThreadIsHoldingLock): * runtime/SamplingProfiler.cpp: (JSC::FrameWalker::isValidFramePointer): (JSC::SamplingProfiler::SamplingProfiler): (JSC::SamplingProfiler::createThreadIfNecessary): (JSC::SamplingProfiler::takeSample): * runtime/SamplingProfiler.h: * runtime/VM.h: (JSC::VM::ownerThread): * runtime/VMTraps.cpp: (JSC::findActiveVMAndStackBounds): (JSC::VMTraps::SignalSender::send): (JSC::VMTraps::fireTrap): Source/WebCore: Mechanical change. Use Thread:: APIs. * Modules/indexeddb/server/IDBServer.cpp: (WebCore::IDBServer::IDBServer::IDBServer): * Modules/indexeddb/server/IDBServer.h: * Modules/webaudio/AsyncAudioDecoder.cpp: (WebCore::AsyncAudioDecoder::AsyncAudioDecoder): (WebCore::AsyncAudioDecoder::~AsyncAudioDecoder): (WebCore::AsyncAudioDecoder::runLoop): * Modules/webaudio/AsyncAudioDecoder.h: * Modules/webaudio/OfflineAudioDestinationNode.cpp: (WebCore::OfflineAudioDestinationNode::OfflineAudioDestinationNode): (WebCore::OfflineAudioDestinationNode::uninitialize): (WebCore::OfflineAudioDestinationNode::startRendering): * Modules/webaudio/OfflineAudioDestinationNode.h: * Modules/webdatabase/Database.cpp: (WebCore::Database::securityOrigin): * Modules/webdatabase/DatabaseThread.cpp: (WebCore::DatabaseThread::start): (WebCore::DatabaseThread::databaseThread): (WebCore::DatabaseThread::recordDatabaseOpen): (WebCore::DatabaseThread::recordDatabaseClosed): * Modules/webdatabase/DatabaseThread.h: (WebCore::DatabaseThread::getThreadID): * bindings/js/GCController.cpp: (WebCore::GCController::garbageCollectOnAlternateThreadForDebugging): * fileapi/AsyncFileStream.cpp: (WebCore::callOnFileThread): * loader/icon/IconDatabase.cpp: (WebCore::IconDatabase::open): (WebCore::IconDatabase::close): * loader/icon/IconDatabase.h: * page/ResourceUsageThread.cpp: (WebCore::ResourceUsageThread::createThreadIfNeeded): * page/ResourceUsageThread.h: * page/scrolling/ScrollingThread.cpp: (WebCore::ScrollingThread::ScrollingThread): (WebCore::ScrollingThread::isCurrentThread): (WebCore::ScrollingThread::createThreadIfNeeded): (WebCore::ScrollingThread::threadCallback): * page/scrolling/ScrollingThread.h: * platform/audio/HRTFDatabaseLoader.cpp: (WebCore::HRTFDatabaseLoader::HRTFDatabaseLoader): (WebCore::HRTFDatabaseLoader::loadAsynchronously): (WebCore::HRTFDatabaseLoader::waitForLoaderThreadCompletion): * platform/audio/HRTFDatabaseLoader.h: * platform/audio/ReverbConvolver.cpp: (WebCore::ReverbConvolver::ReverbConvolver): (WebCore::ReverbConvolver::~ReverbConvolver): * platform/audio/ReverbConvolver.h: * platform/audio/gstreamer/AudioFileReaderGStreamer.cpp: (WebCore::createBusFromAudioFile): (WebCore::createBusFromInMemoryAudioFile): * platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp: (ResourceHandleStreamingClient::ResourceHandleStreamingClient): (ResourceHandleStreamingClient::~ResourceHandleStreamingClient): * platform/network/cf/LoaderRunLoopCF.cpp: (WebCore::loaderRunLoop): * platform/network/curl/CurlDownload.cpp: (WebCore::CurlDownloadManager::startThreadIfNeeded): (WebCore::CurlDownloadManager::stopThread): * platform/network/curl/CurlDownload.h: * platform/network/curl/SocketStreamHandleImpl.h: * platform/network/curl/SocketStreamHandleImplCurl.cpp: (WebCore::SocketStreamHandleImpl::startThread): (WebCore::SocketStreamHandleImpl::stopThread): * workers/WorkerThread.cpp: (WebCore::WorkerThread::WorkerThread): (WebCore::WorkerThread::start): (WebCore::WorkerThread::workerThread): * workers/WorkerThread.h: (WebCore::WorkerThread::threadID): Source/WebKit: Mechanical change. Use Thread:: APIs. * Storage/StorageThread.cpp: (WebCore::StorageThread::StorageThread): (WebCore::StorageThread::~StorageThread): (WebCore::StorageThread::start): (WebCore::StorageThread::dispatch): (WebCore::StorageThread::terminate): * Storage/StorageThread.h: Source/WebKit2: Mechanical change. Use Thread:: APIs. * NetworkProcess/NetworkProcess.cpp: (WebKit::NetworkProcess::initializeNetworkProcess): * NetworkProcess/cache/NetworkCacheIOChannelSoup.cpp: (WebKit::NetworkCache::IOChannel::readSyncInThread): * Platform/IPC/Connection.cpp: (IPC::Connection::processIncomingMessage): * Shared/EntryPointUtilities/mac/XPCService/XPCServiceEntryPoint.h: (WebKit::XPCServiceInitializer): * UIProcess/linux/MemoryPressureMonitor.cpp: (WebKit::MemoryPressureMonitor::MemoryPressureMonitor): * WebProcess/WebProcess.cpp: (WebKit::WebProcess::initializeWebProcess): Source/WTF: This patch is refactoring of WTF Threading mechanism to merge JavaScriptCore's threading extension to WTF Threading. Previously, JavaScriptCore requires richer threading features (such as suspending and resuming threads), and they are implemented for PlatformThread in JavaScriptCore. But these features should be implemented in WTF Threading side instead of maintaining JSC's own threading features too. This patch removes these features from JSC and move it to WTF Threading. However, current WTF Threading has one problem: Windows version of WTF Threading has different semantics from Pthreads one. In Windows WTF Threading, we cannot perform any operation after the target thread is detached: WTF Threading stop tracking the state of the thread once the thread is detached. But this is not the same to Pthreads one. In Pthreads, pthread_detach just means that the resource of the thread will be destroyed automatically. While some operations like pthread_join will be rejected, some operations like pthread_kill will be accepted. The problem is that detached thread can be suspended and resumed in JSC. For example, in jsc.cpp, we start the worker thread and detach it immediately. In worker thread, we will create VM and thus concurrent GC will suspend and resume the detached thread. However, in Windows WTF Threading, we have no reference to the detached thread. Thus we cannot perform suspend and resume operations onto the detached thread. To solve the problem, we change Windows Threading mechanism drastically to align it to the Pthread semantics. In the new Threading, we have RefPtr<Thread> class. It holds a handle to a platform thread. We can perform threading operations with this class. For example, Thread::suspend is offered. And we use destructor of the thread local variable to release the resources held by RefPtr<Thread>. In Windows, Thread::detach does nothing because the resource will be destroyed automatically by RefPtr<Thread>. To do so, we introduce ThreadHolder for Windows. This is similar to the previous ThreadIdentifierData for Pthreads. It holds RefPtr<Thread> in the thread local storage (technically, it is Fiber Local Storage in Windows). Thread::current() will return this reference. The problematic situation is that the order of the deallocation of the thread local storage is not defined. So we should not touch thread local storage in the destructor of the thread local storage. To avoid such edge cases, we have currentThread() / Thread::currentID() APIs. They are safe to be called even in the destructor of the other thread local storage. And in Windows, in the FLS destructor, we will create the thread_local variable to defer the destruction of the ThreadHolder. We ensure that this destructor is called after the other FLS destructors are called in Windows 10. This patch is performance neutral. * WTF.xcodeproj/project.pbxproj: * benchmarks/ConditionSpeedTest.cpp: * benchmarks/LockFairnessTest.cpp: * benchmarks/LockSpeedTest.cpp: * wtf/AutomaticThread.cpp: (WTF::AutomaticThread::start): * wtf/CMakeLists.txt: * wtf/MainThread.h: * wtf/MemoryPressureHandler.h: * wtf/ParallelJobsGeneric.cpp: (WTF::ParallelEnvironment::ThreadPrivate::tryLockFor): (WTF::ParallelEnvironment::ThreadPrivate::workerThread): * wtf/ParallelJobsGeneric.h: (WTF::ParallelEnvironment::ThreadPrivate::ThreadPrivate): Deleted. * wtf/ParkingLot.cpp: (WTF::ParkingLot::forEachImpl): * wtf/ParkingLot.h: (WTF::ParkingLot::forEach): * wtf/PlatformRegisters.h: Renamed from Source/JavaScriptCore/runtime/PlatformThread.h. * wtf/RefPtr.h: (WTF::RefPtr::RefPtr): * wtf/ThreadFunctionInvocation.h: (WTF::ThreadFunctionInvocation::ThreadFunctionInvocation): * wtf/ThreadHolder.cpp: Added. (WTF::ThreadHolder::~ThreadHolder): (WTF::ThreadHolder::initialize): * wtf/ThreadHolder.h: Renamed from Source/WTF/wtf/ThreadIdentifierDataPthreads.h. (WTF::ThreadHolder::thread): (WTF::ThreadHolder::ThreadHolder): * wtf/ThreadHolderPthreads.cpp: Renamed from Source/WTF/wtf/ThreadIdentifierDataPthreads.cpp. (WTF::ThreadHolder::initializeOnce): (WTF::ThreadHolder::current): (WTF::ThreadHolder::destruct): * wtf/ThreadHolderWin.cpp: Added. (WTF::threadMapMutex): (WTF::threadMap): (WTF::ThreadHolder::initializeOnce): (WTF::ThreadHolder::current): (WTF::ThreadHolder::destruct): * wtf/ThreadSpecific.h: * wtf/Threading.cpp: (WTF::Thread::normalizeThreadName): (WTF::threadEntryPoint): (WTF::Thread::create): (WTF::Thread::setCurrentThreadIsUserInteractive): (WTF::Thread::setCurrentThreadIsUserInitiated): (WTF::Thread::setGlobalMaxQOSClass): (WTF::Thread::adjustedQOSClass): (WTF::Thread::dump): (WTF::initializeThreading): (WTF::normalizeThreadName): Deleted. (WTF::createThread): Deleted. (WTF::setCurrentThreadIsUserInteractive): Deleted. (WTF::setCurrentThreadIsUserInitiated): Deleted. (WTF::setGlobalMaxQOSClass): Deleted. (WTF::adjustedQOSClass): Deleted. * wtf/Threading.h: (WTF::Thread::id): (WTF::Thread::operator==): (WTF::Thread::operator!=): (WTF::Thread::joinableState): (WTF::Thread::didBecomeDetached): (WTF::Thread::didJoin): (WTF::Thread::hasExited): (WTF::currentThread): * wtf/ThreadingPthreads.cpp: (WTF::Thread::Thread): (WTF::Thread::~Thread): (WTF::Thread::signalHandlerSuspendResume): (WTF::Thread::initializePlatformThreading): (WTF::initializeCurrentThreadEvenIfNonWTFCreated): (WTF::wtfThreadEntryPoint): (WTF::Thread::createInternal): (WTF::Thread::initializeCurrentThreadInternal): (WTF::Thread::changePriority): (WTF::Thread::waitForCompletion): (WTF::Thread::detach): (WTF::Thread::current): (WTF::Thread::currentID): (WTF::Thread::signal): (WTF::Thread::resume): (WTF::Thread::getRegisters): (WTF::Thread::didExit): (WTF::Thread::establish): (WTF::PthreadState::PthreadState): Deleted. (WTF::PthreadState::joinableState): Deleted. (WTF::PthreadState::pthreadHandle): Deleted. (WTF::PthreadState::didBecomeDetached): Deleted. (WTF::PthreadState::didExit): Deleted. (WTF::PthreadState::didJoin): Deleted. (WTF::PthreadState::hasExited): Deleted. (WTF::threadMapMutex): Deleted. (WTF::initializeThreading): Deleted. (WTF::threadMap): Deleted. (WTF::identifierByPthreadHandle): Deleted. (WTF::establishIdentifierForPthreadHandle): Deleted. (WTF::pthreadHandleForIdentifierWithLockAlreadyHeld): Deleted. (WTF::createThreadInternal): Deleted. (WTF::initializeCurrentThreadInternal): Deleted. (WTF::changeThreadPriority): Deleted. (WTF::waitForThreadCompletion): Deleted. (WTF::detachThread): Deleted. (WTF::threadDidExit): Deleted. (WTF::currentThread): Deleted. (WTF::signalThread): Deleted. * wtf/ThreadingWin.cpp: (WTF::Thread::Thread): (WTF::Thread::~Thread): (WTF::Thread::initializeCurrentThreadInternal): (WTF::Thread::initializePlatformThreading): (WTF::wtfThreadEntryPoint): (WTF::Thread::createInternal): (WTF::Thread::changePriority): (WTF::Thread::waitForCompletion): (WTF::Thread::detach): (WTF::Thread::resume): (WTF::Thread::getRegisters): (WTF::Thread::current): (WTF::Thread::currentID): (WTF::Thread::didExit): (WTF::Thread::establish): (WTF::initializeCurrentThreadInternal): Deleted. (WTF::threadMapMutex): Deleted. (WTF::initializeThreading): Deleted. (WTF::threadMap): Deleted. (WTF::storeThreadHandleByIdentifier): Deleted. (WTF::threadHandleForIdentifier): Deleted. (WTF::clearThreadHandleForIdentifier): Deleted. (WTF::createThreadInternal): Deleted. (WTF::changeThreadPriority): Deleted. (WTF::waitForThreadCompletion): Deleted. (WTF::detachThread): Deleted. (WTF::currentThread): Deleted. * wtf/WorkQueue.cpp: (WTF::WorkQueue::concurrentApply): * wtf/WorkQueue.h: * wtf/cocoa/WorkQueueCocoa.cpp: (WTF::dispatchQOSClass): * wtf/generic/WorkQueueGeneric.cpp: (WorkQueue::platformInitialize): (WorkQueue::platformInvalidate): * wtf/linux/MemoryPressureHandlerLinux.cpp: (WTF::MemoryPressureHandler::EventFDPoller::EventFDPoller): (WTF::MemoryPressureHandler::EventFDPoller::~EventFDPoller): * wtf/win/MainThreadWin.cpp: (WTF::initializeMainThreadPlatform): Tools: Mechanical change. Use Thread:: APIs. * DumpRenderTree/JavaScriptThreading.cpp: (runJavaScriptThread): (startJavaScriptThreads): (stopJavaScriptThreads): * DumpRenderTree/mac/DumpRenderTree.mm: (testThreadIdentifierMap): * TestWebKitAPI/Tests/WTF/Condition.cpp: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::runLockTest): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Canonical link: https://commits.webkit.org/187690@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@215265 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-04-12 12:08:29 +00:00
: thread(Thread::current())
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
{
unsigned currentNumThreads;
for (;;) {
unsigned oldNumThreads = numThreads.load();
currentNumThreads = oldNumThreads + 1;
if (numThreads.compareExchangeWeak(oldNumThreads, currentNumThreads))
break;
}
ensureHashtableSize(currentNumThreads);
}
ThreadData::~ThreadData()
{
for (;;) {
unsigned oldNumThreads = numThreads.load();
if (numThreads.compareExchangeWeak(oldNumThreads, oldNumThreads - 1))
break;
}
}
ThreadData* myThreadData()
{
The GC should be in a thread https://bugs.webkit.org/show_bug.cgi?id=163562 Reviewed by Geoffrey Garen and Andreas Kling. Source/JavaScriptCore: In a concurrent GC, the work of collecting happens on a separate thread. This patch implements this, and schedules the thread the way that a concurrent GC thread would be scheduled. But, the GC isn't actually concurrent yet because it calls stopTheWorld() before doing anything and calls resumeTheWorld() after it's done with everything. The next step will be to make it really concurrent by basically calling stopTheWorld()/resumeTheWorld() around bounded snippets of work while making most of the work happen with the world running. Our GC will probably always have stop-the-world phases because the semantics of JSC weak references call for it. This implements concurrent GC scheduling. This means that there is no longer a Heap::collect() API. Instead, you can call collectAsync() which makes sure that a GC is scheduled (it will do nothing if one is scheduled or ongoing) or you can call collectSync() to schedule a GC and wait for it to happen. I made our debugging stuff call collectSync(). It should be a goal to never call collectSync() except for debugging or benchmark harness hacks. The collector thread is an AutomaticThread, so it won't linger when not in use. It works on a ticket-based system, like you would see at the DMV. A ticket is a 64-bit integer. There are two ticket counters: last granted and last served. When you request a collection, last granted is incremented and its new value given to you. When a collection completes, last served is incremented. collectSync() waits until last served catches up to what last granted had been at the time you requested a GC. This means that if you request a sync GC in the middle of an async GC, you will wait for that async GC to finish and then you will request and wait for your sync GC. The synchronization between the collector thread and the main threads is complex. The collector thread needs to be able to ask the main thread to stop. It needs to be able to do some post-GC clean-up, like the synchronous CodeBlock and LargeAllocation sweeps, on the main thread. The collector needs to be able to ask the main thread to execute a cross-modifying code fence before running any JIT code, since the GC might aid the JIT worklist and run JIT finalization. It's possible for the GC to want the main thread to run something at the same time that the main thread wants to wait for the GC. The main thread needs to be able to run non-JSC stuff without causing the GC to completely stall. The main thread needs to be able to query its own state (is there a request to stop?) and change it (running JSC versus not) quickly, since this may happen on hot paths. This kind of intertwined system of requests, notifications, and state changes requires a combination of lock-free algorithms and waiting. So, this is all implemented using a Atomic<unsigned> Heap::m_worldState, which has bits to represent things being requested by the collector and the heap access state of the mutator. I am borrowing a lot of terms that I've seen in other VMs that I've worked on. Here's what they mean: - Stop the world: make sure that either the mutator is not running, or that it's not running code that could mess with the heap. - Heap access: the mutator is said to have heap access if it could mess with the heap. If you stop the world and the mutator doesn't have heap access, all you're doing is making sure that it will block when it tries to acquire heap access. This means that our GC is already fully concurrent in cases where the GC is requested while the mutator has no heap access. This probably won't happen, but if it did then it should just work. Usually, stopping the world means that we state our shouldStop request with m_worldState, and a future call to Heap::stopIfNecessary() will go to slow path and stop. The act of stopping or waiting to acquire heap access is managed by using ParkingLot API directly on m_worldState. This works out great because it would be very awkward to get the same functionality using locks and condition variables, since we want stopIfNecessary/acquireAccess/requestAccess fast paths that are single atomic instructions (load/CAS/CAS, respectively). The mutator will call these things frequently. Currently we have Heap::stopIfNecessary() polling on every allocator slow path, but we may want to make it even more frequent than that. Currently only JSC API clients benefit from the heap access optimization. The DOM forces us to assume that heap access is permanently on, since DOM manipulation doesn't always hold the JSLock. We could still allow the GC to proceed when the runloop is idle by having the GC put a task on the runloop that just calls stopIfNecessary(). This is perf neutral. The only behavior change that clients ought to observe is that marking and the weak fixpoint happen on a separate thread. Marking was already parallel so it already handled multiple threads, but now it _never_ runs on the main thread. The weak fixpoint needed some help to be able to run on another thread - mostly because there was some code in IndexedDB that was using thread specifics in the weak fixpoint. * API/JSBase.cpp: (JSSynchronousEdenCollectForDebugging): * API/JSManagedValue.mm: (-[JSManagedValue initWithValue:]): * heap/EdenGCActivityCallback.cpp: (JSC::EdenGCActivityCallback::doCollection): * heap/FullGCActivityCallback.cpp: (JSC::FullGCActivityCallback::doCollection): * heap/Heap.cpp: (JSC::Heap::Thread::Thread): (JSC::Heap::Heap): (JSC::Heap::lastChanceToFinalize): (JSC::Heap::markRoots): (JSC::Heap::gatherStackRoots): (JSC::Heap::deleteUnmarkedCompiledCode): (JSC::Heap::collectAllGarbage): (JSC::Heap::collectAsync): (JSC::Heap::collectSync): (JSC::Heap::shouldCollectInThread): (JSC::Heap::collectInThread): (JSC::Heap::stopTheWorld): (JSC::Heap::resumeTheWorld): (JSC::Heap::stopIfNecessarySlow): (JSC::Heap::acquireAccessSlow): (JSC::Heap::releaseAccessSlow): (JSC::Heap::handleDidJIT): (JSC::Heap::handleNeedFinalize): (JSC::Heap::setDidJIT): (JSC::Heap::setNeedFinalize): (JSC::Heap::waitWhileNeedFinalize): (JSC::Heap::finalize): (JSC::Heap::requestCollection): (JSC::Heap::waitForCollection): (JSC::Heap::didFinishCollection): (JSC::Heap::canCollect): (JSC::Heap::shouldCollectHeuristic): (JSC::Heap::shouldCollect): (JSC::Heap::collectIfNecessaryOrDefer): (JSC::Heap::collectAccordingToDeferGCProbability): (JSC::Heap::collect): Deleted. (JSC::Heap::collectWithoutAnySweep): Deleted. (JSC::Heap::collectImpl): Deleted. * heap/Heap.h: (JSC::Heap::ReleaseAccessScope::ReleaseAccessScope): (JSC::Heap::ReleaseAccessScope::~ReleaseAccessScope): * heap/HeapInlines.h: (JSC::Heap::acquireAccess): (JSC::Heap::releaseAccess): (JSC::Heap::stopIfNecessary): * heap/MachineStackMarker.cpp: (JSC::MachineThreads::gatherConservativeRoots): (JSC::MachineThreads::gatherFromCurrentThread): Deleted. * heap/MachineStackMarker.h: * jit/JITWorklist.cpp: (JSC::JITWorklist::completeAllForVM): * jit/JITWorklist.h: * jsc.cpp: (functionFullGC): (functionEdenGC): * runtime/InitializeThreading.cpp: (JSC::initializeThreading): * runtime/JSLock.cpp: (JSC::JSLock::didAcquireLock): (JSC::JSLock::unlock): (JSC::JSLock::willReleaseLock): * tools/JSDollarVMPrototype.cpp: (JSC::JSDollarVMPrototype::edenGC): Source/WebCore: No new tests because existing tests cover this. We now need to be more careful about using JSLock. This fixes some places that were not holding it. New assertions in the GC are more likely to catch this than before. * bindings/js/WorkerScriptController.cpp: (WebCore::WorkerScriptController::WorkerScriptController): Source/WTF: This fixes some bugs and adds a few features. * wtf/Atomics.h: The GC may do work on behalf of the JIT. If it does, the main thread needs to execute a cross-modifying code fence. This is cpuid on x86 and I believe it's isb on ARM. It would have been an isync on PPC and I think that isb is the ARM equivalent. (WTF::arm_isb): (WTF::crossModifyingCodeFence): (WTF::x86_ortop): (WTF::x86_cpuid): * wtf/AutomaticThread.cpp: I accidentally had AutomaticThreadCondition inherit from ThreadSafeRefCounted<AutomaticThread> [sic]. This never crashed before because all of our prior AutomaticThreadConditions were immortal. (WTF::AutomaticThread::AutomaticThread): (WTF::AutomaticThread::~AutomaticThread): (WTF::AutomaticThread::start): * wtf/AutomaticThread.h: * wtf/MainThread.cpp: Need to allow initializeGCThreads() to be called separately because it's now more than just a debugging thing. (WTF::initializeGCThreads): Canonical link: https://commits.webkit.org/182065@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208306 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-11-02 22:01:04 +00:00
static ThreadSpecific<RefPtr<ThreadData>, CanBeGCThread::True>* threadData;
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
static std::once_flag initializeOnce;
std::call_once(
initializeOnce,
[] {
The GC should be in a thread https://bugs.webkit.org/show_bug.cgi?id=163562 Reviewed by Geoffrey Garen and Andreas Kling. Source/JavaScriptCore: In a concurrent GC, the work of collecting happens on a separate thread. This patch implements this, and schedules the thread the way that a concurrent GC thread would be scheduled. But, the GC isn't actually concurrent yet because it calls stopTheWorld() before doing anything and calls resumeTheWorld() after it's done with everything. The next step will be to make it really concurrent by basically calling stopTheWorld()/resumeTheWorld() around bounded snippets of work while making most of the work happen with the world running. Our GC will probably always have stop-the-world phases because the semantics of JSC weak references call for it. This implements concurrent GC scheduling. This means that there is no longer a Heap::collect() API. Instead, you can call collectAsync() which makes sure that a GC is scheduled (it will do nothing if one is scheduled or ongoing) or you can call collectSync() to schedule a GC and wait for it to happen. I made our debugging stuff call collectSync(). It should be a goal to never call collectSync() except for debugging or benchmark harness hacks. The collector thread is an AutomaticThread, so it won't linger when not in use. It works on a ticket-based system, like you would see at the DMV. A ticket is a 64-bit integer. There are two ticket counters: last granted and last served. When you request a collection, last granted is incremented and its new value given to you. When a collection completes, last served is incremented. collectSync() waits until last served catches up to what last granted had been at the time you requested a GC. This means that if you request a sync GC in the middle of an async GC, you will wait for that async GC to finish and then you will request and wait for your sync GC. The synchronization between the collector thread and the main threads is complex. The collector thread needs to be able to ask the main thread to stop. It needs to be able to do some post-GC clean-up, like the synchronous CodeBlock and LargeAllocation sweeps, on the main thread. The collector needs to be able to ask the main thread to execute a cross-modifying code fence before running any JIT code, since the GC might aid the JIT worklist and run JIT finalization. It's possible for the GC to want the main thread to run something at the same time that the main thread wants to wait for the GC. The main thread needs to be able to run non-JSC stuff without causing the GC to completely stall. The main thread needs to be able to query its own state (is there a request to stop?) and change it (running JSC versus not) quickly, since this may happen on hot paths. This kind of intertwined system of requests, notifications, and state changes requires a combination of lock-free algorithms and waiting. So, this is all implemented using a Atomic<unsigned> Heap::m_worldState, which has bits to represent things being requested by the collector and the heap access state of the mutator. I am borrowing a lot of terms that I've seen in other VMs that I've worked on. Here's what they mean: - Stop the world: make sure that either the mutator is not running, or that it's not running code that could mess with the heap. - Heap access: the mutator is said to have heap access if it could mess with the heap. If you stop the world and the mutator doesn't have heap access, all you're doing is making sure that it will block when it tries to acquire heap access. This means that our GC is already fully concurrent in cases where the GC is requested while the mutator has no heap access. This probably won't happen, but if it did then it should just work. Usually, stopping the world means that we state our shouldStop request with m_worldState, and a future call to Heap::stopIfNecessary() will go to slow path and stop. The act of stopping or waiting to acquire heap access is managed by using ParkingLot API directly on m_worldState. This works out great because it would be very awkward to get the same functionality using locks and condition variables, since we want stopIfNecessary/acquireAccess/requestAccess fast paths that are single atomic instructions (load/CAS/CAS, respectively). The mutator will call these things frequently. Currently we have Heap::stopIfNecessary() polling on every allocator slow path, but we may want to make it even more frequent than that. Currently only JSC API clients benefit from the heap access optimization. The DOM forces us to assume that heap access is permanently on, since DOM manipulation doesn't always hold the JSLock. We could still allow the GC to proceed when the runloop is idle by having the GC put a task on the runloop that just calls stopIfNecessary(). This is perf neutral. The only behavior change that clients ought to observe is that marking and the weak fixpoint happen on a separate thread. Marking was already parallel so it already handled multiple threads, but now it _never_ runs on the main thread. The weak fixpoint needed some help to be able to run on another thread - mostly because there was some code in IndexedDB that was using thread specifics in the weak fixpoint. * API/JSBase.cpp: (JSSynchronousEdenCollectForDebugging): * API/JSManagedValue.mm: (-[JSManagedValue initWithValue:]): * heap/EdenGCActivityCallback.cpp: (JSC::EdenGCActivityCallback::doCollection): * heap/FullGCActivityCallback.cpp: (JSC::FullGCActivityCallback::doCollection): * heap/Heap.cpp: (JSC::Heap::Thread::Thread): (JSC::Heap::Heap): (JSC::Heap::lastChanceToFinalize): (JSC::Heap::markRoots): (JSC::Heap::gatherStackRoots): (JSC::Heap::deleteUnmarkedCompiledCode): (JSC::Heap::collectAllGarbage): (JSC::Heap::collectAsync): (JSC::Heap::collectSync): (JSC::Heap::shouldCollectInThread): (JSC::Heap::collectInThread): (JSC::Heap::stopTheWorld): (JSC::Heap::resumeTheWorld): (JSC::Heap::stopIfNecessarySlow): (JSC::Heap::acquireAccessSlow): (JSC::Heap::releaseAccessSlow): (JSC::Heap::handleDidJIT): (JSC::Heap::handleNeedFinalize): (JSC::Heap::setDidJIT): (JSC::Heap::setNeedFinalize): (JSC::Heap::waitWhileNeedFinalize): (JSC::Heap::finalize): (JSC::Heap::requestCollection): (JSC::Heap::waitForCollection): (JSC::Heap::didFinishCollection): (JSC::Heap::canCollect): (JSC::Heap::shouldCollectHeuristic): (JSC::Heap::shouldCollect): (JSC::Heap::collectIfNecessaryOrDefer): (JSC::Heap::collectAccordingToDeferGCProbability): (JSC::Heap::collect): Deleted. (JSC::Heap::collectWithoutAnySweep): Deleted. (JSC::Heap::collectImpl): Deleted. * heap/Heap.h: (JSC::Heap::ReleaseAccessScope::ReleaseAccessScope): (JSC::Heap::ReleaseAccessScope::~ReleaseAccessScope): * heap/HeapInlines.h: (JSC::Heap::acquireAccess): (JSC::Heap::releaseAccess): (JSC::Heap::stopIfNecessary): * heap/MachineStackMarker.cpp: (JSC::MachineThreads::gatherConservativeRoots): (JSC::MachineThreads::gatherFromCurrentThread): Deleted. * heap/MachineStackMarker.h: * jit/JITWorklist.cpp: (JSC::JITWorklist::completeAllForVM): * jit/JITWorklist.h: * jsc.cpp: (functionFullGC): (functionEdenGC): * runtime/InitializeThreading.cpp: (JSC::initializeThreading): * runtime/JSLock.cpp: (JSC::JSLock::didAcquireLock): (JSC::JSLock::unlock): (JSC::JSLock::willReleaseLock): * tools/JSDollarVMPrototype.cpp: (JSC::JSDollarVMPrototype::edenGC): Source/WebCore: No new tests because existing tests cover this. We now need to be more careful about using JSLock. This fixes some places that were not holding it. New assertions in the GC are more likely to catch this than before. * bindings/js/WorkerScriptController.cpp: (WebCore::WorkerScriptController::WorkerScriptController): Source/WTF: This fixes some bugs and adds a few features. * wtf/Atomics.h: The GC may do work on behalf of the JIT. If it does, the main thread needs to execute a cross-modifying code fence. This is cpuid on x86 and I believe it's isb on ARM. It would have been an isync on PPC and I think that isb is the ARM equivalent. (WTF::arm_isb): (WTF::crossModifyingCodeFence): (WTF::x86_ortop): (WTF::x86_cpuid): * wtf/AutomaticThread.cpp: I accidentally had AutomaticThreadCondition inherit from ThreadSafeRefCounted<AutomaticThread> [sic]. This never crashed before because all of our prior AutomaticThreadConditions were immortal. (WTF::AutomaticThread::AutomaticThread): (WTF::AutomaticThread::~AutomaticThread): (WTF::AutomaticThread::start): * wtf/AutomaticThread.h: * wtf/MainThread.cpp: Need to allow initializeGCThreads() to be called separately because it's now more than just a debugging thing. (WTF::initializeGCThreads): Canonical link: https://commits.webkit.org/182065@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208306 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-11-02 22:01:04 +00:00
threadData = new ThreadSpecific<RefPtr<ThreadData>, CanBeGCThread::True>();
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
});
RefPtr<ThreadData>& result = **threadData;
if (!result)
result = adoptRef(new ThreadData());
return result.get();
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
}
template<typename Functor>
bool enqueue(const void* address, const Functor& functor)
{
unsigned hash = hashAddress(address);
for (;;) {
WTF::Lock should not suffer from the thundering herd https://bugs.webkit.org/show_bug.cgi?id=147947 Reviewed by Geoffrey Garen. Source/WTF: This changes Lock::unlockSlow() to use unparkOne() instead of unparkAll(). The problem with doing this is that it's not obvious after calling unparkOne() if there are any other threads that are still parked on the lock's queue. If we assume that there are and leave the hasParkedBit set, then future calls to unlock() will take the slow path. We don't want that if there aren't actually any threads parked. On the other hand, if we assume that there aren't any threads parked and clear the hasParkedBit, then if there actually were some threads parked, then they may never be awoken since future calls to unlock() won't take slow path and so won't call unparkOne(). In other words, we need a way to be very precise about when we clear the hasParkedBit and we need to do it in a race-free way: it can't be the case that we clear the bit just as some thread gets parked on the queue. A similar problem arises in futexes, and one of the solutions is to have a thread that acquires a lock after parking sets the hasParkedBit. This is what Rusty Russel's usersem does. It's a subtle algorithm. Also, it means that if a thread barges in before the unparked thread runs, then that barging thread will not know that there are threads parked. This could increase the severity of barging. Since ParkingLot is a user-level API, we don't have to worry about the kernel-user security issues and so we can expose callbacks while ParkingLot is holding its internal locks. This change does exactly that for unparkOne(). The new variant of unparkOne() will call a user function while the queue from which we are unparking is locked. The callback is told basic stats about the queue: did we unpark a thread this time, and could there be more threads to unpark in the future. The callback runs while it's impossible for the queue state to change, since the ParkingLot's internal locks for the queue is held. This means that Lock::unlockSlow() can either clear, or leave, the hasParkedBit while releasing the lock inside the callback from unparkOne(). This takes care of the thundering herd problem while also reducing the greed that arises from barging threads. This required some careful reworking of the ParkingLot algorithm. The first thing I noticed was that the ThreadData::shouldPark flag was useless, since it's set exactly when ThreadData::address is non-null. Then I had to make sure that dequeue() could lazily create both hashtables and buckets, since the "callback is called while queue is locked" invariant requires that we didn't exit early due to the hashtable or bucket not being present. Note that all of this is done in such a way that the old unparkOne() and unparkAll() don't have to create any buckets, though they now may create the hashtable. We don't care as much about the hashtable being created by unpark since it's just such an unlikely scenario and it would only happen once. This change reduces the kernel CPU usage of WTF::Lock for the long critical section test by about 8x and makes it always perform as well as WTF::WordLock and WTF::Mutex for that benchmark. * benchmarks/LockSpeedTest.cpp: * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): * wtf/Lock.h: (WTF::LockBase::isLocked): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: * wtf/WordLock.h: (WTF::WordLock::isLocked): (WTF::WordLock::isFullyReset): Tools: Add testing that checks that locks return to a pristine state after contention is over. * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::LockInspector::isFullyReset): (TestWebKitAPI::runLockTest): (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/166072@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188374 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 03:51:25 +00:00
Hashtable* myHashtable = ensureHashtable();
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
unsigned index = hash % myHashtable->size;
Atomic<Bucket*>& bucketPointer = myHashtable->data[index];
Bucket* bucket;
for (;;) {
bucket = bucketPointer.load();
if (!bucket) {
bucket = new Bucket();
if (!bucketPointer.compareExchangeWeak(nullptr, bucket)) {
delete bucket;
continue;
}
}
break;
}
if (verbose)
WTF shouldn't have both Thread and ThreadIdentifier https://bugs.webkit.org/show_bug.cgi?id=180308 Reviewed by Darin Adler. Source/JavaScriptCore: * heap/MachineStackMarker.cpp: (JSC::MachineThreads::tryCopyOtherThreadStacks): * llint/LLIntSlowPaths.cpp: (JSC::LLInt::llint_trace_operand): (JSC::LLInt::llint_trace_value): (JSC::LLInt::LLINT_SLOW_PATH_DECL): (JSC::LLInt::traceFunctionPrologue): * runtime/ExceptionScope.cpp: (JSC::ExceptionScope::unexpectedExceptionMessage): * runtime/JSLock.h: (JSC::JSLock::currentThreadIsHoldingLock): * runtime/VM.cpp: (JSC::VM::throwException): * runtime/VM.h: (JSC::VM::throwingThread const): (JSC::VM::clearException): * tools/HeapVerifier.cpp: (JSC::HeapVerifier::printVerificationHeader): Source/WebCore: No behavior change. * Modules/indexeddb/IDBActiveDOMObject.h: (WebCore::IDBActiveDOMObject::originThread const): (WebCore::IDBActiveDOMObject::performCallbackOnOriginThread): (WebCore::IDBActiveDOMObject::callFunctionOnOriginThread): (WebCore::IDBActiveDOMObject::originThreadID const): Deleted. * Modules/indexeddb/IDBCursor.cpp: (WebCore::IDBCursor::IDBCursor): (WebCore::IDBCursor::~IDBCursor): (WebCore::IDBCursor::sourcesDeleted const): (WebCore::IDBCursor::transaction const): (WebCore::IDBCursor::update): (WebCore::IDBCursor::advance): (WebCore::IDBCursor::continueFunction): (WebCore::IDBCursor::uncheckedIterateCursor): (WebCore::IDBCursor::deleteFunction): (WebCore::IDBCursor::setGetResult): * Modules/indexeddb/IDBDatabase.cpp: (WebCore::IDBDatabase::~IDBDatabase): (WebCore::IDBDatabase::hasPendingActivity const): (WebCore::IDBDatabase::name const): (WebCore::IDBDatabase::version const): (WebCore::IDBDatabase::objectStoreNames const): (WebCore::IDBDatabase::renameObjectStore): (WebCore::IDBDatabase::renameIndex): (WebCore::IDBDatabase::createObjectStore): (WebCore::IDBDatabase::transaction): (WebCore::IDBDatabase::deleteObjectStore): (WebCore::IDBDatabase::close): (WebCore::IDBDatabase::connectionToServerLost): (WebCore::IDBDatabase::maybeCloseInServer): (WebCore::IDBDatabase::activeDOMObjectName const): (WebCore::IDBDatabase::canSuspendForDocumentSuspension const): (WebCore::IDBDatabase::stop): (WebCore::IDBDatabase::startVersionChangeTransaction): (WebCore::IDBDatabase::didStartTransaction): (WebCore::IDBDatabase::willCommitTransaction): (WebCore::IDBDatabase::didCommitTransaction): (WebCore::IDBDatabase::willAbortTransaction): (WebCore::IDBDatabase::didAbortTransaction): (WebCore::IDBDatabase::didCommitOrAbortTransaction): (WebCore::IDBDatabase::fireVersionChangeEvent): (WebCore::IDBDatabase::dispatchEvent): (WebCore::IDBDatabase::didCreateIndexInfo): (WebCore::IDBDatabase::didDeleteIndexInfo): * Modules/indexeddb/IDBIndex.cpp: (WebCore::IDBIndex::IDBIndex): (WebCore::IDBIndex::~IDBIndex): (WebCore::IDBIndex::name const): (WebCore::IDBIndex::setName): (WebCore::IDBIndex::objectStore): (WebCore::IDBIndex::keyPath const): (WebCore::IDBIndex::unique const): (WebCore::IDBIndex::multiEntry const): (WebCore::IDBIndex::rollbackInfoForVersionChangeAbort): (WebCore::IDBIndex::openCursor): (WebCore::IDBIndex::openKeyCursor): (WebCore::IDBIndex::doCount): (WebCore::IDBIndex::doGet): (WebCore::IDBIndex::doGetKey): (WebCore::IDBIndex::getAll): (WebCore::IDBIndex::getAllKeys): (WebCore::IDBIndex::markAsDeleted): * Modules/indexeddb/IDBObjectStore.cpp: (WebCore::IDBObjectStore::IDBObjectStore): (WebCore::IDBObjectStore::~IDBObjectStore): (WebCore::IDBObjectStore::name const): (WebCore::IDBObjectStore::setName): (WebCore::IDBObjectStore::keyPath const): (WebCore::IDBObjectStore::indexNames const): (WebCore::IDBObjectStore::transaction): (WebCore::IDBObjectStore::autoIncrement const): (WebCore::IDBObjectStore::openCursor): (WebCore::IDBObjectStore::openKeyCursor): (WebCore::IDBObjectStore::get): (WebCore::IDBObjectStore::getKey): (WebCore::IDBObjectStore::putOrAdd): (WebCore::IDBObjectStore::doDelete): (WebCore::IDBObjectStore::clear): (WebCore::IDBObjectStore::createIndex): (WebCore::IDBObjectStore::index): (WebCore::IDBObjectStore::deleteIndex): (WebCore::IDBObjectStore::doCount): (WebCore::IDBObjectStore::getAll): (WebCore::IDBObjectStore::getAllKeys): (WebCore::IDBObjectStore::markAsDeleted): (WebCore::IDBObjectStore::rollbackForVersionChangeAbort): * Modules/indexeddb/IDBOpenDBRequest.cpp: (WebCore::IDBOpenDBRequest::~IDBOpenDBRequest): (WebCore::IDBOpenDBRequest::onError): (WebCore::IDBOpenDBRequest::versionChangeTransactionDidFinish): (WebCore::IDBOpenDBRequest::fireSuccessAfterVersionChangeCommit): (WebCore::IDBOpenDBRequest::fireErrorAfterVersionChangeCompletion): (WebCore::IDBOpenDBRequest::dispatchEvent): (WebCore::IDBOpenDBRequest::onSuccess): (WebCore::IDBOpenDBRequest::onUpgradeNeeded): (WebCore::IDBOpenDBRequest::onDeleteDatabaseSuccess): (WebCore::IDBOpenDBRequest::requestCompleted): (WebCore::IDBOpenDBRequest::requestBlocked): * Modules/indexeddb/IDBRequest.cpp: (WebCore::IDBRequest::~IDBRequest): (WebCore:: const): (WebCore::IDBRequest::setSource): (WebCore::IDBRequest::setVersionChangeTransaction): (WebCore::IDBRequest::transaction const): (WebCore::IDBRequest::sourceObjectStoreIdentifier const): (WebCore::IDBRequest::sourceIndexIdentifier const): (WebCore::IDBRequest::requestedObjectStoreRecordType const): (WebCore::IDBRequest::requestedIndexRecordType const): (WebCore::IDBRequest::eventTargetInterface const): (WebCore::IDBRequest::activeDOMObjectName const): (WebCore::IDBRequest::canSuspendForDocumentSuspension const): (WebCore::IDBRequest::hasPendingActivity const): (WebCore::IDBRequest::stop): (WebCore::IDBRequest::enqueueEvent): (WebCore::IDBRequest::dispatchEvent): (WebCore::IDBRequest::uncaughtExceptionInEventHandler): (WebCore::IDBRequest::setResult): (WebCore::IDBRequest::setResultToStructuredClone): (WebCore::IDBRequest::setResultToUndefined): (WebCore::IDBRequest::resultCursor): (WebCore::IDBRequest::willIterateCursor): (WebCore::IDBRequest::didOpenOrIterateCursor): (WebCore::IDBRequest::completeRequestAndDispatchEvent): (WebCore::IDBRequest::onError): (WebCore::IDBRequest::onSuccess): * Modules/indexeddb/IDBTransaction.cpp: (WebCore::IDBTransaction::IDBTransaction): (WebCore::IDBTransaction::~IDBTransaction): (WebCore::IDBTransaction::objectStoreNames const): (WebCore::IDBTransaction::db): (WebCore::IDBTransaction::error const): (WebCore::IDBTransaction::objectStore): (WebCore::IDBTransaction::abortDueToFailedRequest): (WebCore::IDBTransaction::transitionedToFinishing): (WebCore::IDBTransaction::abort): (WebCore::IDBTransaction::internalAbort): (WebCore::IDBTransaction::abortOnServerAndCancelRequests): (WebCore::IDBTransaction::activeDOMObjectName const): (WebCore::IDBTransaction::canSuspendForDocumentSuspension const): (WebCore::IDBTransaction::hasPendingActivity const): (WebCore::IDBTransaction::stop): (WebCore::IDBTransaction::isActive const): (WebCore::IDBTransaction::isFinishedOrFinishing const): (WebCore::IDBTransaction::addRequest): (WebCore::IDBTransaction::removeRequest): (WebCore::IDBTransaction::scheduleOperation): (WebCore::IDBTransaction::schedulePendingOperationTimer): (WebCore::IDBTransaction::pendingOperationTimerFired): (WebCore::IDBTransaction::operationCompletedOnServer): (WebCore::IDBTransaction::scheduleCompletedOperationTimer): (WebCore::IDBTransaction::completedOperationTimerFired): (WebCore::IDBTransaction::commit): (WebCore::IDBTransaction::commitOnServer): (WebCore::IDBTransaction::finishAbortOrCommit): (WebCore::IDBTransaction::didStart): (WebCore::IDBTransaction::notifyDidAbort): (WebCore::IDBTransaction::didAbort): (WebCore::IDBTransaction::didCommit): (WebCore::IDBTransaction::fireOnComplete): (WebCore::IDBTransaction::fireOnAbort): (WebCore::IDBTransaction::enqueueEvent): (WebCore::IDBTransaction::dispatchEvent): (WebCore::IDBTransaction::createObjectStore): (WebCore::IDBTransaction::createObjectStoreOnServer): (WebCore::IDBTransaction::didCreateObjectStoreOnServer): (WebCore::IDBTransaction::renameObjectStore): (WebCore::IDBTransaction::renameObjectStoreOnServer): (WebCore::IDBTransaction::didRenameObjectStoreOnServer): (WebCore::IDBTransaction::createIndex): (WebCore::IDBTransaction::createIndexOnServer): (WebCore::IDBTransaction::didCreateIndexOnServer): (WebCore::IDBTransaction::renameIndex): (WebCore::IDBTransaction::renameIndexOnServer): (WebCore::IDBTransaction::didRenameIndexOnServer): (WebCore::IDBTransaction::requestOpenCursor): (WebCore::IDBTransaction::doRequestOpenCursor): (WebCore::IDBTransaction::openCursorOnServer): (WebCore::IDBTransaction::didOpenCursorOnServer): (WebCore::IDBTransaction::iterateCursor): (WebCore::IDBTransaction::iterateCursorOnServer): (WebCore::IDBTransaction::didIterateCursorOnServer): (WebCore::IDBTransaction::requestGetAllObjectStoreRecords): (WebCore::IDBTransaction::requestGetAllIndexRecords): (WebCore::IDBTransaction::getAllRecordsOnServer): (WebCore::IDBTransaction::didGetAllRecordsOnServer): (WebCore::IDBTransaction::requestGetRecord): (WebCore::IDBTransaction::requestGetValue): (WebCore::IDBTransaction::requestGetKey): (WebCore::IDBTransaction::requestIndexRecord): (WebCore::IDBTransaction::getRecordOnServer): (WebCore::IDBTransaction::didGetRecordOnServer): (WebCore::IDBTransaction::requestCount): (WebCore::IDBTransaction::getCountOnServer): (WebCore::IDBTransaction::didGetCountOnServer): (WebCore::IDBTransaction::requestDeleteRecord): (WebCore::IDBTransaction::deleteRecordOnServer): (WebCore::IDBTransaction::didDeleteRecordOnServer): (WebCore::IDBTransaction::requestClearObjectStore): (WebCore::IDBTransaction::clearObjectStoreOnServer): (WebCore::IDBTransaction::didClearObjectStoreOnServer): (WebCore::IDBTransaction::requestPutOrAdd): (WebCore::IDBTransaction::putOrAddOnServer): (WebCore::IDBTransaction::didPutOrAddOnServer): (WebCore::IDBTransaction::deleteObjectStore): (WebCore::IDBTransaction::deleteObjectStoreOnServer): (WebCore::IDBTransaction::didDeleteObjectStoreOnServer): (WebCore::IDBTransaction::deleteIndex): (WebCore::IDBTransaction::deleteIndexOnServer): (WebCore::IDBTransaction::didDeleteIndexOnServer): (WebCore::IDBTransaction::operationCompletedOnClient): (WebCore::IDBTransaction::establishOnServer): (WebCore::IDBTransaction::activate): (WebCore::IDBTransaction::deactivate): * Modules/indexeddb/client/IDBConnectionProxy.cpp: (WebCore::IDBClient::removeItemsMatchingCurrentThread): * Modules/indexeddb/client/TransactionOperation.h: (WebCore::IDBClient::TransactionOperation::~TransactionOperation): (WebCore::IDBClient::TransactionOperation::perform): (WebCore::IDBClient::TransactionOperation::transitionToCompleteOnThisThread): (WebCore::IDBClient::TransactionOperation::transitionToComplete): (WebCore::IDBClient::TransactionOperation::doComplete): (WebCore::IDBClient::TransactionOperation::originThread const): (WebCore::IDBClient::TransactionOperation::originThreadID const): Deleted. * Modules/webaudio/AudioContext.cpp: (WebCore::AudioContext::AudioContext): (WebCore::AudioContext::lock): (WebCore::AudioContext::tryLock): (WebCore::AudioContext::unlock): (WebCore::AudioContext::isAudioThread const): (WebCore::AudioContext::isGraphOwner const): * Modules/webaudio/AudioContext.h: (WebCore::AudioContext::setAudioThread): (WebCore::AudioContext::audioThread const): * Modules/webaudio/AudioDestinationNode.cpp: (WebCore::AudioDestinationNode::render): * Modules/webdatabase/Database.cpp: (WebCore::Database::performClose): (WebCore::Database::securityOrigin): * Modules/webdatabase/DatabaseDetails.h: (WebCore::DatabaseDetails::DatabaseDetails): (WebCore::DatabaseDetails::operator=): (WebCore::DatabaseDetails::thread const): (WebCore::DatabaseDetails::threadID const): Deleted. * Modules/webdatabase/DatabaseManager.cpp: (WebCore::DatabaseManager::detailsForNameAndOrigin): * Modules/webdatabase/DatabaseThread.cpp: (WebCore::DatabaseThread::databaseThread): (WebCore::DatabaseThread::recordDatabaseOpen): (WebCore::DatabaseThread::recordDatabaseClosed): * Modules/webdatabase/DatabaseThread.h: (WebCore::DatabaseThread::getThread): (WebCore::DatabaseThread::getThreadID): Deleted. * Modules/webdatabase/SQLTransaction.cpp: (WebCore::SQLTransaction::checkAndHandleClosedDatabase): * Modules/webdatabase/SQLTransactionBackend.cpp: (WebCore::SQLTransactionBackend::doCleanup): (WebCore::SQLTransactionBackend::notifyDatabaseThreadIsShuttingDown): * bindings/js/JSCallbackData.h: (WebCore::JSCallbackData::JSCallbackData): (WebCore::JSCallbackData::~JSCallbackData): * bindings/js/ScheduledAction.cpp: (WebCore::ScheduledAction::execute): * dom/ScriptExecutionContext.cpp: (WebCore::ScriptExecutionContext::createdMessagePort): (WebCore::ScriptExecutionContext::destroyedMessagePort): * page/ResourceUsageOverlay.h: * page/scrolling/ScrollingThread.cpp: (WebCore::ScrollingThread::isCurrentThread): * platform/Supplementable.h: (WebCore::Supplementable::provideSupplement): (WebCore::Supplementable::removeSupplement): (WebCore::Supplementable::requireSupplement): (WebCore::Supplementable::Supplementable): Deleted. * platform/Timer.cpp: (WebCore::TimerBase::TimerBase): (WebCore::TimerBase::start): (WebCore::TimerBase::stop): (WebCore::TimerBase::setNextFireTime): * platform/Timer.h: (WebCore::TimerBase::isActive const): * platform/graphics/cocoa/FontCacheCoreText.cpp: (WebCore::shouldAutoActivateFontIfNeeded): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.cpp: (WebCore::TextureMapperPlatformLayerProxy::activateOnCompositingThread): (WebCore::TextureMapperPlatformLayerProxy::invalidate): (WebCore::TextureMapperPlatformLayerProxy::getAvailableBuffer): (WebCore::TextureMapperPlatformLayerProxy::appendToUnusedBuffers): (WebCore::TextureMapperPlatformLayerProxy::swapBuffer): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.h: (): Deleted. * platform/ios/wak/WebCoreThread.mm: (RunWebThread): (StartWebThread): * platform/sql/SQLiteDatabase.cpp: (WebCore::SQLiteDatabase::open): (WebCore::SQLiteDatabase::close): * platform/sql/SQLiteDatabase.h: (WebCore::SQLiteDatabase::sqlite3Handle const): * workers/WorkerGlobalScope.cpp: (WebCore::WorkerGlobalScope::~WorkerGlobalScope): (WebCore::WorkerGlobalScope::isContextThread const): * workers/WorkerMessagingProxy.cpp: (WebCore::WorkerMessagingProxy::WorkerMessagingProxy): (WebCore::WorkerMessagingProxy::~WorkerMessagingProxy): * workers/WorkerRunLoop.cpp: (WebCore::WorkerRunLoop::runInMode): (WebCore::WorkerRunLoop::runCleanupTasks): * workers/WorkerThread.h: (WebCore::WorkerThread::thread const): (WebCore::WorkerThread::threadID const): Deleted. * workers/service/ServiceWorkerContainer.cpp: (WebCore::ServiceWorkerContainer::~ServiceWorkerContainer): (WebCore::ServiceWorkerContainer::scheduleJob): (WebCore::ServiceWorkerContainer::jobFailedWithException): (WebCore::ServiceWorkerContainer::scheduleTaskToFireUpdateFoundEvent): (WebCore::ServiceWorkerContainer::jobResolvedWithRegistration): (WebCore::ServiceWorkerContainer::jobResolvedWithUnregistrationResult): (WebCore::ServiceWorkerContainer::startScriptFetchForJob): (WebCore::ServiceWorkerContainer::jobFinishedLoadingScript): (WebCore::ServiceWorkerContainer::jobFailedLoadingScript): (WebCore::ServiceWorkerContainer::jobDidFinish): (WebCore::ServiceWorkerContainer::addRegistration): (WebCore::ServiceWorkerContainer::removeRegistration): (WebCore::ServiceWorkerContainer::scheduleTaskToFireControllerChangeEvent): (WebCore::ServiceWorkerContainer::contextIdentifier): * workers/service/ServiceWorkerContainer.h: * workers/service/ServiceWorkerJob.cpp: (WebCore::ServiceWorkerJob::~ServiceWorkerJob): (WebCore::ServiceWorkerJob::failedWithException): (WebCore::ServiceWorkerJob::resolvedWithRegistration): (WebCore::ServiceWorkerJob::resolvedWithUnregistrationResult): (WebCore::ServiceWorkerJob::startScriptFetch): (WebCore::ServiceWorkerJob::fetchScriptWithContext): (WebCore::ServiceWorkerJob::didReceiveResponse): (WebCore::ServiceWorkerJob::notifyFinished): * workers/service/ServiceWorkerJob.h: * xml/parser/XMLDocumentParserLibxml2.cpp: (WebCore::matchFunc): (WebCore::openFunc): (WebCore::initializeXMLParser): (WebCore::XMLParserContext::createStringParser): (WebCore::XMLParserContext::createMemoryParser): Source/WebKit: * UIProcess/API/glib/IconDatabase.cpp: * UIProcess/GenericCallback.h: (WebKit::GenericCallback::~GenericCallback): (WebKit::GenericCallback::performCallbackWithReturnValue): Source/WTF: We should use a pointer of WTF::Thread instead of ThreadIdentifier. One problem is that Windows support library uses WTF::createThread, which returns ThreadIdentifier. So we cannot drop ThreadIdentifier in Windows environment. This patch keeps ThreadIdentifier in Windows. * wtf/MainThread.cpp: (WTF::initializeMainThread): (WTF::isMainThread): (WTF::canAccessThreadLocalDataForThread): * wtf/MainThread.h: * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkCount): * wtf/RecursiveLockAdapter.h: (WTF::RecursiveLockAdapter::lock): (WTF::RecursiveLockAdapter::unlock): (WTF::RecursiveLockAdapter::tryLock): * wtf/Threading.cpp: (WTF::Thread::dump const): * wtf/Threading.h: (WTF::Thread::id const): (WTF::Thread::operator==): Deleted. (WTF::Thread::operator!=): Deleted. (WTF::currentThread): Deleted. * wtf/ThreadingPrimitives.h: * wtf/ThreadingPthreads.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::detach): (WTF::Thread::initializeCurrentTLS): (WTF::Thread::suspend): (WTF::Thread::establishPlatformSpecificHandle): (WTF::Thread::currentID): Deleted. * wtf/ThreadingWin.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::suspend): (WTF::Thread::currentDying): * wtf/mac/MainThreadMac.mm: (WTF::initializeApplicationUIThread): (WTF::initializeWebThreadPlatform): (WTF::canAccessThreadLocalDataForThread): (WTF::initializeApplicationUIThreadIdentifier): Deleted. (WTF::initializeWebThreadIdentifier): Deleted. Tools: * DumpRenderTree/mac/DumpRenderTree.mm: (dumpRenderTree): (runThread): Deleted. (runPthread): Deleted. (testThreadIdentifierMap): Deleted. * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: * TestWebKitAPI/Tests/WTF/Threading.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/196314@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@225470 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-12-04 06:13:05 +00:00
dataLog(toString(Thread::current(), ": enqueueing onto bucket ", RawPointer(bucket), " with index ", index, " for address ", RawPointer(address), " with hash ", hash, "\n"));
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
bucket->lock.lock();
// At this point the hashtable could have rehashed under us.
if (hashtable.load() != myHashtable) {
bucket->lock.unlock();
continue;
}
ThreadData* threadData = functor();
bool result;
if (threadData) {
if (verbose)
WTF shouldn't have both Thread and ThreadIdentifier https://bugs.webkit.org/show_bug.cgi?id=180308 Reviewed by Darin Adler. Source/JavaScriptCore: * heap/MachineStackMarker.cpp: (JSC::MachineThreads::tryCopyOtherThreadStacks): * llint/LLIntSlowPaths.cpp: (JSC::LLInt::llint_trace_operand): (JSC::LLInt::llint_trace_value): (JSC::LLInt::LLINT_SLOW_PATH_DECL): (JSC::LLInt::traceFunctionPrologue): * runtime/ExceptionScope.cpp: (JSC::ExceptionScope::unexpectedExceptionMessage): * runtime/JSLock.h: (JSC::JSLock::currentThreadIsHoldingLock): * runtime/VM.cpp: (JSC::VM::throwException): * runtime/VM.h: (JSC::VM::throwingThread const): (JSC::VM::clearException): * tools/HeapVerifier.cpp: (JSC::HeapVerifier::printVerificationHeader): Source/WebCore: No behavior change. * Modules/indexeddb/IDBActiveDOMObject.h: (WebCore::IDBActiveDOMObject::originThread const): (WebCore::IDBActiveDOMObject::performCallbackOnOriginThread): (WebCore::IDBActiveDOMObject::callFunctionOnOriginThread): (WebCore::IDBActiveDOMObject::originThreadID const): Deleted. * Modules/indexeddb/IDBCursor.cpp: (WebCore::IDBCursor::IDBCursor): (WebCore::IDBCursor::~IDBCursor): (WebCore::IDBCursor::sourcesDeleted const): (WebCore::IDBCursor::transaction const): (WebCore::IDBCursor::update): (WebCore::IDBCursor::advance): (WebCore::IDBCursor::continueFunction): (WebCore::IDBCursor::uncheckedIterateCursor): (WebCore::IDBCursor::deleteFunction): (WebCore::IDBCursor::setGetResult): * Modules/indexeddb/IDBDatabase.cpp: (WebCore::IDBDatabase::~IDBDatabase): (WebCore::IDBDatabase::hasPendingActivity const): (WebCore::IDBDatabase::name const): (WebCore::IDBDatabase::version const): (WebCore::IDBDatabase::objectStoreNames const): (WebCore::IDBDatabase::renameObjectStore): (WebCore::IDBDatabase::renameIndex): (WebCore::IDBDatabase::createObjectStore): (WebCore::IDBDatabase::transaction): (WebCore::IDBDatabase::deleteObjectStore): (WebCore::IDBDatabase::close): (WebCore::IDBDatabase::connectionToServerLost): (WebCore::IDBDatabase::maybeCloseInServer): (WebCore::IDBDatabase::activeDOMObjectName const): (WebCore::IDBDatabase::canSuspendForDocumentSuspension const): (WebCore::IDBDatabase::stop): (WebCore::IDBDatabase::startVersionChangeTransaction): (WebCore::IDBDatabase::didStartTransaction): (WebCore::IDBDatabase::willCommitTransaction): (WebCore::IDBDatabase::didCommitTransaction): (WebCore::IDBDatabase::willAbortTransaction): (WebCore::IDBDatabase::didAbortTransaction): (WebCore::IDBDatabase::didCommitOrAbortTransaction): (WebCore::IDBDatabase::fireVersionChangeEvent): (WebCore::IDBDatabase::dispatchEvent): (WebCore::IDBDatabase::didCreateIndexInfo): (WebCore::IDBDatabase::didDeleteIndexInfo): * Modules/indexeddb/IDBIndex.cpp: (WebCore::IDBIndex::IDBIndex): (WebCore::IDBIndex::~IDBIndex): (WebCore::IDBIndex::name const): (WebCore::IDBIndex::setName): (WebCore::IDBIndex::objectStore): (WebCore::IDBIndex::keyPath const): (WebCore::IDBIndex::unique const): (WebCore::IDBIndex::multiEntry const): (WebCore::IDBIndex::rollbackInfoForVersionChangeAbort): (WebCore::IDBIndex::openCursor): (WebCore::IDBIndex::openKeyCursor): (WebCore::IDBIndex::doCount): (WebCore::IDBIndex::doGet): (WebCore::IDBIndex::doGetKey): (WebCore::IDBIndex::getAll): (WebCore::IDBIndex::getAllKeys): (WebCore::IDBIndex::markAsDeleted): * Modules/indexeddb/IDBObjectStore.cpp: (WebCore::IDBObjectStore::IDBObjectStore): (WebCore::IDBObjectStore::~IDBObjectStore): (WebCore::IDBObjectStore::name const): (WebCore::IDBObjectStore::setName): (WebCore::IDBObjectStore::keyPath const): (WebCore::IDBObjectStore::indexNames const): (WebCore::IDBObjectStore::transaction): (WebCore::IDBObjectStore::autoIncrement const): (WebCore::IDBObjectStore::openCursor): (WebCore::IDBObjectStore::openKeyCursor): (WebCore::IDBObjectStore::get): (WebCore::IDBObjectStore::getKey): (WebCore::IDBObjectStore::putOrAdd): (WebCore::IDBObjectStore::doDelete): (WebCore::IDBObjectStore::clear): (WebCore::IDBObjectStore::createIndex): (WebCore::IDBObjectStore::index): (WebCore::IDBObjectStore::deleteIndex): (WebCore::IDBObjectStore::doCount): (WebCore::IDBObjectStore::getAll): (WebCore::IDBObjectStore::getAllKeys): (WebCore::IDBObjectStore::markAsDeleted): (WebCore::IDBObjectStore::rollbackForVersionChangeAbort): * Modules/indexeddb/IDBOpenDBRequest.cpp: (WebCore::IDBOpenDBRequest::~IDBOpenDBRequest): (WebCore::IDBOpenDBRequest::onError): (WebCore::IDBOpenDBRequest::versionChangeTransactionDidFinish): (WebCore::IDBOpenDBRequest::fireSuccessAfterVersionChangeCommit): (WebCore::IDBOpenDBRequest::fireErrorAfterVersionChangeCompletion): (WebCore::IDBOpenDBRequest::dispatchEvent): (WebCore::IDBOpenDBRequest::onSuccess): (WebCore::IDBOpenDBRequest::onUpgradeNeeded): (WebCore::IDBOpenDBRequest::onDeleteDatabaseSuccess): (WebCore::IDBOpenDBRequest::requestCompleted): (WebCore::IDBOpenDBRequest::requestBlocked): * Modules/indexeddb/IDBRequest.cpp: (WebCore::IDBRequest::~IDBRequest): (WebCore:: const): (WebCore::IDBRequest::setSource): (WebCore::IDBRequest::setVersionChangeTransaction): (WebCore::IDBRequest::transaction const): (WebCore::IDBRequest::sourceObjectStoreIdentifier const): (WebCore::IDBRequest::sourceIndexIdentifier const): (WebCore::IDBRequest::requestedObjectStoreRecordType const): (WebCore::IDBRequest::requestedIndexRecordType const): (WebCore::IDBRequest::eventTargetInterface const): (WebCore::IDBRequest::activeDOMObjectName const): (WebCore::IDBRequest::canSuspendForDocumentSuspension const): (WebCore::IDBRequest::hasPendingActivity const): (WebCore::IDBRequest::stop): (WebCore::IDBRequest::enqueueEvent): (WebCore::IDBRequest::dispatchEvent): (WebCore::IDBRequest::uncaughtExceptionInEventHandler): (WebCore::IDBRequest::setResult): (WebCore::IDBRequest::setResultToStructuredClone): (WebCore::IDBRequest::setResultToUndefined): (WebCore::IDBRequest::resultCursor): (WebCore::IDBRequest::willIterateCursor): (WebCore::IDBRequest::didOpenOrIterateCursor): (WebCore::IDBRequest::completeRequestAndDispatchEvent): (WebCore::IDBRequest::onError): (WebCore::IDBRequest::onSuccess): * Modules/indexeddb/IDBTransaction.cpp: (WebCore::IDBTransaction::IDBTransaction): (WebCore::IDBTransaction::~IDBTransaction): (WebCore::IDBTransaction::objectStoreNames const): (WebCore::IDBTransaction::db): (WebCore::IDBTransaction::error const): (WebCore::IDBTransaction::objectStore): (WebCore::IDBTransaction::abortDueToFailedRequest): (WebCore::IDBTransaction::transitionedToFinishing): (WebCore::IDBTransaction::abort): (WebCore::IDBTransaction::internalAbort): (WebCore::IDBTransaction::abortOnServerAndCancelRequests): (WebCore::IDBTransaction::activeDOMObjectName const): (WebCore::IDBTransaction::canSuspendForDocumentSuspension const): (WebCore::IDBTransaction::hasPendingActivity const): (WebCore::IDBTransaction::stop): (WebCore::IDBTransaction::isActive const): (WebCore::IDBTransaction::isFinishedOrFinishing const): (WebCore::IDBTransaction::addRequest): (WebCore::IDBTransaction::removeRequest): (WebCore::IDBTransaction::scheduleOperation): (WebCore::IDBTransaction::schedulePendingOperationTimer): (WebCore::IDBTransaction::pendingOperationTimerFired): (WebCore::IDBTransaction::operationCompletedOnServer): (WebCore::IDBTransaction::scheduleCompletedOperationTimer): (WebCore::IDBTransaction::completedOperationTimerFired): (WebCore::IDBTransaction::commit): (WebCore::IDBTransaction::commitOnServer): (WebCore::IDBTransaction::finishAbortOrCommit): (WebCore::IDBTransaction::didStart): (WebCore::IDBTransaction::notifyDidAbort): (WebCore::IDBTransaction::didAbort): (WebCore::IDBTransaction::didCommit): (WebCore::IDBTransaction::fireOnComplete): (WebCore::IDBTransaction::fireOnAbort): (WebCore::IDBTransaction::enqueueEvent): (WebCore::IDBTransaction::dispatchEvent): (WebCore::IDBTransaction::createObjectStore): (WebCore::IDBTransaction::createObjectStoreOnServer): (WebCore::IDBTransaction::didCreateObjectStoreOnServer): (WebCore::IDBTransaction::renameObjectStore): (WebCore::IDBTransaction::renameObjectStoreOnServer): (WebCore::IDBTransaction::didRenameObjectStoreOnServer): (WebCore::IDBTransaction::createIndex): (WebCore::IDBTransaction::createIndexOnServer): (WebCore::IDBTransaction::didCreateIndexOnServer): (WebCore::IDBTransaction::renameIndex): (WebCore::IDBTransaction::renameIndexOnServer): (WebCore::IDBTransaction::didRenameIndexOnServer): (WebCore::IDBTransaction::requestOpenCursor): (WebCore::IDBTransaction::doRequestOpenCursor): (WebCore::IDBTransaction::openCursorOnServer): (WebCore::IDBTransaction::didOpenCursorOnServer): (WebCore::IDBTransaction::iterateCursor): (WebCore::IDBTransaction::iterateCursorOnServer): (WebCore::IDBTransaction::didIterateCursorOnServer): (WebCore::IDBTransaction::requestGetAllObjectStoreRecords): (WebCore::IDBTransaction::requestGetAllIndexRecords): (WebCore::IDBTransaction::getAllRecordsOnServer): (WebCore::IDBTransaction::didGetAllRecordsOnServer): (WebCore::IDBTransaction::requestGetRecord): (WebCore::IDBTransaction::requestGetValue): (WebCore::IDBTransaction::requestGetKey): (WebCore::IDBTransaction::requestIndexRecord): (WebCore::IDBTransaction::getRecordOnServer): (WebCore::IDBTransaction::didGetRecordOnServer): (WebCore::IDBTransaction::requestCount): (WebCore::IDBTransaction::getCountOnServer): (WebCore::IDBTransaction::didGetCountOnServer): (WebCore::IDBTransaction::requestDeleteRecord): (WebCore::IDBTransaction::deleteRecordOnServer): (WebCore::IDBTransaction::didDeleteRecordOnServer): (WebCore::IDBTransaction::requestClearObjectStore): (WebCore::IDBTransaction::clearObjectStoreOnServer): (WebCore::IDBTransaction::didClearObjectStoreOnServer): (WebCore::IDBTransaction::requestPutOrAdd): (WebCore::IDBTransaction::putOrAddOnServer): (WebCore::IDBTransaction::didPutOrAddOnServer): (WebCore::IDBTransaction::deleteObjectStore): (WebCore::IDBTransaction::deleteObjectStoreOnServer): (WebCore::IDBTransaction::didDeleteObjectStoreOnServer): (WebCore::IDBTransaction::deleteIndex): (WebCore::IDBTransaction::deleteIndexOnServer): (WebCore::IDBTransaction::didDeleteIndexOnServer): (WebCore::IDBTransaction::operationCompletedOnClient): (WebCore::IDBTransaction::establishOnServer): (WebCore::IDBTransaction::activate): (WebCore::IDBTransaction::deactivate): * Modules/indexeddb/client/IDBConnectionProxy.cpp: (WebCore::IDBClient::removeItemsMatchingCurrentThread): * Modules/indexeddb/client/TransactionOperation.h: (WebCore::IDBClient::TransactionOperation::~TransactionOperation): (WebCore::IDBClient::TransactionOperation::perform): (WebCore::IDBClient::TransactionOperation::transitionToCompleteOnThisThread): (WebCore::IDBClient::TransactionOperation::transitionToComplete): (WebCore::IDBClient::TransactionOperation::doComplete): (WebCore::IDBClient::TransactionOperation::originThread const): (WebCore::IDBClient::TransactionOperation::originThreadID const): Deleted. * Modules/webaudio/AudioContext.cpp: (WebCore::AudioContext::AudioContext): (WebCore::AudioContext::lock): (WebCore::AudioContext::tryLock): (WebCore::AudioContext::unlock): (WebCore::AudioContext::isAudioThread const): (WebCore::AudioContext::isGraphOwner const): * Modules/webaudio/AudioContext.h: (WebCore::AudioContext::setAudioThread): (WebCore::AudioContext::audioThread const): * Modules/webaudio/AudioDestinationNode.cpp: (WebCore::AudioDestinationNode::render): * Modules/webdatabase/Database.cpp: (WebCore::Database::performClose): (WebCore::Database::securityOrigin): * Modules/webdatabase/DatabaseDetails.h: (WebCore::DatabaseDetails::DatabaseDetails): (WebCore::DatabaseDetails::operator=): (WebCore::DatabaseDetails::thread const): (WebCore::DatabaseDetails::threadID const): Deleted. * Modules/webdatabase/DatabaseManager.cpp: (WebCore::DatabaseManager::detailsForNameAndOrigin): * Modules/webdatabase/DatabaseThread.cpp: (WebCore::DatabaseThread::databaseThread): (WebCore::DatabaseThread::recordDatabaseOpen): (WebCore::DatabaseThread::recordDatabaseClosed): * Modules/webdatabase/DatabaseThread.h: (WebCore::DatabaseThread::getThread): (WebCore::DatabaseThread::getThreadID): Deleted. * Modules/webdatabase/SQLTransaction.cpp: (WebCore::SQLTransaction::checkAndHandleClosedDatabase): * Modules/webdatabase/SQLTransactionBackend.cpp: (WebCore::SQLTransactionBackend::doCleanup): (WebCore::SQLTransactionBackend::notifyDatabaseThreadIsShuttingDown): * bindings/js/JSCallbackData.h: (WebCore::JSCallbackData::JSCallbackData): (WebCore::JSCallbackData::~JSCallbackData): * bindings/js/ScheduledAction.cpp: (WebCore::ScheduledAction::execute): * dom/ScriptExecutionContext.cpp: (WebCore::ScriptExecutionContext::createdMessagePort): (WebCore::ScriptExecutionContext::destroyedMessagePort): * page/ResourceUsageOverlay.h: * page/scrolling/ScrollingThread.cpp: (WebCore::ScrollingThread::isCurrentThread): * platform/Supplementable.h: (WebCore::Supplementable::provideSupplement): (WebCore::Supplementable::removeSupplement): (WebCore::Supplementable::requireSupplement): (WebCore::Supplementable::Supplementable): Deleted. * platform/Timer.cpp: (WebCore::TimerBase::TimerBase): (WebCore::TimerBase::start): (WebCore::TimerBase::stop): (WebCore::TimerBase::setNextFireTime): * platform/Timer.h: (WebCore::TimerBase::isActive const): * platform/graphics/cocoa/FontCacheCoreText.cpp: (WebCore::shouldAutoActivateFontIfNeeded): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.cpp: (WebCore::TextureMapperPlatformLayerProxy::activateOnCompositingThread): (WebCore::TextureMapperPlatformLayerProxy::invalidate): (WebCore::TextureMapperPlatformLayerProxy::getAvailableBuffer): (WebCore::TextureMapperPlatformLayerProxy::appendToUnusedBuffers): (WebCore::TextureMapperPlatformLayerProxy::swapBuffer): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.h: (): Deleted. * platform/ios/wak/WebCoreThread.mm: (RunWebThread): (StartWebThread): * platform/sql/SQLiteDatabase.cpp: (WebCore::SQLiteDatabase::open): (WebCore::SQLiteDatabase::close): * platform/sql/SQLiteDatabase.h: (WebCore::SQLiteDatabase::sqlite3Handle const): * workers/WorkerGlobalScope.cpp: (WebCore::WorkerGlobalScope::~WorkerGlobalScope): (WebCore::WorkerGlobalScope::isContextThread const): * workers/WorkerMessagingProxy.cpp: (WebCore::WorkerMessagingProxy::WorkerMessagingProxy): (WebCore::WorkerMessagingProxy::~WorkerMessagingProxy): * workers/WorkerRunLoop.cpp: (WebCore::WorkerRunLoop::runInMode): (WebCore::WorkerRunLoop::runCleanupTasks): * workers/WorkerThread.h: (WebCore::WorkerThread::thread const): (WebCore::WorkerThread::threadID const): Deleted. * workers/service/ServiceWorkerContainer.cpp: (WebCore::ServiceWorkerContainer::~ServiceWorkerContainer): (WebCore::ServiceWorkerContainer::scheduleJob): (WebCore::ServiceWorkerContainer::jobFailedWithException): (WebCore::ServiceWorkerContainer::scheduleTaskToFireUpdateFoundEvent): (WebCore::ServiceWorkerContainer::jobResolvedWithRegistration): (WebCore::ServiceWorkerContainer::jobResolvedWithUnregistrationResult): (WebCore::ServiceWorkerContainer::startScriptFetchForJob): (WebCore::ServiceWorkerContainer::jobFinishedLoadingScript): (WebCore::ServiceWorkerContainer::jobFailedLoadingScript): (WebCore::ServiceWorkerContainer::jobDidFinish): (WebCore::ServiceWorkerContainer::addRegistration): (WebCore::ServiceWorkerContainer::removeRegistration): (WebCore::ServiceWorkerContainer::scheduleTaskToFireControllerChangeEvent): (WebCore::ServiceWorkerContainer::contextIdentifier): * workers/service/ServiceWorkerContainer.h: * workers/service/ServiceWorkerJob.cpp: (WebCore::ServiceWorkerJob::~ServiceWorkerJob): (WebCore::ServiceWorkerJob::failedWithException): (WebCore::ServiceWorkerJob::resolvedWithRegistration): (WebCore::ServiceWorkerJob::resolvedWithUnregistrationResult): (WebCore::ServiceWorkerJob::startScriptFetch): (WebCore::ServiceWorkerJob::fetchScriptWithContext): (WebCore::ServiceWorkerJob::didReceiveResponse): (WebCore::ServiceWorkerJob::notifyFinished): * workers/service/ServiceWorkerJob.h: * xml/parser/XMLDocumentParserLibxml2.cpp: (WebCore::matchFunc): (WebCore::openFunc): (WebCore::initializeXMLParser): (WebCore::XMLParserContext::createStringParser): (WebCore::XMLParserContext::createMemoryParser): Source/WebKit: * UIProcess/API/glib/IconDatabase.cpp: * UIProcess/GenericCallback.h: (WebKit::GenericCallback::~GenericCallback): (WebKit::GenericCallback::performCallbackWithReturnValue): Source/WTF: We should use a pointer of WTF::Thread instead of ThreadIdentifier. One problem is that Windows support library uses WTF::createThread, which returns ThreadIdentifier. So we cannot drop ThreadIdentifier in Windows environment. This patch keeps ThreadIdentifier in Windows. * wtf/MainThread.cpp: (WTF::initializeMainThread): (WTF::isMainThread): (WTF::canAccessThreadLocalDataForThread): * wtf/MainThread.h: * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkCount): * wtf/RecursiveLockAdapter.h: (WTF::RecursiveLockAdapter::lock): (WTF::RecursiveLockAdapter::unlock): (WTF::RecursiveLockAdapter::tryLock): * wtf/Threading.cpp: (WTF::Thread::dump const): * wtf/Threading.h: (WTF::Thread::id const): (WTF::Thread::operator==): Deleted. (WTF::Thread::operator!=): Deleted. (WTF::currentThread): Deleted. * wtf/ThreadingPrimitives.h: * wtf/ThreadingPthreads.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::detach): (WTF::Thread::initializeCurrentTLS): (WTF::Thread::suspend): (WTF::Thread::establishPlatformSpecificHandle): (WTF::Thread::currentID): Deleted. * wtf/ThreadingWin.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::suspend): (WTF::Thread::currentDying): * wtf/mac/MainThreadMac.mm: (WTF::initializeApplicationUIThread): (WTF::initializeWebThreadPlatform): (WTF::canAccessThreadLocalDataForThread): (WTF::initializeApplicationUIThreadIdentifier): Deleted. (WTF::initializeWebThreadIdentifier): Deleted. Tools: * DumpRenderTree/mac/DumpRenderTree.mm: (dumpRenderTree): (runThread): Deleted. (runPthread): Deleted. (testThreadIdentifierMap): Deleted. * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: * TestWebKitAPI/Tests/WTF/Threading.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/196314@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@225470 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-12-04 06:13:05 +00:00
dataLog(toString(Thread::current(), ": proceeding to enqueue ", RawPointer(threadData), "\n"));
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
bucket->enqueue(threadData);
result = true;
} else
result = false;
bucket->lock.unlock();
return result;
}
}
WTF::Lock should not suffer from the thundering herd https://bugs.webkit.org/show_bug.cgi?id=147947 Reviewed by Geoffrey Garen. Source/WTF: This changes Lock::unlockSlow() to use unparkOne() instead of unparkAll(). The problem with doing this is that it's not obvious after calling unparkOne() if there are any other threads that are still parked on the lock's queue. If we assume that there are and leave the hasParkedBit set, then future calls to unlock() will take the slow path. We don't want that if there aren't actually any threads parked. On the other hand, if we assume that there aren't any threads parked and clear the hasParkedBit, then if there actually were some threads parked, then they may never be awoken since future calls to unlock() won't take slow path and so won't call unparkOne(). In other words, we need a way to be very precise about when we clear the hasParkedBit and we need to do it in a race-free way: it can't be the case that we clear the bit just as some thread gets parked on the queue. A similar problem arises in futexes, and one of the solutions is to have a thread that acquires a lock after parking sets the hasParkedBit. This is what Rusty Russel's usersem does. It's a subtle algorithm. Also, it means that if a thread barges in before the unparked thread runs, then that barging thread will not know that there are threads parked. This could increase the severity of barging. Since ParkingLot is a user-level API, we don't have to worry about the kernel-user security issues and so we can expose callbacks while ParkingLot is holding its internal locks. This change does exactly that for unparkOne(). The new variant of unparkOne() will call a user function while the queue from which we are unparking is locked. The callback is told basic stats about the queue: did we unpark a thread this time, and could there be more threads to unpark in the future. The callback runs while it's impossible for the queue state to change, since the ParkingLot's internal locks for the queue is held. This means that Lock::unlockSlow() can either clear, or leave, the hasParkedBit while releasing the lock inside the callback from unparkOne(). This takes care of the thundering herd problem while also reducing the greed that arises from barging threads. This required some careful reworking of the ParkingLot algorithm. The first thing I noticed was that the ThreadData::shouldPark flag was useless, since it's set exactly when ThreadData::address is non-null. Then I had to make sure that dequeue() could lazily create both hashtables and buckets, since the "callback is called while queue is locked" invariant requires that we didn't exit early due to the hashtable or bucket not being present. Note that all of this is done in such a way that the old unparkOne() and unparkAll() don't have to create any buckets, though they now may create the hashtable. We don't care as much about the hashtable being created by unpark since it's just such an unlikely scenario and it would only happen once. This change reduces the kernel CPU usage of WTF::Lock for the long critical section test by about 8x and makes it always perform as well as WTF::WordLock and WTF::Mutex for that benchmark. * benchmarks/LockSpeedTest.cpp: * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): * wtf/Lock.h: (WTF::LockBase::isLocked): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: * wtf/WordLock.h: (WTF::WordLock::isLocked): (WTF::WordLock::isFullyReset): Tools: Add testing that checks that locks return to a pristine state after contention is over. * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::LockInspector::isFullyReset): (TestWebKitAPI::runLockTest): (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/166072@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188374 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 03:51:25 +00:00
enum class BucketMode {
EnsureNonEmpty,
IgnoreEmpty
};
template<typename DequeueFunctor, typename FinishFunctor>
bool dequeue(
const void* address, BucketMode bucketMode, const DequeueFunctor& dequeueFunctor,
const FinishFunctor& finishFunctor)
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
{
unsigned hash = hashAddress(address);
for (;;) {
WTF::Lock should not suffer from the thundering herd https://bugs.webkit.org/show_bug.cgi?id=147947 Reviewed by Geoffrey Garen. Source/WTF: This changes Lock::unlockSlow() to use unparkOne() instead of unparkAll(). The problem with doing this is that it's not obvious after calling unparkOne() if there are any other threads that are still parked on the lock's queue. If we assume that there are and leave the hasParkedBit set, then future calls to unlock() will take the slow path. We don't want that if there aren't actually any threads parked. On the other hand, if we assume that there aren't any threads parked and clear the hasParkedBit, then if there actually were some threads parked, then they may never be awoken since future calls to unlock() won't take slow path and so won't call unparkOne(). In other words, we need a way to be very precise about when we clear the hasParkedBit and we need to do it in a race-free way: it can't be the case that we clear the bit just as some thread gets parked on the queue. A similar problem arises in futexes, and one of the solutions is to have a thread that acquires a lock after parking sets the hasParkedBit. This is what Rusty Russel's usersem does. It's a subtle algorithm. Also, it means that if a thread barges in before the unparked thread runs, then that barging thread will not know that there are threads parked. This could increase the severity of barging. Since ParkingLot is a user-level API, we don't have to worry about the kernel-user security issues and so we can expose callbacks while ParkingLot is holding its internal locks. This change does exactly that for unparkOne(). The new variant of unparkOne() will call a user function while the queue from which we are unparking is locked. The callback is told basic stats about the queue: did we unpark a thread this time, and could there be more threads to unpark in the future. The callback runs while it's impossible for the queue state to change, since the ParkingLot's internal locks for the queue is held. This means that Lock::unlockSlow() can either clear, or leave, the hasParkedBit while releasing the lock inside the callback from unparkOne(). This takes care of the thundering herd problem while also reducing the greed that arises from barging threads. This required some careful reworking of the ParkingLot algorithm. The first thing I noticed was that the ThreadData::shouldPark flag was useless, since it's set exactly when ThreadData::address is non-null. Then I had to make sure that dequeue() could lazily create both hashtables and buckets, since the "callback is called while queue is locked" invariant requires that we didn't exit early due to the hashtable or bucket not being present. Note that all of this is done in such a way that the old unparkOne() and unparkAll() don't have to create any buckets, though they now may create the hashtable. We don't care as much about the hashtable being created by unpark since it's just such an unlikely scenario and it would only happen once. This change reduces the kernel CPU usage of WTF::Lock for the long critical section test by about 8x and makes it always perform as well as WTF::WordLock and WTF::Mutex for that benchmark. * benchmarks/LockSpeedTest.cpp: * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): * wtf/Lock.h: (WTF::LockBase::isLocked): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: * wtf/WordLock.h: (WTF::WordLock::isLocked): (WTF::WordLock::isFullyReset): Tools: Add testing that checks that locks return to a pristine state after contention is over. * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::LockInspector::isFullyReset): (TestWebKitAPI::runLockTest): (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/166072@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188374 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 03:51:25 +00:00
Hashtable* myHashtable = ensureHashtable();
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
unsigned index = hash % myHashtable->size;
WTF::Lock should not suffer from the thundering herd https://bugs.webkit.org/show_bug.cgi?id=147947 Reviewed by Geoffrey Garen. Source/WTF: This changes Lock::unlockSlow() to use unparkOne() instead of unparkAll(). The problem with doing this is that it's not obvious after calling unparkOne() if there are any other threads that are still parked on the lock's queue. If we assume that there are and leave the hasParkedBit set, then future calls to unlock() will take the slow path. We don't want that if there aren't actually any threads parked. On the other hand, if we assume that there aren't any threads parked and clear the hasParkedBit, then if there actually were some threads parked, then they may never be awoken since future calls to unlock() won't take slow path and so won't call unparkOne(). In other words, we need a way to be very precise about when we clear the hasParkedBit and we need to do it in a race-free way: it can't be the case that we clear the bit just as some thread gets parked on the queue. A similar problem arises in futexes, and one of the solutions is to have a thread that acquires a lock after parking sets the hasParkedBit. This is what Rusty Russel's usersem does. It's a subtle algorithm. Also, it means that if a thread barges in before the unparked thread runs, then that barging thread will not know that there are threads parked. This could increase the severity of barging. Since ParkingLot is a user-level API, we don't have to worry about the kernel-user security issues and so we can expose callbacks while ParkingLot is holding its internal locks. This change does exactly that for unparkOne(). The new variant of unparkOne() will call a user function while the queue from which we are unparking is locked. The callback is told basic stats about the queue: did we unpark a thread this time, and could there be more threads to unpark in the future. The callback runs while it's impossible for the queue state to change, since the ParkingLot's internal locks for the queue is held. This means that Lock::unlockSlow() can either clear, or leave, the hasParkedBit while releasing the lock inside the callback from unparkOne(). This takes care of the thundering herd problem while also reducing the greed that arises from barging threads. This required some careful reworking of the ParkingLot algorithm. The first thing I noticed was that the ThreadData::shouldPark flag was useless, since it's set exactly when ThreadData::address is non-null. Then I had to make sure that dequeue() could lazily create both hashtables and buckets, since the "callback is called while queue is locked" invariant requires that we didn't exit early due to the hashtable or bucket not being present. Note that all of this is done in such a way that the old unparkOne() and unparkAll() don't have to create any buckets, though they now may create the hashtable. We don't care as much about the hashtable being created by unpark since it's just such an unlikely scenario and it would only happen once. This change reduces the kernel CPU usage of WTF::Lock for the long critical section test by about 8x and makes it always perform as well as WTF::WordLock and WTF::Mutex for that benchmark. * benchmarks/LockSpeedTest.cpp: * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): * wtf/Lock.h: (WTF::LockBase::isLocked): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: * wtf/WordLock.h: (WTF::WordLock::isLocked): (WTF::WordLock::isFullyReset): Tools: Add testing that checks that locks return to a pristine state after contention is over. * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::LockInspector::isFullyReset): (TestWebKitAPI::runLockTest): (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/166072@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188374 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 03:51:25 +00:00
Atomic<Bucket*>& bucketPointer = myHashtable->data[index];
Bucket* bucket = bucketPointer.load();
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
if (!bucket) {
WTF::Lock should not suffer from the thundering herd https://bugs.webkit.org/show_bug.cgi?id=147947 Reviewed by Geoffrey Garen. Source/WTF: This changes Lock::unlockSlow() to use unparkOne() instead of unparkAll(). The problem with doing this is that it's not obvious after calling unparkOne() if there are any other threads that are still parked on the lock's queue. If we assume that there are and leave the hasParkedBit set, then future calls to unlock() will take the slow path. We don't want that if there aren't actually any threads parked. On the other hand, if we assume that there aren't any threads parked and clear the hasParkedBit, then if there actually were some threads parked, then they may never be awoken since future calls to unlock() won't take slow path and so won't call unparkOne(). In other words, we need a way to be very precise about when we clear the hasParkedBit and we need to do it in a race-free way: it can't be the case that we clear the bit just as some thread gets parked on the queue. A similar problem arises in futexes, and one of the solutions is to have a thread that acquires a lock after parking sets the hasParkedBit. This is what Rusty Russel's usersem does. It's a subtle algorithm. Also, it means that if a thread barges in before the unparked thread runs, then that barging thread will not know that there are threads parked. This could increase the severity of barging. Since ParkingLot is a user-level API, we don't have to worry about the kernel-user security issues and so we can expose callbacks while ParkingLot is holding its internal locks. This change does exactly that for unparkOne(). The new variant of unparkOne() will call a user function while the queue from which we are unparking is locked. The callback is told basic stats about the queue: did we unpark a thread this time, and could there be more threads to unpark in the future. The callback runs while it's impossible for the queue state to change, since the ParkingLot's internal locks for the queue is held. This means that Lock::unlockSlow() can either clear, or leave, the hasParkedBit while releasing the lock inside the callback from unparkOne(). This takes care of the thundering herd problem while also reducing the greed that arises from barging threads. This required some careful reworking of the ParkingLot algorithm. The first thing I noticed was that the ThreadData::shouldPark flag was useless, since it's set exactly when ThreadData::address is non-null. Then I had to make sure that dequeue() could lazily create both hashtables and buckets, since the "callback is called while queue is locked" invariant requires that we didn't exit early due to the hashtable or bucket not being present. Note that all of this is done in such a way that the old unparkOne() and unparkAll() don't have to create any buckets, though they now may create the hashtable. We don't care as much about the hashtable being created by unpark since it's just such an unlikely scenario and it would only happen once. This change reduces the kernel CPU usage of WTF::Lock for the long critical section test by about 8x and makes it always perform as well as WTF::WordLock and WTF::Mutex for that benchmark. * benchmarks/LockSpeedTest.cpp: * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): * wtf/Lock.h: (WTF::LockBase::isLocked): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: * wtf/WordLock.h: (WTF::WordLock::isLocked): (WTF::WordLock::isFullyReset): Tools: Add testing that checks that locks return to a pristine state after contention is over. * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::LockInspector::isFullyReset): (TestWebKitAPI::runLockTest): (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/166072@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188374 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 03:51:25 +00:00
if (bucketMode == BucketMode::IgnoreEmpty)
return false;
for (;;) {
bucket = bucketPointer.load();
if (!bucket) {
bucket = new Bucket();
if (!bucketPointer.compareExchangeWeak(nullptr, bucket)) {
delete bucket;
continue;
}
}
break;
}
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
}
bucket->lock.lock();
// At this point the hashtable could have rehashed under us.
if (hashtable.load() != myHashtable) {
bucket->lock.unlock();
continue;
}
WTF::Lock should not suffer from the thundering herd https://bugs.webkit.org/show_bug.cgi?id=147947 Reviewed by Geoffrey Garen. Source/WTF: This changes Lock::unlockSlow() to use unparkOne() instead of unparkAll(). The problem with doing this is that it's not obvious after calling unparkOne() if there are any other threads that are still parked on the lock's queue. If we assume that there are and leave the hasParkedBit set, then future calls to unlock() will take the slow path. We don't want that if there aren't actually any threads parked. On the other hand, if we assume that there aren't any threads parked and clear the hasParkedBit, then if there actually were some threads parked, then they may never be awoken since future calls to unlock() won't take slow path and so won't call unparkOne(). In other words, we need a way to be very precise about when we clear the hasParkedBit and we need to do it in a race-free way: it can't be the case that we clear the bit just as some thread gets parked on the queue. A similar problem arises in futexes, and one of the solutions is to have a thread that acquires a lock after parking sets the hasParkedBit. This is what Rusty Russel's usersem does. It's a subtle algorithm. Also, it means that if a thread barges in before the unparked thread runs, then that barging thread will not know that there are threads parked. This could increase the severity of barging. Since ParkingLot is a user-level API, we don't have to worry about the kernel-user security issues and so we can expose callbacks while ParkingLot is holding its internal locks. This change does exactly that for unparkOne(). The new variant of unparkOne() will call a user function while the queue from which we are unparking is locked. The callback is told basic stats about the queue: did we unpark a thread this time, and could there be more threads to unpark in the future. The callback runs while it's impossible for the queue state to change, since the ParkingLot's internal locks for the queue is held. This means that Lock::unlockSlow() can either clear, or leave, the hasParkedBit while releasing the lock inside the callback from unparkOne(). This takes care of the thundering herd problem while also reducing the greed that arises from barging threads. This required some careful reworking of the ParkingLot algorithm. The first thing I noticed was that the ThreadData::shouldPark flag was useless, since it's set exactly when ThreadData::address is non-null. Then I had to make sure that dequeue() could lazily create both hashtables and buckets, since the "callback is called while queue is locked" invariant requires that we didn't exit early due to the hashtable or bucket not being present. Note that all of this is done in such a way that the old unparkOne() and unparkAll() don't have to create any buckets, though they now may create the hashtable. We don't care as much about the hashtable being created by unpark since it's just such an unlikely scenario and it would only happen once. This change reduces the kernel CPU usage of WTF::Lock for the long critical section test by about 8x and makes it always perform as well as WTF::WordLock and WTF::Mutex for that benchmark. * benchmarks/LockSpeedTest.cpp: * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): * wtf/Lock.h: (WTF::LockBase::isLocked): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: * wtf/WordLock.h: (WTF::WordLock::isLocked): (WTF::WordLock::isFullyReset): Tools: Add testing that checks that locks return to a pristine state after contention is over. * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::LockInspector::isFullyReset): (TestWebKitAPI::runLockTest): (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/166072@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188374 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 03:51:25 +00:00
bucket->genericDequeue(dequeueFunctor);
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
bool result = !!bucket->queueHead;
WTF::Lock should not suffer from the thundering herd https://bugs.webkit.org/show_bug.cgi?id=147947 Reviewed by Geoffrey Garen. Source/WTF: This changes Lock::unlockSlow() to use unparkOne() instead of unparkAll(). The problem with doing this is that it's not obvious after calling unparkOne() if there are any other threads that are still parked on the lock's queue. If we assume that there are and leave the hasParkedBit set, then future calls to unlock() will take the slow path. We don't want that if there aren't actually any threads parked. On the other hand, if we assume that there aren't any threads parked and clear the hasParkedBit, then if there actually were some threads parked, then they may never be awoken since future calls to unlock() won't take slow path and so won't call unparkOne(). In other words, we need a way to be very precise about when we clear the hasParkedBit and we need to do it in a race-free way: it can't be the case that we clear the bit just as some thread gets parked on the queue. A similar problem arises in futexes, and one of the solutions is to have a thread that acquires a lock after parking sets the hasParkedBit. This is what Rusty Russel's usersem does. It's a subtle algorithm. Also, it means that if a thread barges in before the unparked thread runs, then that barging thread will not know that there are threads parked. This could increase the severity of barging. Since ParkingLot is a user-level API, we don't have to worry about the kernel-user security issues and so we can expose callbacks while ParkingLot is holding its internal locks. This change does exactly that for unparkOne(). The new variant of unparkOne() will call a user function while the queue from which we are unparking is locked. The callback is told basic stats about the queue: did we unpark a thread this time, and could there be more threads to unpark in the future. The callback runs while it's impossible for the queue state to change, since the ParkingLot's internal locks for the queue is held. This means that Lock::unlockSlow() can either clear, or leave, the hasParkedBit while releasing the lock inside the callback from unparkOne(). This takes care of the thundering herd problem while also reducing the greed that arises from barging threads. This required some careful reworking of the ParkingLot algorithm. The first thing I noticed was that the ThreadData::shouldPark flag was useless, since it's set exactly when ThreadData::address is non-null. Then I had to make sure that dequeue() could lazily create both hashtables and buckets, since the "callback is called while queue is locked" invariant requires that we didn't exit early due to the hashtable or bucket not being present. Note that all of this is done in such a way that the old unparkOne() and unparkAll() don't have to create any buckets, though they now may create the hashtable. We don't care as much about the hashtable being created by unpark since it's just such an unlikely scenario and it would only happen once. This change reduces the kernel CPU usage of WTF::Lock for the long critical section test by about 8x and makes it always perform as well as WTF::WordLock and WTF::Mutex for that benchmark. * benchmarks/LockSpeedTest.cpp: * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): * wtf/Lock.h: (WTF::LockBase::isLocked): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: * wtf/WordLock.h: (WTF::WordLock::isLocked): (WTF::WordLock::isFullyReset): Tools: Add testing that checks that locks return to a pristine state after contention is over. * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::LockInspector::isFullyReset): (TestWebKitAPI::runLockTest): (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/166072@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188374 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 03:51:25 +00:00
finishFunctor(result);
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
bucket->lock.unlock();
return result;
}
}
} // anonymous namespace
WTF::Lock should be fair eventually https://bugs.webkit.org/show_bug.cgi?id=159384 Reviewed by Geoffrey Garen. Source/WTF: In https://webkit.org/blog/6161/locking-in-webkit/ we showed how relaxing the fairness of locks makes them fast. That post presented lock fairness as a trade-off between two extremes: - Barging. A barging lock, like WTF::Lock, releases the lock in unlock() even if there was a thread on the queue. If there was a thread on the queue, the lock is released and that thread is made runnable. That thread may then grab the lock, or some other thread may grab the lock first (it may barge). Usually, the barging thread is the thread that released the lock in the first place. This maximizes throughput but hurts fairness. There is no good theoretical bound on how unfair the lock may become, but empirical data suggests that it's fair enough for the cases we previously measured. - FIFO. A FIFO lock, like HandoffLock in ToyLocks.h, does not release the lock in unlock() if there is a thread waiting. If there is a thread waiting, unlock() will make that thread runnable and inform it that it now holds the lock. This ensures perfect round-robin fairness and allows us to reason theoretically about how long it may take for a thread to grab the lock. For example, if we know that only N threads are running and each one may contend on a critical section, and each one may hold the lock for at most S seconds, then the time it takes to grab the lock is N * S. Unfortunately, FIFO locks perform very badly in most cases. This is because for the common case of short critical sections, they force a context switch after each critical section if the lock is contended. This change makes WTF::Lock almost as fair as FIFO while still being as fast as barging. Thanks to this new algorithm, you can now have both of these things at the same time. This change makes WTF::Lock eventually fair. We can almost (more on the caveats below) guarantee that the time it takes to grab a lock is N * max(1ms, S). In other words, critical sections that are longer than 1ms are always fair. For shorter critical sections, the amount of time that any thread waits is 1ms times the number of threads. There are some caveats that arise from our use of randomness, but even then, in the limit as the critical section length goes to infinity, the lock becomes fair. The corner cases are unlikely to happen; our experiments show that the lock becomes exactly as fair as a FIFO lock for any critical section that is 1ms or longer. The fairness mechanism is broken into two parts. WTF::Lock can now choose to unlock a lock fairly or unfairly thanks to the new ParkingLot token mechanism. WTF::Lock knows when to use fair unlocking based on a timeout mechanism in ParkingLot called timeToBeFair. ParkingLot::unparkOne() and ParkingLot::parkConditionally() can now communicate with each other via a token. unparkOne() can pass a token, which parkConditionally() will return. This change also makes parkConditionally() a lot more precise about when it was unparked due to a call to unparkOne(). If unparkOne() is told that a thread was unparked then this thread is guaranteed to report that it was unparked rather than timing out, and that thread is guaranteed to get the token that unparkOne() passed. The token is an intptr_t. We use it as a boolean variable in WTF::Lock, but you could use it to pass arbitrary data structures. By default, the token is zero. WTF::Lock's unlock() will pass 1 as the token if it is doing fair unlocking. In that case, unlock() will not release the lock, and lock() will know that it holds the lock as soon as parkConditionally() returns. Note that this algorithm relies on unparkOne() invoking WTF::Lock's callback while the queue lock is held, so that WTF::Lock can make a decision about unlock strategy and inject a token while it has complete knowledge over the state of the queue. As such, it's not immediately obvious how to implement this algorithm on top of futexes. You really need ParkingLot! WTF::Lock does not use fair unlocking every time. We expose a new API, Lock::unlockFairly(), which forces the fair unlocking behavior. Additionally, ParkingLot now maintains a per-bucket stochastic fairness timeout. When the timeout fires, the unparkOne() callback sees UnparkResult::timeToBeFair = true. This timeout is set to be anywhere from 0ms to 1ms at random. When a dequeue happens and there are threads that actually get dequeued, we check if the time since the last unfair unlock (the last time timeToBeFair was set to true) is more than the timeout amount. If so, then we set timeToBeFair to true and reset the timeout. This means that in the absence of ParkingLot collisions, unfair unlocking is guaranteed to happen at least once per millisecond. It will happen at 2 KHz on average. If there are collisions, then each collision adds one millisecond to the worst case (and 0.5 ms to the average case). The reason why we don't just use a fixed 1ms timeout is that we want to avoid resonance. Imagine a program in which some thread acquires a lock at 1 KHz in-phase with the timeToBeFair timeout. Then this thread would be the benefactor of fairness to the detriment of everyone else. Randomness ensures that we aren't too fair to any one thread. Empirically, this is neutral on our major benchmarks like JetStream but it's an enormous improvement in LockFairnessTest. It's common for an unfair lock (either our BargingLock, the old WTF::Lock, any of the other futex-based locks that barge, or new os_unfair_lock) to allow only one thread to hold the lock during a whole second in which each thread is holding the lock for 1ms at a time. This is because in a barging lock, releasing a lock after holding it for 1ms and then reacquiring it immediately virtually ensures that none of the other threads can wake up in time to grab it before it's relocked. But the new WTF::Lock handles this case like a champ: each thread gets equal turns. Here's some data. If we launch 10 threads and have each of them run for 1 second while repeatedly holding a critical section for 1ms, then here's how many times each thread gets to hold the lock using the old WTF::Lock algorithm: 799, 6, 1, 1, 1, 1, 1, 1, 1, 1 One thread hogged the lock for almost the whole time! With the new WTF::Lock, the lock becomes totally fair: 80, 79, 79, 79, 79, 79, 79, 80, 80, 79 I don't know of anyone creating such an automatically-fair adaptive lock before, so I think that this is a pretty awesome advancement to the state of the art! This change is good for three reasons: - We do have long critical sections in WebKit and we don't want to have to worry about starvation. This reduces the likelihood that we will see starvation due to our lock strategy. - I was talking to ggaren about bmalloc's locking needs, and he wanted unlockFairly() or lockFairly() or some moral equivalent for the scavenger thread. - If we use a WTF::Lock to manage heap access in a multithreaded GC, we'll need the ability to unlock and relock without barging. * benchmarks/LockFairnessTest.cpp: (main): * benchmarks/ToyLocks.h: * wtf/Condition.h: (WTF::ConditionBase::waitUntil): (WTF::ConditionBase::notifyOne): * wtf/Lock.cpp: (WTF::LockBase::lockSlow): (WTF::LockBase::unlockSlow): (WTF::LockBase::unlockFairlySlow): (WTF::LockBase::unlockSlowImpl): * wtf/Lock.h: (WTF::LockBase::try_lock): (WTF::LockBase::unlock): (WTF::LockBase::unlockFairly): (WTF::LockBase::isHeld): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::compareAndPark): (WTF::ParkingLot::unparkOne): Tools: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Canonical link: https://commits.webkit.org/178039@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@203350 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-07-18 18:32:52 +00:00
NEVER_INLINE ParkingLot::ParkResult ParkingLot::parkConditionallyImpl(
WTF should have a compact Condition object to use with Lock https://bugs.webkit.org/show_bug.cgi?id=147986 Reviewed by Geoffrey Garen. Source/WTF: Adds a condition variable implementation based on ParkingLot, called simply WTF::Condition. It can be used with WTF::Lock or actually any lock implementation. It should even work with WTF::SpinLock, WTF::Mutex, or std::mutex. Best of all, Condition only requires one byte. ParkingLot almost contained all of the functionality needed to implemenet wait/notify. We could have implemented Condition using a 32-bit (or even 64-bit) version that protects against a notify that happens just before we park. But, this changes the ParkingLot API to give us the ability to run some code between when ParkingLot enqueues the current thread and when it actually sleeps. This callback is called with no locks held, so it can call unlock() on any kind of lock, so long as that lock's unlock() method doesn't recurse into ParkingLot::parkConditionally(). That seems unlikely; unlock() is more likely to call ParkingLot::unparkOne() or unparkAll(). WTF::Lock will never call parkConditionally() inside unlock(), so WTF::Lock is definitely appropriate for use with Condition. Condition supports most of the API that std::condition_variable supports. It does some things to try to reduce footgun potential. The preferred timeout form is waitUntil() which takes an absolute time from the steady_clock. The only relative timeout form also takes a predicate callback, so it's impossible to write the subtly incorrect "while (...) wait_for(...)" idiom. This patch doesn't actually introduce any uses of WTF::Condition other than the unit tests. I'll start switching code over to using WTF::Condition in another patch. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/Condition.h: Added. (WTF::Condition::Condition): (WTF::Condition::waitUntil): (WTF::Condition::waitFor): (WTF::Condition::wait): (WTF::Condition::notifyOne): (WTF::Condition::notifyAll): * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): Make this useful assertion be a release assertion. It catches cases where you unlock the lock even though you don't hold it. * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): Add the beforeSleep() callback. (WTF::ParkingLot::unparkOne): * wtf/ParkingLot.h: (WTF::ParkingLot::compareAndPark): Tools: Add a test for WTF::Condition. * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Condition.cpp: Added. (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::runLockTest): Change the name of the thread. Canonical link: https://commits.webkit.org/166094@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188400 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 20:42:11 +00:00
const void* address,
ScopedLambda should have a lifetime story that makes sense to the compiler https://bugs.webkit.org/show_bug.cgi?id=158118 Reviewed by Mark Lam. Source/WTF: Prior to this change, there were two lifetime bugs in ScopedLambda: - scopedLambda(Functor&&) would bind Functor to const lambda&, so the resulting ScopedLambdaFunctor would hold a reference to the original lambda. This would have surprising behavior; for example it meant that this code was wrong: auto l = scopedLambda<things>([&] ...); The solution is to have explicit copy/move versions of scopedLambda() rather than rely on perfect forwarding. - ScopedLambdaFunctor did not override its copy or move operations, so if the compiler did not RVO scopedLambda(), it would return a ScopedLambdaFunctor whose m_arg points to a dead temporary ScopedLambdaFunctor instance. The solution is to have explicit copy/move constructors and operators, which preserve the invariant that ScopedLambda::m_arg points to this. One nice side-effect of all of these constructors and operators being explicit is that we can rely on WTFMove's excellent assertions, which helped catch the first issue. This reverts ParkingLot to use ScopedLambda again. * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): * wtf/ParkingLot.h: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): * wtf/ScopedLambda.h: (WTF::scopedLambda): Tools: Added a test case. This test crashes before the fix and now it passes. * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/ScopedLambda.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/176236@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@201433 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-05-26 21:58:42 +00:00
const ScopedLambda<bool()>& validation,
const ScopedLambda<void()>& beforeSleep,
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): Canonical link: https://commits.webkit.org/182152@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208415 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-11-05 03:02:39 +00:00
const TimeWithDynamicClockType& timeout)
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
{
if (verbose)
WTF shouldn't have both Thread and ThreadIdentifier https://bugs.webkit.org/show_bug.cgi?id=180308 Reviewed by Darin Adler. Source/JavaScriptCore: * heap/MachineStackMarker.cpp: (JSC::MachineThreads::tryCopyOtherThreadStacks): * llint/LLIntSlowPaths.cpp: (JSC::LLInt::llint_trace_operand): (JSC::LLInt::llint_trace_value): (JSC::LLInt::LLINT_SLOW_PATH_DECL): (JSC::LLInt::traceFunctionPrologue): * runtime/ExceptionScope.cpp: (JSC::ExceptionScope::unexpectedExceptionMessage): * runtime/JSLock.h: (JSC::JSLock::currentThreadIsHoldingLock): * runtime/VM.cpp: (JSC::VM::throwException): * runtime/VM.h: (JSC::VM::throwingThread const): (JSC::VM::clearException): * tools/HeapVerifier.cpp: (JSC::HeapVerifier::printVerificationHeader): Source/WebCore: No behavior change. * Modules/indexeddb/IDBActiveDOMObject.h: (WebCore::IDBActiveDOMObject::originThread const): (WebCore::IDBActiveDOMObject::performCallbackOnOriginThread): (WebCore::IDBActiveDOMObject::callFunctionOnOriginThread): (WebCore::IDBActiveDOMObject::originThreadID const): Deleted. * Modules/indexeddb/IDBCursor.cpp: (WebCore::IDBCursor::IDBCursor): (WebCore::IDBCursor::~IDBCursor): (WebCore::IDBCursor::sourcesDeleted const): (WebCore::IDBCursor::transaction const): (WebCore::IDBCursor::update): (WebCore::IDBCursor::advance): (WebCore::IDBCursor::continueFunction): (WebCore::IDBCursor::uncheckedIterateCursor): (WebCore::IDBCursor::deleteFunction): (WebCore::IDBCursor::setGetResult): * Modules/indexeddb/IDBDatabase.cpp: (WebCore::IDBDatabase::~IDBDatabase): (WebCore::IDBDatabase::hasPendingActivity const): (WebCore::IDBDatabase::name const): (WebCore::IDBDatabase::version const): (WebCore::IDBDatabase::objectStoreNames const): (WebCore::IDBDatabase::renameObjectStore): (WebCore::IDBDatabase::renameIndex): (WebCore::IDBDatabase::createObjectStore): (WebCore::IDBDatabase::transaction): (WebCore::IDBDatabase::deleteObjectStore): (WebCore::IDBDatabase::close): (WebCore::IDBDatabase::connectionToServerLost): (WebCore::IDBDatabase::maybeCloseInServer): (WebCore::IDBDatabase::activeDOMObjectName const): (WebCore::IDBDatabase::canSuspendForDocumentSuspension const): (WebCore::IDBDatabase::stop): (WebCore::IDBDatabase::startVersionChangeTransaction): (WebCore::IDBDatabase::didStartTransaction): (WebCore::IDBDatabase::willCommitTransaction): (WebCore::IDBDatabase::didCommitTransaction): (WebCore::IDBDatabase::willAbortTransaction): (WebCore::IDBDatabase::didAbortTransaction): (WebCore::IDBDatabase::didCommitOrAbortTransaction): (WebCore::IDBDatabase::fireVersionChangeEvent): (WebCore::IDBDatabase::dispatchEvent): (WebCore::IDBDatabase::didCreateIndexInfo): (WebCore::IDBDatabase::didDeleteIndexInfo): * Modules/indexeddb/IDBIndex.cpp: (WebCore::IDBIndex::IDBIndex): (WebCore::IDBIndex::~IDBIndex): (WebCore::IDBIndex::name const): (WebCore::IDBIndex::setName): (WebCore::IDBIndex::objectStore): (WebCore::IDBIndex::keyPath const): (WebCore::IDBIndex::unique const): (WebCore::IDBIndex::multiEntry const): (WebCore::IDBIndex::rollbackInfoForVersionChangeAbort): (WebCore::IDBIndex::openCursor): (WebCore::IDBIndex::openKeyCursor): (WebCore::IDBIndex::doCount): (WebCore::IDBIndex::doGet): (WebCore::IDBIndex::doGetKey): (WebCore::IDBIndex::getAll): (WebCore::IDBIndex::getAllKeys): (WebCore::IDBIndex::markAsDeleted): * Modules/indexeddb/IDBObjectStore.cpp: (WebCore::IDBObjectStore::IDBObjectStore): (WebCore::IDBObjectStore::~IDBObjectStore): (WebCore::IDBObjectStore::name const): (WebCore::IDBObjectStore::setName): (WebCore::IDBObjectStore::keyPath const): (WebCore::IDBObjectStore::indexNames const): (WebCore::IDBObjectStore::transaction): (WebCore::IDBObjectStore::autoIncrement const): (WebCore::IDBObjectStore::openCursor): (WebCore::IDBObjectStore::openKeyCursor): (WebCore::IDBObjectStore::get): (WebCore::IDBObjectStore::getKey): (WebCore::IDBObjectStore::putOrAdd): (WebCore::IDBObjectStore::doDelete): (WebCore::IDBObjectStore::clear): (WebCore::IDBObjectStore::createIndex): (WebCore::IDBObjectStore::index): (WebCore::IDBObjectStore::deleteIndex): (WebCore::IDBObjectStore::doCount): (WebCore::IDBObjectStore::getAll): (WebCore::IDBObjectStore::getAllKeys): (WebCore::IDBObjectStore::markAsDeleted): (WebCore::IDBObjectStore::rollbackForVersionChangeAbort): * Modules/indexeddb/IDBOpenDBRequest.cpp: (WebCore::IDBOpenDBRequest::~IDBOpenDBRequest): (WebCore::IDBOpenDBRequest::onError): (WebCore::IDBOpenDBRequest::versionChangeTransactionDidFinish): (WebCore::IDBOpenDBRequest::fireSuccessAfterVersionChangeCommit): (WebCore::IDBOpenDBRequest::fireErrorAfterVersionChangeCompletion): (WebCore::IDBOpenDBRequest::dispatchEvent): (WebCore::IDBOpenDBRequest::onSuccess): (WebCore::IDBOpenDBRequest::onUpgradeNeeded): (WebCore::IDBOpenDBRequest::onDeleteDatabaseSuccess): (WebCore::IDBOpenDBRequest::requestCompleted): (WebCore::IDBOpenDBRequest::requestBlocked): * Modules/indexeddb/IDBRequest.cpp: (WebCore::IDBRequest::~IDBRequest): (WebCore:: const): (WebCore::IDBRequest::setSource): (WebCore::IDBRequest::setVersionChangeTransaction): (WebCore::IDBRequest::transaction const): (WebCore::IDBRequest::sourceObjectStoreIdentifier const): (WebCore::IDBRequest::sourceIndexIdentifier const): (WebCore::IDBRequest::requestedObjectStoreRecordType const): (WebCore::IDBRequest::requestedIndexRecordType const): (WebCore::IDBRequest::eventTargetInterface const): (WebCore::IDBRequest::activeDOMObjectName const): (WebCore::IDBRequest::canSuspendForDocumentSuspension const): (WebCore::IDBRequest::hasPendingActivity const): (WebCore::IDBRequest::stop): (WebCore::IDBRequest::enqueueEvent): (WebCore::IDBRequest::dispatchEvent): (WebCore::IDBRequest::uncaughtExceptionInEventHandler): (WebCore::IDBRequest::setResult): (WebCore::IDBRequest::setResultToStructuredClone): (WebCore::IDBRequest::setResultToUndefined): (WebCore::IDBRequest::resultCursor): (WebCore::IDBRequest::willIterateCursor): (WebCore::IDBRequest::didOpenOrIterateCursor): (WebCore::IDBRequest::completeRequestAndDispatchEvent): (WebCore::IDBRequest::onError): (WebCore::IDBRequest::onSuccess): * Modules/indexeddb/IDBTransaction.cpp: (WebCore::IDBTransaction::IDBTransaction): (WebCore::IDBTransaction::~IDBTransaction): (WebCore::IDBTransaction::objectStoreNames const): (WebCore::IDBTransaction::db): (WebCore::IDBTransaction::error const): (WebCore::IDBTransaction::objectStore): (WebCore::IDBTransaction::abortDueToFailedRequest): (WebCore::IDBTransaction::transitionedToFinishing): (WebCore::IDBTransaction::abort): (WebCore::IDBTransaction::internalAbort): (WebCore::IDBTransaction::abortOnServerAndCancelRequests): (WebCore::IDBTransaction::activeDOMObjectName const): (WebCore::IDBTransaction::canSuspendForDocumentSuspension const): (WebCore::IDBTransaction::hasPendingActivity const): (WebCore::IDBTransaction::stop): (WebCore::IDBTransaction::isActive const): (WebCore::IDBTransaction::isFinishedOrFinishing const): (WebCore::IDBTransaction::addRequest): (WebCore::IDBTransaction::removeRequest): (WebCore::IDBTransaction::scheduleOperation): (WebCore::IDBTransaction::schedulePendingOperationTimer): (WebCore::IDBTransaction::pendingOperationTimerFired): (WebCore::IDBTransaction::operationCompletedOnServer): (WebCore::IDBTransaction::scheduleCompletedOperationTimer): (WebCore::IDBTransaction::completedOperationTimerFired): (WebCore::IDBTransaction::commit): (WebCore::IDBTransaction::commitOnServer): (WebCore::IDBTransaction::finishAbortOrCommit): (WebCore::IDBTransaction::didStart): (WebCore::IDBTransaction::notifyDidAbort): (WebCore::IDBTransaction::didAbort): (WebCore::IDBTransaction::didCommit): (WebCore::IDBTransaction::fireOnComplete): (WebCore::IDBTransaction::fireOnAbort): (WebCore::IDBTransaction::enqueueEvent): (WebCore::IDBTransaction::dispatchEvent): (WebCore::IDBTransaction::createObjectStore): (WebCore::IDBTransaction::createObjectStoreOnServer): (WebCore::IDBTransaction::didCreateObjectStoreOnServer): (WebCore::IDBTransaction::renameObjectStore): (WebCore::IDBTransaction::renameObjectStoreOnServer): (WebCore::IDBTransaction::didRenameObjectStoreOnServer): (WebCore::IDBTransaction::createIndex): (WebCore::IDBTransaction::createIndexOnServer): (WebCore::IDBTransaction::didCreateIndexOnServer): (WebCore::IDBTransaction::renameIndex): (WebCore::IDBTransaction::renameIndexOnServer): (WebCore::IDBTransaction::didRenameIndexOnServer): (WebCore::IDBTransaction::requestOpenCursor): (WebCore::IDBTransaction::doRequestOpenCursor): (WebCore::IDBTransaction::openCursorOnServer): (WebCore::IDBTransaction::didOpenCursorOnServer): (WebCore::IDBTransaction::iterateCursor): (WebCore::IDBTransaction::iterateCursorOnServer): (WebCore::IDBTransaction::didIterateCursorOnServer): (WebCore::IDBTransaction::requestGetAllObjectStoreRecords): (WebCore::IDBTransaction::requestGetAllIndexRecords): (WebCore::IDBTransaction::getAllRecordsOnServer): (WebCore::IDBTransaction::didGetAllRecordsOnServer): (WebCore::IDBTransaction::requestGetRecord): (WebCore::IDBTransaction::requestGetValue): (WebCore::IDBTransaction::requestGetKey): (WebCore::IDBTransaction::requestIndexRecord): (WebCore::IDBTransaction::getRecordOnServer): (WebCore::IDBTransaction::didGetRecordOnServer): (WebCore::IDBTransaction::requestCount): (WebCore::IDBTransaction::getCountOnServer): (WebCore::IDBTransaction::didGetCountOnServer): (WebCore::IDBTransaction::requestDeleteRecord): (WebCore::IDBTransaction::deleteRecordOnServer): (WebCore::IDBTransaction::didDeleteRecordOnServer): (WebCore::IDBTransaction::requestClearObjectStore): (WebCore::IDBTransaction::clearObjectStoreOnServer): (WebCore::IDBTransaction::didClearObjectStoreOnServer): (WebCore::IDBTransaction::requestPutOrAdd): (WebCore::IDBTransaction::putOrAddOnServer): (WebCore::IDBTransaction::didPutOrAddOnServer): (WebCore::IDBTransaction::deleteObjectStore): (WebCore::IDBTransaction::deleteObjectStoreOnServer): (WebCore::IDBTransaction::didDeleteObjectStoreOnServer): (WebCore::IDBTransaction::deleteIndex): (WebCore::IDBTransaction::deleteIndexOnServer): (WebCore::IDBTransaction::didDeleteIndexOnServer): (WebCore::IDBTransaction::operationCompletedOnClient): (WebCore::IDBTransaction::establishOnServer): (WebCore::IDBTransaction::activate): (WebCore::IDBTransaction::deactivate): * Modules/indexeddb/client/IDBConnectionProxy.cpp: (WebCore::IDBClient::removeItemsMatchingCurrentThread): * Modules/indexeddb/client/TransactionOperation.h: (WebCore::IDBClient::TransactionOperation::~TransactionOperation): (WebCore::IDBClient::TransactionOperation::perform): (WebCore::IDBClient::TransactionOperation::transitionToCompleteOnThisThread): (WebCore::IDBClient::TransactionOperation::transitionToComplete): (WebCore::IDBClient::TransactionOperation::doComplete): (WebCore::IDBClient::TransactionOperation::originThread const): (WebCore::IDBClient::TransactionOperation::originThreadID const): Deleted. * Modules/webaudio/AudioContext.cpp: (WebCore::AudioContext::AudioContext): (WebCore::AudioContext::lock): (WebCore::AudioContext::tryLock): (WebCore::AudioContext::unlock): (WebCore::AudioContext::isAudioThread const): (WebCore::AudioContext::isGraphOwner const): * Modules/webaudio/AudioContext.h: (WebCore::AudioContext::setAudioThread): (WebCore::AudioContext::audioThread const): * Modules/webaudio/AudioDestinationNode.cpp: (WebCore::AudioDestinationNode::render): * Modules/webdatabase/Database.cpp: (WebCore::Database::performClose): (WebCore::Database::securityOrigin): * Modules/webdatabase/DatabaseDetails.h: (WebCore::DatabaseDetails::DatabaseDetails): (WebCore::DatabaseDetails::operator=): (WebCore::DatabaseDetails::thread const): (WebCore::DatabaseDetails::threadID const): Deleted. * Modules/webdatabase/DatabaseManager.cpp: (WebCore::DatabaseManager::detailsForNameAndOrigin): * Modules/webdatabase/DatabaseThread.cpp: (WebCore::DatabaseThread::databaseThread): (WebCore::DatabaseThread::recordDatabaseOpen): (WebCore::DatabaseThread::recordDatabaseClosed): * Modules/webdatabase/DatabaseThread.h: (WebCore::DatabaseThread::getThread): (WebCore::DatabaseThread::getThreadID): Deleted. * Modules/webdatabase/SQLTransaction.cpp: (WebCore::SQLTransaction::checkAndHandleClosedDatabase): * Modules/webdatabase/SQLTransactionBackend.cpp: (WebCore::SQLTransactionBackend::doCleanup): (WebCore::SQLTransactionBackend::notifyDatabaseThreadIsShuttingDown): * bindings/js/JSCallbackData.h: (WebCore::JSCallbackData::JSCallbackData): (WebCore::JSCallbackData::~JSCallbackData): * bindings/js/ScheduledAction.cpp: (WebCore::ScheduledAction::execute): * dom/ScriptExecutionContext.cpp: (WebCore::ScriptExecutionContext::createdMessagePort): (WebCore::ScriptExecutionContext::destroyedMessagePort): * page/ResourceUsageOverlay.h: * page/scrolling/ScrollingThread.cpp: (WebCore::ScrollingThread::isCurrentThread): * platform/Supplementable.h: (WebCore::Supplementable::provideSupplement): (WebCore::Supplementable::removeSupplement): (WebCore::Supplementable::requireSupplement): (WebCore::Supplementable::Supplementable): Deleted. * platform/Timer.cpp: (WebCore::TimerBase::TimerBase): (WebCore::TimerBase::start): (WebCore::TimerBase::stop): (WebCore::TimerBase::setNextFireTime): * platform/Timer.h: (WebCore::TimerBase::isActive const): * platform/graphics/cocoa/FontCacheCoreText.cpp: (WebCore::shouldAutoActivateFontIfNeeded): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.cpp: (WebCore::TextureMapperPlatformLayerProxy::activateOnCompositingThread): (WebCore::TextureMapperPlatformLayerProxy::invalidate): (WebCore::TextureMapperPlatformLayerProxy::getAvailableBuffer): (WebCore::TextureMapperPlatformLayerProxy::appendToUnusedBuffers): (WebCore::TextureMapperPlatformLayerProxy::swapBuffer): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.h: (): Deleted. * platform/ios/wak/WebCoreThread.mm: (RunWebThread): (StartWebThread): * platform/sql/SQLiteDatabase.cpp: (WebCore::SQLiteDatabase::open): (WebCore::SQLiteDatabase::close): * platform/sql/SQLiteDatabase.h: (WebCore::SQLiteDatabase::sqlite3Handle const): * workers/WorkerGlobalScope.cpp: (WebCore::WorkerGlobalScope::~WorkerGlobalScope): (WebCore::WorkerGlobalScope::isContextThread const): * workers/WorkerMessagingProxy.cpp: (WebCore::WorkerMessagingProxy::WorkerMessagingProxy): (WebCore::WorkerMessagingProxy::~WorkerMessagingProxy): * workers/WorkerRunLoop.cpp: (WebCore::WorkerRunLoop::runInMode): (WebCore::WorkerRunLoop::runCleanupTasks): * workers/WorkerThread.h: (WebCore::WorkerThread::thread const): (WebCore::WorkerThread::threadID const): Deleted. * workers/service/ServiceWorkerContainer.cpp: (WebCore::ServiceWorkerContainer::~ServiceWorkerContainer): (WebCore::ServiceWorkerContainer::scheduleJob): (WebCore::ServiceWorkerContainer::jobFailedWithException): (WebCore::ServiceWorkerContainer::scheduleTaskToFireUpdateFoundEvent): (WebCore::ServiceWorkerContainer::jobResolvedWithRegistration): (WebCore::ServiceWorkerContainer::jobResolvedWithUnregistrationResult): (WebCore::ServiceWorkerContainer::startScriptFetchForJob): (WebCore::ServiceWorkerContainer::jobFinishedLoadingScript): (WebCore::ServiceWorkerContainer::jobFailedLoadingScript): (WebCore::ServiceWorkerContainer::jobDidFinish): (WebCore::ServiceWorkerContainer::addRegistration): (WebCore::ServiceWorkerContainer::removeRegistration): (WebCore::ServiceWorkerContainer::scheduleTaskToFireControllerChangeEvent): (WebCore::ServiceWorkerContainer::contextIdentifier): * workers/service/ServiceWorkerContainer.h: * workers/service/ServiceWorkerJob.cpp: (WebCore::ServiceWorkerJob::~ServiceWorkerJob): (WebCore::ServiceWorkerJob::failedWithException): (WebCore::ServiceWorkerJob::resolvedWithRegistration): (WebCore::ServiceWorkerJob::resolvedWithUnregistrationResult): (WebCore::ServiceWorkerJob::startScriptFetch): (WebCore::ServiceWorkerJob::fetchScriptWithContext): (WebCore::ServiceWorkerJob::didReceiveResponse): (WebCore::ServiceWorkerJob::notifyFinished): * workers/service/ServiceWorkerJob.h: * xml/parser/XMLDocumentParserLibxml2.cpp: (WebCore::matchFunc): (WebCore::openFunc): (WebCore::initializeXMLParser): (WebCore::XMLParserContext::createStringParser): (WebCore::XMLParserContext::createMemoryParser): Source/WebKit: * UIProcess/API/glib/IconDatabase.cpp: * UIProcess/GenericCallback.h: (WebKit::GenericCallback::~GenericCallback): (WebKit::GenericCallback::performCallbackWithReturnValue): Source/WTF: We should use a pointer of WTF::Thread instead of ThreadIdentifier. One problem is that Windows support library uses WTF::createThread, which returns ThreadIdentifier. So we cannot drop ThreadIdentifier in Windows environment. This patch keeps ThreadIdentifier in Windows. * wtf/MainThread.cpp: (WTF::initializeMainThread): (WTF::isMainThread): (WTF::canAccessThreadLocalDataForThread): * wtf/MainThread.h: * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkCount): * wtf/RecursiveLockAdapter.h: (WTF::RecursiveLockAdapter::lock): (WTF::RecursiveLockAdapter::unlock): (WTF::RecursiveLockAdapter::tryLock): * wtf/Threading.cpp: (WTF::Thread::dump const): * wtf/Threading.h: (WTF::Thread::id const): (WTF::Thread::operator==): Deleted. (WTF::Thread::operator!=): Deleted. (WTF::currentThread): Deleted. * wtf/ThreadingPrimitives.h: * wtf/ThreadingPthreads.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::detach): (WTF::Thread::initializeCurrentTLS): (WTF::Thread::suspend): (WTF::Thread::establishPlatformSpecificHandle): (WTF::Thread::currentID): Deleted. * wtf/ThreadingWin.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::suspend): (WTF::Thread::currentDying): * wtf/mac/MainThreadMac.mm: (WTF::initializeApplicationUIThread): (WTF::initializeWebThreadPlatform): (WTF::canAccessThreadLocalDataForThread): (WTF::initializeApplicationUIThreadIdentifier): Deleted. (WTF::initializeWebThreadIdentifier): Deleted. Tools: * DumpRenderTree/mac/DumpRenderTree.mm: (dumpRenderTree): (runThread): Deleted. (runPthread): Deleted. (testThreadIdentifierMap): Deleted. * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: * TestWebKitAPI/Tests/WTF/Threading.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/196314@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@225470 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-12-04 06:13:05 +00:00
dataLog(toString(Thread::current(), ": parking.\n"));
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
ThreadData* me = myThreadData();
WTF::Lock should be fair eventually https://bugs.webkit.org/show_bug.cgi?id=159384 Reviewed by Geoffrey Garen. Source/WTF: In https://webkit.org/blog/6161/locking-in-webkit/ we showed how relaxing the fairness of locks makes them fast. That post presented lock fairness as a trade-off between two extremes: - Barging. A barging lock, like WTF::Lock, releases the lock in unlock() even if there was a thread on the queue. If there was a thread on the queue, the lock is released and that thread is made runnable. That thread may then grab the lock, or some other thread may grab the lock first (it may barge). Usually, the barging thread is the thread that released the lock in the first place. This maximizes throughput but hurts fairness. There is no good theoretical bound on how unfair the lock may become, but empirical data suggests that it's fair enough for the cases we previously measured. - FIFO. A FIFO lock, like HandoffLock in ToyLocks.h, does not release the lock in unlock() if there is a thread waiting. If there is a thread waiting, unlock() will make that thread runnable and inform it that it now holds the lock. This ensures perfect round-robin fairness and allows us to reason theoretically about how long it may take for a thread to grab the lock. For example, if we know that only N threads are running and each one may contend on a critical section, and each one may hold the lock for at most S seconds, then the time it takes to grab the lock is N * S. Unfortunately, FIFO locks perform very badly in most cases. This is because for the common case of short critical sections, they force a context switch after each critical section if the lock is contended. This change makes WTF::Lock almost as fair as FIFO while still being as fast as barging. Thanks to this new algorithm, you can now have both of these things at the same time. This change makes WTF::Lock eventually fair. We can almost (more on the caveats below) guarantee that the time it takes to grab a lock is N * max(1ms, S). In other words, critical sections that are longer than 1ms are always fair. For shorter critical sections, the amount of time that any thread waits is 1ms times the number of threads. There are some caveats that arise from our use of randomness, but even then, in the limit as the critical section length goes to infinity, the lock becomes fair. The corner cases are unlikely to happen; our experiments show that the lock becomes exactly as fair as a FIFO lock for any critical section that is 1ms or longer. The fairness mechanism is broken into two parts. WTF::Lock can now choose to unlock a lock fairly or unfairly thanks to the new ParkingLot token mechanism. WTF::Lock knows when to use fair unlocking based on a timeout mechanism in ParkingLot called timeToBeFair. ParkingLot::unparkOne() and ParkingLot::parkConditionally() can now communicate with each other via a token. unparkOne() can pass a token, which parkConditionally() will return. This change also makes parkConditionally() a lot more precise about when it was unparked due to a call to unparkOne(). If unparkOne() is told that a thread was unparked then this thread is guaranteed to report that it was unparked rather than timing out, and that thread is guaranteed to get the token that unparkOne() passed. The token is an intptr_t. We use it as a boolean variable in WTF::Lock, but you could use it to pass arbitrary data structures. By default, the token is zero. WTF::Lock's unlock() will pass 1 as the token if it is doing fair unlocking. In that case, unlock() will not release the lock, and lock() will know that it holds the lock as soon as parkConditionally() returns. Note that this algorithm relies on unparkOne() invoking WTF::Lock's callback while the queue lock is held, so that WTF::Lock can make a decision about unlock strategy and inject a token while it has complete knowledge over the state of the queue. As such, it's not immediately obvious how to implement this algorithm on top of futexes. You really need ParkingLot! WTF::Lock does not use fair unlocking every time. We expose a new API, Lock::unlockFairly(), which forces the fair unlocking behavior. Additionally, ParkingLot now maintains a per-bucket stochastic fairness timeout. When the timeout fires, the unparkOne() callback sees UnparkResult::timeToBeFair = true. This timeout is set to be anywhere from 0ms to 1ms at random. When a dequeue happens and there are threads that actually get dequeued, we check if the time since the last unfair unlock (the last time timeToBeFair was set to true) is more than the timeout amount. If so, then we set timeToBeFair to true and reset the timeout. This means that in the absence of ParkingLot collisions, unfair unlocking is guaranteed to happen at least once per millisecond. It will happen at 2 KHz on average. If there are collisions, then each collision adds one millisecond to the worst case (and 0.5 ms to the average case). The reason why we don't just use a fixed 1ms timeout is that we want to avoid resonance. Imagine a program in which some thread acquires a lock at 1 KHz in-phase with the timeToBeFair timeout. Then this thread would be the benefactor of fairness to the detriment of everyone else. Randomness ensures that we aren't too fair to any one thread. Empirically, this is neutral on our major benchmarks like JetStream but it's an enormous improvement in LockFairnessTest. It's common for an unfair lock (either our BargingLock, the old WTF::Lock, any of the other futex-based locks that barge, or new os_unfair_lock) to allow only one thread to hold the lock during a whole second in which each thread is holding the lock for 1ms at a time. This is because in a barging lock, releasing a lock after holding it for 1ms and then reacquiring it immediately virtually ensures that none of the other threads can wake up in time to grab it before it's relocked. But the new WTF::Lock handles this case like a champ: each thread gets equal turns. Here's some data. If we launch 10 threads and have each of them run for 1 second while repeatedly holding a critical section for 1ms, then here's how many times each thread gets to hold the lock using the old WTF::Lock algorithm: 799, 6, 1, 1, 1, 1, 1, 1, 1, 1 One thread hogged the lock for almost the whole time! With the new WTF::Lock, the lock becomes totally fair: 80, 79, 79, 79, 79, 79, 79, 80, 80, 79 I don't know of anyone creating such an automatically-fair adaptive lock before, so I think that this is a pretty awesome advancement to the state of the art! This change is good for three reasons: - We do have long critical sections in WebKit and we don't want to have to worry about starvation. This reduces the likelihood that we will see starvation due to our lock strategy. - I was talking to ggaren about bmalloc's locking needs, and he wanted unlockFairly() or lockFairly() or some moral equivalent for the scavenger thread. - If we use a WTF::Lock to manage heap access in a multithreaded GC, we'll need the ability to unlock and relock without barging. * benchmarks/LockFairnessTest.cpp: (main): * benchmarks/ToyLocks.h: * wtf/Condition.h: (WTF::ConditionBase::waitUntil): (WTF::ConditionBase::notifyOne): * wtf/Lock.cpp: (WTF::LockBase::lockSlow): (WTF::LockBase::unlockSlow): (WTF::LockBase::unlockFairlySlow): (WTF::LockBase::unlockSlowImpl): * wtf/Lock.h: (WTF::LockBase::try_lock): (WTF::LockBase::unlock): (WTF::LockBase::unlockFairly): (WTF::LockBase::isHeld): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::compareAndPark): (WTF::ParkingLot::unparkOne): Tools: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Canonical link: https://commits.webkit.org/178039@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@203350 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-07-18 18:32:52 +00:00
me->token = 0;
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
WTF should have a compact Condition object to use with Lock https://bugs.webkit.org/show_bug.cgi?id=147986 Reviewed by Geoffrey Garen. Source/WTF: Adds a condition variable implementation based on ParkingLot, called simply WTF::Condition. It can be used with WTF::Lock or actually any lock implementation. It should even work with WTF::SpinLock, WTF::Mutex, or std::mutex. Best of all, Condition only requires one byte. ParkingLot almost contained all of the functionality needed to implemenet wait/notify. We could have implemented Condition using a 32-bit (or even 64-bit) version that protects against a notify that happens just before we park. But, this changes the ParkingLot API to give us the ability to run some code between when ParkingLot enqueues the current thread and when it actually sleeps. This callback is called with no locks held, so it can call unlock() on any kind of lock, so long as that lock's unlock() method doesn't recurse into ParkingLot::parkConditionally(). That seems unlikely; unlock() is more likely to call ParkingLot::unparkOne() or unparkAll(). WTF::Lock will never call parkConditionally() inside unlock(), so WTF::Lock is definitely appropriate for use with Condition. Condition supports most of the API that std::condition_variable supports. It does some things to try to reduce footgun potential. The preferred timeout form is waitUntil() which takes an absolute time from the steady_clock. The only relative timeout form also takes a predicate callback, so it's impossible to write the subtly incorrect "while (...) wait_for(...)" idiom. This patch doesn't actually introduce any uses of WTF::Condition other than the unit tests. I'll start switching code over to using WTF::Condition in another patch. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/Condition.h: Added. (WTF::Condition::Condition): (WTF::Condition::waitUntil): (WTF::Condition::waitFor): (WTF::Condition::wait): (WTF::Condition::notifyOne): (WTF::Condition::notifyAll): * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): Make this useful assertion be a release assertion. It catches cases where you unlock the lock even though you don't hold it. * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): Add the beforeSleep() callback. (WTF::ParkingLot::unparkOne): * wtf/ParkingLot.h: (WTF::ParkingLot::compareAndPark): Tools: Add a test for WTF::Condition. * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Condition.cpp: Added. (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::runLockTest): Change the name of the thread. Canonical link: https://commits.webkit.org/166094@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188400 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 20:42:11 +00:00
// Guard against someone calling parkConditionally() recursively from beforeSleep().
RELEASE_ASSERT(!me->address);
WTF::Lock should be fair eventually https://bugs.webkit.org/show_bug.cgi?id=159384 Reviewed by Geoffrey Garen. Source/WTF: In https://webkit.org/blog/6161/locking-in-webkit/ we showed how relaxing the fairness of locks makes them fast. That post presented lock fairness as a trade-off between two extremes: - Barging. A barging lock, like WTF::Lock, releases the lock in unlock() even if there was a thread on the queue. If there was a thread on the queue, the lock is released and that thread is made runnable. That thread may then grab the lock, or some other thread may grab the lock first (it may barge). Usually, the barging thread is the thread that released the lock in the first place. This maximizes throughput but hurts fairness. There is no good theoretical bound on how unfair the lock may become, but empirical data suggests that it's fair enough for the cases we previously measured. - FIFO. A FIFO lock, like HandoffLock in ToyLocks.h, does not release the lock in unlock() if there is a thread waiting. If there is a thread waiting, unlock() will make that thread runnable and inform it that it now holds the lock. This ensures perfect round-robin fairness and allows us to reason theoretically about how long it may take for a thread to grab the lock. For example, if we know that only N threads are running and each one may contend on a critical section, and each one may hold the lock for at most S seconds, then the time it takes to grab the lock is N * S. Unfortunately, FIFO locks perform very badly in most cases. This is because for the common case of short critical sections, they force a context switch after each critical section if the lock is contended. This change makes WTF::Lock almost as fair as FIFO while still being as fast as barging. Thanks to this new algorithm, you can now have both of these things at the same time. This change makes WTF::Lock eventually fair. We can almost (more on the caveats below) guarantee that the time it takes to grab a lock is N * max(1ms, S). In other words, critical sections that are longer than 1ms are always fair. For shorter critical sections, the amount of time that any thread waits is 1ms times the number of threads. There are some caveats that arise from our use of randomness, but even then, in the limit as the critical section length goes to infinity, the lock becomes fair. The corner cases are unlikely to happen; our experiments show that the lock becomes exactly as fair as a FIFO lock for any critical section that is 1ms or longer. The fairness mechanism is broken into two parts. WTF::Lock can now choose to unlock a lock fairly or unfairly thanks to the new ParkingLot token mechanism. WTF::Lock knows when to use fair unlocking based on a timeout mechanism in ParkingLot called timeToBeFair. ParkingLot::unparkOne() and ParkingLot::parkConditionally() can now communicate with each other via a token. unparkOne() can pass a token, which parkConditionally() will return. This change also makes parkConditionally() a lot more precise about when it was unparked due to a call to unparkOne(). If unparkOne() is told that a thread was unparked then this thread is guaranteed to report that it was unparked rather than timing out, and that thread is guaranteed to get the token that unparkOne() passed. The token is an intptr_t. We use it as a boolean variable in WTF::Lock, but you could use it to pass arbitrary data structures. By default, the token is zero. WTF::Lock's unlock() will pass 1 as the token if it is doing fair unlocking. In that case, unlock() will not release the lock, and lock() will know that it holds the lock as soon as parkConditionally() returns. Note that this algorithm relies on unparkOne() invoking WTF::Lock's callback while the queue lock is held, so that WTF::Lock can make a decision about unlock strategy and inject a token while it has complete knowledge over the state of the queue. As such, it's not immediately obvious how to implement this algorithm on top of futexes. You really need ParkingLot! WTF::Lock does not use fair unlocking every time. We expose a new API, Lock::unlockFairly(), which forces the fair unlocking behavior. Additionally, ParkingLot now maintains a per-bucket stochastic fairness timeout. When the timeout fires, the unparkOne() callback sees UnparkResult::timeToBeFair = true. This timeout is set to be anywhere from 0ms to 1ms at random. When a dequeue happens and there are threads that actually get dequeued, we check if the time since the last unfair unlock (the last time timeToBeFair was set to true) is more than the timeout amount. If so, then we set timeToBeFair to true and reset the timeout. This means that in the absence of ParkingLot collisions, unfair unlocking is guaranteed to happen at least once per millisecond. It will happen at 2 KHz on average. If there are collisions, then each collision adds one millisecond to the worst case (and 0.5 ms to the average case). The reason why we don't just use a fixed 1ms timeout is that we want to avoid resonance. Imagine a program in which some thread acquires a lock at 1 KHz in-phase with the timeToBeFair timeout. Then this thread would be the benefactor of fairness to the detriment of everyone else. Randomness ensures that we aren't too fair to any one thread. Empirically, this is neutral on our major benchmarks like JetStream but it's an enormous improvement in LockFairnessTest. It's common for an unfair lock (either our BargingLock, the old WTF::Lock, any of the other futex-based locks that barge, or new os_unfair_lock) to allow only one thread to hold the lock during a whole second in which each thread is holding the lock for 1ms at a time. This is because in a barging lock, releasing a lock after holding it for 1ms and then reacquiring it immediately virtually ensures that none of the other threads can wake up in time to grab it before it's relocked. But the new WTF::Lock handles this case like a champ: each thread gets equal turns. Here's some data. If we launch 10 threads and have each of them run for 1 second while repeatedly holding a critical section for 1ms, then here's how many times each thread gets to hold the lock using the old WTF::Lock algorithm: 799, 6, 1, 1, 1, 1, 1, 1, 1, 1 One thread hogged the lock for almost the whole time! With the new WTF::Lock, the lock becomes totally fair: 80, 79, 79, 79, 79, 79, 79, 80, 80, 79 I don't know of anyone creating such an automatically-fair adaptive lock before, so I think that this is a pretty awesome advancement to the state of the art! This change is good for three reasons: - We do have long critical sections in WebKit and we don't want to have to worry about starvation. This reduces the likelihood that we will see starvation due to our lock strategy. - I was talking to ggaren about bmalloc's locking needs, and he wanted unlockFairly() or lockFairly() or some moral equivalent for the scavenger thread. - If we use a WTF::Lock to manage heap access in a multithreaded GC, we'll need the ability to unlock and relock without barging. * benchmarks/LockFairnessTest.cpp: (main): * benchmarks/ToyLocks.h: * wtf/Condition.h: (WTF::ConditionBase::waitUntil): (WTF::ConditionBase::notifyOne): * wtf/Lock.cpp: (WTF::LockBase::lockSlow): (WTF::LockBase::unlockSlow): (WTF::LockBase::unlockFairlySlow): (WTF::LockBase::unlockSlowImpl): * wtf/Lock.h: (WTF::LockBase::try_lock): (WTF::LockBase::unlock): (WTF::LockBase::unlockFairly): (WTF::LockBase::isHeld): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::compareAndPark): (WTF::ParkingLot::unparkOne): Tools: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Canonical link: https://commits.webkit.org/178039@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@203350 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-07-18 18:32:52 +00:00
bool enqueueResult = enqueue(
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
address,
[&] () -> ThreadData* {
if (!validation())
return nullptr;
me->address = address;
return me;
});
WTF::Lock should be fair eventually https://bugs.webkit.org/show_bug.cgi?id=159384 Reviewed by Geoffrey Garen. Source/WTF: In https://webkit.org/blog/6161/locking-in-webkit/ we showed how relaxing the fairness of locks makes them fast. That post presented lock fairness as a trade-off between two extremes: - Barging. A barging lock, like WTF::Lock, releases the lock in unlock() even if there was a thread on the queue. If there was a thread on the queue, the lock is released and that thread is made runnable. That thread may then grab the lock, or some other thread may grab the lock first (it may barge). Usually, the barging thread is the thread that released the lock in the first place. This maximizes throughput but hurts fairness. There is no good theoretical bound on how unfair the lock may become, but empirical data suggests that it's fair enough for the cases we previously measured. - FIFO. A FIFO lock, like HandoffLock in ToyLocks.h, does not release the lock in unlock() if there is a thread waiting. If there is a thread waiting, unlock() will make that thread runnable and inform it that it now holds the lock. This ensures perfect round-robin fairness and allows us to reason theoretically about how long it may take for a thread to grab the lock. For example, if we know that only N threads are running and each one may contend on a critical section, and each one may hold the lock for at most S seconds, then the time it takes to grab the lock is N * S. Unfortunately, FIFO locks perform very badly in most cases. This is because for the common case of short critical sections, they force a context switch after each critical section if the lock is contended. This change makes WTF::Lock almost as fair as FIFO while still being as fast as barging. Thanks to this new algorithm, you can now have both of these things at the same time. This change makes WTF::Lock eventually fair. We can almost (more on the caveats below) guarantee that the time it takes to grab a lock is N * max(1ms, S). In other words, critical sections that are longer than 1ms are always fair. For shorter critical sections, the amount of time that any thread waits is 1ms times the number of threads. There are some caveats that arise from our use of randomness, but even then, in the limit as the critical section length goes to infinity, the lock becomes fair. The corner cases are unlikely to happen; our experiments show that the lock becomes exactly as fair as a FIFO lock for any critical section that is 1ms or longer. The fairness mechanism is broken into two parts. WTF::Lock can now choose to unlock a lock fairly or unfairly thanks to the new ParkingLot token mechanism. WTF::Lock knows when to use fair unlocking based on a timeout mechanism in ParkingLot called timeToBeFair. ParkingLot::unparkOne() and ParkingLot::parkConditionally() can now communicate with each other via a token. unparkOne() can pass a token, which parkConditionally() will return. This change also makes parkConditionally() a lot more precise about when it was unparked due to a call to unparkOne(). If unparkOne() is told that a thread was unparked then this thread is guaranteed to report that it was unparked rather than timing out, and that thread is guaranteed to get the token that unparkOne() passed. The token is an intptr_t. We use it as a boolean variable in WTF::Lock, but you could use it to pass arbitrary data structures. By default, the token is zero. WTF::Lock's unlock() will pass 1 as the token if it is doing fair unlocking. In that case, unlock() will not release the lock, and lock() will know that it holds the lock as soon as parkConditionally() returns. Note that this algorithm relies on unparkOne() invoking WTF::Lock's callback while the queue lock is held, so that WTF::Lock can make a decision about unlock strategy and inject a token while it has complete knowledge over the state of the queue. As such, it's not immediately obvious how to implement this algorithm on top of futexes. You really need ParkingLot! WTF::Lock does not use fair unlocking every time. We expose a new API, Lock::unlockFairly(), which forces the fair unlocking behavior. Additionally, ParkingLot now maintains a per-bucket stochastic fairness timeout. When the timeout fires, the unparkOne() callback sees UnparkResult::timeToBeFair = true. This timeout is set to be anywhere from 0ms to 1ms at random. When a dequeue happens and there are threads that actually get dequeued, we check if the time since the last unfair unlock (the last time timeToBeFair was set to true) is more than the timeout amount. If so, then we set timeToBeFair to true and reset the timeout. This means that in the absence of ParkingLot collisions, unfair unlocking is guaranteed to happen at least once per millisecond. It will happen at 2 KHz on average. If there are collisions, then each collision adds one millisecond to the worst case (and 0.5 ms to the average case). The reason why we don't just use a fixed 1ms timeout is that we want to avoid resonance. Imagine a program in which some thread acquires a lock at 1 KHz in-phase with the timeToBeFair timeout. Then this thread would be the benefactor of fairness to the detriment of everyone else. Randomness ensures that we aren't too fair to any one thread. Empirically, this is neutral on our major benchmarks like JetStream but it's an enormous improvement in LockFairnessTest. It's common for an unfair lock (either our BargingLock, the old WTF::Lock, any of the other futex-based locks that barge, or new os_unfair_lock) to allow only one thread to hold the lock during a whole second in which each thread is holding the lock for 1ms at a time. This is because in a barging lock, releasing a lock after holding it for 1ms and then reacquiring it immediately virtually ensures that none of the other threads can wake up in time to grab it before it's relocked. But the new WTF::Lock handles this case like a champ: each thread gets equal turns. Here's some data. If we launch 10 threads and have each of them run for 1 second while repeatedly holding a critical section for 1ms, then here's how many times each thread gets to hold the lock using the old WTF::Lock algorithm: 799, 6, 1, 1, 1, 1, 1, 1, 1, 1 One thread hogged the lock for almost the whole time! With the new WTF::Lock, the lock becomes totally fair: 80, 79, 79, 79, 79, 79, 79, 80, 80, 79 I don't know of anyone creating such an automatically-fair adaptive lock before, so I think that this is a pretty awesome advancement to the state of the art! This change is good for three reasons: - We do have long critical sections in WebKit and we don't want to have to worry about starvation. This reduces the likelihood that we will see starvation due to our lock strategy. - I was talking to ggaren about bmalloc's locking needs, and he wanted unlockFairly() or lockFairly() or some moral equivalent for the scavenger thread. - If we use a WTF::Lock to manage heap access in a multithreaded GC, we'll need the ability to unlock and relock without barging. * benchmarks/LockFairnessTest.cpp: (main): * benchmarks/ToyLocks.h: * wtf/Condition.h: (WTF::ConditionBase::waitUntil): (WTF::ConditionBase::notifyOne): * wtf/Lock.cpp: (WTF::LockBase::lockSlow): (WTF::LockBase::unlockSlow): (WTF::LockBase::unlockFairlySlow): (WTF::LockBase::unlockSlowImpl): * wtf/Lock.h: (WTF::LockBase::try_lock): (WTF::LockBase::unlock): (WTF::LockBase::unlockFairly): (WTF::LockBase::isHeld): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::compareAndPark): (WTF::ParkingLot::unparkOne): Tools: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Canonical link: https://commits.webkit.org/178039@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@203350 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-07-18 18:32:52 +00:00
if (!enqueueResult)
return ParkResult();
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
WTF should have a compact Condition object to use with Lock https://bugs.webkit.org/show_bug.cgi?id=147986 Reviewed by Geoffrey Garen. Source/WTF: Adds a condition variable implementation based on ParkingLot, called simply WTF::Condition. It can be used with WTF::Lock or actually any lock implementation. It should even work with WTF::SpinLock, WTF::Mutex, or std::mutex. Best of all, Condition only requires one byte. ParkingLot almost contained all of the functionality needed to implemenet wait/notify. We could have implemented Condition using a 32-bit (or even 64-bit) version that protects against a notify that happens just before we park. But, this changes the ParkingLot API to give us the ability to run some code between when ParkingLot enqueues the current thread and when it actually sleeps. This callback is called with no locks held, so it can call unlock() on any kind of lock, so long as that lock's unlock() method doesn't recurse into ParkingLot::parkConditionally(). That seems unlikely; unlock() is more likely to call ParkingLot::unparkOne() or unparkAll(). WTF::Lock will never call parkConditionally() inside unlock(), so WTF::Lock is definitely appropriate for use with Condition. Condition supports most of the API that std::condition_variable supports. It does some things to try to reduce footgun potential. The preferred timeout form is waitUntil() which takes an absolute time from the steady_clock. The only relative timeout form also takes a predicate callback, so it's impossible to write the subtly incorrect "while (...) wait_for(...)" idiom. This patch doesn't actually introduce any uses of WTF::Condition other than the unit tests. I'll start switching code over to using WTF::Condition in another patch. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/Condition.h: Added. (WTF::Condition::Condition): (WTF::Condition::waitUntil): (WTF::Condition::waitFor): (WTF::Condition::wait): (WTF::Condition::notifyOne): (WTF::Condition::notifyAll): * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): Make this useful assertion be a release assertion. It catches cases where you unlock the lock even though you don't hold it. * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): Add the beforeSleep() callback. (WTF::ParkingLot::unparkOne): * wtf/ParkingLot.h: (WTF::ParkingLot::compareAndPark): Tools: Add a test for WTF::Condition. * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Condition.cpp: Added. (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::runLockTest): Change the name of the thread. Canonical link: https://commits.webkit.org/166094@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188400 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 20:42:11 +00:00
beforeSleep();
Use WTF::Lock and WTF::Condition instead of WTF::Mutex, WTF::ThreadCondition, std::mutex, and std::condition_variable https://bugs.webkit.org/show_bug.cgi?id=147999 Reviewed by Geoffrey Garen. Source/JavaScriptCore: * API/JSVirtualMachine.mm: (initWrapperCache): (+[JSVMWrapperCache addWrapper:forJSContextGroupRef:]): (+[JSVMWrapperCache wrapperForJSContextGroupRef:]): (wrapperCacheMutex): Deleted. * bytecode/SamplingTool.cpp: (JSC::SamplingTool::doRun): (JSC::SamplingTool::notifyOfScope): * bytecode/SamplingTool.h: * dfg/DFGThreadData.h: * dfg/DFGWorklist.cpp: (JSC::DFG::Worklist::~Worklist): (JSC::DFG::Worklist::isActiveForVM): (JSC::DFG::Worklist::enqueue): (JSC::DFG::Worklist::compilationState): (JSC::DFG::Worklist::waitUntilAllPlansForVMAreReady): (JSC::DFG::Worklist::removeAllReadyPlansForVM): (JSC::DFG::Worklist::completeAllReadyPlansForVM): (JSC::DFG::Worklist::visitWeakReferences): (JSC::DFG::Worklist::removeDeadPlans): (JSC::DFG::Worklist::queueLength): (JSC::DFG::Worklist::dump): (JSC::DFG::Worklist::runThread): * dfg/DFGWorklist.h: * disassembler/Disassembler.cpp: * heap/CopiedSpace.cpp: (JSC::CopiedSpace::doneFillingBlock): (JSC::CopiedSpace::doneCopying): * heap/CopiedSpace.h: * heap/CopiedSpaceInlines.h: (JSC::CopiedSpace::recycleBorrowedBlock): (JSC::CopiedSpace::allocateBlockForCopyingPhase): * heap/GCThread.cpp: (JSC::GCThread::waitForNextPhase): (JSC::GCThread::gcThreadMain): * heap/GCThreadSharedData.cpp: (JSC::GCThreadSharedData::GCThreadSharedData): (JSC::GCThreadSharedData::~GCThreadSharedData): (JSC::GCThreadSharedData::startNextPhase): (JSC::GCThreadSharedData::endCurrentPhase): (JSC::GCThreadSharedData::didStartMarking): (JSC::GCThreadSharedData::didFinishMarking): * heap/GCThreadSharedData.h: * heap/HeapTimer.h: * heap/MachineStackMarker.cpp: (JSC::ActiveMachineThreadsManager::Locker::Locker): (JSC::ActiveMachineThreadsManager::add): (JSC::ActiveMachineThreadsManager::remove): (JSC::ActiveMachineThreadsManager::ActiveMachineThreadsManager): (JSC::MachineThreads::~MachineThreads): (JSC::MachineThreads::addCurrentThread): (JSC::MachineThreads::removeThreadIfFound): (JSC::MachineThreads::tryCopyOtherThreadStack): (JSC::MachineThreads::tryCopyOtherThreadStacks): (JSC::MachineThreads::gatherConservativeRoots): * heap/MachineStackMarker.h: * heap/SlotVisitor.cpp: (JSC::SlotVisitor::donateKnownParallel): (JSC::SlotVisitor::drain): (JSC::SlotVisitor::drainFromShared): (JSC::SlotVisitor::mergeOpaqueRoots): * heap/SlotVisitorInlines.h: (JSC::SlotVisitor::containsOpaqueRootTriState): * inspector/remote/RemoteInspectorDebuggableConnection.h: * inspector/remote/RemoteInspectorDebuggableConnection.mm: (Inspector::RemoteInspectorHandleRunSourceGlobal): (Inspector::RemoteInspectorQueueTaskOnGlobalQueue): (Inspector::RemoteInspectorInitializeGlobalQueue): (Inspector::RemoteInspectorHandleRunSourceWithInfo): (Inspector::RemoteInspectorDebuggableConnection::setup): (Inspector::RemoteInspectorDebuggableConnection::closeFromDebuggable): (Inspector::RemoteInspectorDebuggableConnection::close): (Inspector::RemoteInspectorDebuggableConnection::sendMessageToBackend): (Inspector::RemoteInspectorDebuggableConnection::queueTaskOnPrivateRunLoop): * interpreter/JSStack.cpp: (JSC::JSStack::JSStack): (JSC::JSStack::releaseExcessCapacity): (JSC::JSStack::addToCommittedByteCount): (JSC::JSStack::committedByteCount): (JSC::stackStatisticsMutex): Deleted. (JSC::JSStack::initializeThreading): Deleted. * interpreter/JSStack.h: (JSC::JSStack::gatherConservativeRoots): (JSC::JSStack::sanitizeStack): (JSC::JSStack::size): (JSC::JSStack::initializeThreading): Deleted. * jit/ExecutableAllocator.cpp: (JSC::DemandExecutableAllocator::DemandExecutableAllocator): (JSC::DemandExecutableAllocator::~DemandExecutableAllocator): (JSC::DemandExecutableAllocator::bytesAllocatedByAllAllocators): (JSC::DemandExecutableAllocator::bytesCommittedByAllocactors): (JSC::DemandExecutableAllocator::dumpProfileFromAllAllocators): (JSC::DemandExecutableAllocator::allocators): (JSC::DemandExecutableAllocator::allocatorsMutex): * jit/JITThunks.cpp: (JSC::JITThunks::ctiStub): * jit/JITThunks.h: * profiler/ProfilerDatabase.cpp: (JSC::Profiler::Database::ensureBytecodesFor): (JSC::Profiler::Database::notifyDestruction): * profiler/ProfilerDatabase.h: * runtime/InitializeThreading.cpp: (JSC::initializeThreading): * runtime/JSLock.cpp: (JSC::GlobalJSLock::GlobalJSLock): (JSC::GlobalJSLock::~GlobalJSLock): (JSC::JSLockHolder::JSLockHolder): (JSC::GlobalJSLock::initialize): Deleted. * runtime/JSLock.h: Source/WTF: Relanding after fixing a deadlock on Linux. * wtf/Condition.h: "using WTF::Condition". * wtf/Lock.h: (WTF::LockBase::lock): (WTF::LockBase::tryLock): Add tryLock() because it turns out that we use it sometimes. (WTF::LockBase::try_lock): unique_lock needs this. (WTF::LockBase::unlock): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): Work around a Linux C++ bug where wait_until with time_point::max() immediately returns and doesn't flash the lock. Canonical link: https://commits.webkit.org/166166@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188499 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-15 00:14:52 +00:00
WTF should have a compact Condition object to use with Lock https://bugs.webkit.org/show_bug.cgi?id=147986 Reviewed by Geoffrey Garen. Source/WTF: Adds a condition variable implementation based on ParkingLot, called simply WTF::Condition. It can be used with WTF::Lock or actually any lock implementation. It should even work with WTF::SpinLock, WTF::Mutex, or std::mutex. Best of all, Condition only requires one byte. ParkingLot almost contained all of the functionality needed to implemenet wait/notify. We could have implemented Condition using a 32-bit (or even 64-bit) version that protects against a notify that happens just before we park. But, this changes the ParkingLot API to give us the ability to run some code between when ParkingLot enqueues the current thread and when it actually sleeps. This callback is called with no locks held, so it can call unlock() on any kind of lock, so long as that lock's unlock() method doesn't recurse into ParkingLot::parkConditionally(). That seems unlikely; unlock() is more likely to call ParkingLot::unparkOne() or unparkAll(). WTF::Lock will never call parkConditionally() inside unlock(), so WTF::Lock is definitely appropriate for use with Condition. Condition supports most of the API that std::condition_variable supports. It does some things to try to reduce footgun potential. The preferred timeout form is waitUntil() which takes an absolute time from the steady_clock. The only relative timeout form also takes a predicate callback, so it's impossible to write the subtly incorrect "while (...) wait_for(...)" idiom. This patch doesn't actually introduce any uses of WTF::Condition other than the unit tests. I'll start switching code over to using WTF::Condition in another patch. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/Condition.h: Added. (WTF::Condition::Condition): (WTF::Condition::waitUntil): (WTF::Condition::waitFor): (WTF::Condition::wait): (WTF::Condition::notifyOne): (WTF::Condition::notifyAll): * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): Make this useful assertion be a release assertion. It catches cases where you unlock the lock even though you don't hold it. * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): Add the beforeSleep() callback. (WTF::ParkingLot::unparkOne): * wtf/ParkingLot.h: (WTF::ParkingLot::compareAndPark): Tools: Add a test for WTF::Condition. * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Condition.cpp: Added. (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::runLockTest): Change the name of the thread. Canonical link: https://commits.webkit.org/166094@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188400 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 20:42:11 +00:00
bool didGetDequeued;
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
{
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): Canonical link: https://commits.webkit.org/182152@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208415 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-11-05 03:02:39 +00:00
MutexLocker locker(me->parkingLock);
while (me->address && timeout.nowWithSameClock() < timeout) {
me->parkingCondition.timedWait(
Remove currentTime() / currentTimeMS() https://bugs.webkit.org/show_bug.cgi?id=183052 Reviewed by Mark Lam. Source/WebCore: * Modules/geolocation/Geolocation.cpp: (WebCore::Geolocation::haveSuitableCachedPosition): * dom/DOMTimeStamp.h: (WebCore::convertSecondsToDOMTimeStamp): * fileapi/File.cpp: (WebCore::File::File): (WebCore::File::lastModified const): * history/HistoryItem.cpp: (WebCore::generateSequenceNumber): * html/BaseDateAndTimeInputType.cpp: (WebCore::BaseDateAndTimeInputType::defaultValueForStepUp const): * html/DateTimeInputType.cpp: (WebCore::DateTimeInputType::defaultValueForStepUp const): * html/MonthInputType.cpp: (WebCore::MonthInputType::defaultValueForStepUp const): * html/TimeInputType.cpp: (WebCore::TimeInputType::defaultValueForStepUp const): * inspector/agents/InspectorNetworkAgent.cpp: (WebCore::InspectorNetworkAgent::willSendRequest): (WebCore::InspectorNetworkAgent::willSendWebSocketHandshakeRequest): * loader/EmptyFrameLoaderClient.h: * loader/FormSubmission.cpp: (WebCore::generateFormDataIdentifier): * loader/FrameLoader.cpp: (WebCore::FrameLoader::clientRedirected): * loader/FrameLoader.h: * loader/FrameLoaderClient.h: * loader/NavigationScheduler.cpp: * page/History.cpp: (WebCore::History::stateObjectAdded): * page/History.h: * page/PageOverlay.cpp: (WebCore::PageOverlay::startFadeAnimation): (WebCore::PageOverlay::fadeAnimationTimerFired): * page/PageOverlay.h: * platform/graphics/cg/GraphicsContextCG.cpp: (WebCore::GraphicsContext::drawNativeImage): * platform/ios/LegacyTileLayerPool.h: * platform/ios/LegacyTileLayerPool.mm: (WebCore::LegacyTileLayerPool::LegacyTileLayerPool): (WebCore::LegacyTileLayerPool::addLayer): (WebCore::LegacyTileLayerPool::decayedCapacity const): (WebCore::LegacyTileLayerPool::prune): * platform/ios/SystemMemoryIOS.cpp: (WebCore::systemMemoryLevel): * platform/mediastream/mac/DisplayCaptureSourceCocoa.cpp: * platform/mediastream/mac/ScreenDisplayCaptureSourceMac.mm: Source/WebKit: * NetworkProcess/cache/CacheStorageEngineCache.cpp: * PluginProcess/WebProcessConnection.cpp: * Shared/WebProcessCreationParameters.h: * Shared/linux/WebMemorySamplerLinux.cpp: (WebKit::WebMemorySampler::sampleWebKit const): * Shared/mac/WebMemorySampler.mac.mm: (WebKit::WebMemorySampler::sampleWebKit const): * UIProcess/API/C/WKContext.cpp: (WKContextSetPlugInAutoStartOriginsFilteringOutEntriesAddedAfterTime): * UIProcess/API/glib/IconDatabase.cpp: (WebKit::IconDatabase::setIconDataForIconURL): (WebKit::IconDatabase::synchronousLoadDecisionForIconURL): (WebKit::IconDatabase::performURLImport): * UIProcess/DrawingAreaProxyImpl.cpp: * UIProcess/Plugins/PlugInAutoStartProvider.cpp: (WebKit::expirationTimeFromNow): (WebKit::PlugInAutoStartProvider::addAutoStartOriginHash): (WebKit::PlugInAutoStartProvider::autoStartOriginsTableCopy const): (WebKit::PlugInAutoStartProvider::setAutoStartOriginsTable): (WebKit::PlugInAutoStartProvider::setAutoStartOriginsFilteringOutEntriesAddedAfterTime): (WebKit::PlugInAutoStartProvider::setAutoStartOriginsTableWithItemsPassingTest): (WebKit::PlugInAutoStartProvider::didReceiveUserInteraction): * UIProcess/Plugins/PlugInAutoStartProvider.h: * UIProcess/WebProcessPool.cpp: (WebKit::WebProcessPool::processDidFinishLaunching): (WebKit::WebProcessPool::startMemorySampler): (WebKit::WebProcessPool::setPlugInAutoStartOriginsFilteringOutEntriesAddedAfterTime): * UIProcess/WebProcessPool.h: * WebProcess/InjectedBundle/API/APIInjectedBundlePageLoaderClient.h: (API::InjectedBundle::PageLoaderClient::willPerformClientRedirectForFrame): * WebProcess/InjectedBundle/InjectedBundlePageLoaderClient.cpp: (WebKit::InjectedBundlePageLoaderClient::willPerformClientRedirectForFrame): * WebProcess/InjectedBundle/InjectedBundlePageLoaderClient.h: * WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp: (WebKit::WebFrameLoaderClient::dispatchWillPerformClientRedirect): * WebProcess/WebCoreSupport/WebFrameLoaderClient.h: * WebProcess/WebProcess.cpp: (WebKit::m_webSQLiteDatabaseTracker): (WebKit::WebProcess::isPlugInAutoStartOriginHash): (WebKit::WebProcess::plugInDidStartFromOrigin): (WebKit::WebProcess::didAddPlugInAutoStartOriginHash): (WebKit::WebProcess::resetPlugInAutoStartOriginDefaultHashes): (WebKit::WebProcess::resetPlugInAutoStartOriginHashes): (WebKit::WebProcess::plugInDidReceiveUserInteraction): * WebProcess/WebProcess.h: * WebProcess/WebProcess.messages.in: * WebProcess/cocoa/WebProcessCocoa.mm: * WebProcess/wpe/WebProcessMainWPE.cpp: Source/WebKitLegacy/mac: * WebCoreSupport/WebFrameLoaderClient.h: * WebCoreSupport/WebFrameLoaderClient.mm: (WebFrameLoaderClient::dispatchWillPerformClientRedirect): Source/WebKitLegacy/win: * WebCoreSupport/WebFrameLoaderClient.cpp: (WebFrameLoaderClient::dispatchWillPerformClientRedirect): * WebCoreSupport/WebFrameLoaderClient.h: * WebDownload.h: * WebDownloadCFNet.cpp: (WebDownload::didStart): (WebDownload::didReceiveData): (WebDownload::didFinish): Source/WTF: This patch removes WTF::currentTime() and WTF::currentTimeMS(). We have fancy WallTime APIs. It has strong types like WallTime and Seconds, and this reduces the chance of bugs mixing doubles which represent milliseconds and seconds. * wtf/Condition.h: * wtf/CurrentTime.cpp: (WTF::currentTime): (WTF::WallTime::now): * wtf/CurrentTime.h: (WTF::currentTimeMS): Deleted. * wtf/DateMath.h: (WTF::jsCurrentTime): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): * wtf/ThreadingPrimitives.h: * wtf/ThreadingPthreads.cpp: (WTF::ThreadCondition::timedWait): * wtf/ThreadingWin.cpp: (WTF::ThreadCondition::timedWait): (WTF::absoluteTimeToWaitTimeoutInterval): * wtf/WallTime.cpp: (WTF::WallTime::now): Deleted. * wtf/WallTime.h: Tools: * DumpRenderTree/TestRunner.cpp: (preciseTimeCallback): * DumpRenderTree/mac/TestRunnerMac.mm: (TestRunner::setMockGeolocationPosition): * TestWebKitAPI/Tests/WTF/Condition.cpp: * TestWebKitAPI/Tests/WTF/ThreadGroup.cpp: * TestWebKitAPI/Tests/WTF/WorkQueue.cpp: * WebKitTestRunner/GeolocationProviderMock.cpp: (WTR::GeolocationProviderMock::setPosition): * WebKitTestRunner/InjectedBundle/TestRunner.cpp: (WTR::TestRunner::preciseTime): Canonical link: https://commits.webkit.org/198809@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@228942 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2018-02-23 04:18:17 +00:00
me->parkingLock, timeout.approximateWallTime());
Use WTF::Lock and WTF::Condition instead of WTF::Mutex, WTF::ThreadCondition, std::mutex, and std::condition_variable https://bugs.webkit.org/show_bug.cgi?id=147999 Reviewed by Geoffrey Garen. Source/JavaScriptCore: * API/JSVirtualMachine.mm: (initWrapperCache): (+[JSVMWrapperCache addWrapper:forJSContextGroupRef:]): (+[JSVMWrapperCache wrapperForJSContextGroupRef:]): (wrapperCacheMutex): Deleted. * bytecode/SamplingTool.cpp: (JSC::SamplingTool::doRun): (JSC::SamplingTool::notifyOfScope): * bytecode/SamplingTool.h: * dfg/DFGThreadData.h: * dfg/DFGWorklist.cpp: (JSC::DFG::Worklist::~Worklist): (JSC::DFG::Worklist::isActiveForVM): (JSC::DFG::Worklist::enqueue): (JSC::DFG::Worklist::compilationState): (JSC::DFG::Worklist::waitUntilAllPlansForVMAreReady): (JSC::DFG::Worklist::removeAllReadyPlansForVM): (JSC::DFG::Worklist::completeAllReadyPlansForVM): (JSC::DFG::Worklist::visitWeakReferences): (JSC::DFG::Worklist::removeDeadPlans): (JSC::DFG::Worklist::queueLength): (JSC::DFG::Worklist::dump): (JSC::DFG::Worklist::runThread): * dfg/DFGWorklist.h: * disassembler/Disassembler.cpp: * heap/CopiedSpace.cpp: (JSC::CopiedSpace::doneFillingBlock): (JSC::CopiedSpace::doneCopying): * heap/CopiedSpace.h: * heap/CopiedSpaceInlines.h: (JSC::CopiedSpace::recycleBorrowedBlock): (JSC::CopiedSpace::allocateBlockForCopyingPhase): * heap/GCThread.cpp: (JSC::GCThread::waitForNextPhase): (JSC::GCThread::gcThreadMain): * heap/GCThreadSharedData.cpp: (JSC::GCThreadSharedData::GCThreadSharedData): (JSC::GCThreadSharedData::~GCThreadSharedData): (JSC::GCThreadSharedData::startNextPhase): (JSC::GCThreadSharedData::endCurrentPhase): (JSC::GCThreadSharedData::didStartMarking): (JSC::GCThreadSharedData::didFinishMarking): * heap/GCThreadSharedData.h: * heap/HeapTimer.h: * heap/MachineStackMarker.cpp: (JSC::ActiveMachineThreadsManager::Locker::Locker): (JSC::ActiveMachineThreadsManager::add): (JSC::ActiveMachineThreadsManager::remove): (JSC::ActiveMachineThreadsManager::ActiveMachineThreadsManager): (JSC::MachineThreads::~MachineThreads): (JSC::MachineThreads::addCurrentThread): (JSC::MachineThreads::removeThreadIfFound): (JSC::MachineThreads::tryCopyOtherThreadStack): (JSC::MachineThreads::tryCopyOtherThreadStacks): (JSC::MachineThreads::gatherConservativeRoots): * heap/MachineStackMarker.h: * heap/SlotVisitor.cpp: (JSC::SlotVisitor::donateKnownParallel): (JSC::SlotVisitor::drain): (JSC::SlotVisitor::drainFromShared): (JSC::SlotVisitor::mergeOpaqueRoots): * heap/SlotVisitorInlines.h: (JSC::SlotVisitor::containsOpaqueRootTriState): * inspector/remote/RemoteInspectorDebuggableConnection.h: * inspector/remote/RemoteInspectorDebuggableConnection.mm: (Inspector::RemoteInspectorHandleRunSourceGlobal): (Inspector::RemoteInspectorQueueTaskOnGlobalQueue): (Inspector::RemoteInspectorInitializeGlobalQueue): (Inspector::RemoteInspectorHandleRunSourceWithInfo): (Inspector::RemoteInspectorDebuggableConnection::setup): (Inspector::RemoteInspectorDebuggableConnection::closeFromDebuggable): (Inspector::RemoteInspectorDebuggableConnection::close): (Inspector::RemoteInspectorDebuggableConnection::sendMessageToBackend): (Inspector::RemoteInspectorDebuggableConnection::queueTaskOnPrivateRunLoop): * interpreter/JSStack.cpp: (JSC::JSStack::JSStack): (JSC::JSStack::releaseExcessCapacity): (JSC::JSStack::addToCommittedByteCount): (JSC::JSStack::committedByteCount): (JSC::stackStatisticsMutex): Deleted. (JSC::JSStack::initializeThreading): Deleted. * interpreter/JSStack.h: (JSC::JSStack::gatherConservativeRoots): (JSC::JSStack::sanitizeStack): (JSC::JSStack::size): (JSC::JSStack::initializeThreading): Deleted. * jit/ExecutableAllocator.cpp: (JSC::DemandExecutableAllocator::DemandExecutableAllocator): (JSC::DemandExecutableAllocator::~DemandExecutableAllocator): (JSC::DemandExecutableAllocator::bytesAllocatedByAllAllocators): (JSC::DemandExecutableAllocator::bytesCommittedByAllocactors): (JSC::DemandExecutableAllocator::dumpProfileFromAllAllocators): (JSC::DemandExecutableAllocator::allocators): (JSC::DemandExecutableAllocator::allocatorsMutex): * jit/JITThunks.cpp: (JSC::JITThunks::ctiStub): * jit/JITThunks.h: * profiler/ProfilerDatabase.cpp: (JSC::Profiler::Database::ensureBytecodesFor): (JSC::Profiler::Database::notifyDestruction): * profiler/ProfilerDatabase.h: * runtime/InitializeThreading.cpp: (JSC::initializeThreading): * runtime/JSLock.cpp: (JSC::GlobalJSLock::GlobalJSLock): (JSC::GlobalJSLock::~GlobalJSLock): (JSC::JSLockHolder::JSLockHolder): (JSC::GlobalJSLock::initialize): Deleted. * runtime/JSLock.h: Source/WTF: Relanding after fixing a deadlock on Linux. * wtf/Condition.h: "using WTF::Condition". * wtf/Lock.h: (WTF::LockBase::lock): (WTF::LockBase::tryLock): Add tryLock() because it turns out that we use it sometimes. (WTF::LockBase::try_lock): unique_lock needs this. (WTF::LockBase::unlock): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): Work around a Linux C++ bug where wait_until with time_point::max() immediately returns and doesn't flash the lock. Canonical link: https://commits.webkit.org/166166@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188499 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-15 00:14:52 +00:00
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): Canonical link: https://commits.webkit.org/182152@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208415 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-11-05 03:02:39 +00:00
// It's possible for the OS to decide not to wait. If it does that then it will also
// decide not to release the lock. If there's a bug in the time math, then this could
// result in a deadlock. Flashing the lock means that at worst it's just a CPU-eating
// spin.
me->parkingLock.unlock();
me->parkingLock.lock();
Use WTF::Lock and WTF::Condition instead of WTF::Mutex, WTF::ThreadCondition, std::mutex, and std::condition_variable https://bugs.webkit.org/show_bug.cgi?id=147999 Reviewed by Geoffrey Garen. Source/JavaScriptCore: * API/JSVirtualMachine.mm: (initWrapperCache): (+[JSVMWrapperCache addWrapper:forJSContextGroupRef:]): (+[JSVMWrapperCache wrapperForJSContextGroupRef:]): (wrapperCacheMutex): Deleted. * bytecode/SamplingTool.cpp: (JSC::SamplingTool::doRun): (JSC::SamplingTool::notifyOfScope): * bytecode/SamplingTool.h: * dfg/DFGThreadData.h: * dfg/DFGWorklist.cpp: (JSC::DFG::Worklist::~Worklist): (JSC::DFG::Worklist::isActiveForVM): (JSC::DFG::Worklist::enqueue): (JSC::DFG::Worklist::compilationState): (JSC::DFG::Worklist::waitUntilAllPlansForVMAreReady): (JSC::DFG::Worklist::removeAllReadyPlansForVM): (JSC::DFG::Worklist::completeAllReadyPlansForVM): (JSC::DFG::Worklist::visitWeakReferences): (JSC::DFG::Worklist::removeDeadPlans): (JSC::DFG::Worklist::queueLength): (JSC::DFG::Worklist::dump): (JSC::DFG::Worklist::runThread): * dfg/DFGWorklist.h: * disassembler/Disassembler.cpp: * heap/CopiedSpace.cpp: (JSC::CopiedSpace::doneFillingBlock): (JSC::CopiedSpace::doneCopying): * heap/CopiedSpace.h: * heap/CopiedSpaceInlines.h: (JSC::CopiedSpace::recycleBorrowedBlock): (JSC::CopiedSpace::allocateBlockForCopyingPhase): * heap/GCThread.cpp: (JSC::GCThread::waitForNextPhase): (JSC::GCThread::gcThreadMain): * heap/GCThreadSharedData.cpp: (JSC::GCThreadSharedData::GCThreadSharedData): (JSC::GCThreadSharedData::~GCThreadSharedData): (JSC::GCThreadSharedData::startNextPhase): (JSC::GCThreadSharedData::endCurrentPhase): (JSC::GCThreadSharedData::didStartMarking): (JSC::GCThreadSharedData::didFinishMarking): * heap/GCThreadSharedData.h: * heap/HeapTimer.h: * heap/MachineStackMarker.cpp: (JSC::ActiveMachineThreadsManager::Locker::Locker): (JSC::ActiveMachineThreadsManager::add): (JSC::ActiveMachineThreadsManager::remove): (JSC::ActiveMachineThreadsManager::ActiveMachineThreadsManager): (JSC::MachineThreads::~MachineThreads): (JSC::MachineThreads::addCurrentThread): (JSC::MachineThreads::removeThreadIfFound): (JSC::MachineThreads::tryCopyOtherThreadStack): (JSC::MachineThreads::tryCopyOtherThreadStacks): (JSC::MachineThreads::gatherConservativeRoots): * heap/MachineStackMarker.h: * heap/SlotVisitor.cpp: (JSC::SlotVisitor::donateKnownParallel): (JSC::SlotVisitor::drain): (JSC::SlotVisitor::drainFromShared): (JSC::SlotVisitor::mergeOpaqueRoots): * heap/SlotVisitorInlines.h: (JSC::SlotVisitor::containsOpaqueRootTriState): * inspector/remote/RemoteInspectorDebuggableConnection.h: * inspector/remote/RemoteInspectorDebuggableConnection.mm: (Inspector::RemoteInspectorHandleRunSourceGlobal): (Inspector::RemoteInspectorQueueTaskOnGlobalQueue): (Inspector::RemoteInspectorInitializeGlobalQueue): (Inspector::RemoteInspectorHandleRunSourceWithInfo): (Inspector::RemoteInspectorDebuggableConnection::setup): (Inspector::RemoteInspectorDebuggableConnection::closeFromDebuggable): (Inspector::RemoteInspectorDebuggableConnection::close): (Inspector::RemoteInspectorDebuggableConnection::sendMessageToBackend): (Inspector::RemoteInspectorDebuggableConnection::queueTaskOnPrivateRunLoop): * interpreter/JSStack.cpp: (JSC::JSStack::JSStack): (JSC::JSStack::releaseExcessCapacity): (JSC::JSStack::addToCommittedByteCount): (JSC::JSStack::committedByteCount): (JSC::stackStatisticsMutex): Deleted. (JSC::JSStack::initializeThreading): Deleted. * interpreter/JSStack.h: (JSC::JSStack::gatherConservativeRoots): (JSC::JSStack::sanitizeStack): (JSC::JSStack::size): (JSC::JSStack::initializeThreading): Deleted. * jit/ExecutableAllocator.cpp: (JSC::DemandExecutableAllocator::DemandExecutableAllocator): (JSC::DemandExecutableAllocator::~DemandExecutableAllocator): (JSC::DemandExecutableAllocator::bytesAllocatedByAllAllocators): (JSC::DemandExecutableAllocator::bytesCommittedByAllocactors): (JSC::DemandExecutableAllocator::dumpProfileFromAllAllocators): (JSC::DemandExecutableAllocator::allocators): (JSC::DemandExecutableAllocator::allocatorsMutex): * jit/JITThunks.cpp: (JSC::JITThunks::ctiStub): * jit/JITThunks.h: * profiler/ProfilerDatabase.cpp: (JSC::Profiler::Database::ensureBytecodesFor): (JSC::Profiler::Database::notifyDestruction): * profiler/ProfilerDatabase.h: * runtime/InitializeThreading.cpp: (JSC::initializeThreading): * runtime/JSLock.cpp: (JSC::GlobalJSLock::GlobalJSLock): (JSC::GlobalJSLock::~GlobalJSLock): (JSC::JSLockHolder::JSLockHolder): (JSC::GlobalJSLock::initialize): Deleted. * runtime/JSLock.h: Source/WTF: Relanding after fixing a deadlock on Linux. * wtf/Condition.h: "using WTF::Condition". * wtf/Lock.h: (WTF::LockBase::lock): (WTF::LockBase::tryLock): Add tryLock() because it turns out that we use it sometimes. (WTF::LockBase::try_lock): unique_lock needs this. (WTF::LockBase::unlock): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): Work around a Linux C++ bug where wait_until with time_point::max() immediately returns and doesn't flash the lock. Canonical link: https://commits.webkit.org/166166@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188499 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-15 00:14:52 +00:00
}
WTF should have a compact Condition object to use with Lock https://bugs.webkit.org/show_bug.cgi?id=147986 Reviewed by Geoffrey Garen. Source/WTF: Adds a condition variable implementation based on ParkingLot, called simply WTF::Condition. It can be used with WTF::Lock or actually any lock implementation. It should even work with WTF::SpinLock, WTF::Mutex, or std::mutex. Best of all, Condition only requires one byte. ParkingLot almost contained all of the functionality needed to implemenet wait/notify. We could have implemented Condition using a 32-bit (or even 64-bit) version that protects against a notify that happens just before we park. But, this changes the ParkingLot API to give us the ability to run some code between when ParkingLot enqueues the current thread and when it actually sleeps. This callback is called with no locks held, so it can call unlock() on any kind of lock, so long as that lock's unlock() method doesn't recurse into ParkingLot::parkConditionally(). That seems unlikely; unlock() is more likely to call ParkingLot::unparkOne() or unparkAll(). WTF::Lock will never call parkConditionally() inside unlock(), so WTF::Lock is definitely appropriate for use with Condition. Condition supports most of the API that std::condition_variable supports. It does some things to try to reduce footgun potential. The preferred timeout form is waitUntil() which takes an absolute time from the steady_clock. The only relative timeout form also takes a predicate callback, so it's impossible to write the subtly incorrect "while (...) wait_for(...)" idiom. This patch doesn't actually introduce any uses of WTF::Condition other than the unit tests. I'll start switching code over to using WTF::Condition in another patch. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/Condition.h: Added. (WTF::Condition::Condition): (WTF::Condition::waitUntil): (WTF::Condition::waitFor): (WTF::Condition::wait): (WTF::Condition::notifyOne): (WTF::Condition::notifyAll): * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): Make this useful assertion be a release assertion. It catches cases where you unlock the lock even though you don't hold it. * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): Add the beforeSleep() callback. (WTF::ParkingLot::unparkOne): * wtf/ParkingLot.h: (WTF::ParkingLot::compareAndPark): Tools: Add a test for WTF::Condition. * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Condition.cpp: Added. (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::runLockTest): Change the name of the thread. Canonical link: https://commits.webkit.org/166094@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188400 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 20:42:11 +00:00
ASSERT(!me->address || me->address == address);
didGetDequeued = !me->address;
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
}
Use WTF::Lock and WTF::Condition instead of WTF::Mutex, WTF::ThreadCondition, std::mutex, and std::condition_variable https://bugs.webkit.org/show_bug.cgi?id=147999 Reviewed by Geoffrey Garen. Source/JavaScriptCore: * API/JSVirtualMachine.mm: (initWrapperCache): (+[JSVMWrapperCache addWrapper:forJSContextGroupRef:]): (+[JSVMWrapperCache wrapperForJSContextGroupRef:]): (wrapperCacheMutex): Deleted. * bytecode/SamplingTool.cpp: (JSC::SamplingTool::doRun): (JSC::SamplingTool::notifyOfScope): * bytecode/SamplingTool.h: * dfg/DFGThreadData.h: * dfg/DFGWorklist.cpp: (JSC::DFG::Worklist::~Worklist): (JSC::DFG::Worklist::isActiveForVM): (JSC::DFG::Worklist::enqueue): (JSC::DFG::Worklist::compilationState): (JSC::DFG::Worklist::waitUntilAllPlansForVMAreReady): (JSC::DFG::Worklist::removeAllReadyPlansForVM): (JSC::DFG::Worklist::completeAllReadyPlansForVM): (JSC::DFG::Worklist::visitWeakReferences): (JSC::DFG::Worklist::removeDeadPlans): (JSC::DFG::Worklist::queueLength): (JSC::DFG::Worklist::dump): (JSC::DFG::Worklist::runThread): * dfg/DFGWorklist.h: * disassembler/Disassembler.cpp: * heap/CopiedSpace.cpp: (JSC::CopiedSpace::doneFillingBlock): (JSC::CopiedSpace::doneCopying): * heap/CopiedSpace.h: * heap/CopiedSpaceInlines.h: (JSC::CopiedSpace::recycleBorrowedBlock): (JSC::CopiedSpace::allocateBlockForCopyingPhase): * heap/GCThread.cpp: (JSC::GCThread::waitForNextPhase): (JSC::GCThread::gcThreadMain): * heap/GCThreadSharedData.cpp: (JSC::GCThreadSharedData::GCThreadSharedData): (JSC::GCThreadSharedData::~GCThreadSharedData): (JSC::GCThreadSharedData::startNextPhase): (JSC::GCThreadSharedData::endCurrentPhase): (JSC::GCThreadSharedData::didStartMarking): (JSC::GCThreadSharedData::didFinishMarking): * heap/GCThreadSharedData.h: * heap/HeapTimer.h: * heap/MachineStackMarker.cpp: (JSC::ActiveMachineThreadsManager::Locker::Locker): (JSC::ActiveMachineThreadsManager::add): (JSC::ActiveMachineThreadsManager::remove): (JSC::ActiveMachineThreadsManager::ActiveMachineThreadsManager): (JSC::MachineThreads::~MachineThreads): (JSC::MachineThreads::addCurrentThread): (JSC::MachineThreads::removeThreadIfFound): (JSC::MachineThreads::tryCopyOtherThreadStack): (JSC::MachineThreads::tryCopyOtherThreadStacks): (JSC::MachineThreads::gatherConservativeRoots): * heap/MachineStackMarker.h: * heap/SlotVisitor.cpp: (JSC::SlotVisitor::donateKnownParallel): (JSC::SlotVisitor::drain): (JSC::SlotVisitor::drainFromShared): (JSC::SlotVisitor::mergeOpaqueRoots): * heap/SlotVisitorInlines.h: (JSC::SlotVisitor::containsOpaqueRootTriState): * inspector/remote/RemoteInspectorDebuggableConnection.h: * inspector/remote/RemoteInspectorDebuggableConnection.mm: (Inspector::RemoteInspectorHandleRunSourceGlobal): (Inspector::RemoteInspectorQueueTaskOnGlobalQueue): (Inspector::RemoteInspectorInitializeGlobalQueue): (Inspector::RemoteInspectorHandleRunSourceWithInfo): (Inspector::RemoteInspectorDebuggableConnection::setup): (Inspector::RemoteInspectorDebuggableConnection::closeFromDebuggable): (Inspector::RemoteInspectorDebuggableConnection::close): (Inspector::RemoteInspectorDebuggableConnection::sendMessageToBackend): (Inspector::RemoteInspectorDebuggableConnection::queueTaskOnPrivateRunLoop): * interpreter/JSStack.cpp: (JSC::JSStack::JSStack): (JSC::JSStack::releaseExcessCapacity): (JSC::JSStack::addToCommittedByteCount): (JSC::JSStack::committedByteCount): (JSC::stackStatisticsMutex): Deleted. (JSC::JSStack::initializeThreading): Deleted. * interpreter/JSStack.h: (JSC::JSStack::gatherConservativeRoots): (JSC::JSStack::sanitizeStack): (JSC::JSStack::size): (JSC::JSStack::initializeThreading): Deleted. * jit/ExecutableAllocator.cpp: (JSC::DemandExecutableAllocator::DemandExecutableAllocator): (JSC::DemandExecutableAllocator::~DemandExecutableAllocator): (JSC::DemandExecutableAllocator::bytesAllocatedByAllAllocators): (JSC::DemandExecutableAllocator::bytesCommittedByAllocactors): (JSC::DemandExecutableAllocator::dumpProfileFromAllAllocators): (JSC::DemandExecutableAllocator::allocators): (JSC::DemandExecutableAllocator::allocatorsMutex): * jit/JITThunks.cpp: (JSC::JITThunks::ctiStub): * jit/JITThunks.h: * profiler/ProfilerDatabase.cpp: (JSC::Profiler::Database::ensureBytecodesFor): (JSC::Profiler::Database::notifyDestruction): * profiler/ProfilerDatabase.h: * runtime/InitializeThreading.cpp: (JSC::initializeThreading): * runtime/JSLock.cpp: (JSC::GlobalJSLock::GlobalJSLock): (JSC::GlobalJSLock::~GlobalJSLock): (JSC::JSLockHolder::JSLockHolder): (JSC::GlobalJSLock::initialize): Deleted. * runtime/JSLock.h: Source/WTF: Relanding after fixing a deadlock on Linux. * wtf/Condition.h: "using WTF::Condition". * wtf/Lock.h: (WTF::LockBase::lock): (WTF::LockBase::tryLock): Add tryLock() because it turns out that we use it sometimes. (WTF::LockBase::try_lock): unique_lock needs this. (WTF::LockBase::unlock): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): Work around a Linux C++ bug where wait_until with time_point::max() immediately returns and doesn't flash the lock. Canonical link: https://commits.webkit.org/166166@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188499 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-15 00:14:52 +00:00
WTF should have a compact Condition object to use with Lock https://bugs.webkit.org/show_bug.cgi?id=147986 Reviewed by Geoffrey Garen. Source/WTF: Adds a condition variable implementation based on ParkingLot, called simply WTF::Condition. It can be used with WTF::Lock or actually any lock implementation. It should even work with WTF::SpinLock, WTF::Mutex, or std::mutex. Best of all, Condition only requires one byte. ParkingLot almost contained all of the functionality needed to implemenet wait/notify. We could have implemented Condition using a 32-bit (or even 64-bit) version that protects against a notify that happens just before we park. But, this changes the ParkingLot API to give us the ability to run some code between when ParkingLot enqueues the current thread and when it actually sleeps. This callback is called with no locks held, so it can call unlock() on any kind of lock, so long as that lock's unlock() method doesn't recurse into ParkingLot::parkConditionally(). That seems unlikely; unlock() is more likely to call ParkingLot::unparkOne() or unparkAll(). WTF::Lock will never call parkConditionally() inside unlock(), so WTF::Lock is definitely appropriate for use with Condition. Condition supports most of the API that std::condition_variable supports. It does some things to try to reduce footgun potential. The preferred timeout form is waitUntil() which takes an absolute time from the steady_clock. The only relative timeout form also takes a predicate callback, so it's impossible to write the subtly incorrect "while (...) wait_for(...)" idiom. This patch doesn't actually introduce any uses of WTF::Condition other than the unit tests. I'll start switching code over to using WTF::Condition in another patch. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/Condition.h: Added. (WTF::Condition::Condition): (WTF::Condition::waitUntil): (WTF::Condition::waitFor): (WTF::Condition::wait): (WTF::Condition::notifyOne): (WTF::Condition::notifyAll): * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): Make this useful assertion be a release assertion. It catches cases where you unlock the lock even though you don't hold it. * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): Add the beforeSleep() callback. (WTF::ParkingLot::unparkOne): * wtf/ParkingLot.h: (WTF::ParkingLot::compareAndPark): Tools: Add a test for WTF::Condition. * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Condition.cpp: Added. (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::runLockTest): Change the name of the thread. Canonical link: https://commits.webkit.org/166094@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188400 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 20:42:11 +00:00
if (didGetDequeued) {
// Great! We actually got dequeued rather than the timeout expiring.
WTF::Lock should be fair eventually https://bugs.webkit.org/show_bug.cgi?id=159384 Reviewed by Geoffrey Garen. Source/WTF: In https://webkit.org/blog/6161/locking-in-webkit/ we showed how relaxing the fairness of locks makes them fast. That post presented lock fairness as a trade-off between two extremes: - Barging. A barging lock, like WTF::Lock, releases the lock in unlock() even if there was a thread on the queue. If there was a thread on the queue, the lock is released and that thread is made runnable. That thread may then grab the lock, or some other thread may grab the lock first (it may barge). Usually, the barging thread is the thread that released the lock in the first place. This maximizes throughput but hurts fairness. There is no good theoretical bound on how unfair the lock may become, but empirical data suggests that it's fair enough for the cases we previously measured. - FIFO. A FIFO lock, like HandoffLock in ToyLocks.h, does not release the lock in unlock() if there is a thread waiting. If there is a thread waiting, unlock() will make that thread runnable and inform it that it now holds the lock. This ensures perfect round-robin fairness and allows us to reason theoretically about how long it may take for a thread to grab the lock. For example, if we know that only N threads are running and each one may contend on a critical section, and each one may hold the lock for at most S seconds, then the time it takes to grab the lock is N * S. Unfortunately, FIFO locks perform very badly in most cases. This is because for the common case of short critical sections, they force a context switch after each critical section if the lock is contended. This change makes WTF::Lock almost as fair as FIFO while still being as fast as barging. Thanks to this new algorithm, you can now have both of these things at the same time. This change makes WTF::Lock eventually fair. We can almost (more on the caveats below) guarantee that the time it takes to grab a lock is N * max(1ms, S). In other words, critical sections that are longer than 1ms are always fair. For shorter critical sections, the amount of time that any thread waits is 1ms times the number of threads. There are some caveats that arise from our use of randomness, but even then, in the limit as the critical section length goes to infinity, the lock becomes fair. The corner cases are unlikely to happen; our experiments show that the lock becomes exactly as fair as a FIFO lock for any critical section that is 1ms or longer. The fairness mechanism is broken into two parts. WTF::Lock can now choose to unlock a lock fairly or unfairly thanks to the new ParkingLot token mechanism. WTF::Lock knows when to use fair unlocking based on a timeout mechanism in ParkingLot called timeToBeFair. ParkingLot::unparkOne() and ParkingLot::parkConditionally() can now communicate with each other via a token. unparkOne() can pass a token, which parkConditionally() will return. This change also makes parkConditionally() a lot more precise about when it was unparked due to a call to unparkOne(). If unparkOne() is told that a thread was unparked then this thread is guaranteed to report that it was unparked rather than timing out, and that thread is guaranteed to get the token that unparkOne() passed. The token is an intptr_t. We use it as a boolean variable in WTF::Lock, but you could use it to pass arbitrary data structures. By default, the token is zero. WTF::Lock's unlock() will pass 1 as the token if it is doing fair unlocking. In that case, unlock() will not release the lock, and lock() will know that it holds the lock as soon as parkConditionally() returns. Note that this algorithm relies on unparkOne() invoking WTF::Lock's callback while the queue lock is held, so that WTF::Lock can make a decision about unlock strategy and inject a token while it has complete knowledge over the state of the queue. As such, it's not immediately obvious how to implement this algorithm on top of futexes. You really need ParkingLot! WTF::Lock does not use fair unlocking every time. We expose a new API, Lock::unlockFairly(), which forces the fair unlocking behavior. Additionally, ParkingLot now maintains a per-bucket stochastic fairness timeout. When the timeout fires, the unparkOne() callback sees UnparkResult::timeToBeFair = true. This timeout is set to be anywhere from 0ms to 1ms at random. When a dequeue happens and there are threads that actually get dequeued, we check if the time since the last unfair unlock (the last time timeToBeFair was set to true) is more than the timeout amount. If so, then we set timeToBeFair to true and reset the timeout. This means that in the absence of ParkingLot collisions, unfair unlocking is guaranteed to happen at least once per millisecond. It will happen at 2 KHz on average. If there are collisions, then each collision adds one millisecond to the worst case (and 0.5 ms to the average case). The reason why we don't just use a fixed 1ms timeout is that we want to avoid resonance. Imagine a program in which some thread acquires a lock at 1 KHz in-phase with the timeToBeFair timeout. Then this thread would be the benefactor of fairness to the detriment of everyone else. Randomness ensures that we aren't too fair to any one thread. Empirically, this is neutral on our major benchmarks like JetStream but it's an enormous improvement in LockFairnessTest. It's common for an unfair lock (either our BargingLock, the old WTF::Lock, any of the other futex-based locks that barge, or new os_unfair_lock) to allow only one thread to hold the lock during a whole second in which each thread is holding the lock for 1ms at a time. This is because in a barging lock, releasing a lock after holding it for 1ms and then reacquiring it immediately virtually ensures that none of the other threads can wake up in time to grab it before it's relocked. But the new WTF::Lock handles this case like a champ: each thread gets equal turns. Here's some data. If we launch 10 threads and have each of them run for 1 second while repeatedly holding a critical section for 1ms, then here's how many times each thread gets to hold the lock using the old WTF::Lock algorithm: 799, 6, 1, 1, 1, 1, 1, 1, 1, 1 One thread hogged the lock for almost the whole time! With the new WTF::Lock, the lock becomes totally fair: 80, 79, 79, 79, 79, 79, 79, 80, 80, 79 I don't know of anyone creating such an automatically-fair adaptive lock before, so I think that this is a pretty awesome advancement to the state of the art! This change is good for three reasons: - We do have long critical sections in WebKit and we don't want to have to worry about starvation. This reduces the likelihood that we will see starvation due to our lock strategy. - I was talking to ggaren about bmalloc's locking needs, and he wanted unlockFairly() or lockFairly() or some moral equivalent for the scavenger thread. - If we use a WTF::Lock to manage heap access in a multithreaded GC, we'll need the ability to unlock and relock without barging. * benchmarks/LockFairnessTest.cpp: (main): * benchmarks/ToyLocks.h: * wtf/Condition.h: (WTF::ConditionBase::waitUntil): (WTF::ConditionBase::notifyOne): * wtf/Lock.cpp: (WTF::LockBase::lockSlow): (WTF::LockBase::unlockSlow): (WTF::LockBase::unlockFairlySlow): (WTF::LockBase::unlockSlowImpl): * wtf/Lock.h: (WTF::LockBase::try_lock): (WTF::LockBase::unlock): (WTF::LockBase::unlockFairly): (WTF::LockBase::isHeld): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::compareAndPark): (WTF::ParkingLot::unparkOne): Tools: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Canonical link: https://commits.webkit.org/178039@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@203350 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-07-18 18:32:52 +00:00
ParkResult result;
result.wasUnparked = true;
result.token = me->token;
return result;
WTF should have a compact Condition object to use with Lock https://bugs.webkit.org/show_bug.cgi?id=147986 Reviewed by Geoffrey Garen. Source/WTF: Adds a condition variable implementation based on ParkingLot, called simply WTF::Condition. It can be used with WTF::Lock or actually any lock implementation. It should even work with WTF::SpinLock, WTF::Mutex, or std::mutex. Best of all, Condition only requires one byte. ParkingLot almost contained all of the functionality needed to implemenet wait/notify. We could have implemented Condition using a 32-bit (or even 64-bit) version that protects against a notify that happens just before we park. But, this changes the ParkingLot API to give us the ability to run some code between when ParkingLot enqueues the current thread and when it actually sleeps. This callback is called with no locks held, so it can call unlock() on any kind of lock, so long as that lock's unlock() method doesn't recurse into ParkingLot::parkConditionally(). That seems unlikely; unlock() is more likely to call ParkingLot::unparkOne() or unparkAll(). WTF::Lock will never call parkConditionally() inside unlock(), so WTF::Lock is definitely appropriate for use with Condition. Condition supports most of the API that std::condition_variable supports. It does some things to try to reduce footgun potential. The preferred timeout form is waitUntil() which takes an absolute time from the steady_clock. The only relative timeout form also takes a predicate callback, so it's impossible to write the subtly incorrect "while (...) wait_for(...)" idiom. This patch doesn't actually introduce any uses of WTF::Condition other than the unit tests. I'll start switching code over to using WTF::Condition in another patch. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/Condition.h: Added. (WTF::Condition::Condition): (WTF::Condition::waitUntil): (WTF::Condition::waitFor): (WTF::Condition::wait): (WTF::Condition::notifyOne): (WTF::Condition::notifyAll): * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): Make this useful assertion be a release assertion. It catches cases where you unlock the lock even though you don't hold it. * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): Add the beforeSleep() callback. (WTF::ParkingLot::unparkOne): * wtf/ParkingLot.h: (WTF::ParkingLot::compareAndPark): Tools: Add a test for WTF::Condition. * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Condition.cpp: Added. (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::runLockTest): Change the name of the thread. Canonical link: https://commits.webkit.org/166094@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188400 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 20:42:11 +00:00
}
// Have to remove ourselves from the queue since we timed out and nobody has dequeued us yet.
WTF::Lock should be fair eventually https://bugs.webkit.org/show_bug.cgi?id=159384 Reviewed by Geoffrey Garen. Source/WTF: In https://webkit.org/blog/6161/locking-in-webkit/ we showed how relaxing the fairness of locks makes them fast. That post presented lock fairness as a trade-off between two extremes: - Barging. A barging lock, like WTF::Lock, releases the lock in unlock() even if there was a thread on the queue. If there was a thread on the queue, the lock is released and that thread is made runnable. That thread may then grab the lock, or some other thread may grab the lock first (it may barge). Usually, the barging thread is the thread that released the lock in the first place. This maximizes throughput but hurts fairness. There is no good theoretical bound on how unfair the lock may become, but empirical data suggests that it's fair enough for the cases we previously measured. - FIFO. A FIFO lock, like HandoffLock in ToyLocks.h, does not release the lock in unlock() if there is a thread waiting. If there is a thread waiting, unlock() will make that thread runnable and inform it that it now holds the lock. This ensures perfect round-robin fairness and allows us to reason theoretically about how long it may take for a thread to grab the lock. For example, if we know that only N threads are running and each one may contend on a critical section, and each one may hold the lock for at most S seconds, then the time it takes to grab the lock is N * S. Unfortunately, FIFO locks perform very badly in most cases. This is because for the common case of short critical sections, they force a context switch after each critical section if the lock is contended. This change makes WTF::Lock almost as fair as FIFO while still being as fast as barging. Thanks to this new algorithm, you can now have both of these things at the same time. This change makes WTF::Lock eventually fair. We can almost (more on the caveats below) guarantee that the time it takes to grab a lock is N * max(1ms, S). In other words, critical sections that are longer than 1ms are always fair. For shorter critical sections, the amount of time that any thread waits is 1ms times the number of threads. There are some caveats that arise from our use of randomness, but even then, in the limit as the critical section length goes to infinity, the lock becomes fair. The corner cases are unlikely to happen; our experiments show that the lock becomes exactly as fair as a FIFO lock for any critical section that is 1ms or longer. The fairness mechanism is broken into two parts. WTF::Lock can now choose to unlock a lock fairly or unfairly thanks to the new ParkingLot token mechanism. WTF::Lock knows when to use fair unlocking based on a timeout mechanism in ParkingLot called timeToBeFair. ParkingLot::unparkOne() and ParkingLot::parkConditionally() can now communicate with each other via a token. unparkOne() can pass a token, which parkConditionally() will return. This change also makes parkConditionally() a lot more precise about when it was unparked due to a call to unparkOne(). If unparkOne() is told that a thread was unparked then this thread is guaranteed to report that it was unparked rather than timing out, and that thread is guaranteed to get the token that unparkOne() passed. The token is an intptr_t. We use it as a boolean variable in WTF::Lock, but you could use it to pass arbitrary data structures. By default, the token is zero. WTF::Lock's unlock() will pass 1 as the token if it is doing fair unlocking. In that case, unlock() will not release the lock, and lock() will know that it holds the lock as soon as parkConditionally() returns. Note that this algorithm relies on unparkOne() invoking WTF::Lock's callback while the queue lock is held, so that WTF::Lock can make a decision about unlock strategy and inject a token while it has complete knowledge over the state of the queue. As such, it's not immediately obvious how to implement this algorithm on top of futexes. You really need ParkingLot! WTF::Lock does not use fair unlocking every time. We expose a new API, Lock::unlockFairly(), which forces the fair unlocking behavior. Additionally, ParkingLot now maintains a per-bucket stochastic fairness timeout. When the timeout fires, the unparkOne() callback sees UnparkResult::timeToBeFair = true. This timeout is set to be anywhere from 0ms to 1ms at random. When a dequeue happens and there are threads that actually get dequeued, we check if the time since the last unfair unlock (the last time timeToBeFair was set to true) is more than the timeout amount. If so, then we set timeToBeFair to true and reset the timeout. This means that in the absence of ParkingLot collisions, unfair unlocking is guaranteed to happen at least once per millisecond. It will happen at 2 KHz on average. If there are collisions, then each collision adds one millisecond to the worst case (and 0.5 ms to the average case). The reason why we don't just use a fixed 1ms timeout is that we want to avoid resonance. Imagine a program in which some thread acquires a lock at 1 KHz in-phase with the timeToBeFair timeout. Then this thread would be the benefactor of fairness to the detriment of everyone else. Randomness ensures that we aren't too fair to any one thread. Empirically, this is neutral on our major benchmarks like JetStream but it's an enormous improvement in LockFairnessTest. It's common for an unfair lock (either our BargingLock, the old WTF::Lock, any of the other futex-based locks that barge, or new os_unfair_lock) to allow only one thread to hold the lock during a whole second in which each thread is holding the lock for 1ms at a time. This is because in a barging lock, releasing a lock after holding it for 1ms and then reacquiring it immediately virtually ensures that none of the other threads can wake up in time to grab it before it's relocked. But the new WTF::Lock handles this case like a champ: each thread gets equal turns. Here's some data. If we launch 10 threads and have each of them run for 1 second while repeatedly holding a critical section for 1ms, then here's how many times each thread gets to hold the lock using the old WTF::Lock algorithm: 799, 6, 1, 1, 1, 1, 1, 1, 1, 1 One thread hogged the lock for almost the whole time! With the new WTF::Lock, the lock becomes totally fair: 80, 79, 79, 79, 79, 79, 79, 80, 80, 79 I don't know of anyone creating such an automatically-fair adaptive lock before, so I think that this is a pretty awesome advancement to the state of the art! This change is good for three reasons: - We do have long critical sections in WebKit and we don't want to have to worry about starvation. This reduces the likelihood that we will see starvation due to our lock strategy. - I was talking to ggaren about bmalloc's locking needs, and he wanted unlockFairly() or lockFairly() or some moral equivalent for the scavenger thread. - If we use a WTF::Lock to manage heap access in a multithreaded GC, we'll need the ability to unlock and relock without barging. * benchmarks/LockFairnessTest.cpp: (main): * benchmarks/ToyLocks.h: * wtf/Condition.h: (WTF::ConditionBase::waitUntil): (WTF::ConditionBase::notifyOne): * wtf/Lock.cpp: (WTF::LockBase::lockSlow): (WTF::LockBase::unlockSlow): (WTF::LockBase::unlockFairlySlow): (WTF::LockBase::unlockSlowImpl): * wtf/Lock.h: (WTF::LockBase::try_lock): (WTF::LockBase::unlock): (WTF::LockBase::unlockFairly): (WTF::LockBase::isHeld): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::compareAndPark): (WTF::ParkingLot::unparkOne): Tools: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Canonical link: https://commits.webkit.org/178039@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@203350 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-07-18 18:32:52 +00:00
bool didDequeue = false;
WTF should have a compact Condition object to use with Lock https://bugs.webkit.org/show_bug.cgi?id=147986 Reviewed by Geoffrey Garen. Source/WTF: Adds a condition variable implementation based on ParkingLot, called simply WTF::Condition. It can be used with WTF::Lock or actually any lock implementation. It should even work with WTF::SpinLock, WTF::Mutex, or std::mutex. Best of all, Condition only requires one byte. ParkingLot almost contained all of the functionality needed to implemenet wait/notify. We could have implemented Condition using a 32-bit (or even 64-bit) version that protects against a notify that happens just before we park. But, this changes the ParkingLot API to give us the ability to run some code between when ParkingLot enqueues the current thread and when it actually sleeps. This callback is called with no locks held, so it can call unlock() on any kind of lock, so long as that lock's unlock() method doesn't recurse into ParkingLot::parkConditionally(). That seems unlikely; unlock() is more likely to call ParkingLot::unparkOne() or unparkAll(). WTF::Lock will never call parkConditionally() inside unlock(), so WTF::Lock is definitely appropriate for use with Condition. Condition supports most of the API that std::condition_variable supports. It does some things to try to reduce footgun potential. The preferred timeout form is waitUntil() which takes an absolute time from the steady_clock. The only relative timeout form also takes a predicate callback, so it's impossible to write the subtly incorrect "while (...) wait_for(...)" idiom. This patch doesn't actually introduce any uses of WTF::Condition other than the unit tests. I'll start switching code over to using WTF::Condition in another patch. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/Condition.h: Added. (WTF::Condition::Condition): (WTF::Condition::waitUntil): (WTF::Condition::waitFor): (WTF::Condition::wait): (WTF::Condition::notifyOne): (WTF::Condition::notifyAll): * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): Make this useful assertion be a release assertion. It catches cases where you unlock the lock even though you don't hold it. * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): Add the beforeSleep() callback. (WTF::ParkingLot::unparkOne): * wtf/ParkingLot.h: (WTF::ParkingLot::compareAndPark): Tools: Add a test for WTF::Condition. * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Condition.cpp: Added. (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::runLockTest): Change the name of the thread. Canonical link: https://commits.webkit.org/166094@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188400 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 20:42:11 +00:00
dequeue(
address, BucketMode::IgnoreEmpty,
WTF::Lock should be fair eventually https://bugs.webkit.org/show_bug.cgi?id=159384 Reviewed by Geoffrey Garen. Source/WTF: In https://webkit.org/blog/6161/locking-in-webkit/ we showed how relaxing the fairness of locks makes them fast. That post presented lock fairness as a trade-off between two extremes: - Barging. A barging lock, like WTF::Lock, releases the lock in unlock() even if there was a thread on the queue. If there was a thread on the queue, the lock is released and that thread is made runnable. That thread may then grab the lock, or some other thread may grab the lock first (it may barge). Usually, the barging thread is the thread that released the lock in the first place. This maximizes throughput but hurts fairness. There is no good theoretical bound on how unfair the lock may become, but empirical data suggests that it's fair enough for the cases we previously measured. - FIFO. A FIFO lock, like HandoffLock in ToyLocks.h, does not release the lock in unlock() if there is a thread waiting. If there is a thread waiting, unlock() will make that thread runnable and inform it that it now holds the lock. This ensures perfect round-robin fairness and allows us to reason theoretically about how long it may take for a thread to grab the lock. For example, if we know that only N threads are running and each one may contend on a critical section, and each one may hold the lock for at most S seconds, then the time it takes to grab the lock is N * S. Unfortunately, FIFO locks perform very badly in most cases. This is because for the common case of short critical sections, they force a context switch after each critical section if the lock is contended. This change makes WTF::Lock almost as fair as FIFO while still being as fast as barging. Thanks to this new algorithm, you can now have both of these things at the same time. This change makes WTF::Lock eventually fair. We can almost (more on the caveats below) guarantee that the time it takes to grab a lock is N * max(1ms, S). In other words, critical sections that are longer than 1ms are always fair. For shorter critical sections, the amount of time that any thread waits is 1ms times the number of threads. There are some caveats that arise from our use of randomness, but even then, in the limit as the critical section length goes to infinity, the lock becomes fair. The corner cases are unlikely to happen; our experiments show that the lock becomes exactly as fair as a FIFO lock for any critical section that is 1ms or longer. The fairness mechanism is broken into two parts. WTF::Lock can now choose to unlock a lock fairly or unfairly thanks to the new ParkingLot token mechanism. WTF::Lock knows when to use fair unlocking based on a timeout mechanism in ParkingLot called timeToBeFair. ParkingLot::unparkOne() and ParkingLot::parkConditionally() can now communicate with each other via a token. unparkOne() can pass a token, which parkConditionally() will return. This change also makes parkConditionally() a lot more precise about when it was unparked due to a call to unparkOne(). If unparkOne() is told that a thread was unparked then this thread is guaranteed to report that it was unparked rather than timing out, and that thread is guaranteed to get the token that unparkOne() passed. The token is an intptr_t. We use it as a boolean variable in WTF::Lock, but you could use it to pass arbitrary data structures. By default, the token is zero. WTF::Lock's unlock() will pass 1 as the token if it is doing fair unlocking. In that case, unlock() will not release the lock, and lock() will know that it holds the lock as soon as parkConditionally() returns. Note that this algorithm relies on unparkOne() invoking WTF::Lock's callback while the queue lock is held, so that WTF::Lock can make a decision about unlock strategy and inject a token while it has complete knowledge over the state of the queue. As such, it's not immediately obvious how to implement this algorithm on top of futexes. You really need ParkingLot! WTF::Lock does not use fair unlocking every time. We expose a new API, Lock::unlockFairly(), which forces the fair unlocking behavior. Additionally, ParkingLot now maintains a per-bucket stochastic fairness timeout. When the timeout fires, the unparkOne() callback sees UnparkResult::timeToBeFair = true. This timeout is set to be anywhere from 0ms to 1ms at random. When a dequeue happens and there are threads that actually get dequeued, we check if the time since the last unfair unlock (the last time timeToBeFair was set to true) is more than the timeout amount. If so, then we set timeToBeFair to true and reset the timeout. This means that in the absence of ParkingLot collisions, unfair unlocking is guaranteed to happen at least once per millisecond. It will happen at 2 KHz on average. If there are collisions, then each collision adds one millisecond to the worst case (and 0.5 ms to the average case). The reason why we don't just use a fixed 1ms timeout is that we want to avoid resonance. Imagine a program in which some thread acquires a lock at 1 KHz in-phase with the timeToBeFair timeout. Then this thread would be the benefactor of fairness to the detriment of everyone else. Randomness ensures that we aren't too fair to any one thread. Empirically, this is neutral on our major benchmarks like JetStream but it's an enormous improvement in LockFairnessTest. It's common for an unfair lock (either our BargingLock, the old WTF::Lock, any of the other futex-based locks that barge, or new os_unfair_lock) to allow only one thread to hold the lock during a whole second in which each thread is holding the lock for 1ms at a time. This is because in a barging lock, releasing a lock after holding it for 1ms and then reacquiring it immediately virtually ensures that none of the other threads can wake up in time to grab it before it's relocked. But the new WTF::Lock handles this case like a champ: each thread gets equal turns. Here's some data. If we launch 10 threads and have each of them run for 1 second while repeatedly holding a critical section for 1ms, then here's how many times each thread gets to hold the lock using the old WTF::Lock algorithm: 799, 6, 1, 1, 1, 1, 1, 1, 1, 1 One thread hogged the lock for almost the whole time! With the new WTF::Lock, the lock becomes totally fair: 80, 79, 79, 79, 79, 79, 79, 80, 80, 79 I don't know of anyone creating such an automatically-fair adaptive lock before, so I think that this is a pretty awesome advancement to the state of the art! This change is good for three reasons: - We do have long critical sections in WebKit and we don't want to have to worry about starvation. This reduces the likelihood that we will see starvation due to our lock strategy. - I was talking to ggaren about bmalloc's locking needs, and he wanted unlockFairly() or lockFairly() or some moral equivalent for the scavenger thread. - If we use a WTF::Lock to manage heap access in a multithreaded GC, we'll need the ability to unlock and relock without barging. * benchmarks/LockFairnessTest.cpp: (main): * benchmarks/ToyLocks.h: * wtf/Condition.h: (WTF::ConditionBase::waitUntil): (WTF::ConditionBase::notifyOne): * wtf/Lock.cpp: (WTF::LockBase::lockSlow): (WTF::LockBase::unlockSlow): (WTF::LockBase::unlockFairlySlow): (WTF::LockBase::unlockSlowImpl): * wtf/Lock.h: (WTF::LockBase::try_lock): (WTF::LockBase::unlock): (WTF::LockBase::unlockFairly): (WTF::LockBase::isHeld): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::compareAndPark): (WTF::ParkingLot::unparkOne): Tools: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Canonical link: https://commits.webkit.org/178039@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@203350 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-07-18 18:32:52 +00:00
[&] (ThreadData* element, bool) {
if (element == me) {
didDequeue = true;
WTF should have a compact Condition object to use with Lock https://bugs.webkit.org/show_bug.cgi?id=147986 Reviewed by Geoffrey Garen. Source/WTF: Adds a condition variable implementation based on ParkingLot, called simply WTF::Condition. It can be used with WTF::Lock or actually any lock implementation. It should even work with WTF::SpinLock, WTF::Mutex, or std::mutex. Best of all, Condition only requires one byte. ParkingLot almost contained all of the functionality needed to implemenet wait/notify. We could have implemented Condition using a 32-bit (or even 64-bit) version that protects against a notify that happens just before we park. But, this changes the ParkingLot API to give us the ability to run some code between when ParkingLot enqueues the current thread and when it actually sleeps. This callback is called with no locks held, so it can call unlock() on any kind of lock, so long as that lock's unlock() method doesn't recurse into ParkingLot::parkConditionally(). That seems unlikely; unlock() is more likely to call ParkingLot::unparkOne() or unparkAll(). WTF::Lock will never call parkConditionally() inside unlock(), so WTF::Lock is definitely appropriate for use with Condition. Condition supports most of the API that std::condition_variable supports. It does some things to try to reduce footgun potential. The preferred timeout form is waitUntil() which takes an absolute time from the steady_clock. The only relative timeout form also takes a predicate callback, so it's impossible to write the subtly incorrect "while (...) wait_for(...)" idiom. This patch doesn't actually introduce any uses of WTF::Condition other than the unit tests. I'll start switching code over to using WTF::Condition in another patch. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/Condition.h: Added. (WTF::Condition::Condition): (WTF::Condition::waitUntil): (WTF::Condition::waitFor): (WTF::Condition::wait): (WTF::Condition::notifyOne): (WTF::Condition::notifyAll): * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): Make this useful assertion be a release assertion. It catches cases where you unlock the lock even though you don't hold it. * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): Add the beforeSleep() callback. (WTF::ParkingLot::unparkOne): * wtf/ParkingLot.h: (WTF::ParkingLot::compareAndPark): Tools: Add a test for WTF::Condition. * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Condition.cpp: Added. (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::runLockTest): Change the name of the thread. Canonical link: https://commits.webkit.org/166094@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188400 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 20:42:11 +00:00
return DequeueResult::RemoveAndStop;
WTF::Lock should be fair eventually https://bugs.webkit.org/show_bug.cgi?id=159384 Reviewed by Geoffrey Garen. Source/WTF: In https://webkit.org/blog/6161/locking-in-webkit/ we showed how relaxing the fairness of locks makes them fast. That post presented lock fairness as a trade-off between two extremes: - Barging. A barging lock, like WTF::Lock, releases the lock in unlock() even if there was a thread on the queue. If there was a thread on the queue, the lock is released and that thread is made runnable. That thread may then grab the lock, or some other thread may grab the lock first (it may barge). Usually, the barging thread is the thread that released the lock in the first place. This maximizes throughput but hurts fairness. There is no good theoretical bound on how unfair the lock may become, but empirical data suggests that it's fair enough for the cases we previously measured. - FIFO. A FIFO lock, like HandoffLock in ToyLocks.h, does not release the lock in unlock() if there is a thread waiting. If there is a thread waiting, unlock() will make that thread runnable and inform it that it now holds the lock. This ensures perfect round-robin fairness and allows us to reason theoretically about how long it may take for a thread to grab the lock. For example, if we know that only N threads are running and each one may contend on a critical section, and each one may hold the lock for at most S seconds, then the time it takes to grab the lock is N * S. Unfortunately, FIFO locks perform very badly in most cases. This is because for the common case of short critical sections, they force a context switch after each critical section if the lock is contended. This change makes WTF::Lock almost as fair as FIFO while still being as fast as barging. Thanks to this new algorithm, you can now have both of these things at the same time. This change makes WTF::Lock eventually fair. We can almost (more on the caveats below) guarantee that the time it takes to grab a lock is N * max(1ms, S). In other words, critical sections that are longer than 1ms are always fair. For shorter critical sections, the amount of time that any thread waits is 1ms times the number of threads. There are some caveats that arise from our use of randomness, but even then, in the limit as the critical section length goes to infinity, the lock becomes fair. The corner cases are unlikely to happen; our experiments show that the lock becomes exactly as fair as a FIFO lock for any critical section that is 1ms or longer. The fairness mechanism is broken into two parts. WTF::Lock can now choose to unlock a lock fairly or unfairly thanks to the new ParkingLot token mechanism. WTF::Lock knows when to use fair unlocking based on a timeout mechanism in ParkingLot called timeToBeFair. ParkingLot::unparkOne() and ParkingLot::parkConditionally() can now communicate with each other via a token. unparkOne() can pass a token, which parkConditionally() will return. This change also makes parkConditionally() a lot more precise about when it was unparked due to a call to unparkOne(). If unparkOne() is told that a thread was unparked then this thread is guaranteed to report that it was unparked rather than timing out, and that thread is guaranteed to get the token that unparkOne() passed. The token is an intptr_t. We use it as a boolean variable in WTF::Lock, but you could use it to pass arbitrary data structures. By default, the token is zero. WTF::Lock's unlock() will pass 1 as the token if it is doing fair unlocking. In that case, unlock() will not release the lock, and lock() will know that it holds the lock as soon as parkConditionally() returns. Note that this algorithm relies on unparkOne() invoking WTF::Lock's callback while the queue lock is held, so that WTF::Lock can make a decision about unlock strategy and inject a token while it has complete knowledge over the state of the queue. As such, it's not immediately obvious how to implement this algorithm on top of futexes. You really need ParkingLot! WTF::Lock does not use fair unlocking every time. We expose a new API, Lock::unlockFairly(), which forces the fair unlocking behavior. Additionally, ParkingLot now maintains a per-bucket stochastic fairness timeout. When the timeout fires, the unparkOne() callback sees UnparkResult::timeToBeFair = true. This timeout is set to be anywhere from 0ms to 1ms at random. When a dequeue happens and there are threads that actually get dequeued, we check if the time since the last unfair unlock (the last time timeToBeFair was set to true) is more than the timeout amount. If so, then we set timeToBeFair to true and reset the timeout. This means that in the absence of ParkingLot collisions, unfair unlocking is guaranteed to happen at least once per millisecond. It will happen at 2 KHz on average. If there are collisions, then each collision adds one millisecond to the worst case (and 0.5 ms to the average case). The reason why we don't just use a fixed 1ms timeout is that we want to avoid resonance. Imagine a program in which some thread acquires a lock at 1 KHz in-phase with the timeToBeFair timeout. Then this thread would be the benefactor of fairness to the detriment of everyone else. Randomness ensures that we aren't too fair to any one thread. Empirically, this is neutral on our major benchmarks like JetStream but it's an enormous improvement in LockFairnessTest. It's common for an unfair lock (either our BargingLock, the old WTF::Lock, any of the other futex-based locks that barge, or new os_unfair_lock) to allow only one thread to hold the lock during a whole second in which each thread is holding the lock for 1ms at a time. This is because in a barging lock, releasing a lock after holding it for 1ms and then reacquiring it immediately virtually ensures that none of the other threads can wake up in time to grab it before it's relocked. But the new WTF::Lock handles this case like a champ: each thread gets equal turns. Here's some data. If we launch 10 threads and have each of them run for 1 second while repeatedly holding a critical section for 1ms, then here's how many times each thread gets to hold the lock using the old WTF::Lock algorithm: 799, 6, 1, 1, 1, 1, 1, 1, 1, 1 One thread hogged the lock for almost the whole time! With the new WTF::Lock, the lock becomes totally fair: 80, 79, 79, 79, 79, 79, 79, 80, 80, 79 I don't know of anyone creating such an automatically-fair adaptive lock before, so I think that this is a pretty awesome advancement to the state of the art! This change is good for three reasons: - We do have long critical sections in WebKit and we don't want to have to worry about starvation. This reduces the likelihood that we will see starvation due to our lock strategy. - I was talking to ggaren about bmalloc's locking needs, and he wanted unlockFairly() or lockFairly() or some moral equivalent for the scavenger thread. - If we use a WTF::Lock to manage heap access in a multithreaded GC, we'll need the ability to unlock and relock without barging. * benchmarks/LockFairnessTest.cpp: (main): * benchmarks/ToyLocks.h: * wtf/Condition.h: (WTF::ConditionBase::waitUntil): (WTF::ConditionBase::notifyOne): * wtf/Lock.cpp: (WTF::LockBase::lockSlow): (WTF::LockBase::unlockSlow): (WTF::LockBase::unlockFairlySlow): (WTF::LockBase::unlockSlowImpl): * wtf/Lock.h: (WTF::LockBase::try_lock): (WTF::LockBase::unlock): (WTF::LockBase::unlockFairly): (WTF::LockBase::isHeld): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::compareAndPark): (WTF::ParkingLot::unparkOne): Tools: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Canonical link: https://commits.webkit.org/178039@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@203350 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-07-18 18:32:52 +00:00
}
WTF should have a compact Condition object to use with Lock https://bugs.webkit.org/show_bug.cgi?id=147986 Reviewed by Geoffrey Garen. Source/WTF: Adds a condition variable implementation based on ParkingLot, called simply WTF::Condition. It can be used with WTF::Lock or actually any lock implementation. It should even work with WTF::SpinLock, WTF::Mutex, or std::mutex. Best of all, Condition only requires one byte. ParkingLot almost contained all of the functionality needed to implemenet wait/notify. We could have implemented Condition using a 32-bit (or even 64-bit) version that protects against a notify that happens just before we park. But, this changes the ParkingLot API to give us the ability to run some code between when ParkingLot enqueues the current thread and when it actually sleeps. This callback is called with no locks held, so it can call unlock() on any kind of lock, so long as that lock's unlock() method doesn't recurse into ParkingLot::parkConditionally(). That seems unlikely; unlock() is more likely to call ParkingLot::unparkOne() or unparkAll(). WTF::Lock will never call parkConditionally() inside unlock(), so WTF::Lock is definitely appropriate for use with Condition. Condition supports most of the API that std::condition_variable supports. It does some things to try to reduce footgun potential. The preferred timeout form is waitUntil() which takes an absolute time from the steady_clock. The only relative timeout form also takes a predicate callback, so it's impossible to write the subtly incorrect "while (...) wait_for(...)" idiom. This patch doesn't actually introduce any uses of WTF::Condition other than the unit tests. I'll start switching code over to using WTF::Condition in another patch. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/Condition.h: Added. (WTF::Condition::Condition): (WTF::Condition::waitUntil): (WTF::Condition::waitFor): (WTF::Condition::wait): (WTF::Condition::notifyOne): (WTF::Condition::notifyAll): * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): Make this useful assertion be a release assertion. It catches cases where you unlock the lock even though you don't hold it. * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): Add the beforeSleep() callback. (WTF::ParkingLot::unparkOne): * wtf/ParkingLot.h: (WTF::ParkingLot::compareAndPark): Tools: Add a test for WTF::Condition. * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Condition.cpp: Added. (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::runLockTest): Change the name of the thread. Canonical link: https://commits.webkit.org/166094@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188400 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 20:42:11 +00:00
return DequeueResult::Ignore;
},
[] (bool) { });
WTF::Lock should be fair eventually https://bugs.webkit.org/show_bug.cgi?id=159384 Reviewed by Geoffrey Garen. Source/WTF: In https://webkit.org/blog/6161/locking-in-webkit/ we showed how relaxing the fairness of locks makes them fast. That post presented lock fairness as a trade-off between two extremes: - Barging. A barging lock, like WTF::Lock, releases the lock in unlock() even if there was a thread on the queue. If there was a thread on the queue, the lock is released and that thread is made runnable. That thread may then grab the lock, or some other thread may grab the lock first (it may barge). Usually, the barging thread is the thread that released the lock in the first place. This maximizes throughput but hurts fairness. There is no good theoretical bound on how unfair the lock may become, but empirical data suggests that it's fair enough for the cases we previously measured. - FIFO. A FIFO lock, like HandoffLock in ToyLocks.h, does not release the lock in unlock() if there is a thread waiting. If there is a thread waiting, unlock() will make that thread runnable and inform it that it now holds the lock. This ensures perfect round-robin fairness and allows us to reason theoretically about how long it may take for a thread to grab the lock. For example, if we know that only N threads are running and each one may contend on a critical section, and each one may hold the lock for at most S seconds, then the time it takes to grab the lock is N * S. Unfortunately, FIFO locks perform very badly in most cases. This is because for the common case of short critical sections, they force a context switch after each critical section if the lock is contended. This change makes WTF::Lock almost as fair as FIFO while still being as fast as barging. Thanks to this new algorithm, you can now have both of these things at the same time. This change makes WTF::Lock eventually fair. We can almost (more on the caveats below) guarantee that the time it takes to grab a lock is N * max(1ms, S). In other words, critical sections that are longer than 1ms are always fair. For shorter critical sections, the amount of time that any thread waits is 1ms times the number of threads. There are some caveats that arise from our use of randomness, but even then, in the limit as the critical section length goes to infinity, the lock becomes fair. The corner cases are unlikely to happen; our experiments show that the lock becomes exactly as fair as a FIFO lock for any critical section that is 1ms or longer. The fairness mechanism is broken into two parts. WTF::Lock can now choose to unlock a lock fairly or unfairly thanks to the new ParkingLot token mechanism. WTF::Lock knows when to use fair unlocking based on a timeout mechanism in ParkingLot called timeToBeFair. ParkingLot::unparkOne() and ParkingLot::parkConditionally() can now communicate with each other via a token. unparkOne() can pass a token, which parkConditionally() will return. This change also makes parkConditionally() a lot more precise about when it was unparked due to a call to unparkOne(). If unparkOne() is told that a thread was unparked then this thread is guaranteed to report that it was unparked rather than timing out, and that thread is guaranteed to get the token that unparkOne() passed. The token is an intptr_t. We use it as a boolean variable in WTF::Lock, but you could use it to pass arbitrary data structures. By default, the token is zero. WTF::Lock's unlock() will pass 1 as the token if it is doing fair unlocking. In that case, unlock() will not release the lock, and lock() will know that it holds the lock as soon as parkConditionally() returns. Note that this algorithm relies on unparkOne() invoking WTF::Lock's callback while the queue lock is held, so that WTF::Lock can make a decision about unlock strategy and inject a token while it has complete knowledge over the state of the queue. As such, it's not immediately obvious how to implement this algorithm on top of futexes. You really need ParkingLot! WTF::Lock does not use fair unlocking every time. We expose a new API, Lock::unlockFairly(), which forces the fair unlocking behavior. Additionally, ParkingLot now maintains a per-bucket stochastic fairness timeout. When the timeout fires, the unparkOne() callback sees UnparkResult::timeToBeFair = true. This timeout is set to be anywhere from 0ms to 1ms at random. When a dequeue happens and there are threads that actually get dequeued, we check if the time since the last unfair unlock (the last time timeToBeFair was set to true) is more than the timeout amount. If so, then we set timeToBeFair to true and reset the timeout. This means that in the absence of ParkingLot collisions, unfair unlocking is guaranteed to happen at least once per millisecond. It will happen at 2 KHz on average. If there are collisions, then each collision adds one millisecond to the worst case (and 0.5 ms to the average case). The reason why we don't just use a fixed 1ms timeout is that we want to avoid resonance. Imagine a program in which some thread acquires a lock at 1 KHz in-phase with the timeToBeFair timeout. Then this thread would be the benefactor of fairness to the detriment of everyone else. Randomness ensures that we aren't too fair to any one thread. Empirically, this is neutral on our major benchmarks like JetStream but it's an enormous improvement in LockFairnessTest. It's common for an unfair lock (either our BargingLock, the old WTF::Lock, any of the other futex-based locks that barge, or new os_unfair_lock) to allow only one thread to hold the lock during a whole second in which each thread is holding the lock for 1ms at a time. This is because in a barging lock, releasing a lock after holding it for 1ms and then reacquiring it immediately virtually ensures that none of the other threads can wake up in time to grab it before it's relocked. But the new WTF::Lock handles this case like a champ: each thread gets equal turns. Here's some data. If we launch 10 threads and have each of them run for 1 second while repeatedly holding a critical section for 1ms, then here's how many times each thread gets to hold the lock using the old WTF::Lock algorithm: 799, 6, 1, 1, 1, 1, 1, 1, 1, 1 One thread hogged the lock for almost the whole time! With the new WTF::Lock, the lock becomes totally fair: 80, 79, 79, 79, 79, 79, 79, 80, 80, 79 I don't know of anyone creating such an automatically-fair adaptive lock before, so I think that this is a pretty awesome advancement to the state of the art! This change is good for three reasons: - We do have long critical sections in WebKit and we don't want to have to worry about starvation. This reduces the likelihood that we will see starvation due to our lock strategy. - I was talking to ggaren about bmalloc's locking needs, and he wanted unlockFairly() or lockFairly() or some moral equivalent for the scavenger thread. - If we use a WTF::Lock to manage heap access in a multithreaded GC, we'll need the ability to unlock and relock without barging. * benchmarks/LockFairnessTest.cpp: (main): * benchmarks/ToyLocks.h: * wtf/Condition.h: (WTF::ConditionBase::waitUntil): (WTF::ConditionBase::notifyOne): * wtf/Lock.cpp: (WTF::LockBase::lockSlow): (WTF::LockBase::unlockSlow): (WTF::LockBase::unlockFairlySlow): (WTF::LockBase::unlockSlowImpl): * wtf/Lock.h: (WTF::LockBase::try_lock): (WTF::LockBase::unlock): (WTF::LockBase::unlockFairly): (WTF::LockBase::isHeld): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::compareAndPark): (WTF::ParkingLot::unparkOne): Tools: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Canonical link: https://commits.webkit.org/178039@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@203350 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-07-18 18:32:52 +00:00
// If didDequeue is true, then we dequeued ourselves. This means that we were not unparked.
// If didDequeue is false, then someone unparked us.
RELEASE_ASSERT(!me->nextInQueue);
WTF should have a compact Condition object to use with Lock https://bugs.webkit.org/show_bug.cgi?id=147986 Reviewed by Geoffrey Garen. Source/WTF: Adds a condition variable implementation based on ParkingLot, called simply WTF::Condition. It can be used with WTF::Lock or actually any lock implementation. It should even work with WTF::SpinLock, WTF::Mutex, or std::mutex. Best of all, Condition only requires one byte. ParkingLot almost contained all of the functionality needed to implemenet wait/notify. We could have implemented Condition using a 32-bit (or even 64-bit) version that protects against a notify that happens just before we park. But, this changes the ParkingLot API to give us the ability to run some code between when ParkingLot enqueues the current thread and when it actually sleeps. This callback is called with no locks held, so it can call unlock() on any kind of lock, so long as that lock's unlock() method doesn't recurse into ParkingLot::parkConditionally(). That seems unlikely; unlock() is more likely to call ParkingLot::unparkOne() or unparkAll(). WTF::Lock will never call parkConditionally() inside unlock(), so WTF::Lock is definitely appropriate for use with Condition. Condition supports most of the API that std::condition_variable supports. It does some things to try to reduce footgun potential. The preferred timeout form is waitUntil() which takes an absolute time from the steady_clock. The only relative timeout form also takes a predicate callback, so it's impossible to write the subtly incorrect "while (...) wait_for(...)" idiom. This patch doesn't actually introduce any uses of WTF::Condition other than the unit tests. I'll start switching code over to using WTF::Condition in another patch. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/Condition.h: Added. (WTF::Condition::Condition): (WTF::Condition::waitUntil): (WTF::Condition::waitFor): (WTF::Condition::wait): (WTF::Condition::notifyOne): (WTF::Condition::notifyAll): * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): Make this useful assertion be a release assertion. It catches cases where you unlock the lock even though you don't hold it. * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): Add the beforeSleep() callback. (WTF::ParkingLot::unparkOne): * wtf/ParkingLot.h: (WTF::ParkingLot::compareAndPark): Tools: Add a test for WTF::Condition. * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Condition.cpp: Added. (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::runLockTest): Change the name of the thread. Canonical link: https://commits.webkit.org/166094@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188400 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 20:42:11 +00:00
// Make sure that no matter what, me->address is null after this point.
{
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): Canonical link: https://commits.webkit.org/182152@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208415 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-11-05 03:02:39 +00:00
MutexLocker locker(me->parkingLock);
WTF::Lock should be fair eventually https://bugs.webkit.org/show_bug.cgi?id=159384 Reviewed by Geoffrey Garen. Source/WTF: In https://webkit.org/blog/6161/locking-in-webkit/ we showed how relaxing the fairness of locks makes them fast. That post presented lock fairness as a trade-off between two extremes: - Barging. A barging lock, like WTF::Lock, releases the lock in unlock() even if there was a thread on the queue. If there was a thread on the queue, the lock is released and that thread is made runnable. That thread may then grab the lock, or some other thread may grab the lock first (it may barge). Usually, the barging thread is the thread that released the lock in the first place. This maximizes throughput but hurts fairness. There is no good theoretical bound on how unfair the lock may become, but empirical data suggests that it's fair enough for the cases we previously measured. - FIFO. A FIFO lock, like HandoffLock in ToyLocks.h, does not release the lock in unlock() if there is a thread waiting. If there is a thread waiting, unlock() will make that thread runnable and inform it that it now holds the lock. This ensures perfect round-robin fairness and allows us to reason theoretically about how long it may take for a thread to grab the lock. For example, if we know that only N threads are running and each one may contend on a critical section, and each one may hold the lock for at most S seconds, then the time it takes to grab the lock is N * S. Unfortunately, FIFO locks perform very badly in most cases. This is because for the common case of short critical sections, they force a context switch after each critical section if the lock is contended. This change makes WTF::Lock almost as fair as FIFO while still being as fast as barging. Thanks to this new algorithm, you can now have both of these things at the same time. This change makes WTF::Lock eventually fair. We can almost (more on the caveats below) guarantee that the time it takes to grab a lock is N * max(1ms, S). In other words, critical sections that are longer than 1ms are always fair. For shorter critical sections, the amount of time that any thread waits is 1ms times the number of threads. There are some caveats that arise from our use of randomness, but even then, in the limit as the critical section length goes to infinity, the lock becomes fair. The corner cases are unlikely to happen; our experiments show that the lock becomes exactly as fair as a FIFO lock for any critical section that is 1ms or longer. The fairness mechanism is broken into two parts. WTF::Lock can now choose to unlock a lock fairly or unfairly thanks to the new ParkingLot token mechanism. WTF::Lock knows when to use fair unlocking based on a timeout mechanism in ParkingLot called timeToBeFair. ParkingLot::unparkOne() and ParkingLot::parkConditionally() can now communicate with each other via a token. unparkOne() can pass a token, which parkConditionally() will return. This change also makes parkConditionally() a lot more precise about when it was unparked due to a call to unparkOne(). If unparkOne() is told that a thread was unparked then this thread is guaranteed to report that it was unparked rather than timing out, and that thread is guaranteed to get the token that unparkOne() passed. The token is an intptr_t. We use it as a boolean variable in WTF::Lock, but you could use it to pass arbitrary data structures. By default, the token is zero. WTF::Lock's unlock() will pass 1 as the token if it is doing fair unlocking. In that case, unlock() will not release the lock, and lock() will know that it holds the lock as soon as parkConditionally() returns. Note that this algorithm relies on unparkOne() invoking WTF::Lock's callback while the queue lock is held, so that WTF::Lock can make a decision about unlock strategy and inject a token while it has complete knowledge over the state of the queue. As such, it's not immediately obvious how to implement this algorithm on top of futexes. You really need ParkingLot! WTF::Lock does not use fair unlocking every time. We expose a new API, Lock::unlockFairly(), which forces the fair unlocking behavior. Additionally, ParkingLot now maintains a per-bucket stochastic fairness timeout. When the timeout fires, the unparkOne() callback sees UnparkResult::timeToBeFair = true. This timeout is set to be anywhere from 0ms to 1ms at random. When a dequeue happens and there are threads that actually get dequeued, we check if the time since the last unfair unlock (the last time timeToBeFair was set to true) is more than the timeout amount. If so, then we set timeToBeFair to true and reset the timeout. This means that in the absence of ParkingLot collisions, unfair unlocking is guaranteed to happen at least once per millisecond. It will happen at 2 KHz on average. If there are collisions, then each collision adds one millisecond to the worst case (and 0.5 ms to the average case). The reason why we don't just use a fixed 1ms timeout is that we want to avoid resonance. Imagine a program in which some thread acquires a lock at 1 KHz in-phase with the timeToBeFair timeout. Then this thread would be the benefactor of fairness to the detriment of everyone else. Randomness ensures that we aren't too fair to any one thread. Empirically, this is neutral on our major benchmarks like JetStream but it's an enormous improvement in LockFairnessTest. It's common for an unfair lock (either our BargingLock, the old WTF::Lock, any of the other futex-based locks that barge, or new os_unfair_lock) to allow only one thread to hold the lock during a whole second in which each thread is holding the lock for 1ms at a time. This is because in a barging lock, releasing a lock after holding it for 1ms and then reacquiring it immediately virtually ensures that none of the other threads can wake up in time to grab it before it's relocked. But the new WTF::Lock handles this case like a champ: each thread gets equal turns. Here's some data. If we launch 10 threads and have each of them run for 1 second while repeatedly holding a critical section for 1ms, then here's how many times each thread gets to hold the lock using the old WTF::Lock algorithm: 799, 6, 1, 1, 1, 1, 1, 1, 1, 1 One thread hogged the lock for almost the whole time! With the new WTF::Lock, the lock becomes totally fair: 80, 79, 79, 79, 79, 79, 79, 80, 80, 79 I don't know of anyone creating such an automatically-fair adaptive lock before, so I think that this is a pretty awesome advancement to the state of the art! This change is good for three reasons: - We do have long critical sections in WebKit and we don't want to have to worry about starvation. This reduces the likelihood that we will see starvation due to our lock strategy. - I was talking to ggaren about bmalloc's locking needs, and he wanted unlockFairly() or lockFairly() or some moral equivalent for the scavenger thread. - If we use a WTF::Lock to manage heap access in a multithreaded GC, we'll need the ability to unlock and relock without barging. * benchmarks/LockFairnessTest.cpp: (main): * benchmarks/ToyLocks.h: * wtf/Condition.h: (WTF::ConditionBase::waitUntil): (WTF::ConditionBase::notifyOne): * wtf/Lock.cpp: (WTF::LockBase::lockSlow): (WTF::LockBase::unlockSlow): (WTF::LockBase::unlockFairlySlow): (WTF::LockBase::unlockSlowImpl): * wtf/Lock.h: (WTF::LockBase::try_lock): (WTF::LockBase::unlock): (WTF::LockBase::unlockFairly): (WTF::LockBase::isHeld): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::compareAndPark): (WTF::ParkingLot::unparkOne): Tools: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Canonical link: https://commits.webkit.org/178039@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@203350 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-07-18 18:32:52 +00:00
if (!didDequeue) {
// If we did not dequeue ourselves, then someone else did. They will set our address to
// null. We don't want to proceed until they do this, because otherwise, they may set
// our address to null in some distant future when we're already trying to wait for
// other things.
while (me->address)
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): Canonical link: https://commits.webkit.org/182152@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208415 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-11-05 03:02:39 +00:00
me->parkingCondition.wait(me->parkingLock);
WTF::Lock should be fair eventually https://bugs.webkit.org/show_bug.cgi?id=159384 Reviewed by Geoffrey Garen. Source/WTF: In https://webkit.org/blog/6161/locking-in-webkit/ we showed how relaxing the fairness of locks makes them fast. That post presented lock fairness as a trade-off between two extremes: - Barging. A barging lock, like WTF::Lock, releases the lock in unlock() even if there was a thread on the queue. If there was a thread on the queue, the lock is released and that thread is made runnable. That thread may then grab the lock, or some other thread may grab the lock first (it may barge). Usually, the barging thread is the thread that released the lock in the first place. This maximizes throughput but hurts fairness. There is no good theoretical bound on how unfair the lock may become, but empirical data suggests that it's fair enough for the cases we previously measured. - FIFO. A FIFO lock, like HandoffLock in ToyLocks.h, does not release the lock in unlock() if there is a thread waiting. If there is a thread waiting, unlock() will make that thread runnable and inform it that it now holds the lock. This ensures perfect round-robin fairness and allows us to reason theoretically about how long it may take for a thread to grab the lock. For example, if we know that only N threads are running and each one may contend on a critical section, and each one may hold the lock for at most S seconds, then the time it takes to grab the lock is N * S. Unfortunately, FIFO locks perform very badly in most cases. This is because for the common case of short critical sections, they force a context switch after each critical section if the lock is contended. This change makes WTF::Lock almost as fair as FIFO while still being as fast as barging. Thanks to this new algorithm, you can now have both of these things at the same time. This change makes WTF::Lock eventually fair. We can almost (more on the caveats below) guarantee that the time it takes to grab a lock is N * max(1ms, S). In other words, critical sections that are longer than 1ms are always fair. For shorter critical sections, the amount of time that any thread waits is 1ms times the number of threads. There are some caveats that arise from our use of randomness, but even then, in the limit as the critical section length goes to infinity, the lock becomes fair. The corner cases are unlikely to happen; our experiments show that the lock becomes exactly as fair as a FIFO lock for any critical section that is 1ms or longer. The fairness mechanism is broken into two parts. WTF::Lock can now choose to unlock a lock fairly or unfairly thanks to the new ParkingLot token mechanism. WTF::Lock knows when to use fair unlocking based on a timeout mechanism in ParkingLot called timeToBeFair. ParkingLot::unparkOne() and ParkingLot::parkConditionally() can now communicate with each other via a token. unparkOne() can pass a token, which parkConditionally() will return. This change also makes parkConditionally() a lot more precise about when it was unparked due to a call to unparkOne(). If unparkOne() is told that a thread was unparked then this thread is guaranteed to report that it was unparked rather than timing out, and that thread is guaranteed to get the token that unparkOne() passed. The token is an intptr_t. We use it as a boolean variable in WTF::Lock, but you could use it to pass arbitrary data structures. By default, the token is zero. WTF::Lock's unlock() will pass 1 as the token if it is doing fair unlocking. In that case, unlock() will not release the lock, and lock() will know that it holds the lock as soon as parkConditionally() returns. Note that this algorithm relies on unparkOne() invoking WTF::Lock's callback while the queue lock is held, so that WTF::Lock can make a decision about unlock strategy and inject a token while it has complete knowledge over the state of the queue. As such, it's not immediately obvious how to implement this algorithm on top of futexes. You really need ParkingLot! WTF::Lock does not use fair unlocking every time. We expose a new API, Lock::unlockFairly(), which forces the fair unlocking behavior. Additionally, ParkingLot now maintains a per-bucket stochastic fairness timeout. When the timeout fires, the unparkOne() callback sees UnparkResult::timeToBeFair = true. This timeout is set to be anywhere from 0ms to 1ms at random. When a dequeue happens and there are threads that actually get dequeued, we check if the time since the last unfair unlock (the last time timeToBeFair was set to true) is more than the timeout amount. If so, then we set timeToBeFair to true and reset the timeout. This means that in the absence of ParkingLot collisions, unfair unlocking is guaranteed to happen at least once per millisecond. It will happen at 2 KHz on average. If there are collisions, then each collision adds one millisecond to the worst case (and 0.5 ms to the average case). The reason why we don't just use a fixed 1ms timeout is that we want to avoid resonance. Imagine a program in which some thread acquires a lock at 1 KHz in-phase with the timeToBeFair timeout. Then this thread would be the benefactor of fairness to the detriment of everyone else. Randomness ensures that we aren't too fair to any one thread. Empirically, this is neutral on our major benchmarks like JetStream but it's an enormous improvement in LockFairnessTest. It's common for an unfair lock (either our BargingLock, the old WTF::Lock, any of the other futex-based locks that barge, or new os_unfair_lock) to allow only one thread to hold the lock during a whole second in which each thread is holding the lock for 1ms at a time. This is because in a barging lock, releasing a lock after holding it for 1ms and then reacquiring it immediately virtually ensures that none of the other threads can wake up in time to grab it before it's relocked. But the new WTF::Lock handles this case like a champ: each thread gets equal turns. Here's some data. If we launch 10 threads and have each of them run for 1 second while repeatedly holding a critical section for 1ms, then here's how many times each thread gets to hold the lock using the old WTF::Lock algorithm: 799, 6, 1, 1, 1, 1, 1, 1, 1, 1 One thread hogged the lock for almost the whole time! With the new WTF::Lock, the lock becomes totally fair: 80, 79, 79, 79, 79, 79, 79, 80, 80, 79 I don't know of anyone creating such an automatically-fair adaptive lock before, so I think that this is a pretty awesome advancement to the state of the art! This change is good for three reasons: - We do have long critical sections in WebKit and we don't want to have to worry about starvation. This reduces the likelihood that we will see starvation due to our lock strategy. - I was talking to ggaren about bmalloc's locking needs, and he wanted unlockFairly() or lockFairly() or some moral equivalent for the scavenger thread. - If we use a WTF::Lock to manage heap access in a multithreaded GC, we'll need the ability to unlock and relock without barging. * benchmarks/LockFairnessTest.cpp: (main): * benchmarks/ToyLocks.h: * wtf/Condition.h: (WTF::ConditionBase::waitUntil): (WTF::ConditionBase::notifyOne): * wtf/Lock.cpp: (WTF::LockBase::lockSlow): (WTF::LockBase::unlockSlow): (WTF::LockBase::unlockFairlySlow): (WTF::LockBase::unlockSlowImpl): * wtf/Lock.h: (WTF::LockBase::try_lock): (WTF::LockBase::unlock): (WTF::LockBase::unlockFairly): (WTF::LockBase::isHeld): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::compareAndPark): (WTF::ParkingLot::unparkOne): Tools: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Canonical link: https://commits.webkit.org/178039@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@203350 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-07-18 18:32:52 +00:00
}
WTF should have a compact Condition object to use with Lock https://bugs.webkit.org/show_bug.cgi?id=147986 Reviewed by Geoffrey Garen. Source/WTF: Adds a condition variable implementation based on ParkingLot, called simply WTF::Condition. It can be used with WTF::Lock or actually any lock implementation. It should even work with WTF::SpinLock, WTF::Mutex, or std::mutex. Best of all, Condition only requires one byte. ParkingLot almost contained all of the functionality needed to implemenet wait/notify. We could have implemented Condition using a 32-bit (or even 64-bit) version that protects against a notify that happens just before we park. But, this changes the ParkingLot API to give us the ability to run some code between when ParkingLot enqueues the current thread and when it actually sleeps. This callback is called with no locks held, so it can call unlock() on any kind of lock, so long as that lock's unlock() method doesn't recurse into ParkingLot::parkConditionally(). That seems unlikely; unlock() is more likely to call ParkingLot::unparkOne() or unparkAll(). WTF::Lock will never call parkConditionally() inside unlock(), so WTF::Lock is definitely appropriate for use with Condition. Condition supports most of the API that std::condition_variable supports. It does some things to try to reduce footgun potential. The preferred timeout form is waitUntil() which takes an absolute time from the steady_clock. The only relative timeout form also takes a predicate callback, so it's impossible to write the subtly incorrect "while (...) wait_for(...)" idiom. This patch doesn't actually introduce any uses of WTF::Condition other than the unit tests. I'll start switching code over to using WTF::Condition in another patch. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/Condition.h: Added. (WTF::Condition::Condition): (WTF::Condition::waitUntil): (WTF::Condition::waitFor): (WTF::Condition::wait): (WTF::Condition::notifyOne): (WTF::Condition::notifyAll): * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): Make this useful assertion be a release assertion. It catches cases where you unlock the lock even though you don't hold it. * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): Add the beforeSleep() callback. (WTF::ParkingLot::unparkOne): * wtf/ParkingLot.h: (WTF::ParkingLot::compareAndPark): Tools: Add a test for WTF::Condition. * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Condition.cpp: Added. (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::runLockTest): Change the name of the thread. Canonical link: https://commits.webkit.org/166094@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188400 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 20:42:11 +00:00
me->address = nullptr;
}
WTF::Lock should be fair eventually https://bugs.webkit.org/show_bug.cgi?id=159384 Reviewed by Geoffrey Garen. Source/WTF: In https://webkit.org/blog/6161/locking-in-webkit/ we showed how relaxing the fairness of locks makes them fast. That post presented lock fairness as a trade-off between two extremes: - Barging. A barging lock, like WTF::Lock, releases the lock in unlock() even if there was a thread on the queue. If there was a thread on the queue, the lock is released and that thread is made runnable. That thread may then grab the lock, or some other thread may grab the lock first (it may barge). Usually, the barging thread is the thread that released the lock in the first place. This maximizes throughput but hurts fairness. There is no good theoretical bound on how unfair the lock may become, but empirical data suggests that it's fair enough for the cases we previously measured. - FIFO. A FIFO lock, like HandoffLock in ToyLocks.h, does not release the lock in unlock() if there is a thread waiting. If there is a thread waiting, unlock() will make that thread runnable and inform it that it now holds the lock. This ensures perfect round-robin fairness and allows us to reason theoretically about how long it may take for a thread to grab the lock. For example, if we know that only N threads are running and each one may contend on a critical section, and each one may hold the lock for at most S seconds, then the time it takes to grab the lock is N * S. Unfortunately, FIFO locks perform very badly in most cases. This is because for the common case of short critical sections, they force a context switch after each critical section if the lock is contended. This change makes WTF::Lock almost as fair as FIFO while still being as fast as barging. Thanks to this new algorithm, you can now have both of these things at the same time. This change makes WTF::Lock eventually fair. We can almost (more on the caveats below) guarantee that the time it takes to grab a lock is N * max(1ms, S). In other words, critical sections that are longer than 1ms are always fair. For shorter critical sections, the amount of time that any thread waits is 1ms times the number of threads. There are some caveats that arise from our use of randomness, but even then, in the limit as the critical section length goes to infinity, the lock becomes fair. The corner cases are unlikely to happen; our experiments show that the lock becomes exactly as fair as a FIFO lock for any critical section that is 1ms or longer. The fairness mechanism is broken into two parts. WTF::Lock can now choose to unlock a lock fairly or unfairly thanks to the new ParkingLot token mechanism. WTF::Lock knows when to use fair unlocking based on a timeout mechanism in ParkingLot called timeToBeFair. ParkingLot::unparkOne() and ParkingLot::parkConditionally() can now communicate with each other via a token. unparkOne() can pass a token, which parkConditionally() will return. This change also makes parkConditionally() a lot more precise about when it was unparked due to a call to unparkOne(). If unparkOne() is told that a thread was unparked then this thread is guaranteed to report that it was unparked rather than timing out, and that thread is guaranteed to get the token that unparkOne() passed. The token is an intptr_t. We use it as a boolean variable in WTF::Lock, but you could use it to pass arbitrary data structures. By default, the token is zero. WTF::Lock's unlock() will pass 1 as the token if it is doing fair unlocking. In that case, unlock() will not release the lock, and lock() will know that it holds the lock as soon as parkConditionally() returns. Note that this algorithm relies on unparkOne() invoking WTF::Lock's callback while the queue lock is held, so that WTF::Lock can make a decision about unlock strategy and inject a token while it has complete knowledge over the state of the queue. As such, it's not immediately obvious how to implement this algorithm on top of futexes. You really need ParkingLot! WTF::Lock does not use fair unlocking every time. We expose a new API, Lock::unlockFairly(), which forces the fair unlocking behavior. Additionally, ParkingLot now maintains a per-bucket stochastic fairness timeout. When the timeout fires, the unparkOne() callback sees UnparkResult::timeToBeFair = true. This timeout is set to be anywhere from 0ms to 1ms at random. When a dequeue happens and there are threads that actually get dequeued, we check if the time since the last unfair unlock (the last time timeToBeFair was set to true) is more than the timeout amount. If so, then we set timeToBeFair to true and reset the timeout. This means that in the absence of ParkingLot collisions, unfair unlocking is guaranteed to happen at least once per millisecond. It will happen at 2 KHz on average. If there are collisions, then each collision adds one millisecond to the worst case (and 0.5 ms to the average case). The reason why we don't just use a fixed 1ms timeout is that we want to avoid resonance. Imagine a program in which some thread acquires a lock at 1 KHz in-phase with the timeToBeFair timeout. Then this thread would be the benefactor of fairness to the detriment of everyone else. Randomness ensures that we aren't too fair to any one thread. Empirically, this is neutral on our major benchmarks like JetStream but it's an enormous improvement in LockFairnessTest. It's common for an unfair lock (either our BargingLock, the old WTF::Lock, any of the other futex-based locks that barge, or new os_unfair_lock) to allow only one thread to hold the lock during a whole second in which each thread is holding the lock for 1ms at a time. This is because in a barging lock, releasing a lock after holding it for 1ms and then reacquiring it immediately virtually ensures that none of the other threads can wake up in time to grab it before it's relocked. But the new WTF::Lock handles this case like a champ: each thread gets equal turns. Here's some data. If we launch 10 threads and have each of them run for 1 second while repeatedly holding a critical section for 1ms, then here's how many times each thread gets to hold the lock using the old WTF::Lock algorithm: 799, 6, 1, 1, 1, 1, 1, 1, 1, 1 One thread hogged the lock for almost the whole time! With the new WTF::Lock, the lock becomes totally fair: 80, 79, 79, 79, 79, 79, 79, 80, 80, 79 I don't know of anyone creating such an automatically-fair adaptive lock before, so I think that this is a pretty awesome advancement to the state of the art! This change is good for three reasons: - We do have long critical sections in WebKit and we don't want to have to worry about starvation. This reduces the likelihood that we will see starvation due to our lock strategy. - I was talking to ggaren about bmalloc's locking needs, and he wanted unlockFairly() or lockFairly() or some moral equivalent for the scavenger thread. - If we use a WTF::Lock to manage heap access in a multithreaded GC, we'll need the ability to unlock and relock without barging. * benchmarks/LockFairnessTest.cpp: (main): * benchmarks/ToyLocks.h: * wtf/Condition.h: (WTF::ConditionBase::waitUntil): (WTF::ConditionBase::notifyOne): * wtf/Lock.cpp: (WTF::LockBase::lockSlow): (WTF::LockBase::unlockSlow): (WTF::LockBase::unlockFairlySlow): (WTF::LockBase::unlockSlowImpl): * wtf/Lock.h: (WTF::LockBase::try_lock): (WTF::LockBase::unlock): (WTF::LockBase::unlockFairly): (WTF::LockBase::isHeld): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::compareAndPark): (WTF::ParkingLot::unparkOne): Tools: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Canonical link: https://commits.webkit.org/178039@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@203350 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-07-18 18:32:52 +00:00
ParkResult result;
result.wasUnparked = !didDequeue;
if (!didDequeue) {
// If we were unparked then there should be a token.
result.token = me->token;
}
return result;
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
}
NEVER_INLINE ParkingLot::UnparkResult ParkingLot::unparkOne(const void* address)
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
{
if (verbose)
WTF shouldn't have both Thread and ThreadIdentifier https://bugs.webkit.org/show_bug.cgi?id=180308 Reviewed by Darin Adler. Source/JavaScriptCore: * heap/MachineStackMarker.cpp: (JSC::MachineThreads::tryCopyOtherThreadStacks): * llint/LLIntSlowPaths.cpp: (JSC::LLInt::llint_trace_operand): (JSC::LLInt::llint_trace_value): (JSC::LLInt::LLINT_SLOW_PATH_DECL): (JSC::LLInt::traceFunctionPrologue): * runtime/ExceptionScope.cpp: (JSC::ExceptionScope::unexpectedExceptionMessage): * runtime/JSLock.h: (JSC::JSLock::currentThreadIsHoldingLock): * runtime/VM.cpp: (JSC::VM::throwException): * runtime/VM.h: (JSC::VM::throwingThread const): (JSC::VM::clearException): * tools/HeapVerifier.cpp: (JSC::HeapVerifier::printVerificationHeader): Source/WebCore: No behavior change. * Modules/indexeddb/IDBActiveDOMObject.h: (WebCore::IDBActiveDOMObject::originThread const): (WebCore::IDBActiveDOMObject::performCallbackOnOriginThread): (WebCore::IDBActiveDOMObject::callFunctionOnOriginThread): (WebCore::IDBActiveDOMObject::originThreadID const): Deleted. * Modules/indexeddb/IDBCursor.cpp: (WebCore::IDBCursor::IDBCursor): (WebCore::IDBCursor::~IDBCursor): (WebCore::IDBCursor::sourcesDeleted const): (WebCore::IDBCursor::transaction const): (WebCore::IDBCursor::update): (WebCore::IDBCursor::advance): (WebCore::IDBCursor::continueFunction): (WebCore::IDBCursor::uncheckedIterateCursor): (WebCore::IDBCursor::deleteFunction): (WebCore::IDBCursor::setGetResult): * Modules/indexeddb/IDBDatabase.cpp: (WebCore::IDBDatabase::~IDBDatabase): (WebCore::IDBDatabase::hasPendingActivity const): (WebCore::IDBDatabase::name const): (WebCore::IDBDatabase::version const): (WebCore::IDBDatabase::objectStoreNames const): (WebCore::IDBDatabase::renameObjectStore): (WebCore::IDBDatabase::renameIndex): (WebCore::IDBDatabase::createObjectStore): (WebCore::IDBDatabase::transaction): (WebCore::IDBDatabase::deleteObjectStore): (WebCore::IDBDatabase::close): (WebCore::IDBDatabase::connectionToServerLost): (WebCore::IDBDatabase::maybeCloseInServer): (WebCore::IDBDatabase::activeDOMObjectName const): (WebCore::IDBDatabase::canSuspendForDocumentSuspension const): (WebCore::IDBDatabase::stop): (WebCore::IDBDatabase::startVersionChangeTransaction): (WebCore::IDBDatabase::didStartTransaction): (WebCore::IDBDatabase::willCommitTransaction): (WebCore::IDBDatabase::didCommitTransaction): (WebCore::IDBDatabase::willAbortTransaction): (WebCore::IDBDatabase::didAbortTransaction): (WebCore::IDBDatabase::didCommitOrAbortTransaction): (WebCore::IDBDatabase::fireVersionChangeEvent): (WebCore::IDBDatabase::dispatchEvent): (WebCore::IDBDatabase::didCreateIndexInfo): (WebCore::IDBDatabase::didDeleteIndexInfo): * Modules/indexeddb/IDBIndex.cpp: (WebCore::IDBIndex::IDBIndex): (WebCore::IDBIndex::~IDBIndex): (WebCore::IDBIndex::name const): (WebCore::IDBIndex::setName): (WebCore::IDBIndex::objectStore): (WebCore::IDBIndex::keyPath const): (WebCore::IDBIndex::unique const): (WebCore::IDBIndex::multiEntry const): (WebCore::IDBIndex::rollbackInfoForVersionChangeAbort): (WebCore::IDBIndex::openCursor): (WebCore::IDBIndex::openKeyCursor): (WebCore::IDBIndex::doCount): (WebCore::IDBIndex::doGet): (WebCore::IDBIndex::doGetKey): (WebCore::IDBIndex::getAll): (WebCore::IDBIndex::getAllKeys): (WebCore::IDBIndex::markAsDeleted): * Modules/indexeddb/IDBObjectStore.cpp: (WebCore::IDBObjectStore::IDBObjectStore): (WebCore::IDBObjectStore::~IDBObjectStore): (WebCore::IDBObjectStore::name const): (WebCore::IDBObjectStore::setName): (WebCore::IDBObjectStore::keyPath const): (WebCore::IDBObjectStore::indexNames const): (WebCore::IDBObjectStore::transaction): (WebCore::IDBObjectStore::autoIncrement const): (WebCore::IDBObjectStore::openCursor): (WebCore::IDBObjectStore::openKeyCursor): (WebCore::IDBObjectStore::get): (WebCore::IDBObjectStore::getKey): (WebCore::IDBObjectStore::putOrAdd): (WebCore::IDBObjectStore::doDelete): (WebCore::IDBObjectStore::clear): (WebCore::IDBObjectStore::createIndex): (WebCore::IDBObjectStore::index): (WebCore::IDBObjectStore::deleteIndex): (WebCore::IDBObjectStore::doCount): (WebCore::IDBObjectStore::getAll): (WebCore::IDBObjectStore::getAllKeys): (WebCore::IDBObjectStore::markAsDeleted): (WebCore::IDBObjectStore::rollbackForVersionChangeAbort): * Modules/indexeddb/IDBOpenDBRequest.cpp: (WebCore::IDBOpenDBRequest::~IDBOpenDBRequest): (WebCore::IDBOpenDBRequest::onError): (WebCore::IDBOpenDBRequest::versionChangeTransactionDidFinish): (WebCore::IDBOpenDBRequest::fireSuccessAfterVersionChangeCommit): (WebCore::IDBOpenDBRequest::fireErrorAfterVersionChangeCompletion): (WebCore::IDBOpenDBRequest::dispatchEvent): (WebCore::IDBOpenDBRequest::onSuccess): (WebCore::IDBOpenDBRequest::onUpgradeNeeded): (WebCore::IDBOpenDBRequest::onDeleteDatabaseSuccess): (WebCore::IDBOpenDBRequest::requestCompleted): (WebCore::IDBOpenDBRequest::requestBlocked): * Modules/indexeddb/IDBRequest.cpp: (WebCore::IDBRequest::~IDBRequest): (WebCore:: const): (WebCore::IDBRequest::setSource): (WebCore::IDBRequest::setVersionChangeTransaction): (WebCore::IDBRequest::transaction const): (WebCore::IDBRequest::sourceObjectStoreIdentifier const): (WebCore::IDBRequest::sourceIndexIdentifier const): (WebCore::IDBRequest::requestedObjectStoreRecordType const): (WebCore::IDBRequest::requestedIndexRecordType const): (WebCore::IDBRequest::eventTargetInterface const): (WebCore::IDBRequest::activeDOMObjectName const): (WebCore::IDBRequest::canSuspendForDocumentSuspension const): (WebCore::IDBRequest::hasPendingActivity const): (WebCore::IDBRequest::stop): (WebCore::IDBRequest::enqueueEvent): (WebCore::IDBRequest::dispatchEvent): (WebCore::IDBRequest::uncaughtExceptionInEventHandler): (WebCore::IDBRequest::setResult): (WebCore::IDBRequest::setResultToStructuredClone): (WebCore::IDBRequest::setResultToUndefined): (WebCore::IDBRequest::resultCursor): (WebCore::IDBRequest::willIterateCursor): (WebCore::IDBRequest::didOpenOrIterateCursor): (WebCore::IDBRequest::completeRequestAndDispatchEvent): (WebCore::IDBRequest::onError): (WebCore::IDBRequest::onSuccess): * Modules/indexeddb/IDBTransaction.cpp: (WebCore::IDBTransaction::IDBTransaction): (WebCore::IDBTransaction::~IDBTransaction): (WebCore::IDBTransaction::objectStoreNames const): (WebCore::IDBTransaction::db): (WebCore::IDBTransaction::error const): (WebCore::IDBTransaction::objectStore): (WebCore::IDBTransaction::abortDueToFailedRequest): (WebCore::IDBTransaction::transitionedToFinishing): (WebCore::IDBTransaction::abort): (WebCore::IDBTransaction::internalAbort): (WebCore::IDBTransaction::abortOnServerAndCancelRequests): (WebCore::IDBTransaction::activeDOMObjectName const): (WebCore::IDBTransaction::canSuspendForDocumentSuspension const): (WebCore::IDBTransaction::hasPendingActivity const): (WebCore::IDBTransaction::stop): (WebCore::IDBTransaction::isActive const): (WebCore::IDBTransaction::isFinishedOrFinishing const): (WebCore::IDBTransaction::addRequest): (WebCore::IDBTransaction::removeRequest): (WebCore::IDBTransaction::scheduleOperation): (WebCore::IDBTransaction::schedulePendingOperationTimer): (WebCore::IDBTransaction::pendingOperationTimerFired): (WebCore::IDBTransaction::operationCompletedOnServer): (WebCore::IDBTransaction::scheduleCompletedOperationTimer): (WebCore::IDBTransaction::completedOperationTimerFired): (WebCore::IDBTransaction::commit): (WebCore::IDBTransaction::commitOnServer): (WebCore::IDBTransaction::finishAbortOrCommit): (WebCore::IDBTransaction::didStart): (WebCore::IDBTransaction::notifyDidAbort): (WebCore::IDBTransaction::didAbort): (WebCore::IDBTransaction::didCommit): (WebCore::IDBTransaction::fireOnComplete): (WebCore::IDBTransaction::fireOnAbort): (WebCore::IDBTransaction::enqueueEvent): (WebCore::IDBTransaction::dispatchEvent): (WebCore::IDBTransaction::createObjectStore): (WebCore::IDBTransaction::createObjectStoreOnServer): (WebCore::IDBTransaction::didCreateObjectStoreOnServer): (WebCore::IDBTransaction::renameObjectStore): (WebCore::IDBTransaction::renameObjectStoreOnServer): (WebCore::IDBTransaction::didRenameObjectStoreOnServer): (WebCore::IDBTransaction::createIndex): (WebCore::IDBTransaction::createIndexOnServer): (WebCore::IDBTransaction::didCreateIndexOnServer): (WebCore::IDBTransaction::renameIndex): (WebCore::IDBTransaction::renameIndexOnServer): (WebCore::IDBTransaction::didRenameIndexOnServer): (WebCore::IDBTransaction::requestOpenCursor): (WebCore::IDBTransaction::doRequestOpenCursor): (WebCore::IDBTransaction::openCursorOnServer): (WebCore::IDBTransaction::didOpenCursorOnServer): (WebCore::IDBTransaction::iterateCursor): (WebCore::IDBTransaction::iterateCursorOnServer): (WebCore::IDBTransaction::didIterateCursorOnServer): (WebCore::IDBTransaction::requestGetAllObjectStoreRecords): (WebCore::IDBTransaction::requestGetAllIndexRecords): (WebCore::IDBTransaction::getAllRecordsOnServer): (WebCore::IDBTransaction::didGetAllRecordsOnServer): (WebCore::IDBTransaction::requestGetRecord): (WebCore::IDBTransaction::requestGetValue): (WebCore::IDBTransaction::requestGetKey): (WebCore::IDBTransaction::requestIndexRecord): (WebCore::IDBTransaction::getRecordOnServer): (WebCore::IDBTransaction::didGetRecordOnServer): (WebCore::IDBTransaction::requestCount): (WebCore::IDBTransaction::getCountOnServer): (WebCore::IDBTransaction::didGetCountOnServer): (WebCore::IDBTransaction::requestDeleteRecord): (WebCore::IDBTransaction::deleteRecordOnServer): (WebCore::IDBTransaction::didDeleteRecordOnServer): (WebCore::IDBTransaction::requestClearObjectStore): (WebCore::IDBTransaction::clearObjectStoreOnServer): (WebCore::IDBTransaction::didClearObjectStoreOnServer): (WebCore::IDBTransaction::requestPutOrAdd): (WebCore::IDBTransaction::putOrAddOnServer): (WebCore::IDBTransaction::didPutOrAddOnServer): (WebCore::IDBTransaction::deleteObjectStore): (WebCore::IDBTransaction::deleteObjectStoreOnServer): (WebCore::IDBTransaction::didDeleteObjectStoreOnServer): (WebCore::IDBTransaction::deleteIndex): (WebCore::IDBTransaction::deleteIndexOnServer): (WebCore::IDBTransaction::didDeleteIndexOnServer): (WebCore::IDBTransaction::operationCompletedOnClient): (WebCore::IDBTransaction::establishOnServer): (WebCore::IDBTransaction::activate): (WebCore::IDBTransaction::deactivate): * Modules/indexeddb/client/IDBConnectionProxy.cpp: (WebCore::IDBClient::removeItemsMatchingCurrentThread): * Modules/indexeddb/client/TransactionOperation.h: (WebCore::IDBClient::TransactionOperation::~TransactionOperation): (WebCore::IDBClient::TransactionOperation::perform): (WebCore::IDBClient::TransactionOperation::transitionToCompleteOnThisThread): (WebCore::IDBClient::TransactionOperation::transitionToComplete): (WebCore::IDBClient::TransactionOperation::doComplete): (WebCore::IDBClient::TransactionOperation::originThread const): (WebCore::IDBClient::TransactionOperation::originThreadID const): Deleted. * Modules/webaudio/AudioContext.cpp: (WebCore::AudioContext::AudioContext): (WebCore::AudioContext::lock): (WebCore::AudioContext::tryLock): (WebCore::AudioContext::unlock): (WebCore::AudioContext::isAudioThread const): (WebCore::AudioContext::isGraphOwner const): * Modules/webaudio/AudioContext.h: (WebCore::AudioContext::setAudioThread): (WebCore::AudioContext::audioThread const): * Modules/webaudio/AudioDestinationNode.cpp: (WebCore::AudioDestinationNode::render): * Modules/webdatabase/Database.cpp: (WebCore::Database::performClose): (WebCore::Database::securityOrigin): * Modules/webdatabase/DatabaseDetails.h: (WebCore::DatabaseDetails::DatabaseDetails): (WebCore::DatabaseDetails::operator=): (WebCore::DatabaseDetails::thread const): (WebCore::DatabaseDetails::threadID const): Deleted. * Modules/webdatabase/DatabaseManager.cpp: (WebCore::DatabaseManager::detailsForNameAndOrigin): * Modules/webdatabase/DatabaseThread.cpp: (WebCore::DatabaseThread::databaseThread): (WebCore::DatabaseThread::recordDatabaseOpen): (WebCore::DatabaseThread::recordDatabaseClosed): * Modules/webdatabase/DatabaseThread.h: (WebCore::DatabaseThread::getThread): (WebCore::DatabaseThread::getThreadID): Deleted. * Modules/webdatabase/SQLTransaction.cpp: (WebCore::SQLTransaction::checkAndHandleClosedDatabase): * Modules/webdatabase/SQLTransactionBackend.cpp: (WebCore::SQLTransactionBackend::doCleanup): (WebCore::SQLTransactionBackend::notifyDatabaseThreadIsShuttingDown): * bindings/js/JSCallbackData.h: (WebCore::JSCallbackData::JSCallbackData): (WebCore::JSCallbackData::~JSCallbackData): * bindings/js/ScheduledAction.cpp: (WebCore::ScheduledAction::execute): * dom/ScriptExecutionContext.cpp: (WebCore::ScriptExecutionContext::createdMessagePort): (WebCore::ScriptExecutionContext::destroyedMessagePort): * page/ResourceUsageOverlay.h: * page/scrolling/ScrollingThread.cpp: (WebCore::ScrollingThread::isCurrentThread): * platform/Supplementable.h: (WebCore::Supplementable::provideSupplement): (WebCore::Supplementable::removeSupplement): (WebCore::Supplementable::requireSupplement): (WebCore::Supplementable::Supplementable): Deleted. * platform/Timer.cpp: (WebCore::TimerBase::TimerBase): (WebCore::TimerBase::start): (WebCore::TimerBase::stop): (WebCore::TimerBase::setNextFireTime): * platform/Timer.h: (WebCore::TimerBase::isActive const): * platform/graphics/cocoa/FontCacheCoreText.cpp: (WebCore::shouldAutoActivateFontIfNeeded): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.cpp: (WebCore::TextureMapperPlatformLayerProxy::activateOnCompositingThread): (WebCore::TextureMapperPlatformLayerProxy::invalidate): (WebCore::TextureMapperPlatformLayerProxy::getAvailableBuffer): (WebCore::TextureMapperPlatformLayerProxy::appendToUnusedBuffers): (WebCore::TextureMapperPlatformLayerProxy::swapBuffer): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.h: (): Deleted. * platform/ios/wak/WebCoreThread.mm: (RunWebThread): (StartWebThread): * platform/sql/SQLiteDatabase.cpp: (WebCore::SQLiteDatabase::open): (WebCore::SQLiteDatabase::close): * platform/sql/SQLiteDatabase.h: (WebCore::SQLiteDatabase::sqlite3Handle const): * workers/WorkerGlobalScope.cpp: (WebCore::WorkerGlobalScope::~WorkerGlobalScope): (WebCore::WorkerGlobalScope::isContextThread const): * workers/WorkerMessagingProxy.cpp: (WebCore::WorkerMessagingProxy::WorkerMessagingProxy): (WebCore::WorkerMessagingProxy::~WorkerMessagingProxy): * workers/WorkerRunLoop.cpp: (WebCore::WorkerRunLoop::runInMode): (WebCore::WorkerRunLoop::runCleanupTasks): * workers/WorkerThread.h: (WebCore::WorkerThread::thread const): (WebCore::WorkerThread::threadID const): Deleted. * workers/service/ServiceWorkerContainer.cpp: (WebCore::ServiceWorkerContainer::~ServiceWorkerContainer): (WebCore::ServiceWorkerContainer::scheduleJob): (WebCore::ServiceWorkerContainer::jobFailedWithException): (WebCore::ServiceWorkerContainer::scheduleTaskToFireUpdateFoundEvent): (WebCore::ServiceWorkerContainer::jobResolvedWithRegistration): (WebCore::ServiceWorkerContainer::jobResolvedWithUnregistrationResult): (WebCore::ServiceWorkerContainer::startScriptFetchForJob): (WebCore::ServiceWorkerContainer::jobFinishedLoadingScript): (WebCore::ServiceWorkerContainer::jobFailedLoadingScript): (WebCore::ServiceWorkerContainer::jobDidFinish): (WebCore::ServiceWorkerContainer::addRegistration): (WebCore::ServiceWorkerContainer::removeRegistration): (WebCore::ServiceWorkerContainer::scheduleTaskToFireControllerChangeEvent): (WebCore::ServiceWorkerContainer::contextIdentifier): * workers/service/ServiceWorkerContainer.h: * workers/service/ServiceWorkerJob.cpp: (WebCore::ServiceWorkerJob::~ServiceWorkerJob): (WebCore::ServiceWorkerJob::failedWithException): (WebCore::ServiceWorkerJob::resolvedWithRegistration): (WebCore::ServiceWorkerJob::resolvedWithUnregistrationResult): (WebCore::ServiceWorkerJob::startScriptFetch): (WebCore::ServiceWorkerJob::fetchScriptWithContext): (WebCore::ServiceWorkerJob::didReceiveResponse): (WebCore::ServiceWorkerJob::notifyFinished): * workers/service/ServiceWorkerJob.h: * xml/parser/XMLDocumentParserLibxml2.cpp: (WebCore::matchFunc): (WebCore::openFunc): (WebCore::initializeXMLParser): (WebCore::XMLParserContext::createStringParser): (WebCore::XMLParserContext::createMemoryParser): Source/WebKit: * UIProcess/API/glib/IconDatabase.cpp: * UIProcess/GenericCallback.h: (WebKit::GenericCallback::~GenericCallback): (WebKit::GenericCallback::performCallbackWithReturnValue): Source/WTF: We should use a pointer of WTF::Thread instead of ThreadIdentifier. One problem is that Windows support library uses WTF::createThread, which returns ThreadIdentifier. So we cannot drop ThreadIdentifier in Windows environment. This patch keeps ThreadIdentifier in Windows. * wtf/MainThread.cpp: (WTF::initializeMainThread): (WTF::isMainThread): (WTF::canAccessThreadLocalDataForThread): * wtf/MainThread.h: * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkCount): * wtf/RecursiveLockAdapter.h: (WTF::RecursiveLockAdapter::lock): (WTF::RecursiveLockAdapter::unlock): (WTF::RecursiveLockAdapter::tryLock): * wtf/Threading.cpp: (WTF::Thread::dump const): * wtf/Threading.h: (WTF::Thread::id const): (WTF::Thread::operator==): Deleted. (WTF::Thread::operator!=): Deleted. (WTF::currentThread): Deleted. * wtf/ThreadingPrimitives.h: * wtf/ThreadingPthreads.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::detach): (WTF::Thread::initializeCurrentTLS): (WTF::Thread::suspend): (WTF::Thread::establishPlatformSpecificHandle): (WTF::Thread::currentID): Deleted. * wtf/ThreadingWin.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::suspend): (WTF::Thread::currentDying): * wtf/mac/MainThreadMac.mm: (WTF::initializeApplicationUIThread): (WTF::initializeWebThreadPlatform): (WTF::canAccessThreadLocalDataForThread): (WTF::initializeApplicationUIThreadIdentifier): Deleted. (WTF::initializeWebThreadIdentifier): Deleted. Tools: * DumpRenderTree/mac/DumpRenderTree.mm: (dumpRenderTree): (runThread): Deleted. (runPthread): Deleted. (testThreadIdentifierMap): Deleted. * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: * TestWebKitAPI/Tests/WTF/Threading.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/196314@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@225470 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-12-04 06:13:05 +00:00
dataLog(toString(Thread::current(), ": unparking one.\n"));
UnparkResult result;
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
RefPtr<ThreadData> threadData;
result.mayHaveMoreThreads = dequeue(
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
address,
JSC should support SharedArrayBuffer https://bugs.webkit.org/show_bug.cgi?id=163986 Reviewed by Keith Miller. JSTests: This adds our own test for the various corner cases of SharedArrayBuffer. This test is meant to check all of the things that don't require concurrency. * stress/SharedArrayBuffer.js: Added. (checkAtomics): (shouldFail): (Symbol): (runAtomic): Source/JavaScriptCore: This implements https://tc39.github.io/ecmascript_sharedmem/shmem.html. There is now a new SharedArrayBuffer type. In the JS runtime, which includes typed array types, the SharedArrayBuffer is a drop-in replacement for ArrayBuffer, even though they are distinct types (new SharedArrayBuffer() instanceof ArrayBuffer == false and vice versa). The DOM will not recognize SharedArrayBuffer, or any typed array that wraps it, to ensure safety. This matches what other browsers intend to do, see https://github.com/tc39/ecmascript_sharedmem/issues/38. API is provided for the DOM to opt into SharedArrayBuffer. One notable place is postMessage, which will share the SharedArrayBuffer's underlying data storage with other workers. This creates a pool of shared memory that the workers can use to talk to each other. There is also an Atomics object in global scope, which exposes sequentially consistent atomic operations: add, and, compareExchange, exchange, load, or, store, sub, and xor. Additionally it exposes a Atomics.isLockFree utility, which takes a byte amount and returns true or false. Also there is Atomics.wake/wait, which neatly map to ParkingLot. Accesses to typed arrays that wrap SharedArrayBuffer are optimized by JSC the same way as always. I believe that DFG and B3 already obey the following memory model, which I believe is a bit weaker than Cambridge and a bit stronger than what is being proposed for SharedArrayBuffer. To predict a program's behavior under the B3 memory model, imagine the space of all possible programs that would result from running an optimizer that adversarially follows B3's transformation rules. B3 transformations are correct if the newly created program is equivalent to the old one, assuming that any opaque effect in IR (like the reads and writes of a patchpoint/call/fence) could perform any load/store that satisfies the B3::Effects summary. Opaque effects are a way of describing an infinite set of programs: any program that only does the effects summarized in B3::Effects belongs to the set. For example, this prevents motion of operations across fences since fences are summarized as opaque effects that could read or write memory. This rule alone is not enough, because it leaves the door open for turning an atomic operation (like a load) into a non-atomic one (like a load followed by a store of the same value back to the same location or multiple loads). This is not an optimization that either our compiler or the CPU would want to do. One way to think of what exactly is forbidden is that B3 transformations that mess with memory accesses can only reorder them or remove them. This means that for any execution of the untransformed program, the corresponding execution of the transformed program (i.e. with the same input arguments and the same programs filled in for the opaque effects) must have the same loads and stores, with some removed and some reordered. This is a fairly simple mental model that B3 and DFG already follow and it's based on existing abstractions for the infinite set of programs inside an opaque effect (DFG's AbstractHeaps and B3's Effects). This patch makes all atomics operations intrinsic, but the DFG doesn't know about any of them yet. That's covered by bug 164108. This ought to be perf-neutral, but I am still running tests to confirm this. I'm also still writing new tests to cover all of the Atomics functionality and the behavior of SAB objects. * API/JSTypedArray.cpp: (JSObjectGetTypedArrayBytesPtr): (JSObjectGetTypedArrayBuffer): (JSObjectMakeArrayBufferWithBytesNoCopy): * API/tests/CompareAndSwapTest.cpp: (Bitmap::concurrentTestAndSet): * CMakeLists.txt: * JavaScriptCore.xcodeproj/project.pbxproj: * dfg/DFGDesiredWatchpoints.cpp: (JSC::DFG::ArrayBufferViewWatchpointAdaptor::add): * heap/Heap.cpp: (JSC::Heap::reportExtraMemoryVisited): (JSC::Heap::reportExternalMemoryVisited): * jsc.cpp: (functionTransferArrayBuffer): * runtime/ArrayBuffer.cpp: (JSC::SharedArrayBufferContents::SharedArrayBufferContents): (JSC::SharedArrayBufferContents::~SharedArrayBufferContents): (JSC::ArrayBufferContents::ArrayBufferContents): (JSC::ArrayBufferContents::operator=): (JSC::ArrayBufferContents::~ArrayBufferContents): (JSC::ArrayBufferContents::clear): (JSC::ArrayBufferContents::destroy): (JSC::ArrayBufferContents::reset): (JSC::ArrayBufferContents::tryAllocate): (JSC::ArrayBufferContents::makeShared): (JSC::ArrayBufferContents::transferTo): (JSC::ArrayBufferContents::copyTo): (JSC::ArrayBufferContents::shareWith): (JSC::ArrayBuffer::create): (JSC::ArrayBuffer::createAdopted): (JSC::ArrayBuffer::createFromBytes): (JSC::ArrayBuffer::tryCreate): (JSC::ArrayBuffer::createUninitialized): (JSC::ArrayBuffer::tryCreateUninitialized): (JSC::ArrayBuffer::createInternal): (JSC::ArrayBuffer::ArrayBuffer): (JSC::ArrayBuffer::slice): (JSC::ArrayBuffer::sliceImpl): (JSC::ArrayBuffer::makeShared): (JSC::ArrayBuffer::setSharingMode): (JSC::ArrayBuffer::transferTo): (JSC::ArrayBuffer::transfer): Deleted. * runtime/ArrayBuffer.h: (JSC::arrayBufferSharingModeName): (JSC::SharedArrayBufferContents::data): (JSC::ArrayBufferContents::data): (JSC::ArrayBufferContents::sizeInBytes): (JSC::ArrayBufferContents::isShared): (JSC::ArrayBuffer::sharingMode): (JSC::ArrayBuffer::isShared): (JSC::ArrayBuffer::gcSizeEstimateInBytes): (JSC::arrayBufferDestructorNull): Deleted. (JSC::arrayBufferDestructorDefault): Deleted. (JSC::ArrayBufferContents::ArrayBufferContents): Deleted. (JSC::ArrayBufferContents::transfer): Deleted. (JSC::ArrayBufferContents::copyTo): Deleted. (JSC::ArrayBuffer::create): Deleted. (JSC::ArrayBuffer::createAdopted): Deleted. (JSC::ArrayBuffer::createFromBytes): Deleted. (JSC::ArrayBuffer::tryCreate): Deleted. (JSC::ArrayBuffer::createUninitialized): Deleted. (JSC::ArrayBuffer::tryCreateUninitialized): Deleted. (JSC::ArrayBuffer::createInternal): Deleted. (JSC::ArrayBuffer::ArrayBuffer): Deleted. (JSC::ArrayBuffer::slice): Deleted. (JSC::ArrayBuffer::sliceImpl): Deleted. (JSC::ArrayBufferContents::tryAllocate): Deleted. (JSC::ArrayBufferContents::~ArrayBufferContents): Deleted. * runtime/ArrayBufferSharingMode.h: Added. * runtime/ArrayBufferView.h: (JSC::ArrayBufferView::possiblySharedBuffer): (JSC::ArrayBufferView::unsharedBuffer): (JSC::ArrayBufferView::isShared): (JSC::ArrayBufferView::buffer): Deleted. * runtime/AtomicsObject.cpp: Added. (JSC::AtomicsObject::AtomicsObject): (JSC::AtomicsObject::create): (JSC::AtomicsObject::createStructure): (JSC::AtomicsObject::finishCreation): (JSC::atomicsFuncAdd): (JSC::atomicsFuncAnd): (JSC::atomicsFuncCompareExchange): (JSC::atomicsFuncExchange): (JSC::atomicsFuncIsLockFree): (JSC::atomicsFuncLoad): (JSC::atomicsFuncOr): (JSC::atomicsFuncStore): (JSC::atomicsFuncSub): (JSC::atomicsFuncWait): (JSC::atomicsFuncWake): (JSC::atomicsFuncXor): * runtime/AtomicsObject.h: Added. * runtime/CommonIdentifiers.h: * runtime/DataView.cpp: (JSC::DataView::wrap): * runtime/GenericTypedArrayViewInlines.h: (JSC::GenericTypedArrayView<Adaptor>::subarray): * runtime/Intrinsic.h: * runtime/JSArrayBuffer.cpp: (JSC::JSArrayBuffer::finishCreation): (JSC::JSArrayBuffer::isShared): (JSC::JSArrayBuffer::sharingMode): * runtime/JSArrayBuffer.h: (JSC::toPossiblySharedArrayBuffer): (JSC::toUnsharedArrayBuffer): (JSC::JSArrayBuffer::toWrapped): (JSC::toArrayBuffer): Deleted. * runtime/JSArrayBufferConstructor.cpp: (JSC::JSArrayBufferConstructor::JSArrayBufferConstructor): (JSC::JSArrayBufferConstructor::finishCreation): (JSC::JSArrayBufferConstructor::create): (JSC::constructArrayBuffer): * runtime/JSArrayBufferConstructor.h: (JSC::JSArrayBufferConstructor::sharingMode): * runtime/JSArrayBufferPrototype.cpp: (JSC::arrayBufferProtoFuncSlice): (JSC::JSArrayBufferPrototype::JSArrayBufferPrototype): (JSC::JSArrayBufferPrototype::finishCreation): (JSC::JSArrayBufferPrototype::create): * runtime/JSArrayBufferPrototype.h: * runtime/JSArrayBufferView.cpp: (JSC::JSArrayBufferView::finishCreation): (JSC::JSArrayBufferView::visitChildren): (JSC::JSArrayBufferView::unsharedBuffer): (JSC::JSArrayBufferView::unsharedJSBuffer): (JSC::JSArrayBufferView::possiblySharedJSBuffer): (JSC::JSArrayBufferView::neuter): (JSC::JSArrayBufferView::toWrapped): Deleted. * runtime/JSArrayBufferView.h: (JSC::JSArrayBufferView::jsBuffer): Deleted. * runtime/JSArrayBufferViewInlines.h: (JSC::JSArrayBufferView::isShared): (JSC::JSArrayBufferView::possiblySharedBuffer): (JSC::JSArrayBufferView::possiblySharedImpl): (JSC::JSArrayBufferView::unsharedImpl): (JSC::JSArrayBufferView::byteOffset): (JSC::JSArrayBufferView::toWrapped): (JSC::JSArrayBufferView::buffer): Deleted. (JSC::JSArrayBufferView::impl): Deleted. (JSC::JSArrayBufferView::neuter): Deleted. * runtime/JSDataView.cpp: (JSC::JSDataView::possiblySharedTypedImpl): (JSC::JSDataView::unsharedTypedImpl): (JSC::JSDataView::getTypedArrayImpl): (JSC::JSDataView::typedImpl): Deleted. * runtime/JSDataView.h: (JSC::JSDataView::possiblySharedBuffer): (JSC::JSDataView::unsharedBuffer): (JSC::JSDataView::buffer): Deleted. * runtime/JSDataViewPrototype.cpp: (JSC::dataViewProtoGetterBuffer): * runtime/JSGenericTypedArrayView.h: (JSC::toPossiblySharedNativeTypedView): (JSC::toUnsharedNativeTypedView): (JSC::JSGenericTypedArrayView<Adaptor>::toWrapped): (JSC::JSGenericTypedArrayView::typedImpl): Deleted. (JSC::toNativeTypedView): Deleted. * runtime/JSGenericTypedArrayViewInlines.h: (JSC::JSGenericTypedArrayView<Adaptor>::create): (JSC::JSGenericTypedArrayView<Adaptor>::possiblySharedTypedImpl): (JSC::JSGenericTypedArrayView<Adaptor>::unsharedTypedImpl): (JSC::JSGenericTypedArrayView<Adaptor>::getTypedArrayImpl): * runtime/JSGenericTypedArrayViewPrototypeFunctions.h: (JSC::genericTypedArrayViewProtoGetterFuncBuffer): (JSC::genericTypedArrayViewPrivateFuncSubarrayCreate): * runtime/JSGlobalObject.cpp: (JSC::createAtomicsProperty): (JSC::JSGlobalObject::init): (JSC::JSGlobalObject::visitChildren): * runtime/JSGlobalObject.h: (JSC::JSGlobalObject::arrayBufferPrototype): (JSC::JSGlobalObject::arrayBufferStructure): * runtime/MathObject.cpp: * runtime/RuntimeFlags.h: * runtime/SimpleTypedArrayController.cpp: (JSC::SimpleTypedArrayController::toJS): * runtime/TypedArrayType.h: (JSC::typedArrayTypeForType): Source/WebCore: New tests added in the LayoutTests/workers/sab directory. This teaches WebCore that a typed array could be shared or not. By default, WebCore will reject shared typed arrays as if they were not typed arrays. This ensures that we don't get race conditions in code that can't handle it. If you postMessage a SharedArrayBuffer or something that wraps it, you will send the shared memory to the other worker. * Modules/encryptedmedia/CDMSessionClearKey.cpp: (WebCore::CDMSessionClearKey::cachedKeyForKeyID): * Modules/fetch/FetchBody.cpp: (WebCore::FetchBody::extract): * Modules/mediastream/RTCDataChannel.cpp: (WebCore::RTCDataChannel::send): * Modules/webaudio/AudioBuffer.cpp: (WebCore::AudioBuffer::getChannelData): * Modules/websockets/WebSocket.cpp: (WebCore::WebSocket::send): * bindings/js/JSBlobCustom.cpp: (WebCore::constructJSBlob): * bindings/js/JSCryptoAlgorithmDictionary.cpp: (WebCore::createRsaKeyGenParams): * bindings/js/JSCryptoCustom.cpp: (WebCore::JSCrypto::getRandomValues): * bindings/js/JSCryptoOperationData.cpp: (WebCore::cryptoOperationDataFromJSValue): * bindings/js/JSDOMBinding.h: (WebCore::toJS): (WebCore::toPossiblySharedArrayBufferView): (WebCore::toUnsharedArrayBufferView): (WebCore::toPossiblySharedInt8Array): (WebCore::toPossiblySharedInt16Array): (WebCore::toPossiblySharedInt32Array): (WebCore::toPossiblySharedUint8Array): (WebCore::toPossiblySharedUint8ClampedArray): (WebCore::toPossiblySharedUint16Array): (WebCore::toPossiblySharedUint32Array): (WebCore::toPossiblySharedFloat32Array): (WebCore::toPossiblySharedFloat64Array): (WebCore::toUnsharedInt8Array): (WebCore::toUnsharedInt16Array): (WebCore::toUnsharedInt32Array): (WebCore::toUnsharedUint8Array): (WebCore::toUnsharedUint8ClampedArray): (WebCore::toUnsharedUint16Array): (WebCore::toUnsharedUint32Array): (WebCore::toUnsharedFloat32Array): (WebCore::toUnsharedFloat64Array): (WebCore::toArrayBufferView): Deleted. (WebCore::toInt8Array): Deleted. (WebCore::toInt16Array): Deleted. (WebCore::toInt32Array): Deleted. (WebCore::toUint8Array): Deleted. (WebCore::toUint8ClampedArray): Deleted. (WebCore::toUint16Array): Deleted. (WebCore::toUint32Array): Deleted. (WebCore::toFloat32Array): Deleted. (WebCore::toFloat64Array): Deleted. * bindings/js/JSDataCueCustom.cpp: (WebCore::constructJSDataCue): * bindings/js/JSDictionary.cpp: (WebCore::JSDictionary::convertValue): * bindings/js/JSFileCustom.cpp: (WebCore::constructJSFile): * bindings/js/JSMessagePortCustom.cpp: (WebCore::extractTransferables): * bindings/js/JSWebGLRenderingContextBaseCustom.cpp: (WebCore::dataFunctionf): (WebCore::dataFunctioni): (WebCore::dataFunctionMatrix): * bindings/js/JSXMLHttpRequestCustom.cpp: (WebCore::JSXMLHttpRequest::send): * bindings/js/SerializedScriptValue.cpp: (WebCore::CloneSerializer::dumpArrayBufferView): (WebCore::CloneSerializer::dumpIfTerminal): (WebCore::CloneDeserializer::readArrayBufferView): (WebCore::CloneDeserializer::readTerminal): (WebCore::SerializedScriptValue::transferArrayBuffers): * bindings/js/StructuredClone.cpp: (WebCore::structuredCloneArrayBuffer): (WebCore::structuredCloneArrayBufferView): * bindings/scripts/CodeGeneratorJS.pm: (JSValueToNative): * css/FontFace.cpp: (WebCore::FontFace::create): * html/canvas/WebGL2RenderingContext.cpp: (WebCore::WebGL2RenderingContext::bufferData): (WebCore::WebGL2RenderingContext::bufferSubData): * platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp: (WebCore::MediaPlayerPrivateAVFoundation::extractKeyURIKeyIDAndCertificateFromInitData): Source/WebKit/mac: Support the RuntimeFlag. * WebView/WebPreferencesPrivate.h: Source/WebKit/win: Support the RuntimeFlag. * Interfaces/IWebPreferencesPrivate.idl: Source/WebKit2: Adds some small things we need for SharedArrayBuffer. * UIProcess/API/C/WKPreferencesRefPrivate.h: * UIProcess/API/Cocoa/WKPreferencesPrivate.h: * WebProcess/InjectedBundle/InjectedBundle.cpp: (WebKit::InjectedBundle::createWebDataFromUint8Array): Source/WTF: Adds some small things we need for SharedArrayBuffer. * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeakRelaxed): (WTF::Atomic::exchangeAdd): (WTF::Atomic::exchangeAnd): (WTF::Atomic::exchangeOr): (WTF::Atomic::exchangeSub): (WTF::Atomic::exchangeXor): (WTF::atomicLoad): (WTF::atomicStore): (WTF::atomicCompareExchangeWeak): (WTF::atomicCompareExchangeWeakRelaxed): (WTF::atomicCompareExchangeStrong): (WTF::atomicExchangeAdd): (WTF::atomicExchangeAnd): (WTF::atomicExchangeOr): (WTF::atomicExchangeSub): (WTF::atomicExchangeXor): (WTF::atomicExchange): (WTF::Atomic::exchangeAndAdd): Deleted. (WTF::weakCompareAndSwap): Deleted. We need to be able to do atomics operations on naked pointers. We also need to be able to do all of the things that std::atomic does. This adds those things and renames weakCompareAndSwap to atomicCompareExchangeWeakRelaxed so that we're using consistent terminology. * wtf/Bitmap.h: (WTF::WordType>::concurrentTestAndSet): Renamed weakCompareAndSwap. (WTF::WordType>::concurrentTestAndClear): Renamed weakCompareAndSwap. * wtf/FastBitVector.h: (WTF::FastBitVector::atomicSetAndCheck): Renamed weakCompareAndSwap. * wtf/ParkingLot.cpp: (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkCount): * wtf/ParkingLot.h: Added unparkCount(), which lets you unpark some bounded number of threads and returns the number of threads unparked. This is just a modest extension of unparkAll(). unparkAll() now just calls unparkCount(ptr, UINT_MAX). Tools: Use the right kind of typed array API. * DumpRenderTree/TestRunner.cpp: (setAudioResultCallback): LayoutTests: Adding tests. This is a work in progress. * workers/sab: Added. * workers/sab/simple-worker-1.js: Added. (onmessage): * workers/sab/simple-worker-2.js: Added. (onmessage): * workers/sab/simple.html: Added. Canonical link: https://commits.webkit.org/181984@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208209 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-11-01 03:10:00 +00:00
// Why is this here?
// FIXME: It seems like this could be IgnoreEmpty, but I switched this to EnsureNonEmpty
// without explanation in r199760. We need it to use EnsureNonEmpty if we need to perform
// some operation while holding the bucket lock, which usually goes into the finish func.
// But if that operation is a no-op, then it's not clear why we need this.
BucketMode::EnsureNonEmpty,
WTF::Lock should be fair eventually https://bugs.webkit.org/show_bug.cgi?id=159384 Reviewed by Geoffrey Garen. Source/WTF: In https://webkit.org/blog/6161/locking-in-webkit/ we showed how relaxing the fairness of locks makes them fast. That post presented lock fairness as a trade-off between two extremes: - Barging. A barging lock, like WTF::Lock, releases the lock in unlock() even if there was a thread on the queue. If there was a thread on the queue, the lock is released and that thread is made runnable. That thread may then grab the lock, or some other thread may grab the lock first (it may barge). Usually, the barging thread is the thread that released the lock in the first place. This maximizes throughput but hurts fairness. There is no good theoretical bound on how unfair the lock may become, but empirical data suggests that it's fair enough for the cases we previously measured. - FIFO. A FIFO lock, like HandoffLock in ToyLocks.h, does not release the lock in unlock() if there is a thread waiting. If there is a thread waiting, unlock() will make that thread runnable and inform it that it now holds the lock. This ensures perfect round-robin fairness and allows us to reason theoretically about how long it may take for a thread to grab the lock. For example, if we know that only N threads are running and each one may contend on a critical section, and each one may hold the lock for at most S seconds, then the time it takes to grab the lock is N * S. Unfortunately, FIFO locks perform very badly in most cases. This is because for the common case of short critical sections, they force a context switch after each critical section if the lock is contended. This change makes WTF::Lock almost as fair as FIFO while still being as fast as barging. Thanks to this new algorithm, you can now have both of these things at the same time. This change makes WTF::Lock eventually fair. We can almost (more on the caveats below) guarantee that the time it takes to grab a lock is N * max(1ms, S). In other words, critical sections that are longer than 1ms are always fair. For shorter critical sections, the amount of time that any thread waits is 1ms times the number of threads. There are some caveats that arise from our use of randomness, but even then, in the limit as the critical section length goes to infinity, the lock becomes fair. The corner cases are unlikely to happen; our experiments show that the lock becomes exactly as fair as a FIFO lock for any critical section that is 1ms or longer. The fairness mechanism is broken into two parts. WTF::Lock can now choose to unlock a lock fairly or unfairly thanks to the new ParkingLot token mechanism. WTF::Lock knows when to use fair unlocking based on a timeout mechanism in ParkingLot called timeToBeFair. ParkingLot::unparkOne() and ParkingLot::parkConditionally() can now communicate with each other via a token. unparkOne() can pass a token, which parkConditionally() will return. This change also makes parkConditionally() a lot more precise about when it was unparked due to a call to unparkOne(). If unparkOne() is told that a thread was unparked then this thread is guaranteed to report that it was unparked rather than timing out, and that thread is guaranteed to get the token that unparkOne() passed. The token is an intptr_t. We use it as a boolean variable in WTF::Lock, but you could use it to pass arbitrary data structures. By default, the token is zero. WTF::Lock's unlock() will pass 1 as the token if it is doing fair unlocking. In that case, unlock() will not release the lock, and lock() will know that it holds the lock as soon as parkConditionally() returns. Note that this algorithm relies on unparkOne() invoking WTF::Lock's callback while the queue lock is held, so that WTF::Lock can make a decision about unlock strategy and inject a token while it has complete knowledge over the state of the queue. As such, it's not immediately obvious how to implement this algorithm on top of futexes. You really need ParkingLot! WTF::Lock does not use fair unlocking every time. We expose a new API, Lock::unlockFairly(), which forces the fair unlocking behavior. Additionally, ParkingLot now maintains a per-bucket stochastic fairness timeout. When the timeout fires, the unparkOne() callback sees UnparkResult::timeToBeFair = true. This timeout is set to be anywhere from 0ms to 1ms at random. When a dequeue happens and there are threads that actually get dequeued, we check if the time since the last unfair unlock (the last time timeToBeFair was set to true) is more than the timeout amount. If so, then we set timeToBeFair to true and reset the timeout. This means that in the absence of ParkingLot collisions, unfair unlocking is guaranteed to happen at least once per millisecond. It will happen at 2 KHz on average. If there are collisions, then each collision adds one millisecond to the worst case (and 0.5 ms to the average case). The reason why we don't just use a fixed 1ms timeout is that we want to avoid resonance. Imagine a program in which some thread acquires a lock at 1 KHz in-phase with the timeToBeFair timeout. Then this thread would be the benefactor of fairness to the detriment of everyone else. Randomness ensures that we aren't too fair to any one thread. Empirically, this is neutral on our major benchmarks like JetStream but it's an enormous improvement in LockFairnessTest. It's common for an unfair lock (either our BargingLock, the old WTF::Lock, any of the other futex-based locks that barge, or new os_unfair_lock) to allow only one thread to hold the lock during a whole second in which each thread is holding the lock for 1ms at a time. This is because in a barging lock, releasing a lock after holding it for 1ms and then reacquiring it immediately virtually ensures that none of the other threads can wake up in time to grab it before it's relocked. But the new WTF::Lock handles this case like a champ: each thread gets equal turns. Here's some data. If we launch 10 threads and have each of them run for 1 second while repeatedly holding a critical section for 1ms, then here's how many times each thread gets to hold the lock using the old WTF::Lock algorithm: 799, 6, 1, 1, 1, 1, 1, 1, 1, 1 One thread hogged the lock for almost the whole time! With the new WTF::Lock, the lock becomes totally fair: 80, 79, 79, 79, 79, 79, 79, 80, 80, 79 I don't know of anyone creating such an automatically-fair adaptive lock before, so I think that this is a pretty awesome advancement to the state of the art! This change is good for three reasons: - We do have long critical sections in WebKit and we don't want to have to worry about starvation. This reduces the likelihood that we will see starvation due to our lock strategy. - I was talking to ggaren about bmalloc's locking needs, and he wanted unlockFairly() or lockFairly() or some moral equivalent for the scavenger thread. - If we use a WTF::Lock to manage heap access in a multithreaded GC, we'll need the ability to unlock and relock without barging. * benchmarks/LockFairnessTest.cpp: (main): * benchmarks/ToyLocks.h: * wtf/Condition.h: (WTF::ConditionBase::waitUntil): (WTF::ConditionBase::notifyOne): * wtf/Lock.cpp: (WTF::LockBase::lockSlow): (WTF::LockBase::unlockSlow): (WTF::LockBase::unlockFairlySlow): (WTF::LockBase::unlockSlowImpl): * wtf/Lock.h: (WTF::LockBase::try_lock): (WTF::LockBase::unlock): (WTF::LockBase::unlockFairly): (WTF::LockBase::isHeld): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::compareAndPark): (WTF::ParkingLot::unparkOne): Tools: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Canonical link: https://commits.webkit.org/178039@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@203350 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-07-18 18:32:52 +00:00
[&] (ThreadData* element, bool) {
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
if (element->address != address)
return DequeueResult::Ignore;
threadData = element;
result.didUnparkThread = true;
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
return DequeueResult::RemoveAndStop;
WTF::Lock should not suffer from the thundering herd https://bugs.webkit.org/show_bug.cgi?id=147947 Reviewed by Geoffrey Garen. Source/WTF: This changes Lock::unlockSlow() to use unparkOne() instead of unparkAll(). The problem with doing this is that it's not obvious after calling unparkOne() if there are any other threads that are still parked on the lock's queue. If we assume that there are and leave the hasParkedBit set, then future calls to unlock() will take the slow path. We don't want that if there aren't actually any threads parked. On the other hand, if we assume that there aren't any threads parked and clear the hasParkedBit, then if there actually were some threads parked, then they may never be awoken since future calls to unlock() won't take slow path and so won't call unparkOne(). In other words, we need a way to be very precise about when we clear the hasParkedBit and we need to do it in a race-free way: it can't be the case that we clear the bit just as some thread gets parked on the queue. A similar problem arises in futexes, and one of the solutions is to have a thread that acquires a lock after parking sets the hasParkedBit. This is what Rusty Russel's usersem does. It's a subtle algorithm. Also, it means that if a thread barges in before the unparked thread runs, then that barging thread will not know that there are threads parked. This could increase the severity of barging. Since ParkingLot is a user-level API, we don't have to worry about the kernel-user security issues and so we can expose callbacks while ParkingLot is holding its internal locks. This change does exactly that for unparkOne(). The new variant of unparkOne() will call a user function while the queue from which we are unparking is locked. The callback is told basic stats about the queue: did we unpark a thread this time, and could there be more threads to unpark in the future. The callback runs while it's impossible for the queue state to change, since the ParkingLot's internal locks for the queue is held. This means that Lock::unlockSlow() can either clear, or leave, the hasParkedBit while releasing the lock inside the callback from unparkOne(). This takes care of the thundering herd problem while also reducing the greed that arises from barging threads. This required some careful reworking of the ParkingLot algorithm. The first thing I noticed was that the ThreadData::shouldPark flag was useless, since it's set exactly when ThreadData::address is non-null. Then I had to make sure that dequeue() could lazily create both hashtables and buckets, since the "callback is called while queue is locked" invariant requires that we didn't exit early due to the hashtable or bucket not being present. Note that all of this is done in such a way that the old unparkOne() and unparkAll() don't have to create any buckets, though they now may create the hashtable. We don't care as much about the hashtable being created by unpark since it's just such an unlikely scenario and it would only happen once. This change reduces the kernel CPU usage of WTF::Lock for the long critical section test by about 8x and makes it always perform as well as WTF::WordLock and WTF::Mutex for that benchmark. * benchmarks/LockSpeedTest.cpp: * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): * wtf/Lock.h: (WTF::LockBase::isLocked): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: * wtf/WordLock.h: (WTF::WordLock::isLocked): (WTF::WordLock::isFullyReset): Tools: Add testing that checks that locks return to a pristine state after contention is over. * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::LockInspector::isFullyReset): (TestWebKitAPI::runLockTest): (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/166072@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188374 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 03:51:25 +00:00
},
[] (bool) { });
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
if (!threadData) {
ASSERT(!result.didUnparkThread);
result.mayHaveMoreThreads = false;
return result;
}
WTF::Lock should not suffer from the thundering herd https://bugs.webkit.org/show_bug.cgi?id=147947 Reviewed by Geoffrey Garen. Source/WTF: This changes Lock::unlockSlow() to use unparkOne() instead of unparkAll(). The problem with doing this is that it's not obvious after calling unparkOne() if there are any other threads that are still parked on the lock's queue. If we assume that there are and leave the hasParkedBit set, then future calls to unlock() will take the slow path. We don't want that if there aren't actually any threads parked. On the other hand, if we assume that there aren't any threads parked and clear the hasParkedBit, then if there actually were some threads parked, then they may never be awoken since future calls to unlock() won't take slow path and so won't call unparkOne(). In other words, we need a way to be very precise about when we clear the hasParkedBit and we need to do it in a race-free way: it can't be the case that we clear the bit just as some thread gets parked on the queue. A similar problem arises in futexes, and one of the solutions is to have a thread that acquires a lock after parking sets the hasParkedBit. This is what Rusty Russel's usersem does. It's a subtle algorithm. Also, it means that if a thread barges in before the unparked thread runs, then that barging thread will not know that there are threads parked. This could increase the severity of barging. Since ParkingLot is a user-level API, we don't have to worry about the kernel-user security issues and so we can expose callbacks while ParkingLot is holding its internal locks. This change does exactly that for unparkOne(). The new variant of unparkOne() will call a user function while the queue from which we are unparking is locked. The callback is told basic stats about the queue: did we unpark a thread this time, and could there be more threads to unpark in the future. The callback runs while it's impossible for the queue state to change, since the ParkingLot's internal locks for the queue is held. This means that Lock::unlockSlow() can either clear, or leave, the hasParkedBit while releasing the lock inside the callback from unparkOne(). This takes care of the thundering herd problem while also reducing the greed that arises from barging threads. This required some careful reworking of the ParkingLot algorithm. The first thing I noticed was that the ThreadData::shouldPark flag was useless, since it's set exactly when ThreadData::address is non-null. Then I had to make sure that dequeue() could lazily create both hashtables and buckets, since the "callback is called while queue is locked" invariant requires that we didn't exit early due to the hashtable or bucket not being present. Note that all of this is done in such a way that the old unparkOne() and unparkAll() don't have to create any buckets, though they now may create the hashtable. We don't care as much about the hashtable being created by unpark since it's just such an unlikely scenario and it would only happen once. This change reduces the kernel CPU usage of WTF::Lock for the long critical section test by about 8x and makes it always perform as well as WTF::WordLock and WTF::Mutex for that benchmark. * benchmarks/LockSpeedTest.cpp: * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): * wtf/Lock.h: (WTF::LockBase::isLocked): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: * wtf/WordLock.h: (WTF::WordLock::isLocked): (WTF::WordLock::isFullyReset): Tools: Add testing that checks that locks return to a pristine state after contention is over. * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::LockInspector::isFullyReset): (TestWebKitAPI::runLockTest): (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/166072@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188374 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 03:51:25 +00:00
ASSERT(threadData->address);
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
{
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): Canonical link: https://commits.webkit.org/182152@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208415 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-11-05 03:02:39 +00:00
MutexLocker locker(threadData->parkingLock);
WTF::Lock should not suffer from the thundering herd https://bugs.webkit.org/show_bug.cgi?id=147947 Reviewed by Geoffrey Garen. Source/WTF: This changes Lock::unlockSlow() to use unparkOne() instead of unparkAll(). The problem with doing this is that it's not obvious after calling unparkOne() if there are any other threads that are still parked on the lock's queue. If we assume that there are and leave the hasParkedBit set, then future calls to unlock() will take the slow path. We don't want that if there aren't actually any threads parked. On the other hand, if we assume that there aren't any threads parked and clear the hasParkedBit, then if there actually were some threads parked, then they may never be awoken since future calls to unlock() won't take slow path and so won't call unparkOne(). In other words, we need a way to be very precise about when we clear the hasParkedBit and we need to do it in a race-free way: it can't be the case that we clear the bit just as some thread gets parked on the queue. A similar problem arises in futexes, and one of the solutions is to have a thread that acquires a lock after parking sets the hasParkedBit. This is what Rusty Russel's usersem does. It's a subtle algorithm. Also, it means that if a thread barges in before the unparked thread runs, then that barging thread will not know that there are threads parked. This could increase the severity of barging. Since ParkingLot is a user-level API, we don't have to worry about the kernel-user security issues and so we can expose callbacks while ParkingLot is holding its internal locks. This change does exactly that for unparkOne(). The new variant of unparkOne() will call a user function while the queue from which we are unparking is locked. The callback is told basic stats about the queue: did we unpark a thread this time, and could there be more threads to unpark in the future. The callback runs while it's impossible for the queue state to change, since the ParkingLot's internal locks for the queue is held. This means that Lock::unlockSlow() can either clear, or leave, the hasParkedBit while releasing the lock inside the callback from unparkOne(). This takes care of the thundering herd problem while also reducing the greed that arises from barging threads. This required some careful reworking of the ParkingLot algorithm. The first thing I noticed was that the ThreadData::shouldPark flag was useless, since it's set exactly when ThreadData::address is non-null. Then I had to make sure that dequeue() could lazily create both hashtables and buckets, since the "callback is called while queue is locked" invariant requires that we didn't exit early due to the hashtable or bucket not being present. Note that all of this is done in such a way that the old unparkOne() and unparkAll() don't have to create any buckets, though they now may create the hashtable. We don't care as much about the hashtable being created by unpark since it's just such an unlikely scenario and it would only happen once. This change reduces the kernel CPU usage of WTF::Lock for the long critical section test by about 8x and makes it always perform as well as WTF::WordLock and WTF::Mutex for that benchmark. * benchmarks/LockSpeedTest.cpp: * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): * wtf/Lock.h: (WTF::LockBase::isLocked): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: * wtf/WordLock.h: (WTF::WordLock::isLocked): (WTF::WordLock::isFullyReset): Tools: Add testing that checks that locks return to a pristine state after contention is over. * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::LockInspector::isFullyReset): (TestWebKitAPI::runLockTest): (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/166072@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188374 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 03:51:25 +00:00
threadData->address = nullptr;
WTF::Lock should be fair eventually https://bugs.webkit.org/show_bug.cgi?id=159384 Reviewed by Geoffrey Garen. Source/WTF: In https://webkit.org/blog/6161/locking-in-webkit/ we showed how relaxing the fairness of locks makes them fast. That post presented lock fairness as a trade-off between two extremes: - Barging. A barging lock, like WTF::Lock, releases the lock in unlock() even if there was a thread on the queue. If there was a thread on the queue, the lock is released and that thread is made runnable. That thread may then grab the lock, or some other thread may grab the lock first (it may barge). Usually, the barging thread is the thread that released the lock in the first place. This maximizes throughput but hurts fairness. There is no good theoretical bound on how unfair the lock may become, but empirical data suggests that it's fair enough for the cases we previously measured. - FIFO. A FIFO lock, like HandoffLock in ToyLocks.h, does not release the lock in unlock() if there is a thread waiting. If there is a thread waiting, unlock() will make that thread runnable and inform it that it now holds the lock. This ensures perfect round-robin fairness and allows us to reason theoretically about how long it may take for a thread to grab the lock. For example, if we know that only N threads are running and each one may contend on a critical section, and each one may hold the lock for at most S seconds, then the time it takes to grab the lock is N * S. Unfortunately, FIFO locks perform very badly in most cases. This is because for the common case of short critical sections, they force a context switch after each critical section if the lock is contended. This change makes WTF::Lock almost as fair as FIFO while still being as fast as barging. Thanks to this new algorithm, you can now have both of these things at the same time. This change makes WTF::Lock eventually fair. We can almost (more on the caveats below) guarantee that the time it takes to grab a lock is N * max(1ms, S). In other words, critical sections that are longer than 1ms are always fair. For shorter critical sections, the amount of time that any thread waits is 1ms times the number of threads. There are some caveats that arise from our use of randomness, but even then, in the limit as the critical section length goes to infinity, the lock becomes fair. The corner cases are unlikely to happen; our experiments show that the lock becomes exactly as fair as a FIFO lock for any critical section that is 1ms or longer. The fairness mechanism is broken into two parts. WTF::Lock can now choose to unlock a lock fairly or unfairly thanks to the new ParkingLot token mechanism. WTF::Lock knows when to use fair unlocking based on a timeout mechanism in ParkingLot called timeToBeFair. ParkingLot::unparkOne() and ParkingLot::parkConditionally() can now communicate with each other via a token. unparkOne() can pass a token, which parkConditionally() will return. This change also makes parkConditionally() a lot more precise about when it was unparked due to a call to unparkOne(). If unparkOne() is told that a thread was unparked then this thread is guaranteed to report that it was unparked rather than timing out, and that thread is guaranteed to get the token that unparkOne() passed. The token is an intptr_t. We use it as a boolean variable in WTF::Lock, but you could use it to pass arbitrary data structures. By default, the token is zero. WTF::Lock's unlock() will pass 1 as the token if it is doing fair unlocking. In that case, unlock() will not release the lock, and lock() will know that it holds the lock as soon as parkConditionally() returns. Note that this algorithm relies on unparkOne() invoking WTF::Lock's callback while the queue lock is held, so that WTF::Lock can make a decision about unlock strategy and inject a token while it has complete knowledge over the state of the queue. As such, it's not immediately obvious how to implement this algorithm on top of futexes. You really need ParkingLot! WTF::Lock does not use fair unlocking every time. We expose a new API, Lock::unlockFairly(), which forces the fair unlocking behavior. Additionally, ParkingLot now maintains a per-bucket stochastic fairness timeout. When the timeout fires, the unparkOne() callback sees UnparkResult::timeToBeFair = true. This timeout is set to be anywhere from 0ms to 1ms at random. When a dequeue happens and there are threads that actually get dequeued, we check if the time since the last unfair unlock (the last time timeToBeFair was set to true) is more than the timeout amount. If so, then we set timeToBeFair to true and reset the timeout. This means that in the absence of ParkingLot collisions, unfair unlocking is guaranteed to happen at least once per millisecond. It will happen at 2 KHz on average. If there are collisions, then each collision adds one millisecond to the worst case (and 0.5 ms to the average case). The reason why we don't just use a fixed 1ms timeout is that we want to avoid resonance. Imagine a program in which some thread acquires a lock at 1 KHz in-phase with the timeToBeFair timeout. Then this thread would be the benefactor of fairness to the detriment of everyone else. Randomness ensures that we aren't too fair to any one thread. Empirically, this is neutral on our major benchmarks like JetStream but it's an enormous improvement in LockFairnessTest. It's common for an unfair lock (either our BargingLock, the old WTF::Lock, any of the other futex-based locks that barge, or new os_unfair_lock) to allow only one thread to hold the lock during a whole second in which each thread is holding the lock for 1ms at a time. This is because in a barging lock, releasing a lock after holding it for 1ms and then reacquiring it immediately virtually ensures that none of the other threads can wake up in time to grab it before it's relocked. But the new WTF::Lock handles this case like a champ: each thread gets equal turns. Here's some data. If we launch 10 threads and have each of them run for 1 second while repeatedly holding a critical section for 1ms, then here's how many times each thread gets to hold the lock using the old WTF::Lock algorithm: 799, 6, 1, 1, 1, 1, 1, 1, 1, 1 One thread hogged the lock for almost the whole time! With the new WTF::Lock, the lock becomes totally fair: 80, 79, 79, 79, 79, 79, 79, 80, 80, 79 I don't know of anyone creating such an automatically-fair adaptive lock before, so I think that this is a pretty awesome advancement to the state of the art! This change is good for three reasons: - We do have long critical sections in WebKit and we don't want to have to worry about starvation. This reduces the likelihood that we will see starvation due to our lock strategy. - I was talking to ggaren about bmalloc's locking needs, and he wanted unlockFairly() or lockFairly() or some moral equivalent for the scavenger thread. - If we use a WTF::Lock to manage heap access in a multithreaded GC, we'll need the ability to unlock and relock without barging. * benchmarks/LockFairnessTest.cpp: (main): * benchmarks/ToyLocks.h: * wtf/Condition.h: (WTF::ConditionBase::waitUntil): (WTF::ConditionBase::notifyOne): * wtf/Lock.cpp: (WTF::LockBase::lockSlow): (WTF::LockBase::unlockSlow): (WTF::LockBase::unlockFairlySlow): (WTF::LockBase::unlockSlowImpl): * wtf/Lock.h: (WTF::LockBase::try_lock): (WTF::LockBase::unlock): (WTF::LockBase::unlockFairly): (WTF::LockBase::isHeld): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::compareAndPark): (WTF::ParkingLot::unparkOne): Tools: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Canonical link: https://commits.webkit.org/178039@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@203350 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-07-18 18:32:52 +00:00
threadData->token = 0;
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
}
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): Canonical link: https://commits.webkit.org/182152@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208415 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-11-05 03:02:39 +00:00
threadData->parkingCondition.signal();
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
return result;
}
ScopedLambda should have a lifetime story that makes sense to the compiler https://bugs.webkit.org/show_bug.cgi?id=158118 Reviewed by Mark Lam. Source/WTF: Prior to this change, there were two lifetime bugs in ScopedLambda: - scopedLambda(Functor&&) would bind Functor to const lambda&, so the resulting ScopedLambdaFunctor would hold a reference to the original lambda. This would have surprising behavior; for example it meant that this code was wrong: auto l = scopedLambda<things>([&] ...); The solution is to have explicit copy/move versions of scopedLambda() rather than rely on perfect forwarding. - ScopedLambdaFunctor did not override its copy or move operations, so if the compiler did not RVO scopedLambda(), it would return a ScopedLambdaFunctor whose m_arg points to a dead temporary ScopedLambdaFunctor instance. The solution is to have explicit copy/move constructors and operators, which preserve the invariant that ScopedLambda::m_arg points to this. One nice side-effect of all of these constructors and operators being explicit is that we can rely on WTFMove's excellent assertions, which helped catch the first issue. This reverts ParkingLot to use ScopedLambda again. * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): * wtf/ParkingLot.h: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): * wtf/ScopedLambda.h: (WTF::scopedLambda): Tools: Added a test case. This test crashes before the fix and now it passes. * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/ScopedLambda.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/176236@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@201433 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-05-26 21:58:42 +00:00
NEVER_INLINE void ParkingLot::unparkOneImpl(
WTF::Lock should not suffer from the thundering herd https://bugs.webkit.org/show_bug.cgi?id=147947 Reviewed by Geoffrey Garen. Source/WTF: This changes Lock::unlockSlow() to use unparkOne() instead of unparkAll(). The problem with doing this is that it's not obvious after calling unparkOne() if there are any other threads that are still parked on the lock's queue. If we assume that there are and leave the hasParkedBit set, then future calls to unlock() will take the slow path. We don't want that if there aren't actually any threads parked. On the other hand, if we assume that there aren't any threads parked and clear the hasParkedBit, then if there actually were some threads parked, then they may never be awoken since future calls to unlock() won't take slow path and so won't call unparkOne(). In other words, we need a way to be very precise about when we clear the hasParkedBit and we need to do it in a race-free way: it can't be the case that we clear the bit just as some thread gets parked on the queue. A similar problem arises in futexes, and one of the solutions is to have a thread that acquires a lock after parking sets the hasParkedBit. This is what Rusty Russel's usersem does. It's a subtle algorithm. Also, it means that if a thread barges in before the unparked thread runs, then that barging thread will not know that there are threads parked. This could increase the severity of barging. Since ParkingLot is a user-level API, we don't have to worry about the kernel-user security issues and so we can expose callbacks while ParkingLot is holding its internal locks. This change does exactly that for unparkOne(). The new variant of unparkOne() will call a user function while the queue from which we are unparking is locked. The callback is told basic stats about the queue: did we unpark a thread this time, and could there be more threads to unpark in the future. The callback runs while it's impossible for the queue state to change, since the ParkingLot's internal locks for the queue is held. This means that Lock::unlockSlow() can either clear, or leave, the hasParkedBit while releasing the lock inside the callback from unparkOne(). This takes care of the thundering herd problem while also reducing the greed that arises from barging threads. This required some careful reworking of the ParkingLot algorithm. The first thing I noticed was that the ThreadData::shouldPark flag was useless, since it's set exactly when ThreadData::address is non-null. Then I had to make sure that dequeue() could lazily create both hashtables and buckets, since the "callback is called while queue is locked" invariant requires that we didn't exit early due to the hashtable or bucket not being present. Note that all of this is done in such a way that the old unparkOne() and unparkAll() don't have to create any buckets, though they now may create the hashtable. We don't care as much about the hashtable being created by unpark since it's just such an unlikely scenario and it would only happen once. This change reduces the kernel CPU usage of WTF::Lock for the long critical section test by about 8x and makes it always perform as well as WTF::WordLock and WTF::Mutex for that benchmark. * benchmarks/LockSpeedTest.cpp: * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): * wtf/Lock.h: (WTF::LockBase::isLocked): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: * wtf/WordLock.h: (WTF::WordLock::isLocked): (WTF::WordLock::isFullyReset): Tools: Add testing that checks that locks return to a pristine state after contention is over. * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::LockInspector::isFullyReset): (TestWebKitAPI::runLockTest): (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/166072@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188374 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 03:51:25 +00:00
const void* address,
WTF::Lock should be fair eventually https://bugs.webkit.org/show_bug.cgi?id=159384 Reviewed by Geoffrey Garen. Source/WTF: In https://webkit.org/blog/6161/locking-in-webkit/ we showed how relaxing the fairness of locks makes them fast. That post presented lock fairness as a trade-off between two extremes: - Barging. A barging lock, like WTF::Lock, releases the lock in unlock() even if there was a thread on the queue. If there was a thread on the queue, the lock is released and that thread is made runnable. That thread may then grab the lock, or some other thread may grab the lock first (it may barge). Usually, the barging thread is the thread that released the lock in the first place. This maximizes throughput but hurts fairness. There is no good theoretical bound on how unfair the lock may become, but empirical data suggests that it's fair enough for the cases we previously measured. - FIFO. A FIFO lock, like HandoffLock in ToyLocks.h, does not release the lock in unlock() if there is a thread waiting. If there is a thread waiting, unlock() will make that thread runnable and inform it that it now holds the lock. This ensures perfect round-robin fairness and allows us to reason theoretically about how long it may take for a thread to grab the lock. For example, if we know that only N threads are running and each one may contend on a critical section, and each one may hold the lock for at most S seconds, then the time it takes to grab the lock is N * S. Unfortunately, FIFO locks perform very badly in most cases. This is because for the common case of short critical sections, they force a context switch after each critical section if the lock is contended. This change makes WTF::Lock almost as fair as FIFO while still being as fast as barging. Thanks to this new algorithm, you can now have both of these things at the same time. This change makes WTF::Lock eventually fair. We can almost (more on the caveats below) guarantee that the time it takes to grab a lock is N * max(1ms, S). In other words, critical sections that are longer than 1ms are always fair. For shorter critical sections, the amount of time that any thread waits is 1ms times the number of threads. There are some caveats that arise from our use of randomness, but even then, in the limit as the critical section length goes to infinity, the lock becomes fair. The corner cases are unlikely to happen; our experiments show that the lock becomes exactly as fair as a FIFO lock for any critical section that is 1ms or longer. The fairness mechanism is broken into two parts. WTF::Lock can now choose to unlock a lock fairly or unfairly thanks to the new ParkingLot token mechanism. WTF::Lock knows when to use fair unlocking based on a timeout mechanism in ParkingLot called timeToBeFair. ParkingLot::unparkOne() and ParkingLot::parkConditionally() can now communicate with each other via a token. unparkOne() can pass a token, which parkConditionally() will return. This change also makes parkConditionally() a lot more precise about when it was unparked due to a call to unparkOne(). If unparkOne() is told that a thread was unparked then this thread is guaranteed to report that it was unparked rather than timing out, and that thread is guaranteed to get the token that unparkOne() passed. The token is an intptr_t. We use it as a boolean variable in WTF::Lock, but you could use it to pass arbitrary data structures. By default, the token is zero. WTF::Lock's unlock() will pass 1 as the token if it is doing fair unlocking. In that case, unlock() will not release the lock, and lock() will know that it holds the lock as soon as parkConditionally() returns. Note that this algorithm relies on unparkOne() invoking WTF::Lock's callback while the queue lock is held, so that WTF::Lock can make a decision about unlock strategy and inject a token while it has complete knowledge over the state of the queue. As such, it's not immediately obvious how to implement this algorithm on top of futexes. You really need ParkingLot! WTF::Lock does not use fair unlocking every time. We expose a new API, Lock::unlockFairly(), which forces the fair unlocking behavior. Additionally, ParkingLot now maintains a per-bucket stochastic fairness timeout. When the timeout fires, the unparkOne() callback sees UnparkResult::timeToBeFair = true. This timeout is set to be anywhere from 0ms to 1ms at random. When a dequeue happens and there are threads that actually get dequeued, we check if the time since the last unfair unlock (the last time timeToBeFair was set to true) is more than the timeout amount. If so, then we set timeToBeFair to true and reset the timeout. This means that in the absence of ParkingLot collisions, unfair unlocking is guaranteed to happen at least once per millisecond. It will happen at 2 KHz on average. If there are collisions, then each collision adds one millisecond to the worst case (and 0.5 ms to the average case). The reason why we don't just use a fixed 1ms timeout is that we want to avoid resonance. Imagine a program in which some thread acquires a lock at 1 KHz in-phase with the timeToBeFair timeout. Then this thread would be the benefactor of fairness to the detriment of everyone else. Randomness ensures that we aren't too fair to any one thread. Empirically, this is neutral on our major benchmarks like JetStream but it's an enormous improvement in LockFairnessTest. It's common for an unfair lock (either our BargingLock, the old WTF::Lock, any of the other futex-based locks that barge, or new os_unfair_lock) to allow only one thread to hold the lock during a whole second in which each thread is holding the lock for 1ms at a time. This is because in a barging lock, releasing a lock after holding it for 1ms and then reacquiring it immediately virtually ensures that none of the other threads can wake up in time to grab it before it's relocked. But the new WTF::Lock handles this case like a champ: each thread gets equal turns. Here's some data. If we launch 10 threads and have each of them run for 1 second while repeatedly holding a critical section for 1ms, then here's how many times each thread gets to hold the lock using the old WTF::Lock algorithm: 799, 6, 1, 1, 1, 1, 1, 1, 1, 1 One thread hogged the lock for almost the whole time! With the new WTF::Lock, the lock becomes totally fair: 80, 79, 79, 79, 79, 79, 79, 80, 80, 79 I don't know of anyone creating such an automatically-fair adaptive lock before, so I think that this is a pretty awesome advancement to the state of the art! This change is good for three reasons: - We do have long critical sections in WebKit and we don't want to have to worry about starvation. This reduces the likelihood that we will see starvation due to our lock strategy. - I was talking to ggaren about bmalloc's locking needs, and he wanted unlockFairly() or lockFairly() or some moral equivalent for the scavenger thread. - If we use a WTF::Lock to manage heap access in a multithreaded GC, we'll need the ability to unlock and relock without barging. * benchmarks/LockFairnessTest.cpp: (main): * benchmarks/ToyLocks.h: * wtf/Condition.h: (WTF::ConditionBase::waitUntil): (WTF::ConditionBase::notifyOne): * wtf/Lock.cpp: (WTF::LockBase::lockSlow): (WTF::LockBase::unlockSlow): (WTF::LockBase::unlockFairlySlow): (WTF::LockBase::unlockSlowImpl): * wtf/Lock.h: (WTF::LockBase::try_lock): (WTF::LockBase::unlock): (WTF::LockBase::unlockFairly): (WTF::LockBase::isHeld): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::compareAndPark): (WTF::ParkingLot::unparkOne): Tools: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Canonical link: https://commits.webkit.org/178039@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@203350 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-07-18 18:32:52 +00:00
const ScopedLambda<intptr_t(ParkingLot::UnparkResult)>& callback)
WTF::Lock should not suffer from the thundering herd https://bugs.webkit.org/show_bug.cgi?id=147947 Reviewed by Geoffrey Garen. Source/WTF: This changes Lock::unlockSlow() to use unparkOne() instead of unparkAll(). The problem with doing this is that it's not obvious after calling unparkOne() if there are any other threads that are still parked on the lock's queue. If we assume that there are and leave the hasParkedBit set, then future calls to unlock() will take the slow path. We don't want that if there aren't actually any threads parked. On the other hand, if we assume that there aren't any threads parked and clear the hasParkedBit, then if there actually were some threads parked, then they may never be awoken since future calls to unlock() won't take slow path and so won't call unparkOne(). In other words, we need a way to be very precise about when we clear the hasParkedBit and we need to do it in a race-free way: it can't be the case that we clear the bit just as some thread gets parked on the queue. A similar problem arises in futexes, and one of the solutions is to have a thread that acquires a lock after parking sets the hasParkedBit. This is what Rusty Russel's usersem does. It's a subtle algorithm. Also, it means that if a thread barges in before the unparked thread runs, then that barging thread will not know that there are threads parked. This could increase the severity of barging. Since ParkingLot is a user-level API, we don't have to worry about the kernel-user security issues and so we can expose callbacks while ParkingLot is holding its internal locks. This change does exactly that for unparkOne(). The new variant of unparkOne() will call a user function while the queue from which we are unparking is locked. The callback is told basic stats about the queue: did we unpark a thread this time, and could there be more threads to unpark in the future. The callback runs while it's impossible for the queue state to change, since the ParkingLot's internal locks for the queue is held. This means that Lock::unlockSlow() can either clear, or leave, the hasParkedBit while releasing the lock inside the callback from unparkOne(). This takes care of the thundering herd problem while also reducing the greed that arises from barging threads. This required some careful reworking of the ParkingLot algorithm. The first thing I noticed was that the ThreadData::shouldPark flag was useless, since it's set exactly when ThreadData::address is non-null. Then I had to make sure that dequeue() could lazily create both hashtables and buckets, since the "callback is called while queue is locked" invariant requires that we didn't exit early due to the hashtable or bucket not being present. Note that all of this is done in such a way that the old unparkOne() and unparkAll() don't have to create any buckets, though they now may create the hashtable. We don't care as much about the hashtable being created by unpark since it's just such an unlikely scenario and it would only happen once. This change reduces the kernel CPU usage of WTF::Lock for the long critical section test by about 8x and makes it always perform as well as WTF::WordLock and WTF::Mutex for that benchmark. * benchmarks/LockSpeedTest.cpp: * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): * wtf/Lock.h: (WTF::LockBase::isLocked): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: * wtf/WordLock.h: (WTF::WordLock::isLocked): (WTF::WordLock::isFullyReset): Tools: Add testing that checks that locks return to a pristine state after contention is over. * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::LockInspector::isFullyReset): (TestWebKitAPI::runLockTest): (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/166072@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188374 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 03:51:25 +00:00
{
if (verbose)
WTF shouldn't have both Thread and ThreadIdentifier https://bugs.webkit.org/show_bug.cgi?id=180308 Reviewed by Darin Adler. Source/JavaScriptCore: * heap/MachineStackMarker.cpp: (JSC::MachineThreads::tryCopyOtherThreadStacks): * llint/LLIntSlowPaths.cpp: (JSC::LLInt::llint_trace_operand): (JSC::LLInt::llint_trace_value): (JSC::LLInt::LLINT_SLOW_PATH_DECL): (JSC::LLInt::traceFunctionPrologue): * runtime/ExceptionScope.cpp: (JSC::ExceptionScope::unexpectedExceptionMessage): * runtime/JSLock.h: (JSC::JSLock::currentThreadIsHoldingLock): * runtime/VM.cpp: (JSC::VM::throwException): * runtime/VM.h: (JSC::VM::throwingThread const): (JSC::VM::clearException): * tools/HeapVerifier.cpp: (JSC::HeapVerifier::printVerificationHeader): Source/WebCore: No behavior change. * Modules/indexeddb/IDBActiveDOMObject.h: (WebCore::IDBActiveDOMObject::originThread const): (WebCore::IDBActiveDOMObject::performCallbackOnOriginThread): (WebCore::IDBActiveDOMObject::callFunctionOnOriginThread): (WebCore::IDBActiveDOMObject::originThreadID const): Deleted. * Modules/indexeddb/IDBCursor.cpp: (WebCore::IDBCursor::IDBCursor): (WebCore::IDBCursor::~IDBCursor): (WebCore::IDBCursor::sourcesDeleted const): (WebCore::IDBCursor::transaction const): (WebCore::IDBCursor::update): (WebCore::IDBCursor::advance): (WebCore::IDBCursor::continueFunction): (WebCore::IDBCursor::uncheckedIterateCursor): (WebCore::IDBCursor::deleteFunction): (WebCore::IDBCursor::setGetResult): * Modules/indexeddb/IDBDatabase.cpp: (WebCore::IDBDatabase::~IDBDatabase): (WebCore::IDBDatabase::hasPendingActivity const): (WebCore::IDBDatabase::name const): (WebCore::IDBDatabase::version const): (WebCore::IDBDatabase::objectStoreNames const): (WebCore::IDBDatabase::renameObjectStore): (WebCore::IDBDatabase::renameIndex): (WebCore::IDBDatabase::createObjectStore): (WebCore::IDBDatabase::transaction): (WebCore::IDBDatabase::deleteObjectStore): (WebCore::IDBDatabase::close): (WebCore::IDBDatabase::connectionToServerLost): (WebCore::IDBDatabase::maybeCloseInServer): (WebCore::IDBDatabase::activeDOMObjectName const): (WebCore::IDBDatabase::canSuspendForDocumentSuspension const): (WebCore::IDBDatabase::stop): (WebCore::IDBDatabase::startVersionChangeTransaction): (WebCore::IDBDatabase::didStartTransaction): (WebCore::IDBDatabase::willCommitTransaction): (WebCore::IDBDatabase::didCommitTransaction): (WebCore::IDBDatabase::willAbortTransaction): (WebCore::IDBDatabase::didAbortTransaction): (WebCore::IDBDatabase::didCommitOrAbortTransaction): (WebCore::IDBDatabase::fireVersionChangeEvent): (WebCore::IDBDatabase::dispatchEvent): (WebCore::IDBDatabase::didCreateIndexInfo): (WebCore::IDBDatabase::didDeleteIndexInfo): * Modules/indexeddb/IDBIndex.cpp: (WebCore::IDBIndex::IDBIndex): (WebCore::IDBIndex::~IDBIndex): (WebCore::IDBIndex::name const): (WebCore::IDBIndex::setName): (WebCore::IDBIndex::objectStore): (WebCore::IDBIndex::keyPath const): (WebCore::IDBIndex::unique const): (WebCore::IDBIndex::multiEntry const): (WebCore::IDBIndex::rollbackInfoForVersionChangeAbort): (WebCore::IDBIndex::openCursor): (WebCore::IDBIndex::openKeyCursor): (WebCore::IDBIndex::doCount): (WebCore::IDBIndex::doGet): (WebCore::IDBIndex::doGetKey): (WebCore::IDBIndex::getAll): (WebCore::IDBIndex::getAllKeys): (WebCore::IDBIndex::markAsDeleted): * Modules/indexeddb/IDBObjectStore.cpp: (WebCore::IDBObjectStore::IDBObjectStore): (WebCore::IDBObjectStore::~IDBObjectStore): (WebCore::IDBObjectStore::name const): (WebCore::IDBObjectStore::setName): (WebCore::IDBObjectStore::keyPath const): (WebCore::IDBObjectStore::indexNames const): (WebCore::IDBObjectStore::transaction): (WebCore::IDBObjectStore::autoIncrement const): (WebCore::IDBObjectStore::openCursor): (WebCore::IDBObjectStore::openKeyCursor): (WebCore::IDBObjectStore::get): (WebCore::IDBObjectStore::getKey): (WebCore::IDBObjectStore::putOrAdd): (WebCore::IDBObjectStore::doDelete): (WebCore::IDBObjectStore::clear): (WebCore::IDBObjectStore::createIndex): (WebCore::IDBObjectStore::index): (WebCore::IDBObjectStore::deleteIndex): (WebCore::IDBObjectStore::doCount): (WebCore::IDBObjectStore::getAll): (WebCore::IDBObjectStore::getAllKeys): (WebCore::IDBObjectStore::markAsDeleted): (WebCore::IDBObjectStore::rollbackForVersionChangeAbort): * Modules/indexeddb/IDBOpenDBRequest.cpp: (WebCore::IDBOpenDBRequest::~IDBOpenDBRequest): (WebCore::IDBOpenDBRequest::onError): (WebCore::IDBOpenDBRequest::versionChangeTransactionDidFinish): (WebCore::IDBOpenDBRequest::fireSuccessAfterVersionChangeCommit): (WebCore::IDBOpenDBRequest::fireErrorAfterVersionChangeCompletion): (WebCore::IDBOpenDBRequest::dispatchEvent): (WebCore::IDBOpenDBRequest::onSuccess): (WebCore::IDBOpenDBRequest::onUpgradeNeeded): (WebCore::IDBOpenDBRequest::onDeleteDatabaseSuccess): (WebCore::IDBOpenDBRequest::requestCompleted): (WebCore::IDBOpenDBRequest::requestBlocked): * Modules/indexeddb/IDBRequest.cpp: (WebCore::IDBRequest::~IDBRequest): (WebCore:: const): (WebCore::IDBRequest::setSource): (WebCore::IDBRequest::setVersionChangeTransaction): (WebCore::IDBRequest::transaction const): (WebCore::IDBRequest::sourceObjectStoreIdentifier const): (WebCore::IDBRequest::sourceIndexIdentifier const): (WebCore::IDBRequest::requestedObjectStoreRecordType const): (WebCore::IDBRequest::requestedIndexRecordType const): (WebCore::IDBRequest::eventTargetInterface const): (WebCore::IDBRequest::activeDOMObjectName const): (WebCore::IDBRequest::canSuspendForDocumentSuspension const): (WebCore::IDBRequest::hasPendingActivity const): (WebCore::IDBRequest::stop): (WebCore::IDBRequest::enqueueEvent): (WebCore::IDBRequest::dispatchEvent): (WebCore::IDBRequest::uncaughtExceptionInEventHandler): (WebCore::IDBRequest::setResult): (WebCore::IDBRequest::setResultToStructuredClone): (WebCore::IDBRequest::setResultToUndefined): (WebCore::IDBRequest::resultCursor): (WebCore::IDBRequest::willIterateCursor): (WebCore::IDBRequest::didOpenOrIterateCursor): (WebCore::IDBRequest::completeRequestAndDispatchEvent): (WebCore::IDBRequest::onError): (WebCore::IDBRequest::onSuccess): * Modules/indexeddb/IDBTransaction.cpp: (WebCore::IDBTransaction::IDBTransaction): (WebCore::IDBTransaction::~IDBTransaction): (WebCore::IDBTransaction::objectStoreNames const): (WebCore::IDBTransaction::db): (WebCore::IDBTransaction::error const): (WebCore::IDBTransaction::objectStore): (WebCore::IDBTransaction::abortDueToFailedRequest): (WebCore::IDBTransaction::transitionedToFinishing): (WebCore::IDBTransaction::abort): (WebCore::IDBTransaction::internalAbort): (WebCore::IDBTransaction::abortOnServerAndCancelRequests): (WebCore::IDBTransaction::activeDOMObjectName const): (WebCore::IDBTransaction::canSuspendForDocumentSuspension const): (WebCore::IDBTransaction::hasPendingActivity const): (WebCore::IDBTransaction::stop): (WebCore::IDBTransaction::isActive const): (WebCore::IDBTransaction::isFinishedOrFinishing const): (WebCore::IDBTransaction::addRequest): (WebCore::IDBTransaction::removeRequest): (WebCore::IDBTransaction::scheduleOperation): (WebCore::IDBTransaction::schedulePendingOperationTimer): (WebCore::IDBTransaction::pendingOperationTimerFired): (WebCore::IDBTransaction::operationCompletedOnServer): (WebCore::IDBTransaction::scheduleCompletedOperationTimer): (WebCore::IDBTransaction::completedOperationTimerFired): (WebCore::IDBTransaction::commit): (WebCore::IDBTransaction::commitOnServer): (WebCore::IDBTransaction::finishAbortOrCommit): (WebCore::IDBTransaction::didStart): (WebCore::IDBTransaction::notifyDidAbort): (WebCore::IDBTransaction::didAbort): (WebCore::IDBTransaction::didCommit): (WebCore::IDBTransaction::fireOnComplete): (WebCore::IDBTransaction::fireOnAbort): (WebCore::IDBTransaction::enqueueEvent): (WebCore::IDBTransaction::dispatchEvent): (WebCore::IDBTransaction::createObjectStore): (WebCore::IDBTransaction::createObjectStoreOnServer): (WebCore::IDBTransaction::didCreateObjectStoreOnServer): (WebCore::IDBTransaction::renameObjectStore): (WebCore::IDBTransaction::renameObjectStoreOnServer): (WebCore::IDBTransaction::didRenameObjectStoreOnServer): (WebCore::IDBTransaction::createIndex): (WebCore::IDBTransaction::createIndexOnServer): (WebCore::IDBTransaction::didCreateIndexOnServer): (WebCore::IDBTransaction::renameIndex): (WebCore::IDBTransaction::renameIndexOnServer): (WebCore::IDBTransaction::didRenameIndexOnServer): (WebCore::IDBTransaction::requestOpenCursor): (WebCore::IDBTransaction::doRequestOpenCursor): (WebCore::IDBTransaction::openCursorOnServer): (WebCore::IDBTransaction::didOpenCursorOnServer): (WebCore::IDBTransaction::iterateCursor): (WebCore::IDBTransaction::iterateCursorOnServer): (WebCore::IDBTransaction::didIterateCursorOnServer): (WebCore::IDBTransaction::requestGetAllObjectStoreRecords): (WebCore::IDBTransaction::requestGetAllIndexRecords): (WebCore::IDBTransaction::getAllRecordsOnServer): (WebCore::IDBTransaction::didGetAllRecordsOnServer): (WebCore::IDBTransaction::requestGetRecord): (WebCore::IDBTransaction::requestGetValue): (WebCore::IDBTransaction::requestGetKey): (WebCore::IDBTransaction::requestIndexRecord): (WebCore::IDBTransaction::getRecordOnServer): (WebCore::IDBTransaction::didGetRecordOnServer): (WebCore::IDBTransaction::requestCount): (WebCore::IDBTransaction::getCountOnServer): (WebCore::IDBTransaction::didGetCountOnServer): (WebCore::IDBTransaction::requestDeleteRecord): (WebCore::IDBTransaction::deleteRecordOnServer): (WebCore::IDBTransaction::didDeleteRecordOnServer): (WebCore::IDBTransaction::requestClearObjectStore): (WebCore::IDBTransaction::clearObjectStoreOnServer): (WebCore::IDBTransaction::didClearObjectStoreOnServer): (WebCore::IDBTransaction::requestPutOrAdd): (WebCore::IDBTransaction::putOrAddOnServer): (WebCore::IDBTransaction::didPutOrAddOnServer): (WebCore::IDBTransaction::deleteObjectStore): (WebCore::IDBTransaction::deleteObjectStoreOnServer): (WebCore::IDBTransaction::didDeleteObjectStoreOnServer): (WebCore::IDBTransaction::deleteIndex): (WebCore::IDBTransaction::deleteIndexOnServer): (WebCore::IDBTransaction::didDeleteIndexOnServer): (WebCore::IDBTransaction::operationCompletedOnClient): (WebCore::IDBTransaction::establishOnServer): (WebCore::IDBTransaction::activate): (WebCore::IDBTransaction::deactivate): * Modules/indexeddb/client/IDBConnectionProxy.cpp: (WebCore::IDBClient::removeItemsMatchingCurrentThread): * Modules/indexeddb/client/TransactionOperation.h: (WebCore::IDBClient::TransactionOperation::~TransactionOperation): (WebCore::IDBClient::TransactionOperation::perform): (WebCore::IDBClient::TransactionOperation::transitionToCompleteOnThisThread): (WebCore::IDBClient::TransactionOperation::transitionToComplete): (WebCore::IDBClient::TransactionOperation::doComplete): (WebCore::IDBClient::TransactionOperation::originThread const): (WebCore::IDBClient::TransactionOperation::originThreadID const): Deleted. * Modules/webaudio/AudioContext.cpp: (WebCore::AudioContext::AudioContext): (WebCore::AudioContext::lock): (WebCore::AudioContext::tryLock): (WebCore::AudioContext::unlock): (WebCore::AudioContext::isAudioThread const): (WebCore::AudioContext::isGraphOwner const): * Modules/webaudio/AudioContext.h: (WebCore::AudioContext::setAudioThread): (WebCore::AudioContext::audioThread const): * Modules/webaudio/AudioDestinationNode.cpp: (WebCore::AudioDestinationNode::render): * Modules/webdatabase/Database.cpp: (WebCore::Database::performClose): (WebCore::Database::securityOrigin): * Modules/webdatabase/DatabaseDetails.h: (WebCore::DatabaseDetails::DatabaseDetails): (WebCore::DatabaseDetails::operator=): (WebCore::DatabaseDetails::thread const): (WebCore::DatabaseDetails::threadID const): Deleted. * Modules/webdatabase/DatabaseManager.cpp: (WebCore::DatabaseManager::detailsForNameAndOrigin): * Modules/webdatabase/DatabaseThread.cpp: (WebCore::DatabaseThread::databaseThread): (WebCore::DatabaseThread::recordDatabaseOpen): (WebCore::DatabaseThread::recordDatabaseClosed): * Modules/webdatabase/DatabaseThread.h: (WebCore::DatabaseThread::getThread): (WebCore::DatabaseThread::getThreadID): Deleted. * Modules/webdatabase/SQLTransaction.cpp: (WebCore::SQLTransaction::checkAndHandleClosedDatabase): * Modules/webdatabase/SQLTransactionBackend.cpp: (WebCore::SQLTransactionBackend::doCleanup): (WebCore::SQLTransactionBackend::notifyDatabaseThreadIsShuttingDown): * bindings/js/JSCallbackData.h: (WebCore::JSCallbackData::JSCallbackData): (WebCore::JSCallbackData::~JSCallbackData): * bindings/js/ScheduledAction.cpp: (WebCore::ScheduledAction::execute): * dom/ScriptExecutionContext.cpp: (WebCore::ScriptExecutionContext::createdMessagePort): (WebCore::ScriptExecutionContext::destroyedMessagePort): * page/ResourceUsageOverlay.h: * page/scrolling/ScrollingThread.cpp: (WebCore::ScrollingThread::isCurrentThread): * platform/Supplementable.h: (WebCore::Supplementable::provideSupplement): (WebCore::Supplementable::removeSupplement): (WebCore::Supplementable::requireSupplement): (WebCore::Supplementable::Supplementable): Deleted. * platform/Timer.cpp: (WebCore::TimerBase::TimerBase): (WebCore::TimerBase::start): (WebCore::TimerBase::stop): (WebCore::TimerBase::setNextFireTime): * platform/Timer.h: (WebCore::TimerBase::isActive const): * platform/graphics/cocoa/FontCacheCoreText.cpp: (WebCore::shouldAutoActivateFontIfNeeded): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.cpp: (WebCore::TextureMapperPlatformLayerProxy::activateOnCompositingThread): (WebCore::TextureMapperPlatformLayerProxy::invalidate): (WebCore::TextureMapperPlatformLayerProxy::getAvailableBuffer): (WebCore::TextureMapperPlatformLayerProxy::appendToUnusedBuffers): (WebCore::TextureMapperPlatformLayerProxy::swapBuffer): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.h: (): Deleted. * platform/ios/wak/WebCoreThread.mm: (RunWebThread): (StartWebThread): * platform/sql/SQLiteDatabase.cpp: (WebCore::SQLiteDatabase::open): (WebCore::SQLiteDatabase::close): * platform/sql/SQLiteDatabase.h: (WebCore::SQLiteDatabase::sqlite3Handle const): * workers/WorkerGlobalScope.cpp: (WebCore::WorkerGlobalScope::~WorkerGlobalScope): (WebCore::WorkerGlobalScope::isContextThread const): * workers/WorkerMessagingProxy.cpp: (WebCore::WorkerMessagingProxy::WorkerMessagingProxy): (WebCore::WorkerMessagingProxy::~WorkerMessagingProxy): * workers/WorkerRunLoop.cpp: (WebCore::WorkerRunLoop::runInMode): (WebCore::WorkerRunLoop::runCleanupTasks): * workers/WorkerThread.h: (WebCore::WorkerThread::thread const): (WebCore::WorkerThread::threadID const): Deleted. * workers/service/ServiceWorkerContainer.cpp: (WebCore::ServiceWorkerContainer::~ServiceWorkerContainer): (WebCore::ServiceWorkerContainer::scheduleJob): (WebCore::ServiceWorkerContainer::jobFailedWithException): (WebCore::ServiceWorkerContainer::scheduleTaskToFireUpdateFoundEvent): (WebCore::ServiceWorkerContainer::jobResolvedWithRegistration): (WebCore::ServiceWorkerContainer::jobResolvedWithUnregistrationResult): (WebCore::ServiceWorkerContainer::startScriptFetchForJob): (WebCore::ServiceWorkerContainer::jobFinishedLoadingScript): (WebCore::ServiceWorkerContainer::jobFailedLoadingScript): (WebCore::ServiceWorkerContainer::jobDidFinish): (WebCore::ServiceWorkerContainer::addRegistration): (WebCore::ServiceWorkerContainer::removeRegistration): (WebCore::ServiceWorkerContainer::scheduleTaskToFireControllerChangeEvent): (WebCore::ServiceWorkerContainer::contextIdentifier): * workers/service/ServiceWorkerContainer.h: * workers/service/ServiceWorkerJob.cpp: (WebCore::ServiceWorkerJob::~ServiceWorkerJob): (WebCore::ServiceWorkerJob::failedWithException): (WebCore::ServiceWorkerJob::resolvedWithRegistration): (WebCore::ServiceWorkerJob::resolvedWithUnregistrationResult): (WebCore::ServiceWorkerJob::startScriptFetch): (WebCore::ServiceWorkerJob::fetchScriptWithContext): (WebCore::ServiceWorkerJob::didReceiveResponse): (WebCore::ServiceWorkerJob::notifyFinished): * workers/service/ServiceWorkerJob.h: * xml/parser/XMLDocumentParserLibxml2.cpp: (WebCore::matchFunc): (WebCore::openFunc): (WebCore::initializeXMLParser): (WebCore::XMLParserContext::createStringParser): (WebCore::XMLParserContext::createMemoryParser): Source/WebKit: * UIProcess/API/glib/IconDatabase.cpp: * UIProcess/GenericCallback.h: (WebKit::GenericCallback::~GenericCallback): (WebKit::GenericCallback::performCallbackWithReturnValue): Source/WTF: We should use a pointer of WTF::Thread instead of ThreadIdentifier. One problem is that Windows support library uses WTF::createThread, which returns ThreadIdentifier. So we cannot drop ThreadIdentifier in Windows environment. This patch keeps ThreadIdentifier in Windows. * wtf/MainThread.cpp: (WTF::initializeMainThread): (WTF::isMainThread): (WTF::canAccessThreadLocalDataForThread): * wtf/MainThread.h: * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkCount): * wtf/RecursiveLockAdapter.h: (WTF::RecursiveLockAdapter::lock): (WTF::RecursiveLockAdapter::unlock): (WTF::RecursiveLockAdapter::tryLock): * wtf/Threading.cpp: (WTF::Thread::dump const): * wtf/Threading.h: (WTF::Thread::id const): (WTF::Thread::operator==): Deleted. (WTF::Thread::operator!=): Deleted. (WTF::currentThread): Deleted. * wtf/ThreadingPrimitives.h: * wtf/ThreadingPthreads.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::detach): (WTF::Thread::initializeCurrentTLS): (WTF::Thread::suspend): (WTF::Thread::establishPlatformSpecificHandle): (WTF::Thread::currentID): Deleted. * wtf/ThreadingWin.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::suspend): (WTF::Thread::currentDying): * wtf/mac/MainThreadMac.mm: (WTF::initializeApplicationUIThread): (WTF::initializeWebThreadPlatform): (WTF::canAccessThreadLocalDataForThread): (WTF::initializeApplicationUIThreadIdentifier): Deleted. (WTF::initializeWebThreadIdentifier): Deleted. Tools: * DumpRenderTree/mac/DumpRenderTree.mm: (dumpRenderTree): (runThread): Deleted. (runPthread): Deleted. (testThreadIdentifierMap): Deleted. * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: * TestWebKitAPI/Tests/WTF/Threading.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/196314@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@225470 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-12-04 06:13:05 +00:00
dataLog(toString(Thread::current(), ": unparking one the hard way.\n"));
WTF::Lock should be fair eventually https://bugs.webkit.org/show_bug.cgi?id=159384 Reviewed by Geoffrey Garen. Source/WTF: In https://webkit.org/blog/6161/locking-in-webkit/ we showed how relaxing the fairness of locks makes them fast. That post presented lock fairness as a trade-off between two extremes: - Barging. A barging lock, like WTF::Lock, releases the lock in unlock() even if there was a thread on the queue. If there was a thread on the queue, the lock is released and that thread is made runnable. That thread may then grab the lock, or some other thread may grab the lock first (it may barge). Usually, the barging thread is the thread that released the lock in the first place. This maximizes throughput but hurts fairness. There is no good theoretical bound on how unfair the lock may become, but empirical data suggests that it's fair enough for the cases we previously measured. - FIFO. A FIFO lock, like HandoffLock in ToyLocks.h, does not release the lock in unlock() if there is a thread waiting. If there is a thread waiting, unlock() will make that thread runnable and inform it that it now holds the lock. This ensures perfect round-robin fairness and allows us to reason theoretically about how long it may take for a thread to grab the lock. For example, if we know that only N threads are running and each one may contend on a critical section, and each one may hold the lock for at most S seconds, then the time it takes to grab the lock is N * S. Unfortunately, FIFO locks perform very badly in most cases. This is because for the common case of short critical sections, they force a context switch after each critical section if the lock is contended. This change makes WTF::Lock almost as fair as FIFO while still being as fast as barging. Thanks to this new algorithm, you can now have both of these things at the same time. This change makes WTF::Lock eventually fair. We can almost (more on the caveats below) guarantee that the time it takes to grab a lock is N * max(1ms, S). In other words, critical sections that are longer than 1ms are always fair. For shorter critical sections, the amount of time that any thread waits is 1ms times the number of threads. There are some caveats that arise from our use of randomness, but even then, in the limit as the critical section length goes to infinity, the lock becomes fair. The corner cases are unlikely to happen; our experiments show that the lock becomes exactly as fair as a FIFO lock for any critical section that is 1ms or longer. The fairness mechanism is broken into two parts. WTF::Lock can now choose to unlock a lock fairly or unfairly thanks to the new ParkingLot token mechanism. WTF::Lock knows when to use fair unlocking based on a timeout mechanism in ParkingLot called timeToBeFair. ParkingLot::unparkOne() and ParkingLot::parkConditionally() can now communicate with each other via a token. unparkOne() can pass a token, which parkConditionally() will return. This change also makes parkConditionally() a lot more precise about when it was unparked due to a call to unparkOne(). If unparkOne() is told that a thread was unparked then this thread is guaranteed to report that it was unparked rather than timing out, and that thread is guaranteed to get the token that unparkOne() passed. The token is an intptr_t. We use it as a boolean variable in WTF::Lock, but you could use it to pass arbitrary data structures. By default, the token is zero. WTF::Lock's unlock() will pass 1 as the token if it is doing fair unlocking. In that case, unlock() will not release the lock, and lock() will know that it holds the lock as soon as parkConditionally() returns. Note that this algorithm relies on unparkOne() invoking WTF::Lock's callback while the queue lock is held, so that WTF::Lock can make a decision about unlock strategy and inject a token while it has complete knowledge over the state of the queue. As such, it's not immediately obvious how to implement this algorithm on top of futexes. You really need ParkingLot! WTF::Lock does not use fair unlocking every time. We expose a new API, Lock::unlockFairly(), which forces the fair unlocking behavior. Additionally, ParkingLot now maintains a per-bucket stochastic fairness timeout. When the timeout fires, the unparkOne() callback sees UnparkResult::timeToBeFair = true. This timeout is set to be anywhere from 0ms to 1ms at random. When a dequeue happens and there are threads that actually get dequeued, we check if the time since the last unfair unlock (the last time timeToBeFair was set to true) is more than the timeout amount. If so, then we set timeToBeFair to true and reset the timeout. This means that in the absence of ParkingLot collisions, unfair unlocking is guaranteed to happen at least once per millisecond. It will happen at 2 KHz on average. If there are collisions, then each collision adds one millisecond to the worst case (and 0.5 ms to the average case). The reason why we don't just use a fixed 1ms timeout is that we want to avoid resonance. Imagine a program in which some thread acquires a lock at 1 KHz in-phase with the timeToBeFair timeout. Then this thread would be the benefactor of fairness to the detriment of everyone else. Randomness ensures that we aren't too fair to any one thread. Empirically, this is neutral on our major benchmarks like JetStream but it's an enormous improvement in LockFairnessTest. It's common for an unfair lock (either our BargingLock, the old WTF::Lock, any of the other futex-based locks that barge, or new os_unfair_lock) to allow only one thread to hold the lock during a whole second in which each thread is holding the lock for 1ms at a time. This is because in a barging lock, releasing a lock after holding it for 1ms and then reacquiring it immediately virtually ensures that none of the other threads can wake up in time to grab it before it's relocked. But the new WTF::Lock handles this case like a champ: each thread gets equal turns. Here's some data. If we launch 10 threads and have each of them run for 1 second while repeatedly holding a critical section for 1ms, then here's how many times each thread gets to hold the lock using the old WTF::Lock algorithm: 799, 6, 1, 1, 1, 1, 1, 1, 1, 1 One thread hogged the lock for almost the whole time! With the new WTF::Lock, the lock becomes totally fair: 80, 79, 79, 79, 79, 79, 79, 80, 80, 79 I don't know of anyone creating such an automatically-fair adaptive lock before, so I think that this is a pretty awesome advancement to the state of the art! This change is good for three reasons: - We do have long critical sections in WebKit and we don't want to have to worry about starvation. This reduces the likelihood that we will see starvation due to our lock strategy. - I was talking to ggaren about bmalloc's locking needs, and he wanted unlockFairly() or lockFairly() or some moral equivalent for the scavenger thread. - If we use a WTF::Lock to manage heap access in a multithreaded GC, we'll need the ability to unlock and relock without barging. * benchmarks/LockFairnessTest.cpp: (main): * benchmarks/ToyLocks.h: * wtf/Condition.h: (WTF::ConditionBase::waitUntil): (WTF::ConditionBase::notifyOne): * wtf/Lock.cpp: (WTF::LockBase::lockSlow): (WTF::LockBase::unlockSlow): (WTF::LockBase::unlockFairlySlow): (WTF::LockBase::unlockSlowImpl): * wtf/Lock.h: (WTF::LockBase::try_lock): (WTF::LockBase::unlock): (WTF::LockBase::unlockFairly): (WTF::LockBase::isHeld): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::compareAndPark): (WTF::ParkingLot::unparkOne): Tools: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Canonical link: https://commits.webkit.org/178039@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@203350 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-07-18 18:32:52 +00:00
RefPtr<ThreadData> threadData;
WTF::Lock should be fair eventually https://bugs.webkit.org/show_bug.cgi?id=159384 Reviewed by Geoffrey Garen. Source/WTF: In https://webkit.org/blog/6161/locking-in-webkit/ we showed how relaxing the fairness of locks makes them fast. That post presented lock fairness as a trade-off between two extremes: - Barging. A barging lock, like WTF::Lock, releases the lock in unlock() even if there was a thread on the queue. If there was a thread on the queue, the lock is released and that thread is made runnable. That thread may then grab the lock, or some other thread may grab the lock first (it may barge). Usually, the barging thread is the thread that released the lock in the first place. This maximizes throughput but hurts fairness. There is no good theoretical bound on how unfair the lock may become, but empirical data suggests that it's fair enough for the cases we previously measured. - FIFO. A FIFO lock, like HandoffLock in ToyLocks.h, does not release the lock in unlock() if there is a thread waiting. If there is a thread waiting, unlock() will make that thread runnable and inform it that it now holds the lock. This ensures perfect round-robin fairness and allows us to reason theoretically about how long it may take for a thread to grab the lock. For example, if we know that only N threads are running and each one may contend on a critical section, and each one may hold the lock for at most S seconds, then the time it takes to grab the lock is N * S. Unfortunately, FIFO locks perform very badly in most cases. This is because for the common case of short critical sections, they force a context switch after each critical section if the lock is contended. This change makes WTF::Lock almost as fair as FIFO while still being as fast as barging. Thanks to this new algorithm, you can now have both of these things at the same time. This change makes WTF::Lock eventually fair. We can almost (more on the caveats below) guarantee that the time it takes to grab a lock is N * max(1ms, S). In other words, critical sections that are longer than 1ms are always fair. For shorter critical sections, the amount of time that any thread waits is 1ms times the number of threads. There are some caveats that arise from our use of randomness, but even then, in the limit as the critical section length goes to infinity, the lock becomes fair. The corner cases are unlikely to happen; our experiments show that the lock becomes exactly as fair as a FIFO lock for any critical section that is 1ms or longer. The fairness mechanism is broken into two parts. WTF::Lock can now choose to unlock a lock fairly or unfairly thanks to the new ParkingLot token mechanism. WTF::Lock knows when to use fair unlocking based on a timeout mechanism in ParkingLot called timeToBeFair. ParkingLot::unparkOne() and ParkingLot::parkConditionally() can now communicate with each other via a token. unparkOne() can pass a token, which parkConditionally() will return. This change also makes parkConditionally() a lot more precise about when it was unparked due to a call to unparkOne(). If unparkOne() is told that a thread was unparked then this thread is guaranteed to report that it was unparked rather than timing out, and that thread is guaranteed to get the token that unparkOne() passed. The token is an intptr_t. We use it as a boolean variable in WTF::Lock, but you could use it to pass arbitrary data structures. By default, the token is zero. WTF::Lock's unlock() will pass 1 as the token if it is doing fair unlocking. In that case, unlock() will not release the lock, and lock() will know that it holds the lock as soon as parkConditionally() returns. Note that this algorithm relies on unparkOne() invoking WTF::Lock's callback while the queue lock is held, so that WTF::Lock can make a decision about unlock strategy and inject a token while it has complete knowledge over the state of the queue. As such, it's not immediately obvious how to implement this algorithm on top of futexes. You really need ParkingLot! WTF::Lock does not use fair unlocking every time. We expose a new API, Lock::unlockFairly(), which forces the fair unlocking behavior. Additionally, ParkingLot now maintains a per-bucket stochastic fairness timeout. When the timeout fires, the unparkOne() callback sees UnparkResult::timeToBeFair = true. This timeout is set to be anywhere from 0ms to 1ms at random. When a dequeue happens and there are threads that actually get dequeued, we check if the time since the last unfair unlock (the last time timeToBeFair was set to true) is more than the timeout amount. If so, then we set timeToBeFair to true and reset the timeout. This means that in the absence of ParkingLot collisions, unfair unlocking is guaranteed to happen at least once per millisecond. It will happen at 2 KHz on average. If there are collisions, then each collision adds one millisecond to the worst case (and 0.5 ms to the average case). The reason why we don't just use a fixed 1ms timeout is that we want to avoid resonance. Imagine a program in which some thread acquires a lock at 1 KHz in-phase with the timeToBeFair timeout. Then this thread would be the benefactor of fairness to the detriment of everyone else. Randomness ensures that we aren't too fair to any one thread. Empirically, this is neutral on our major benchmarks like JetStream but it's an enormous improvement in LockFairnessTest. It's common for an unfair lock (either our BargingLock, the old WTF::Lock, any of the other futex-based locks that barge, or new os_unfair_lock) to allow only one thread to hold the lock during a whole second in which each thread is holding the lock for 1ms at a time. This is because in a barging lock, releasing a lock after holding it for 1ms and then reacquiring it immediately virtually ensures that none of the other threads can wake up in time to grab it before it's relocked. But the new WTF::Lock handles this case like a champ: each thread gets equal turns. Here's some data. If we launch 10 threads and have each of them run for 1 second while repeatedly holding a critical section for 1ms, then here's how many times each thread gets to hold the lock using the old WTF::Lock algorithm: 799, 6, 1, 1, 1, 1, 1, 1, 1, 1 One thread hogged the lock for almost the whole time! With the new WTF::Lock, the lock becomes totally fair: 80, 79, 79, 79, 79, 79, 79, 80, 80, 79 I don't know of anyone creating such an automatically-fair adaptive lock before, so I think that this is a pretty awesome advancement to the state of the art! This change is good for three reasons: - We do have long critical sections in WebKit and we don't want to have to worry about starvation. This reduces the likelihood that we will see starvation due to our lock strategy. - I was talking to ggaren about bmalloc's locking needs, and he wanted unlockFairly() or lockFairly() or some moral equivalent for the scavenger thread. - If we use a WTF::Lock to manage heap access in a multithreaded GC, we'll need the ability to unlock and relock without barging. * benchmarks/LockFairnessTest.cpp: (main): * benchmarks/ToyLocks.h: * wtf/Condition.h: (WTF::ConditionBase::waitUntil): (WTF::ConditionBase::notifyOne): * wtf/Lock.cpp: (WTF::LockBase::lockSlow): (WTF::LockBase::unlockSlow): (WTF::LockBase::unlockFairlySlow): (WTF::LockBase::unlockSlowImpl): * wtf/Lock.h: (WTF::LockBase::try_lock): (WTF::LockBase::unlock): (WTF::LockBase::unlockFairly): (WTF::LockBase::isHeld): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::compareAndPark): (WTF::ParkingLot::unparkOne): Tools: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Canonical link: https://commits.webkit.org/178039@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@203350 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-07-18 18:32:52 +00:00
bool timeToBeFair = false;
WTF::Lock should not suffer from the thundering herd https://bugs.webkit.org/show_bug.cgi?id=147947 Reviewed by Geoffrey Garen. Source/WTF: This changes Lock::unlockSlow() to use unparkOne() instead of unparkAll(). The problem with doing this is that it's not obvious after calling unparkOne() if there are any other threads that are still parked on the lock's queue. If we assume that there are and leave the hasParkedBit set, then future calls to unlock() will take the slow path. We don't want that if there aren't actually any threads parked. On the other hand, if we assume that there aren't any threads parked and clear the hasParkedBit, then if there actually were some threads parked, then they may never be awoken since future calls to unlock() won't take slow path and so won't call unparkOne(). In other words, we need a way to be very precise about when we clear the hasParkedBit and we need to do it in a race-free way: it can't be the case that we clear the bit just as some thread gets parked on the queue. A similar problem arises in futexes, and one of the solutions is to have a thread that acquires a lock after parking sets the hasParkedBit. This is what Rusty Russel's usersem does. It's a subtle algorithm. Also, it means that if a thread barges in before the unparked thread runs, then that barging thread will not know that there are threads parked. This could increase the severity of barging. Since ParkingLot is a user-level API, we don't have to worry about the kernel-user security issues and so we can expose callbacks while ParkingLot is holding its internal locks. This change does exactly that for unparkOne(). The new variant of unparkOne() will call a user function while the queue from which we are unparking is locked. The callback is told basic stats about the queue: did we unpark a thread this time, and could there be more threads to unpark in the future. The callback runs while it's impossible for the queue state to change, since the ParkingLot's internal locks for the queue is held. This means that Lock::unlockSlow() can either clear, or leave, the hasParkedBit while releasing the lock inside the callback from unparkOne(). This takes care of the thundering herd problem while also reducing the greed that arises from barging threads. This required some careful reworking of the ParkingLot algorithm. The first thing I noticed was that the ThreadData::shouldPark flag was useless, since it's set exactly when ThreadData::address is non-null. Then I had to make sure that dequeue() could lazily create both hashtables and buckets, since the "callback is called while queue is locked" invariant requires that we didn't exit early due to the hashtable or bucket not being present. Note that all of this is done in such a way that the old unparkOne() and unparkAll() don't have to create any buckets, though they now may create the hashtable. We don't care as much about the hashtable being created by unpark since it's just such an unlikely scenario and it would only happen once. This change reduces the kernel CPU usage of WTF::Lock for the long critical section test by about 8x and makes it always perform as well as WTF::WordLock and WTF::Mutex for that benchmark. * benchmarks/LockSpeedTest.cpp: * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): * wtf/Lock.h: (WTF::LockBase::isLocked): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: * wtf/WordLock.h: (WTF::WordLock::isLocked): (WTF::WordLock::isFullyReset): Tools: Add testing that checks that locks return to a pristine state after contention is over. * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::LockInspector::isFullyReset): (TestWebKitAPI::runLockTest): (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/166072@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188374 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 03:51:25 +00:00
dequeue(
address,
BucketMode::EnsureNonEmpty,
WTF::Lock should be fair eventually https://bugs.webkit.org/show_bug.cgi?id=159384 Reviewed by Geoffrey Garen. Source/WTF: In https://webkit.org/blog/6161/locking-in-webkit/ we showed how relaxing the fairness of locks makes them fast. That post presented lock fairness as a trade-off between two extremes: - Barging. A barging lock, like WTF::Lock, releases the lock in unlock() even if there was a thread on the queue. If there was a thread on the queue, the lock is released and that thread is made runnable. That thread may then grab the lock, or some other thread may grab the lock first (it may barge). Usually, the barging thread is the thread that released the lock in the first place. This maximizes throughput but hurts fairness. There is no good theoretical bound on how unfair the lock may become, but empirical data suggests that it's fair enough for the cases we previously measured. - FIFO. A FIFO lock, like HandoffLock in ToyLocks.h, does not release the lock in unlock() if there is a thread waiting. If there is a thread waiting, unlock() will make that thread runnable and inform it that it now holds the lock. This ensures perfect round-robin fairness and allows us to reason theoretically about how long it may take for a thread to grab the lock. For example, if we know that only N threads are running and each one may contend on a critical section, and each one may hold the lock for at most S seconds, then the time it takes to grab the lock is N * S. Unfortunately, FIFO locks perform very badly in most cases. This is because for the common case of short critical sections, they force a context switch after each critical section if the lock is contended. This change makes WTF::Lock almost as fair as FIFO while still being as fast as barging. Thanks to this new algorithm, you can now have both of these things at the same time. This change makes WTF::Lock eventually fair. We can almost (more on the caveats below) guarantee that the time it takes to grab a lock is N * max(1ms, S). In other words, critical sections that are longer than 1ms are always fair. For shorter critical sections, the amount of time that any thread waits is 1ms times the number of threads. There are some caveats that arise from our use of randomness, but even then, in the limit as the critical section length goes to infinity, the lock becomes fair. The corner cases are unlikely to happen; our experiments show that the lock becomes exactly as fair as a FIFO lock for any critical section that is 1ms or longer. The fairness mechanism is broken into two parts. WTF::Lock can now choose to unlock a lock fairly or unfairly thanks to the new ParkingLot token mechanism. WTF::Lock knows when to use fair unlocking based on a timeout mechanism in ParkingLot called timeToBeFair. ParkingLot::unparkOne() and ParkingLot::parkConditionally() can now communicate with each other via a token. unparkOne() can pass a token, which parkConditionally() will return. This change also makes parkConditionally() a lot more precise about when it was unparked due to a call to unparkOne(). If unparkOne() is told that a thread was unparked then this thread is guaranteed to report that it was unparked rather than timing out, and that thread is guaranteed to get the token that unparkOne() passed. The token is an intptr_t. We use it as a boolean variable in WTF::Lock, but you could use it to pass arbitrary data structures. By default, the token is zero. WTF::Lock's unlock() will pass 1 as the token if it is doing fair unlocking. In that case, unlock() will not release the lock, and lock() will know that it holds the lock as soon as parkConditionally() returns. Note that this algorithm relies on unparkOne() invoking WTF::Lock's callback while the queue lock is held, so that WTF::Lock can make a decision about unlock strategy and inject a token while it has complete knowledge over the state of the queue. As such, it's not immediately obvious how to implement this algorithm on top of futexes. You really need ParkingLot! WTF::Lock does not use fair unlocking every time. We expose a new API, Lock::unlockFairly(), which forces the fair unlocking behavior. Additionally, ParkingLot now maintains a per-bucket stochastic fairness timeout. When the timeout fires, the unparkOne() callback sees UnparkResult::timeToBeFair = true. This timeout is set to be anywhere from 0ms to 1ms at random. When a dequeue happens and there are threads that actually get dequeued, we check if the time since the last unfair unlock (the last time timeToBeFair was set to true) is more than the timeout amount. If so, then we set timeToBeFair to true and reset the timeout. This means that in the absence of ParkingLot collisions, unfair unlocking is guaranteed to happen at least once per millisecond. It will happen at 2 KHz on average. If there are collisions, then each collision adds one millisecond to the worst case (and 0.5 ms to the average case). The reason why we don't just use a fixed 1ms timeout is that we want to avoid resonance. Imagine a program in which some thread acquires a lock at 1 KHz in-phase with the timeToBeFair timeout. Then this thread would be the benefactor of fairness to the detriment of everyone else. Randomness ensures that we aren't too fair to any one thread. Empirically, this is neutral on our major benchmarks like JetStream but it's an enormous improvement in LockFairnessTest. It's common for an unfair lock (either our BargingLock, the old WTF::Lock, any of the other futex-based locks that barge, or new os_unfair_lock) to allow only one thread to hold the lock during a whole second in which each thread is holding the lock for 1ms at a time. This is because in a barging lock, releasing a lock after holding it for 1ms and then reacquiring it immediately virtually ensures that none of the other threads can wake up in time to grab it before it's relocked. But the new WTF::Lock handles this case like a champ: each thread gets equal turns. Here's some data. If we launch 10 threads and have each of them run for 1 second while repeatedly holding a critical section for 1ms, then here's how many times each thread gets to hold the lock using the old WTF::Lock algorithm: 799, 6, 1, 1, 1, 1, 1, 1, 1, 1 One thread hogged the lock for almost the whole time! With the new WTF::Lock, the lock becomes totally fair: 80, 79, 79, 79, 79, 79, 79, 80, 80, 79 I don't know of anyone creating such an automatically-fair adaptive lock before, so I think that this is a pretty awesome advancement to the state of the art! This change is good for three reasons: - We do have long critical sections in WebKit and we don't want to have to worry about starvation. This reduces the likelihood that we will see starvation due to our lock strategy. - I was talking to ggaren about bmalloc's locking needs, and he wanted unlockFairly() or lockFairly() or some moral equivalent for the scavenger thread. - If we use a WTF::Lock to manage heap access in a multithreaded GC, we'll need the ability to unlock and relock without barging. * benchmarks/LockFairnessTest.cpp: (main): * benchmarks/ToyLocks.h: * wtf/Condition.h: (WTF::ConditionBase::waitUntil): (WTF::ConditionBase::notifyOne): * wtf/Lock.cpp: (WTF::LockBase::lockSlow): (WTF::LockBase::unlockSlow): (WTF::LockBase::unlockFairlySlow): (WTF::LockBase::unlockSlowImpl): * wtf/Lock.h: (WTF::LockBase::try_lock): (WTF::LockBase::unlock): (WTF::LockBase::unlockFairly): (WTF::LockBase::isHeld): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::compareAndPark): (WTF::ParkingLot::unparkOne): Tools: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Canonical link: https://commits.webkit.org/178039@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@203350 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-07-18 18:32:52 +00:00
[&] (ThreadData* element, bool passedTimeToBeFair) {
WTF::Lock should not suffer from the thundering herd https://bugs.webkit.org/show_bug.cgi?id=147947 Reviewed by Geoffrey Garen. Source/WTF: This changes Lock::unlockSlow() to use unparkOne() instead of unparkAll(). The problem with doing this is that it's not obvious after calling unparkOne() if there are any other threads that are still parked on the lock's queue. If we assume that there are and leave the hasParkedBit set, then future calls to unlock() will take the slow path. We don't want that if there aren't actually any threads parked. On the other hand, if we assume that there aren't any threads parked and clear the hasParkedBit, then if there actually were some threads parked, then they may never be awoken since future calls to unlock() won't take slow path and so won't call unparkOne(). In other words, we need a way to be very precise about when we clear the hasParkedBit and we need to do it in a race-free way: it can't be the case that we clear the bit just as some thread gets parked on the queue. A similar problem arises in futexes, and one of the solutions is to have a thread that acquires a lock after parking sets the hasParkedBit. This is what Rusty Russel's usersem does. It's a subtle algorithm. Also, it means that if a thread barges in before the unparked thread runs, then that barging thread will not know that there are threads parked. This could increase the severity of barging. Since ParkingLot is a user-level API, we don't have to worry about the kernel-user security issues and so we can expose callbacks while ParkingLot is holding its internal locks. This change does exactly that for unparkOne(). The new variant of unparkOne() will call a user function while the queue from which we are unparking is locked. The callback is told basic stats about the queue: did we unpark a thread this time, and could there be more threads to unpark in the future. The callback runs while it's impossible for the queue state to change, since the ParkingLot's internal locks for the queue is held. This means that Lock::unlockSlow() can either clear, or leave, the hasParkedBit while releasing the lock inside the callback from unparkOne(). This takes care of the thundering herd problem while also reducing the greed that arises from barging threads. This required some careful reworking of the ParkingLot algorithm. The first thing I noticed was that the ThreadData::shouldPark flag was useless, since it's set exactly when ThreadData::address is non-null. Then I had to make sure that dequeue() could lazily create both hashtables and buckets, since the "callback is called while queue is locked" invariant requires that we didn't exit early due to the hashtable or bucket not being present. Note that all of this is done in such a way that the old unparkOne() and unparkAll() don't have to create any buckets, though they now may create the hashtable. We don't care as much about the hashtable being created by unpark since it's just such an unlikely scenario and it would only happen once. This change reduces the kernel CPU usage of WTF::Lock for the long critical section test by about 8x and makes it always perform as well as WTF::WordLock and WTF::Mutex for that benchmark. * benchmarks/LockSpeedTest.cpp: * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): * wtf/Lock.h: (WTF::LockBase::isLocked): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: * wtf/WordLock.h: (WTF::WordLock::isLocked): (WTF::WordLock::isFullyReset): Tools: Add testing that checks that locks return to a pristine state after contention is over. * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::LockInspector::isFullyReset): (TestWebKitAPI::runLockTest): (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/166072@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188374 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 03:51:25 +00:00
if (element->address != address)
return DequeueResult::Ignore;
threadData = element;
WTF::Lock should be fair eventually https://bugs.webkit.org/show_bug.cgi?id=159384 Reviewed by Geoffrey Garen. Source/WTF: In https://webkit.org/blog/6161/locking-in-webkit/ we showed how relaxing the fairness of locks makes them fast. That post presented lock fairness as a trade-off between two extremes: - Barging. A barging lock, like WTF::Lock, releases the lock in unlock() even if there was a thread on the queue. If there was a thread on the queue, the lock is released and that thread is made runnable. That thread may then grab the lock, or some other thread may grab the lock first (it may barge). Usually, the barging thread is the thread that released the lock in the first place. This maximizes throughput but hurts fairness. There is no good theoretical bound on how unfair the lock may become, but empirical data suggests that it's fair enough for the cases we previously measured. - FIFO. A FIFO lock, like HandoffLock in ToyLocks.h, does not release the lock in unlock() if there is a thread waiting. If there is a thread waiting, unlock() will make that thread runnable and inform it that it now holds the lock. This ensures perfect round-robin fairness and allows us to reason theoretically about how long it may take for a thread to grab the lock. For example, if we know that only N threads are running and each one may contend on a critical section, and each one may hold the lock for at most S seconds, then the time it takes to grab the lock is N * S. Unfortunately, FIFO locks perform very badly in most cases. This is because for the common case of short critical sections, they force a context switch after each critical section if the lock is contended. This change makes WTF::Lock almost as fair as FIFO while still being as fast as barging. Thanks to this new algorithm, you can now have both of these things at the same time. This change makes WTF::Lock eventually fair. We can almost (more on the caveats below) guarantee that the time it takes to grab a lock is N * max(1ms, S). In other words, critical sections that are longer than 1ms are always fair. For shorter critical sections, the amount of time that any thread waits is 1ms times the number of threads. There are some caveats that arise from our use of randomness, but even then, in the limit as the critical section length goes to infinity, the lock becomes fair. The corner cases are unlikely to happen; our experiments show that the lock becomes exactly as fair as a FIFO lock for any critical section that is 1ms or longer. The fairness mechanism is broken into two parts. WTF::Lock can now choose to unlock a lock fairly or unfairly thanks to the new ParkingLot token mechanism. WTF::Lock knows when to use fair unlocking based on a timeout mechanism in ParkingLot called timeToBeFair. ParkingLot::unparkOne() and ParkingLot::parkConditionally() can now communicate with each other via a token. unparkOne() can pass a token, which parkConditionally() will return. This change also makes parkConditionally() a lot more precise about when it was unparked due to a call to unparkOne(). If unparkOne() is told that a thread was unparked then this thread is guaranteed to report that it was unparked rather than timing out, and that thread is guaranteed to get the token that unparkOne() passed. The token is an intptr_t. We use it as a boolean variable in WTF::Lock, but you could use it to pass arbitrary data structures. By default, the token is zero. WTF::Lock's unlock() will pass 1 as the token if it is doing fair unlocking. In that case, unlock() will not release the lock, and lock() will know that it holds the lock as soon as parkConditionally() returns. Note that this algorithm relies on unparkOne() invoking WTF::Lock's callback while the queue lock is held, so that WTF::Lock can make a decision about unlock strategy and inject a token while it has complete knowledge over the state of the queue. As such, it's not immediately obvious how to implement this algorithm on top of futexes. You really need ParkingLot! WTF::Lock does not use fair unlocking every time. We expose a new API, Lock::unlockFairly(), which forces the fair unlocking behavior. Additionally, ParkingLot now maintains a per-bucket stochastic fairness timeout. When the timeout fires, the unparkOne() callback sees UnparkResult::timeToBeFair = true. This timeout is set to be anywhere from 0ms to 1ms at random. When a dequeue happens and there are threads that actually get dequeued, we check if the time since the last unfair unlock (the last time timeToBeFair was set to true) is more than the timeout amount. If so, then we set timeToBeFair to true and reset the timeout. This means that in the absence of ParkingLot collisions, unfair unlocking is guaranteed to happen at least once per millisecond. It will happen at 2 KHz on average. If there are collisions, then each collision adds one millisecond to the worst case (and 0.5 ms to the average case). The reason why we don't just use a fixed 1ms timeout is that we want to avoid resonance. Imagine a program in which some thread acquires a lock at 1 KHz in-phase with the timeToBeFair timeout. Then this thread would be the benefactor of fairness to the detriment of everyone else. Randomness ensures that we aren't too fair to any one thread. Empirically, this is neutral on our major benchmarks like JetStream but it's an enormous improvement in LockFairnessTest. It's common for an unfair lock (either our BargingLock, the old WTF::Lock, any of the other futex-based locks that barge, or new os_unfair_lock) to allow only one thread to hold the lock during a whole second in which each thread is holding the lock for 1ms at a time. This is because in a barging lock, releasing a lock after holding it for 1ms and then reacquiring it immediately virtually ensures that none of the other threads can wake up in time to grab it before it's relocked. But the new WTF::Lock handles this case like a champ: each thread gets equal turns. Here's some data. If we launch 10 threads and have each of them run for 1 second while repeatedly holding a critical section for 1ms, then here's how many times each thread gets to hold the lock using the old WTF::Lock algorithm: 799, 6, 1, 1, 1, 1, 1, 1, 1, 1 One thread hogged the lock for almost the whole time! With the new WTF::Lock, the lock becomes totally fair: 80, 79, 79, 79, 79, 79, 79, 80, 80, 79 I don't know of anyone creating such an automatically-fair adaptive lock before, so I think that this is a pretty awesome advancement to the state of the art! This change is good for three reasons: - We do have long critical sections in WebKit and we don't want to have to worry about starvation. This reduces the likelihood that we will see starvation due to our lock strategy. - I was talking to ggaren about bmalloc's locking needs, and he wanted unlockFairly() or lockFairly() or some moral equivalent for the scavenger thread. - If we use a WTF::Lock to manage heap access in a multithreaded GC, we'll need the ability to unlock and relock without barging. * benchmarks/LockFairnessTest.cpp: (main): * benchmarks/ToyLocks.h: * wtf/Condition.h: (WTF::ConditionBase::waitUntil): (WTF::ConditionBase::notifyOne): * wtf/Lock.cpp: (WTF::LockBase::lockSlow): (WTF::LockBase::unlockSlow): (WTF::LockBase::unlockFairlySlow): (WTF::LockBase::unlockSlowImpl): * wtf/Lock.h: (WTF::LockBase::try_lock): (WTF::LockBase::unlock): (WTF::LockBase::unlockFairly): (WTF::LockBase::isHeld): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::compareAndPark): (WTF::ParkingLot::unparkOne): Tools: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Canonical link: https://commits.webkit.org/178039@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@203350 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-07-18 18:32:52 +00:00
timeToBeFair = passedTimeToBeFair;
WTF::Lock should not suffer from the thundering herd https://bugs.webkit.org/show_bug.cgi?id=147947 Reviewed by Geoffrey Garen. Source/WTF: This changes Lock::unlockSlow() to use unparkOne() instead of unparkAll(). The problem with doing this is that it's not obvious after calling unparkOne() if there are any other threads that are still parked on the lock's queue. If we assume that there are and leave the hasParkedBit set, then future calls to unlock() will take the slow path. We don't want that if there aren't actually any threads parked. On the other hand, if we assume that there aren't any threads parked and clear the hasParkedBit, then if there actually were some threads parked, then they may never be awoken since future calls to unlock() won't take slow path and so won't call unparkOne(). In other words, we need a way to be very precise about when we clear the hasParkedBit and we need to do it in a race-free way: it can't be the case that we clear the bit just as some thread gets parked on the queue. A similar problem arises in futexes, and one of the solutions is to have a thread that acquires a lock after parking sets the hasParkedBit. This is what Rusty Russel's usersem does. It's a subtle algorithm. Also, it means that if a thread barges in before the unparked thread runs, then that barging thread will not know that there are threads parked. This could increase the severity of barging. Since ParkingLot is a user-level API, we don't have to worry about the kernel-user security issues and so we can expose callbacks while ParkingLot is holding its internal locks. This change does exactly that for unparkOne(). The new variant of unparkOne() will call a user function while the queue from which we are unparking is locked. The callback is told basic stats about the queue: did we unpark a thread this time, and could there be more threads to unpark in the future. The callback runs while it's impossible for the queue state to change, since the ParkingLot's internal locks for the queue is held. This means that Lock::unlockSlow() can either clear, or leave, the hasParkedBit while releasing the lock inside the callback from unparkOne(). This takes care of the thundering herd problem while also reducing the greed that arises from barging threads. This required some careful reworking of the ParkingLot algorithm. The first thing I noticed was that the ThreadData::shouldPark flag was useless, since it's set exactly when ThreadData::address is non-null. Then I had to make sure that dequeue() could lazily create both hashtables and buckets, since the "callback is called while queue is locked" invariant requires that we didn't exit early due to the hashtable or bucket not being present. Note that all of this is done in such a way that the old unparkOne() and unparkAll() don't have to create any buckets, though they now may create the hashtable. We don't care as much about the hashtable being created by unpark since it's just such an unlikely scenario and it would only happen once. This change reduces the kernel CPU usage of WTF::Lock for the long critical section test by about 8x and makes it always perform as well as WTF::WordLock and WTF::Mutex for that benchmark. * benchmarks/LockSpeedTest.cpp: * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): * wtf/Lock.h: (WTF::LockBase::isLocked): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: * wtf/WordLock.h: (WTF::WordLock::isLocked): (WTF::WordLock::isFullyReset): Tools: Add testing that checks that locks return to a pristine state after contention is over. * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::LockInspector::isFullyReset): (TestWebKitAPI::runLockTest): (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/166072@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188374 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 03:51:25 +00:00
return DequeueResult::RemoveAndStop;
},
[&] (bool mayHaveMoreThreads) {
UnparkResult result;
result.didUnparkThread = !!threadData;
result.mayHaveMoreThreads = result.didUnparkThread && mayHaveMoreThreads;
WTF::Lock should be fair eventually https://bugs.webkit.org/show_bug.cgi?id=159384 Reviewed by Geoffrey Garen. Source/WTF: In https://webkit.org/blog/6161/locking-in-webkit/ we showed how relaxing the fairness of locks makes them fast. That post presented lock fairness as a trade-off between two extremes: - Barging. A barging lock, like WTF::Lock, releases the lock in unlock() even if there was a thread on the queue. If there was a thread on the queue, the lock is released and that thread is made runnable. That thread may then grab the lock, or some other thread may grab the lock first (it may barge). Usually, the barging thread is the thread that released the lock in the first place. This maximizes throughput but hurts fairness. There is no good theoretical bound on how unfair the lock may become, but empirical data suggests that it's fair enough for the cases we previously measured. - FIFO. A FIFO lock, like HandoffLock in ToyLocks.h, does not release the lock in unlock() if there is a thread waiting. If there is a thread waiting, unlock() will make that thread runnable and inform it that it now holds the lock. This ensures perfect round-robin fairness and allows us to reason theoretically about how long it may take for a thread to grab the lock. For example, if we know that only N threads are running and each one may contend on a critical section, and each one may hold the lock for at most S seconds, then the time it takes to grab the lock is N * S. Unfortunately, FIFO locks perform very badly in most cases. This is because for the common case of short critical sections, they force a context switch after each critical section if the lock is contended. This change makes WTF::Lock almost as fair as FIFO while still being as fast as barging. Thanks to this new algorithm, you can now have both of these things at the same time. This change makes WTF::Lock eventually fair. We can almost (more on the caveats below) guarantee that the time it takes to grab a lock is N * max(1ms, S). In other words, critical sections that are longer than 1ms are always fair. For shorter critical sections, the amount of time that any thread waits is 1ms times the number of threads. There are some caveats that arise from our use of randomness, but even then, in the limit as the critical section length goes to infinity, the lock becomes fair. The corner cases are unlikely to happen; our experiments show that the lock becomes exactly as fair as a FIFO lock for any critical section that is 1ms or longer. The fairness mechanism is broken into two parts. WTF::Lock can now choose to unlock a lock fairly or unfairly thanks to the new ParkingLot token mechanism. WTF::Lock knows when to use fair unlocking based on a timeout mechanism in ParkingLot called timeToBeFair. ParkingLot::unparkOne() and ParkingLot::parkConditionally() can now communicate with each other via a token. unparkOne() can pass a token, which parkConditionally() will return. This change also makes parkConditionally() a lot more precise about when it was unparked due to a call to unparkOne(). If unparkOne() is told that a thread was unparked then this thread is guaranteed to report that it was unparked rather than timing out, and that thread is guaranteed to get the token that unparkOne() passed. The token is an intptr_t. We use it as a boolean variable in WTF::Lock, but you could use it to pass arbitrary data structures. By default, the token is zero. WTF::Lock's unlock() will pass 1 as the token if it is doing fair unlocking. In that case, unlock() will not release the lock, and lock() will know that it holds the lock as soon as parkConditionally() returns. Note that this algorithm relies on unparkOne() invoking WTF::Lock's callback while the queue lock is held, so that WTF::Lock can make a decision about unlock strategy and inject a token while it has complete knowledge over the state of the queue. As such, it's not immediately obvious how to implement this algorithm on top of futexes. You really need ParkingLot! WTF::Lock does not use fair unlocking every time. We expose a new API, Lock::unlockFairly(), which forces the fair unlocking behavior. Additionally, ParkingLot now maintains a per-bucket stochastic fairness timeout. When the timeout fires, the unparkOne() callback sees UnparkResult::timeToBeFair = true. This timeout is set to be anywhere from 0ms to 1ms at random. When a dequeue happens and there are threads that actually get dequeued, we check if the time since the last unfair unlock (the last time timeToBeFair was set to true) is more than the timeout amount. If so, then we set timeToBeFair to true and reset the timeout. This means that in the absence of ParkingLot collisions, unfair unlocking is guaranteed to happen at least once per millisecond. It will happen at 2 KHz on average. If there are collisions, then each collision adds one millisecond to the worst case (and 0.5 ms to the average case). The reason why we don't just use a fixed 1ms timeout is that we want to avoid resonance. Imagine a program in which some thread acquires a lock at 1 KHz in-phase with the timeToBeFair timeout. Then this thread would be the benefactor of fairness to the detriment of everyone else. Randomness ensures that we aren't too fair to any one thread. Empirically, this is neutral on our major benchmarks like JetStream but it's an enormous improvement in LockFairnessTest. It's common for an unfair lock (either our BargingLock, the old WTF::Lock, any of the other futex-based locks that barge, or new os_unfair_lock) to allow only one thread to hold the lock during a whole second in which each thread is holding the lock for 1ms at a time. This is because in a barging lock, releasing a lock after holding it for 1ms and then reacquiring it immediately virtually ensures that none of the other threads can wake up in time to grab it before it's relocked. But the new WTF::Lock handles this case like a champ: each thread gets equal turns. Here's some data. If we launch 10 threads and have each of them run for 1 second while repeatedly holding a critical section for 1ms, then here's how many times each thread gets to hold the lock using the old WTF::Lock algorithm: 799, 6, 1, 1, 1, 1, 1, 1, 1, 1 One thread hogged the lock for almost the whole time! With the new WTF::Lock, the lock becomes totally fair: 80, 79, 79, 79, 79, 79, 79, 80, 80, 79 I don't know of anyone creating such an automatically-fair adaptive lock before, so I think that this is a pretty awesome advancement to the state of the art! This change is good for three reasons: - We do have long critical sections in WebKit and we don't want to have to worry about starvation. This reduces the likelihood that we will see starvation due to our lock strategy. - I was talking to ggaren about bmalloc's locking needs, and he wanted unlockFairly() or lockFairly() or some moral equivalent for the scavenger thread. - If we use a WTF::Lock to manage heap access in a multithreaded GC, we'll need the ability to unlock and relock without barging. * benchmarks/LockFairnessTest.cpp: (main): * benchmarks/ToyLocks.h: * wtf/Condition.h: (WTF::ConditionBase::waitUntil): (WTF::ConditionBase::notifyOne): * wtf/Lock.cpp: (WTF::LockBase::lockSlow): (WTF::LockBase::unlockSlow): (WTF::LockBase::unlockFairlySlow): (WTF::LockBase::unlockSlowImpl): * wtf/Lock.h: (WTF::LockBase::try_lock): (WTF::LockBase::unlock): (WTF::LockBase::unlockFairly): (WTF::LockBase::isHeld): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::compareAndPark): (WTF::ParkingLot::unparkOne): Tools: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Canonical link: https://commits.webkit.org/178039@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@203350 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-07-18 18:32:52 +00:00
if (timeToBeFair)
RELEASE_ASSERT(threadData);
result.timeToBeFair = timeToBeFair;
intptr_t token = callback(result);
if (threadData)
threadData->token = token;
WTF::Lock should not suffer from the thundering herd https://bugs.webkit.org/show_bug.cgi?id=147947 Reviewed by Geoffrey Garen. Source/WTF: This changes Lock::unlockSlow() to use unparkOne() instead of unparkAll(). The problem with doing this is that it's not obvious after calling unparkOne() if there are any other threads that are still parked on the lock's queue. If we assume that there are and leave the hasParkedBit set, then future calls to unlock() will take the slow path. We don't want that if there aren't actually any threads parked. On the other hand, if we assume that there aren't any threads parked and clear the hasParkedBit, then if there actually were some threads parked, then they may never be awoken since future calls to unlock() won't take slow path and so won't call unparkOne(). In other words, we need a way to be very precise about when we clear the hasParkedBit and we need to do it in a race-free way: it can't be the case that we clear the bit just as some thread gets parked on the queue. A similar problem arises in futexes, and one of the solutions is to have a thread that acquires a lock after parking sets the hasParkedBit. This is what Rusty Russel's usersem does. It's a subtle algorithm. Also, it means that if a thread barges in before the unparked thread runs, then that barging thread will not know that there are threads parked. This could increase the severity of barging. Since ParkingLot is a user-level API, we don't have to worry about the kernel-user security issues and so we can expose callbacks while ParkingLot is holding its internal locks. This change does exactly that for unparkOne(). The new variant of unparkOne() will call a user function while the queue from which we are unparking is locked. The callback is told basic stats about the queue: did we unpark a thread this time, and could there be more threads to unpark in the future. The callback runs while it's impossible for the queue state to change, since the ParkingLot's internal locks for the queue is held. This means that Lock::unlockSlow() can either clear, or leave, the hasParkedBit while releasing the lock inside the callback from unparkOne(). This takes care of the thundering herd problem while also reducing the greed that arises from barging threads. This required some careful reworking of the ParkingLot algorithm. The first thing I noticed was that the ThreadData::shouldPark flag was useless, since it's set exactly when ThreadData::address is non-null. Then I had to make sure that dequeue() could lazily create both hashtables and buckets, since the "callback is called while queue is locked" invariant requires that we didn't exit early due to the hashtable or bucket not being present. Note that all of this is done in such a way that the old unparkOne() and unparkAll() don't have to create any buckets, though they now may create the hashtable. We don't care as much about the hashtable being created by unpark since it's just such an unlikely scenario and it would only happen once. This change reduces the kernel CPU usage of WTF::Lock for the long critical section test by about 8x and makes it always perform as well as WTF::WordLock and WTF::Mutex for that benchmark. * benchmarks/LockSpeedTest.cpp: * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): * wtf/Lock.h: (WTF::LockBase::isLocked): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: * wtf/WordLock.h: (WTF::WordLock::isLocked): (WTF::WordLock::isFullyReset): Tools: Add testing that checks that locks return to a pristine state after contention is over. * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::LockInspector::isFullyReset): (TestWebKitAPI::runLockTest): (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/166072@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188374 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 03:51:25 +00:00
});
if (!threadData)
return;
ASSERT(threadData->address);
{
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): Canonical link: https://commits.webkit.org/182152@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208415 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-11-05 03:02:39 +00:00
MutexLocker locker(threadData->parkingLock);
WTF::Lock should not suffer from the thundering herd https://bugs.webkit.org/show_bug.cgi?id=147947 Reviewed by Geoffrey Garen. Source/WTF: This changes Lock::unlockSlow() to use unparkOne() instead of unparkAll(). The problem with doing this is that it's not obvious after calling unparkOne() if there are any other threads that are still parked on the lock's queue. If we assume that there are and leave the hasParkedBit set, then future calls to unlock() will take the slow path. We don't want that if there aren't actually any threads parked. On the other hand, if we assume that there aren't any threads parked and clear the hasParkedBit, then if there actually were some threads parked, then they may never be awoken since future calls to unlock() won't take slow path and so won't call unparkOne(). In other words, we need a way to be very precise about when we clear the hasParkedBit and we need to do it in a race-free way: it can't be the case that we clear the bit just as some thread gets parked on the queue. A similar problem arises in futexes, and one of the solutions is to have a thread that acquires a lock after parking sets the hasParkedBit. This is what Rusty Russel's usersem does. It's a subtle algorithm. Also, it means that if a thread barges in before the unparked thread runs, then that barging thread will not know that there are threads parked. This could increase the severity of barging. Since ParkingLot is a user-level API, we don't have to worry about the kernel-user security issues and so we can expose callbacks while ParkingLot is holding its internal locks. This change does exactly that for unparkOne(). The new variant of unparkOne() will call a user function while the queue from which we are unparking is locked. The callback is told basic stats about the queue: did we unpark a thread this time, and could there be more threads to unpark in the future. The callback runs while it's impossible for the queue state to change, since the ParkingLot's internal locks for the queue is held. This means that Lock::unlockSlow() can either clear, or leave, the hasParkedBit while releasing the lock inside the callback from unparkOne(). This takes care of the thundering herd problem while also reducing the greed that arises from barging threads. This required some careful reworking of the ParkingLot algorithm. The first thing I noticed was that the ThreadData::shouldPark flag was useless, since it's set exactly when ThreadData::address is non-null. Then I had to make sure that dequeue() could lazily create both hashtables and buckets, since the "callback is called while queue is locked" invariant requires that we didn't exit early due to the hashtable or bucket not being present. Note that all of this is done in such a way that the old unparkOne() and unparkAll() don't have to create any buckets, though they now may create the hashtable. We don't care as much about the hashtable being created by unpark since it's just such an unlikely scenario and it would only happen once. This change reduces the kernel CPU usage of WTF::Lock for the long critical section test by about 8x and makes it always perform as well as WTF::WordLock and WTF::Mutex for that benchmark. * benchmarks/LockSpeedTest.cpp: * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): * wtf/Lock.h: (WTF::LockBase::isLocked): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: * wtf/WordLock.h: (WTF::WordLock::isLocked): (WTF::WordLock::isFullyReset): Tools: Add testing that checks that locks return to a pristine state after contention is over. * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::LockInspector::isFullyReset): (TestWebKitAPI::runLockTest): (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/166072@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188374 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 03:51:25 +00:00
threadData->address = nullptr;
}
// At this point, the threadData may die. Good thing we have a RefPtr<> on it.
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): Canonical link: https://commits.webkit.org/182152@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208415 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-11-05 03:02:39 +00:00
threadData->parkingCondition.signal();
WTF::Lock should not suffer from the thundering herd https://bugs.webkit.org/show_bug.cgi?id=147947 Reviewed by Geoffrey Garen. Source/WTF: This changes Lock::unlockSlow() to use unparkOne() instead of unparkAll(). The problem with doing this is that it's not obvious after calling unparkOne() if there are any other threads that are still parked on the lock's queue. If we assume that there are and leave the hasParkedBit set, then future calls to unlock() will take the slow path. We don't want that if there aren't actually any threads parked. On the other hand, if we assume that there aren't any threads parked and clear the hasParkedBit, then if there actually were some threads parked, then they may never be awoken since future calls to unlock() won't take slow path and so won't call unparkOne(). In other words, we need a way to be very precise about when we clear the hasParkedBit and we need to do it in a race-free way: it can't be the case that we clear the bit just as some thread gets parked on the queue. A similar problem arises in futexes, and one of the solutions is to have a thread that acquires a lock after parking sets the hasParkedBit. This is what Rusty Russel's usersem does. It's a subtle algorithm. Also, it means that if a thread barges in before the unparked thread runs, then that barging thread will not know that there are threads parked. This could increase the severity of barging. Since ParkingLot is a user-level API, we don't have to worry about the kernel-user security issues and so we can expose callbacks while ParkingLot is holding its internal locks. This change does exactly that for unparkOne(). The new variant of unparkOne() will call a user function while the queue from which we are unparking is locked. The callback is told basic stats about the queue: did we unpark a thread this time, and could there be more threads to unpark in the future. The callback runs while it's impossible for the queue state to change, since the ParkingLot's internal locks for the queue is held. This means that Lock::unlockSlow() can either clear, or leave, the hasParkedBit while releasing the lock inside the callback from unparkOne(). This takes care of the thundering herd problem while also reducing the greed that arises from barging threads. This required some careful reworking of the ParkingLot algorithm. The first thing I noticed was that the ThreadData::shouldPark flag was useless, since it's set exactly when ThreadData::address is non-null. Then I had to make sure that dequeue() could lazily create both hashtables and buckets, since the "callback is called while queue is locked" invariant requires that we didn't exit early due to the hashtable or bucket not being present. Note that all of this is done in such a way that the old unparkOne() and unparkAll() don't have to create any buckets, though they now may create the hashtable. We don't care as much about the hashtable being created by unpark since it's just such an unlikely scenario and it would only happen once. This change reduces the kernel CPU usage of WTF::Lock for the long critical section test by about 8x and makes it always perform as well as WTF::WordLock and WTF::Mutex for that benchmark. * benchmarks/LockSpeedTest.cpp: * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): * wtf/Lock.h: (WTF::LockBase::isLocked): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: * wtf/WordLock.h: (WTF::WordLock::isLocked): (WTF::WordLock::isFullyReset): Tools: Add testing that checks that locks return to a pristine state after contention is over. * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::LockInspector::isFullyReset): (TestWebKitAPI::runLockTest): (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/166072@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188374 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 03:51:25 +00:00
}
JSC should support SharedArrayBuffer https://bugs.webkit.org/show_bug.cgi?id=163986 Reviewed by Keith Miller. JSTests: This adds our own test for the various corner cases of SharedArrayBuffer. This test is meant to check all of the things that don't require concurrency. * stress/SharedArrayBuffer.js: Added. (checkAtomics): (shouldFail): (Symbol): (runAtomic): Source/JavaScriptCore: This implements https://tc39.github.io/ecmascript_sharedmem/shmem.html. There is now a new SharedArrayBuffer type. In the JS runtime, which includes typed array types, the SharedArrayBuffer is a drop-in replacement for ArrayBuffer, even though they are distinct types (new SharedArrayBuffer() instanceof ArrayBuffer == false and vice versa). The DOM will not recognize SharedArrayBuffer, or any typed array that wraps it, to ensure safety. This matches what other browsers intend to do, see https://github.com/tc39/ecmascript_sharedmem/issues/38. API is provided for the DOM to opt into SharedArrayBuffer. One notable place is postMessage, which will share the SharedArrayBuffer's underlying data storage with other workers. This creates a pool of shared memory that the workers can use to talk to each other. There is also an Atomics object in global scope, which exposes sequentially consistent atomic operations: add, and, compareExchange, exchange, load, or, store, sub, and xor. Additionally it exposes a Atomics.isLockFree utility, which takes a byte amount and returns true or false. Also there is Atomics.wake/wait, which neatly map to ParkingLot. Accesses to typed arrays that wrap SharedArrayBuffer are optimized by JSC the same way as always. I believe that DFG and B3 already obey the following memory model, which I believe is a bit weaker than Cambridge and a bit stronger than what is being proposed for SharedArrayBuffer. To predict a program's behavior under the B3 memory model, imagine the space of all possible programs that would result from running an optimizer that adversarially follows B3's transformation rules. B3 transformations are correct if the newly created program is equivalent to the old one, assuming that any opaque effect in IR (like the reads and writes of a patchpoint/call/fence) could perform any load/store that satisfies the B3::Effects summary. Opaque effects are a way of describing an infinite set of programs: any program that only does the effects summarized in B3::Effects belongs to the set. For example, this prevents motion of operations across fences since fences are summarized as opaque effects that could read or write memory. This rule alone is not enough, because it leaves the door open for turning an atomic operation (like a load) into a non-atomic one (like a load followed by a store of the same value back to the same location or multiple loads). This is not an optimization that either our compiler or the CPU would want to do. One way to think of what exactly is forbidden is that B3 transformations that mess with memory accesses can only reorder them or remove them. This means that for any execution of the untransformed program, the corresponding execution of the transformed program (i.e. with the same input arguments and the same programs filled in for the opaque effects) must have the same loads and stores, with some removed and some reordered. This is a fairly simple mental model that B3 and DFG already follow and it's based on existing abstractions for the infinite set of programs inside an opaque effect (DFG's AbstractHeaps and B3's Effects). This patch makes all atomics operations intrinsic, but the DFG doesn't know about any of them yet. That's covered by bug 164108. This ought to be perf-neutral, but I am still running tests to confirm this. I'm also still writing new tests to cover all of the Atomics functionality and the behavior of SAB objects. * API/JSTypedArray.cpp: (JSObjectGetTypedArrayBytesPtr): (JSObjectGetTypedArrayBuffer): (JSObjectMakeArrayBufferWithBytesNoCopy): * API/tests/CompareAndSwapTest.cpp: (Bitmap::concurrentTestAndSet): * CMakeLists.txt: * JavaScriptCore.xcodeproj/project.pbxproj: * dfg/DFGDesiredWatchpoints.cpp: (JSC::DFG::ArrayBufferViewWatchpointAdaptor::add): * heap/Heap.cpp: (JSC::Heap::reportExtraMemoryVisited): (JSC::Heap::reportExternalMemoryVisited): * jsc.cpp: (functionTransferArrayBuffer): * runtime/ArrayBuffer.cpp: (JSC::SharedArrayBufferContents::SharedArrayBufferContents): (JSC::SharedArrayBufferContents::~SharedArrayBufferContents): (JSC::ArrayBufferContents::ArrayBufferContents): (JSC::ArrayBufferContents::operator=): (JSC::ArrayBufferContents::~ArrayBufferContents): (JSC::ArrayBufferContents::clear): (JSC::ArrayBufferContents::destroy): (JSC::ArrayBufferContents::reset): (JSC::ArrayBufferContents::tryAllocate): (JSC::ArrayBufferContents::makeShared): (JSC::ArrayBufferContents::transferTo): (JSC::ArrayBufferContents::copyTo): (JSC::ArrayBufferContents::shareWith): (JSC::ArrayBuffer::create): (JSC::ArrayBuffer::createAdopted): (JSC::ArrayBuffer::createFromBytes): (JSC::ArrayBuffer::tryCreate): (JSC::ArrayBuffer::createUninitialized): (JSC::ArrayBuffer::tryCreateUninitialized): (JSC::ArrayBuffer::createInternal): (JSC::ArrayBuffer::ArrayBuffer): (JSC::ArrayBuffer::slice): (JSC::ArrayBuffer::sliceImpl): (JSC::ArrayBuffer::makeShared): (JSC::ArrayBuffer::setSharingMode): (JSC::ArrayBuffer::transferTo): (JSC::ArrayBuffer::transfer): Deleted. * runtime/ArrayBuffer.h: (JSC::arrayBufferSharingModeName): (JSC::SharedArrayBufferContents::data): (JSC::ArrayBufferContents::data): (JSC::ArrayBufferContents::sizeInBytes): (JSC::ArrayBufferContents::isShared): (JSC::ArrayBuffer::sharingMode): (JSC::ArrayBuffer::isShared): (JSC::ArrayBuffer::gcSizeEstimateInBytes): (JSC::arrayBufferDestructorNull): Deleted. (JSC::arrayBufferDestructorDefault): Deleted. (JSC::ArrayBufferContents::ArrayBufferContents): Deleted. (JSC::ArrayBufferContents::transfer): Deleted. (JSC::ArrayBufferContents::copyTo): Deleted. (JSC::ArrayBuffer::create): Deleted. (JSC::ArrayBuffer::createAdopted): Deleted. (JSC::ArrayBuffer::createFromBytes): Deleted. (JSC::ArrayBuffer::tryCreate): Deleted. (JSC::ArrayBuffer::createUninitialized): Deleted. (JSC::ArrayBuffer::tryCreateUninitialized): Deleted. (JSC::ArrayBuffer::createInternal): Deleted. (JSC::ArrayBuffer::ArrayBuffer): Deleted. (JSC::ArrayBuffer::slice): Deleted. (JSC::ArrayBuffer::sliceImpl): Deleted. (JSC::ArrayBufferContents::tryAllocate): Deleted. (JSC::ArrayBufferContents::~ArrayBufferContents): Deleted. * runtime/ArrayBufferSharingMode.h: Added. * runtime/ArrayBufferView.h: (JSC::ArrayBufferView::possiblySharedBuffer): (JSC::ArrayBufferView::unsharedBuffer): (JSC::ArrayBufferView::isShared): (JSC::ArrayBufferView::buffer): Deleted. * runtime/AtomicsObject.cpp: Added. (JSC::AtomicsObject::AtomicsObject): (JSC::AtomicsObject::create): (JSC::AtomicsObject::createStructure): (JSC::AtomicsObject::finishCreation): (JSC::atomicsFuncAdd): (JSC::atomicsFuncAnd): (JSC::atomicsFuncCompareExchange): (JSC::atomicsFuncExchange): (JSC::atomicsFuncIsLockFree): (JSC::atomicsFuncLoad): (JSC::atomicsFuncOr): (JSC::atomicsFuncStore): (JSC::atomicsFuncSub): (JSC::atomicsFuncWait): (JSC::atomicsFuncWake): (JSC::atomicsFuncXor): * runtime/AtomicsObject.h: Added. * runtime/CommonIdentifiers.h: * runtime/DataView.cpp: (JSC::DataView::wrap): * runtime/GenericTypedArrayViewInlines.h: (JSC::GenericTypedArrayView<Adaptor>::subarray): * runtime/Intrinsic.h: * runtime/JSArrayBuffer.cpp: (JSC::JSArrayBuffer::finishCreation): (JSC::JSArrayBuffer::isShared): (JSC::JSArrayBuffer::sharingMode): * runtime/JSArrayBuffer.h: (JSC::toPossiblySharedArrayBuffer): (JSC::toUnsharedArrayBuffer): (JSC::JSArrayBuffer::toWrapped): (JSC::toArrayBuffer): Deleted. * runtime/JSArrayBufferConstructor.cpp: (JSC::JSArrayBufferConstructor::JSArrayBufferConstructor): (JSC::JSArrayBufferConstructor::finishCreation): (JSC::JSArrayBufferConstructor::create): (JSC::constructArrayBuffer): * runtime/JSArrayBufferConstructor.h: (JSC::JSArrayBufferConstructor::sharingMode): * runtime/JSArrayBufferPrototype.cpp: (JSC::arrayBufferProtoFuncSlice): (JSC::JSArrayBufferPrototype::JSArrayBufferPrototype): (JSC::JSArrayBufferPrototype::finishCreation): (JSC::JSArrayBufferPrototype::create): * runtime/JSArrayBufferPrototype.h: * runtime/JSArrayBufferView.cpp: (JSC::JSArrayBufferView::finishCreation): (JSC::JSArrayBufferView::visitChildren): (JSC::JSArrayBufferView::unsharedBuffer): (JSC::JSArrayBufferView::unsharedJSBuffer): (JSC::JSArrayBufferView::possiblySharedJSBuffer): (JSC::JSArrayBufferView::neuter): (JSC::JSArrayBufferView::toWrapped): Deleted. * runtime/JSArrayBufferView.h: (JSC::JSArrayBufferView::jsBuffer): Deleted. * runtime/JSArrayBufferViewInlines.h: (JSC::JSArrayBufferView::isShared): (JSC::JSArrayBufferView::possiblySharedBuffer): (JSC::JSArrayBufferView::possiblySharedImpl): (JSC::JSArrayBufferView::unsharedImpl): (JSC::JSArrayBufferView::byteOffset): (JSC::JSArrayBufferView::toWrapped): (JSC::JSArrayBufferView::buffer): Deleted. (JSC::JSArrayBufferView::impl): Deleted. (JSC::JSArrayBufferView::neuter): Deleted. * runtime/JSDataView.cpp: (JSC::JSDataView::possiblySharedTypedImpl): (JSC::JSDataView::unsharedTypedImpl): (JSC::JSDataView::getTypedArrayImpl): (JSC::JSDataView::typedImpl): Deleted. * runtime/JSDataView.h: (JSC::JSDataView::possiblySharedBuffer): (JSC::JSDataView::unsharedBuffer): (JSC::JSDataView::buffer): Deleted. * runtime/JSDataViewPrototype.cpp: (JSC::dataViewProtoGetterBuffer): * runtime/JSGenericTypedArrayView.h: (JSC::toPossiblySharedNativeTypedView): (JSC::toUnsharedNativeTypedView): (JSC::JSGenericTypedArrayView<Adaptor>::toWrapped): (JSC::JSGenericTypedArrayView::typedImpl): Deleted. (JSC::toNativeTypedView): Deleted. * runtime/JSGenericTypedArrayViewInlines.h: (JSC::JSGenericTypedArrayView<Adaptor>::create): (JSC::JSGenericTypedArrayView<Adaptor>::possiblySharedTypedImpl): (JSC::JSGenericTypedArrayView<Adaptor>::unsharedTypedImpl): (JSC::JSGenericTypedArrayView<Adaptor>::getTypedArrayImpl): * runtime/JSGenericTypedArrayViewPrototypeFunctions.h: (JSC::genericTypedArrayViewProtoGetterFuncBuffer): (JSC::genericTypedArrayViewPrivateFuncSubarrayCreate): * runtime/JSGlobalObject.cpp: (JSC::createAtomicsProperty): (JSC::JSGlobalObject::init): (JSC::JSGlobalObject::visitChildren): * runtime/JSGlobalObject.h: (JSC::JSGlobalObject::arrayBufferPrototype): (JSC::JSGlobalObject::arrayBufferStructure): * runtime/MathObject.cpp: * runtime/RuntimeFlags.h: * runtime/SimpleTypedArrayController.cpp: (JSC::SimpleTypedArrayController::toJS): * runtime/TypedArrayType.h: (JSC::typedArrayTypeForType): Source/WebCore: New tests added in the LayoutTests/workers/sab directory. This teaches WebCore that a typed array could be shared or not. By default, WebCore will reject shared typed arrays as if they were not typed arrays. This ensures that we don't get race conditions in code that can't handle it. If you postMessage a SharedArrayBuffer or something that wraps it, you will send the shared memory to the other worker. * Modules/encryptedmedia/CDMSessionClearKey.cpp: (WebCore::CDMSessionClearKey::cachedKeyForKeyID): * Modules/fetch/FetchBody.cpp: (WebCore::FetchBody::extract): * Modules/mediastream/RTCDataChannel.cpp: (WebCore::RTCDataChannel::send): * Modules/webaudio/AudioBuffer.cpp: (WebCore::AudioBuffer::getChannelData): * Modules/websockets/WebSocket.cpp: (WebCore::WebSocket::send): * bindings/js/JSBlobCustom.cpp: (WebCore::constructJSBlob): * bindings/js/JSCryptoAlgorithmDictionary.cpp: (WebCore::createRsaKeyGenParams): * bindings/js/JSCryptoCustom.cpp: (WebCore::JSCrypto::getRandomValues): * bindings/js/JSCryptoOperationData.cpp: (WebCore::cryptoOperationDataFromJSValue): * bindings/js/JSDOMBinding.h: (WebCore::toJS): (WebCore::toPossiblySharedArrayBufferView): (WebCore::toUnsharedArrayBufferView): (WebCore::toPossiblySharedInt8Array): (WebCore::toPossiblySharedInt16Array): (WebCore::toPossiblySharedInt32Array): (WebCore::toPossiblySharedUint8Array): (WebCore::toPossiblySharedUint8ClampedArray): (WebCore::toPossiblySharedUint16Array): (WebCore::toPossiblySharedUint32Array): (WebCore::toPossiblySharedFloat32Array): (WebCore::toPossiblySharedFloat64Array): (WebCore::toUnsharedInt8Array): (WebCore::toUnsharedInt16Array): (WebCore::toUnsharedInt32Array): (WebCore::toUnsharedUint8Array): (WebCore::toUnsharedUint8ClampedArray): (WebCore::toUnsharedUint16Array): (WebCore::toUnsharedUint32Array): (WebCore::toUnsharedFloat32Array): (WebCore::toUnsharedFloat64Array): (WebCore::toArrayBufferView): Deleted. (WebCore::toInt8Array): Deleted. (WebCore::toInt16Array): Deleted. (WebCore::toInt32Array): Deleted. (WebCore::toUint8Array): Deleted. (WebCore::toUint8ClampedArray): Deleted. (WebCore::toUint16Array): Deleted. (WebCore::toUint32Array): Deleted. (WebCore::toFloat32Array): Deleted. (WebCore::toFloat64Array): Deleted. * bindings/js/JSDataCueCustom.cpp: (WebCore::constructJSDataCue): * bindings/js/JSDictionary.cpp: (WebCore::JSDictionary::convertValue): * bindings/js/JSFileCustom.cpp: (WebCore::constructJSFile): * bindings/js/JSMessagePortCustom.cpp: (WebCore::extractTransferables): * bindings/js/JSWebGLRenderingContextBaseCustom.cpp: (WebCore::dataFunctionf): (WebCore::dataFunctioni): (WebCore::dataFunctionMatrix): * bindings/js/JSXMLHttpRequestCustom.cpp: (WebCore::JSXMLHttpRequest::send): * bindings/js/SerializedScriptValue.cpp: (WebCore::CloneSerializer::dumpArrayBufferView): (WebCore::CloneSerializer::dumpIfTerminal): (WebCore::CloneDeserializer::readArrayBufferView): (WebCore::CloneDeserializer::readTerminal): (WebCore::SerializedScriptValue::transferArrayBuffers): * bindings/js/StructuredClone.cpp: (WebCore::structuredCloneArrayBuffer): (WebCore::structuredCloneArrayBufferView): * bindings/scripts/CodeGeneratorJS.pm: (JSValueToNative): * css/FontFace.cpp: (WebCore::FontFace::create): * html/canvas/WebGL2RenderingContext.cpp: (WebCore::WebGL2RenderingContext::bufferData): (WebCore::WebGL2RenderingContext::bufferSubData): * platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp: (WebCore::MediaPlayerPrivateAVFoundation::extractKeyURIKeyIDAndCertificateFromInitData): Source/WebKit/mac: Support the RuntimeFlag. * WebView/WebPreferencesPrivate.h: Source/WebKit/win: Support the RuntimeFlag. * Interfaces/IWebPreferencesPrivate.idl: Source/WebKit2: Adds some small things we need for SharedArrayBuffer. * UIProcess/API/C/WKPreferencesRefPrivate.h: * UIProcess/API/Cocoa/WKPreferencesPrivate.h: * WebProcess/InjectedBundle/InjectedBundle.cpp: (WebKit::InjectedBundle::createWebDataFromUint8Array): Source/WTF: Adds some small things we need for SharedArrayBuffer. * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeakRelaxed): (WTF::Atomic::exchangeAdd): (WTF::Atomic::exchangeAnd): (WTF::Atomic::exchangeOr): (WTF::Atomic::exchangeSub): (WTF::Atomic::exchangeXor): (WTF::atomicLoad): (WTF::atomicStore): (WTF::atomicCompareExchangeWeak): (WTF::atomicCompareExchangeWeakRelaxed): (WTF::atomicCompareExchangeStrong): (WTF::atomicExchangeAdd): (WTF::atomicExchangeAnd): (WTF::atomicExchangeOr): (WTF::atomicExchangeSub): (WTF::atomicExchangeXor): (WTF::atomicExchange): (WTF::Atomic::exchangeAndAdd): Deleted. (WTF::weakCompareAndSwap): Deleted. We need to be able to do atomics operations on naked pointers. We also need to be able to do all of the things that std::atomic does. This adds those things and renames weakCompareAndSwap to atomicCompareExchangeWeakRelaxed so that we're using consistent terminology. * wtf/Bitmap.h: (WTF::WordType>::concurrentTestAndSet): Renamed weakCompareAndSwap. (WTF::WordType>::concurrentTestAndClear): Renamed weakCompareAndSwap. * wtf/FastBitVector.h: (WTF::FastBitVector::atomicSetAndCheck): Renamed weakCompareAndSwap. * wtf/ParkingLot.cpp: (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkCount): * wtf/ParkingLot.h: Added unparkCount(), which lets you unpark some bounded number of threads and returns the number of threads unparked. This is just a modest extension of unparkAll(). unparkAll() now just calls unparkCount(ptr, UINT_MAX). Tools: Use the right kind of typed array API. * DumpRenderTree/TestRunner.cpp: (setAudioResultCallback): LayoutTests: Adding tests. This is a work in progress. * workers/sab: Added. * workers/sab/simple-worker-1.js: Added. (onmessage): * workers/sab/simple-worker-2.js: Added. (onmessage): * workers/sab/simple.html: Added. Canonical link: https://commits.webkit.org/181984@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208209 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-11-01 03:10:00 +00:00
NEVER_INLINE unsigned ParkingLot::unparkCount(const void* address, unsigned count)
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
{
JSC should support SharedArrayBuffer https://bugs.webkit.org/show_bug.cgi?id=163986 Reviewed by Keith Miller. JSTests: This adds our own test for the various corner cases of SharedArrayBuffer. This test is meant to check all of the things that don't require concurrency. * stress/SharedArrayBuffer.js: Added. (checkAtomics): (shouldFail): (Symbol): (runAtomic): Source/JavaScriptCore: This implements https://tc39.github.io/ecmascript_sharedmem/shmem.html. There is now a new SharedArrayBuffer type. In the JS runtime, which includes typed array types, the SharedArrayBuffer is a drop-in replacement for ArrayBuffer, even though they are distinct types (new SharedArrayBuffer() instanceof ArrayBuffer == false and vice versa). The DOM will not recognize SharedArrayBuffer, or any typed array that wraps it, to ensure safety. This matches what other browsers intend to do, see https://github.com/tc39/ecmascript_sharedmem/issues/38. API is provided for the DOM to opt into SharedArrayBuffer. One notable place is postMessage, which will share the SharedArrayBuffer's underlying data storage with other workers. This creates a pool of shared memory that the workers can use to talk to each other. There is also an Atomics object in global scope, which exposes sequentially consistent atomic operations: add, and, compareExchange, exchange, load, or, store, sub, and xor. Additionally it exposes a Atomics.isLockFree utility, which takes a byte amount and returns true or false. Also there is Atomics.wake/wait, which neatly map to ParkingLot. Accesses to typed arrays that wrap SharedArrayBuffer are optimized by JSC the same way as always. I believe that DFG and B3 already obey the following memory model, which I believe is a bit weaker than Cambridge and a bit stronger than what is being proposed for SharedArrayBuffer. To predict a program's behavior under the B3 memory model, imagine the space of all possible programs that would result from running an optimizer that adversarially follows B3's transformation rules. B3 transformations are correct if the newly created program is equivalent to the old one, assuming that any opaque effect in IR (like the reads and writes of a patchpoint/call/fence) could perform any load/store that satisfies the B3::Effects summary. Opaque effects are a way of describing an infinite set of programs: any program that only does the effects summarized in B3::Effects belongs to the set. For example, this prevents motion of operations across fences since fences are summarized as opaque effects that could read or write memory. This rule alone is not enough, because it leaves the door open for turning an atomic operation (like a load) into a non-atomic one (like a load followed by a store of the same value back to the same location or multiple loads). This is not an optimization that either our compiler or the CPU would want to do. One way to think of what exactly is forbidden is that B3 transformations that mess with memory accesses can only reorder them or remove them. This means that for any execution of the untransformed program, the corresponding execution of the transformed program (i.e. with the same input arguments and the same programs filled in for the opaque effects) must have the same loads and stores, with some removed and some reordered. This is a fairly simple mental model that B3 and DFG already follow and it's based on existing abstractions for the infinite set of programs inside an opaque effect (DFG's AbstractHeaps and B3's Effects). This patch makes all atomics operations intrinsic, but the DFG doesn't know about any of them yet. That's covered by bug 164108. This ought to be perf-neutral, but I am still running tests to confirm this. I'm also still writing new tests to cover all of the Atomics functionality and the behavior of SAB objects. * API/JSTypedArray.cpp: (JSObjectGetTypedArrayBytesPtr): (JSObjectGetTypedArrayBuffer): (JSObjectMakeArrayBufferWithBytesNoCopy): * API/tests/CompareAndSwapTest.cpp: (Bitmap::concurrentTestAndSet): * CMakeLists.txt: * JavaScriptCore.xcodeproj/project.pbxproj: * dfg/DFGDesiredWatchpoints.cpp: (JSC::DFG::ArrayBufferViewWatchpointAdaptor::add): * heap/Heap.cpp: (JSC::Heap::reportExtraMemoryVisited): (JSC::Heap::reportExternalMemoryVisited): * jsc.cpp: (functionTransferArrayBuffer): * runtime/ArrayBuffer.cpp: (JSC::SharedArrayBufferContents::SharedArrayBufferContents): (JSC::SharedArrayBufferContents::~SharedArrayBufferContents): (JSC::ArrayBufferContents::ArrayBufferContents): (JSC::ArrayBufferContents::operator=): (JSC::ArrayBufferContents::~ArrayBufferContents): (JSC::ArrayBufferContents::clear): (JSC::ArrayBufferContents::destroy): (JSC::ArrayBufferContents::reset): (JSC::ArrayBufferContents::tryAllocate): (JSC::ArrayBufferContents::makeShared): (JSC::ArrayBufferContents::transferTo): (JSC::ArrayBufferContents::copyTo): (JSC::ArrayBufferContents::shareWith): (JSC::ArrayBuffer::create): (JSC::ArrayBuffer::createAdopted): (JSC::ArrayBuffer::createFromBytes): (JSC::ArrayBuffer::tryCreate): (JSC::ArrayBuffer::createUninitialized): (JSC::ArrayBuffer::tryCreateUninitialized): (JSC::ArrayBuffer::createInternal): (JSC::ArrayBuffer::ArrayBuffer): (JSC::ArrayBuffer::slice): (JSC::ArrayBuffer::sliceImpl): (JSC::ArrayBuffer::makeShared): (JSC::ArrayBuffer::setSharingMode): (JSC::ArrayBuffer::transferTo): (JSC::ArrayBuffer::transfer): Deleted. * runtime/ArrayBuffer.h: (JSC::arrayBufferSharingModeName): (JSC::SharedArrayBufferContents::data): (JSC::ArrayBufferContents::data): (JSC::ArrayBufferContents::sizeInBytes): (JSC::ArrayBufferContents::isShared): (JSC::ArrayBuffer::sharingMode): (JSC::ArrayBuffer::isShared): (JSC::ArrayBuffer::gcSizeEstimateInBytes): (JSC::arrayBufferDestructorNull): Deleted. (JSC::arrayBufferDestructorDefault): Deleted. (JSC::ArrayBufferContents::ArrayBufferContents): Deleted. (JSC::ArrayBufferContents::transfer): Deleted. (JSC::ArrayBufferContents::copyTo): Deleted. (JSC::ArrayBuffer::create): Deleted. (JSC::ArrayBuffer::createAdopted): Deleted. (JSC::ArrayBuffer::createFromBytes): Deleted. (JSC::ArrayBuffer::tryCreate): Deleted. (JSC::ArrayBuffer::createUninitialized): Deleted. (JSC::ArrayBuffer::tryCreateUninitialized): Deleted. (JSC::ArrayBuffer::createInternal): Deleted. (JSC::ArrayBuffer::ArrayBuffer): Deleted. (JSC::ArrayBuffer::slice): Deleted. (JSC::ArrayBuffer::sliceImpl): Deleted. (JSC::ArrayBufferContents::tryAllocate): Deleted. (JSC::ArrayBufferContents::~ArrayBufferContents): Deleted. * runtime/ArrayBufferSharingMode.h: Added. * runtime/ArrayBufferView.h: (JSC::ArrayBufferView::possiblySharedBuffer): (JSC::ArrayBufferView::unsharedBuffer): (JSC::ArrayBufferView::isShared): (JSC::ArrayBufferView::buffer): Deleted. * runtime/AtomicsObject.cpp: Added. (JSC::AtomicsObject::AtomicsObject): (JSC::AtomicsObject::create): (JSC::AtomicsObject::createStructure): (JSC::AtomicsObject::finishCreation): (JSC::atomicsFuncAdd): (JSC::atomicsFuncAnd): (JSC::atomicsFuncCompareExchange): (JSC::atomicsFuncExchange): (JSC::atomicsFuncIsLockFree): (JSC::atomicsFuncLoad): (JSC::atomicsFuncOr): (JSC::atomicsFuncStore): (JSC::atomicsFuncSub): (JSC::atomicsFuncWait): (JSC::atomicsFuncWake): (JSC::atomicsFuncXor): * runtime/AtomicsObject.h: Added. * runtime/CommonIdentifiers.h: * runtime/DataView.cpp: (JSC::DataView::wrap): * runtime/GenericTypedArrayViewInlines.h: (JSC::GenericTypedArrayView<Adaptor>::subarray): * runtime/Intrinsic.h: * runtime/JSArrayBuffer.cpp: (JSC::JSArrayBuffer::finishCreation): (JSC::JSArrayBuffer::isShared): (JSC::JSArrayBuffer::sharingMode): * runtime/JSArrayBuffer.h: (JSC::toPossiblySharedArrayBuffer): (JSC::toUnsharedArrayBuffer): (JSC::JSArrayBuffer::toWrapped): (JSC::toArrayBuffer): Deleted. * runtime/JSArrayBufferConstructor.cpp: (JSC::JSArrayBufferConstructor::JSArrayBufferConstructor): (JSC::JSArrayBufferConstructor::finishCreation): (JSC::JSArrayBufferConstructor::create): (JSC::constructArrayBuffer): * runtime/JSArrayBufferConstructor.h: (JSC::JSArrayBufferConstructor::sharingMode): * runtime/JSArrayBufferPrototype.cpp: (JSC::arrayBufferProtoFuncSlice): (JSC::JSArrayBufferPrototype::JSArrayBufferPrototype): (JSC::JSArrayBufferPrototype::finishCreation): (JSC::JSArrayBufferPrototype::create): * runtime/JSArrayBufferPrototype.h: * runtime/JSArrayBufferView.cpp: (JSC::JSArrayBufferView::finishCreation): (JSC::JSArrayBufferView::visitChildren): (JSC::JSArrayBufferView::unsharedBuffer): (JSC::JSArrayBufferView::unsharedJSBuffer): (JSC::JSArrayBufferView::possiblySharedJSBuffer): (JSC::JSArrayBufferView::neuter): (JSC::JSArrayBufferView::toWrapped): Deleted. * runtime/JSArrayBufferView.h: (JSC::JSArrayBufferView::jsBuffer): Deleted. * runtime/JSArrayBufferViewInlines.h: (JSC::JSArrayBufferView::isShared): (JSC::JSArrayBufferView::possiblySharedBuffer): (JSC::JSArrayBufferView::possiblySharedImpl): (JSC::JSArrayBufferView::unsharedImpl): (JSC::JSArrayBufferView::byteOffset): (JSC::JSArrayBufferView::toWrapped): (JSC::JSArrayBufferView::buffer): Deleted. (JSC::JSArrayBufferView::impl): Deleted. (JSC::JSArrayBufferView::neuter): Deleted. * runtime/JSDataView.cpp: (JSC::JSDataView::possiblySharedTypedImpl): (JSC::JSDataView::unsharedTypedImpl): (JSC::JSDataView::getTypedArrayImpl): (JSC::JSDataView::typedImpl): Deleted. * runtime/JSDataView.h: (JSC::JSDataView::possiblySharedBuffer): (JSC::JSDataView::unsharedBuffer): (JSC::JSDataView::buffer): Deleted. * runtime/JSDataViewPrototype.cpp: (JSC::dataViewProtoGetterBuffer): * runtime/JSGenericTypedArrayView.h: (JSC::toPossiblySharedNativeTypedView): (JSC::toUnsharedNativeTypedView): (JSC::JSGenericTypedArrayView<Adaptor>::toWrapped): (JSC::JSGenericTypedArrayView::typedImpl): Deleted. (JSC::toNativeTypedView): Deleted. * runtime/JSGenericTypedArrayViewInlines.h: (JSC::JSGenericTypedArrayView<Adaptor>::create): (JSC::JSGenericTypedArrayView<Adaptor>::possiblySharedTypedImpl): (JSC::JSGenericTypedArrayView<Adaptor>::unsharedTypedImpl): (JSC::JSGenericTypedArrayView<Adaptor>::getTypedArrayImpl): * runtime/JSGenericTypedArrayViewPrototypeFunctions.h: (JSC::genericTypedArrayViewProtoGetterFuncBuffer): (JSC::genericTypedArrayViewPrivateFuncSubarrayCreate): * runtime/JSGlobalObject.cpp: (JSC::createAtomicsProperty): (JSC::JSGlobalObject::init): (JSC::JSGlobalObject::visitChildren): * runtime/JSGlobalObject.h: (JSC::JSGlobalObject::arrayBufferPrototype): (JSC::JSGlobalObject::arrayBufferStructure): * runtime/MathObject.cpp: * runtime/RuntimeFlags.h: * runtime/SimpleTypedArrayController.cpp: (JSC::SimpleTypedArrayController::toJS): * runtime/TypedArrayType.h: (JSC::typedArrayTypeForType): Source/WebCore: New tests added in the LayoutTests/workers/sab directory. This teaches WebCore that a typed array could be shared or not. By default, WebCore will reject shared typed arrays as if they were not typed arrays. This ensures that we don't get race conditions in code that can't handle it. If you postMessage a SharedArrayBuffer or something that wraps it, you will send the shared memory to the other worker. * Modules/encryptedmedia/CDMSessionClearKey.cpp: (WebCore::CDMSessionClearKey::cachedKeyForKeyID): * Modules/fetch/FetchBody.cpp: (WebCore::FetchBody::extract): * Modules/mediastream/RTCDataChannel.cpp: (WebCore::RTCDataChannel::send): * Modules/webaudio/AudioBuffer.cpp: (WebCore::AudioBuffer::getChannelData): * Modules/websockets/WebSocket.cpp: (WebCore::WebSocket::send): * bindings/js/JSBlobCustom.cpp: (WebCore::constructJSBlob): * bindings/js/JSCryptoAlgorithmDictionary.cpp: (WebCore::createRsaKeyGenParams): * bindings/js/JSCryptoCustom.cpp: (WebCore::JSCrypto::getRandomValues): * bindings/js/JSCryptoOperationData.cpp: (WebCore::cryptoOperationDataFromJSValue): * bindings/js/JSDOMBinding.h: (WebCore::toJS): (WebCore::toPossiblySharedArrayBufferView): (WebCore::toUnsharedArrayBufferView): (WebCore::toPossiblySharedInt8Array): (WebCore::toPossiblySharedInt16Array): (WebCore::toPossiblySharedInt32Array): (WebCore::toPossiblySharedUint8Array): (WebCore::toPossiblySharedUint8ClampedArray): (WebCore::toPossiblySharedUint16Array): (WebCore::toPossiblySharedUint32Array): (WebCore::toPossiblySharedFloat32Array): (WebCore::toPossiblySharedFloat64Array): (WebCore::toUnsharedInt8Array): (WebCore::toUnsharedInt16Array): (WebCore::toUnsharedInt32Array): (WebCore::toUnsharedUint8Array): (WebCore::toUnsharedUint8ClampedArray): (WebCore::toUnsharedUint16Array): (WebCore::toUnsharedUint32Array): (WebCore::toUnsharedFloat32Array): (WebCore::toUnsharedFloat64Array): (WebCore::toArrayBufferView): Deleted. (WebCore::toInt8Array): Deleted. (WebCore::toInt16Array): Deleted. (WebCore::toInt32Array): Deleted. (WebCore::toUint8Array): Deleted. (WebCore::toUint8ClampedArray): Deleted. (WebCore::toUint16Array): Deleted. (WebCore::toUint32Array): Deleted. (WebCore::toFloat32Array): Deleted. (WebCore::toFloat64Array): Deleted. * bindings/js/JSDataCueCustom.cpp: (WebCore::constructJSDataCue): * bindings/js/JSDictionary.cpp: (WebCore::JSDictionary::convertValue): * bindings/js/JSFileCustom.cpp: (WebCore::constructJSFile): * bindings/js/JSMessagePortCustom.cpp: (WebCore::extractTransferables): * bindings/js/JSWebGLRenderingContextBaseCustom.cpp: (WebCore::dataFunctionf): (WebCore::dataFunctioni): (WebCore::dataFunctionMatrix): * bindings/js/JSXMLHttpRequestCustom.cpp: (WebCore::JSXMLHttpRequest::send): * bindings/js/SerializedScriptValue.cpp: (WebCore::CloneSerializer::dumpArrayBufferView): (WebCore::CloneSerializer::dumpIfTerminal): (WebCore::CloneDeserializer::readArrayBufferView): (WebCore::CloneDeserializer::readTerminal): (WebCore::SerializedScriptValue::transferArrayBuffers): * bindings/js/StructuredClone.cpp: (WebCore::structuredCloneArrayBuffer): (WebCore::structuredCloneArrayBufferView): * bindings/scripts/CodeGeneratorJS.pm: (JSValueToNative): * css/FontFace.cpp: (WebCore::FontFace::create): * html/canvas/WebGL2RenderingContext.cpp: (WebCore::WebGL2RenderingContext::bufferData): (WebCore::WebGL2RenderingContext::bufferSubData): * platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp: (WebCore::MediaPlayerPrivateAVFoundation::extractKeyURIKeyIDAndCertificateFromInitData): Source/WebKit/mac: Support the RuntimeFlag. * WebView/WebPreferencesPrivate.h: Source/WebKit/win: Support the RuntimeFlag. * Interfaces/IWebPreferencesPrivate.idl: Source/WebKit2: Adds some small things we need for SharedArrayBuffer. * UIProcess/API/C/WKPreferencesRefPrivate.h: * UIProcess/API/Cocoa/WKPreferencesPrivate.h: * WebProcess/InjectedBundle/InjectedBundle.cpp: (WebKit::InjectedBundle::createWebDataFromUint8Array): Source/WTF: Adds some small things we need for SharedArrayBuffer. * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeakRelaxed): (WTF::Atomic::exchangeAdd): (WTF::Atomic::exchangeAnd): (WTF::Atomic::exchangeOr): (WTF::Atomic::exchangeSub): (WTF::Atomic::exchangeXor): (WTF::atomicLoad): (WTF::atomicStore): (WTF::atomicCompareExchangeWeak): (WTF::atomicCompareExchangeWeakRelaxed): (WTF::atomicCompareExchangeStrong): (WTF::atomicExchangeAdd): (WTF::atomicExchangeAnd): (WTF::atomicExchangeOr): (WTF::atomicExchangeSub): (WTF::atomicExchangeXor): (WTF::atomicExchange): (WTF::Atomic::exchangeAndAdd): Deleted. (WTF::weakCompareAndSwap): Deleted. We need to be able to do atomics operations on naked pointers. We also need to be able to do all of the things that std::atomic does. This adds those things and renames weakCompareAndSwap to atomicCompareExchangeWeakRelaxed so that we're using consistent terminology. * wtf/Bitmap.h: (WTF::WordType>::concurrentTestAndSet): Renamed weakCompareAndSwap. (WTF::WordType>::concurrentTestAndClear): Renamed weakCompareAndSwap. * wtf/FastBitVector.h: (WTF::FastBitVector::atomicSetAndCheck): Renamed weakCompareAndSwap. * wtf/ParkingLot.cpp: (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkCount): * wtf/ParkingLot.h: Added unparkCount(), which lets you unpark some bounded number of threads and returns the number of threads unparked. This is just a modest extension of unparkAll(). unparkAll() now just calls unparkCount(ptr, UINT_MAX). Tools: Use the right kind of typed array API. * DumpRenderTree/TestRunner.cpp: (setAudioResultCallback): LayoutTests: Adding tests. This is a work in progress. * workers/sab: Added. * workers/sab/simple-worker-1.js: Added. (onmessage): * workers/sab/simple-worker-2.js: Added. (onmessage): * workers/sab/simple.html: Added. Canonical link: https://commits.webkit.org/181984@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208209 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-11-01 03:10:00 +00:00
if (!count)
return 0;
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
if (verbose)
WTF shouldn't have both Thread and ThreadIdentifier https://bugs.webkit.org/show_bug.cgi?id=180308 Reviewed by Darin Adler. Source/JavaScriptCore: * heap/MachineStackMarker.cpp: (JSC::MachineThreads::tryCopyOtherThreadStacks): * llint/LLIntSlowPaths.cpp: (JSC::LLInt::llint_trace_operand): (JSC::LLInt::llint_trace_value): (JSC::LLInt::LLINT_SLOW_PATH_DECL): (JSC::LLInt::traceFunctionPrologue): * runtime/ExceptionScope.cpp: (JSC::ExceptionScope::unexpectedExceptionMessage): * runtime/JSLock.h: (JSC::JSLock::currentThreadIsHoldingLock): * runtime/VM.cpp: (JSC::VM::throwException): * runtime/VM.h: (JSC::VM::throwingThread const): (JSC::VM::clearException): * tools/HeapVerifier.cpp: (JSC::HeapVerifier::printVerificationHeader): Source/WebCore: No behavior change. * Modules/indexeddb/IDBActiveDOMObject.h: (WebCore::IDBActiveDOMObject::originThread const): (WebCore::IDBActiveDOMObject::performCallbackOnOriginThread): (WebCore::IDBActiveDOMObject::callFunctionOnOriginThread): (WebCore::IDBActiveDOMObject::originThreadID const): Deleted. * Modules/indexeddb/IDBCursor.cpp: (WebCore::IDBCursor::IDBCursor): (WebCore::IDBCursor::~IDBCursor): (WebCore::IDBCursor::sourcesDeleted const): (WebCore::IDBCursor::transaction const): (WebCore::IDBCursor::update): (WebCore::IDBCursor::advance): (WebCore::IDBCursor::continueFunction): (WebCore::IDBCursor::uncheckedIterateCursor): (WebCore::IDBCursor::deleteFunction): (WebCore::IDBCursor::setGetResult): * Modules/indexeddb/IDBDatabase.cpp: (WebCore::IDBDatabase::~IDBDatabase): (WebCore::IDBDatabase::hasPendingActivity const): (WebCore::IDBDatabase::name const): (WebCore::IDBDatabase::version const): (WebCore::IDBDatabase::objectStoreNames const): (WebCore::IDBDatabase::renameObjectStore): (WebCore::IDBDatabase::renameIndex): (WebCore::IDBDatabase::createObjectStore): (WebCore::IDBDatabase::transaction): (WebCore::IDBDatabase::deleteObjectStore): (WebCore::IDBDatabase::close): (WebCore::IDBDatabase::connectionToServerLost): (WebCore::IDBDatabase::maybeCloseInServer): (WebCore::IDBDatabase::activeDOMObjectName const): (WebCore::IDBDatabase::canSuspendForDocumentSuspension const): (WebCore::IDBDatabase::stop): (WebCore::IDBDatabase::startVersionChangeTransaction): (WebCore::IDBDatabase::didStartTransaction): (WebCore::IDBDatabase::willCommitTransaction): (WebCore::IDBDatabase::didCommitTransaction): (WebCore::IDBDatabase::willAbortTransaction): (WebCore::IDBDatabase::didAbortTransaction): (WebCore::IDBDatabase::didCommitOrAbortTransaction): (WebCore::IDBDatabase::fireVersionChangeEvent): (WebCore::IDBDatabase::dispatchEvent): (WebCore::IDBDatabase::didCreateIndexInfo): (WebCore::IDBDatabase::didDeleteIndexInfo): * Modules/indexeddb/IDBIndex.cpp: (WebCore::IDBIndex::IDBIndex): (WebCore::IDBIndex::~IDBIndex): (WebCore::IDBIndex::name const): (WebCore::IDBIndex::setName): (WebCore::IDBIndex::objectStore): (WebCore::IDBIndex::keyPath const): (WebCore::IDBIndex::unique const): (WebCore::IDBIndex::multiEntry const): (WebCore::IDBIndex::rollbackInfoForVersionChangeAbort): (WebCore::IDBIndex::openCursor): (WebCore::IDBIndex::openKeyCursor): (WebCore::IDBIndex::doCount): (WebCore::IDBIndex::doGet): (WebCore::IDBIndex::doGetKey): (WebCore::IDBIndex::getAll): (WebCore::IDBIndex::getAllKeys): (WebCore::IDBIndex::markAsDeleted): * Modules/indexeddb/IDBObjectStore.cpp: (WebCore::IDBObjectStore::IDBObjectStore): (WebCore::IDBObjectStore::~IDBObjectStore): (WebCore::IDBObjectStore::name const): (WebCore::IDBObjectStore::setName): (WebCore::IDBObjectStore::keyPath const): (WebCore::IDBObjectStore::indexNames const): (WebCore::IDBObjectStore::transaction): (WebCore::IDBObjectStore::autoIncrement const): (WebCore::IDBObjectStore::openCursor): (WebCore::IDBObjectStore::openKeyCursor): (WebCore::IDBObjectStore::get): (WebCore::IDBObjectStore::getKey): (WebCore::IDBObjectStore::putOrAdd): (WebCore::IDBObjectStore::doDelete): (WebCore::IDBObjectStore::clear): (WebCore::IDBObjectStore::createIndex): (WebCore::IDBObjectStore::index): (WebCore::IDBObjectStore::deleteIndex): (WebCore::IDBObjectStore::doCount): (WebCore::IDBObjectStore::getAll): (WebCore::IDBObjectStore::getAllKeys): (WebCore::IDBObjectStore::markAsDeleted): (WebCore::IDBObjectStore::rollbackForVersionChangeAbort): * Modules/indexeddb/IDBOpenDBRequest.cpp: (WebCore::IDBOpenDBRequest::~IDBOpenDBRequest): (WebCore::IDBOpenDBRequest::onError): (WebCore::IDBOpenDBRequest::versionChangeTransactionDidFinish): (WebCore::IDBOpenDBRequest::fireSuccessAfterVersionChangeCommit): (WebCore::IDBOpenDBRequest::fireErrorAfterVersionChangeCompletion): (WebCore::IDBOpenDBRequest::dispatchEvent): (WebCore::IDBOpenDBRequest::onSuccess): (WebCore::IDBOpenDBRequest::onUpgradeNeeded): (WebCore::IDBOpenDBRequest::onDeleteDatabaseSuccess): (WebCore::IDBOpenDBRequest::requestCompleted): (WebCore::IDBOpenDBRequest::requestBlocked): * Modules/indexeddb/IDBRequest.cpp: (WebCore::IDBRequest::~IDBRequest): (WebCore:: const): (WebCore::IDBRequest::setSource): (WebCore::IDBRequest::setVersionChangeTransaction): (WebCore::IDBRequest::transaction const): (WebCore::IDBRequest::sourceObjectStoreIdentifier const): (WebCore::IDBRequest::sourceIndexIdentifier const): (WebCore::IDBRequest::requestedObjectStoreRecordType const): (WebCore::IDBRequest::requestedIndexRecordType const): (WebCore::IDBRequest::eventTargetInterface const): (WebCore::IDBRequest::activeDOMObjectName const): (WebCore::IDBRequest::canSuspendForDocumentSuspension const): (WebCore::IDBRequest::hasPendingActivity const): (WebCore::IDBRequest::stop): (WebCore::IDBRequest::enqueueEvent): (WebCore::IDBRequest::dispatchEvent): (WebCore::IDBRequest::uncaughtExceptionInEventHandler): (WebCore::IDBRequest::setResult): (WebCore::IDBRequest::setResultToStructuredClone): (WebCore::IDBRequest::setResultToUndefined): (WebCore::IDBRequest::resultCursor): (WebCore::IDBRequest::willIterateCursor): (WebCore::IDBRequest::didOpenOrIterateCursor): (WebCore::IDBRequest::completeRequestAndDispatchEvent): (WebCore::IDBRequest::onError): (WebCore::IDBRequest::onSuccess): * Modules/indexeddb/IDBTransaction.cpp: (WebCore::IDBTransaction::IDBTransaction): (WebCore::IDBTransaction::~IDBTransaction): (WebCore::IDBTransaction::objectStoreNames const): (WebCore::IDBTransaction::db): (WebCore::IDBTransaction::error const): (WebCore::IDBTransaction::objectStore): (WebCore::IDBTransaction::abortDueToFailedRequest): (WebCore::IDBTransaction::transitionedToFinishing): (WebCore::IDBTransaction::abort): (WebCore::IDBTransaction::internalAbort): (WebCore::IDBTransaction::abortOnServerAndCancelRequests): (WebCore::IDBTransaction::activeDOMObjectName const): (WebCore::IDBTransaction::canSuspendForDocumentSuspension const): (WebCore::IDBTransaction::hasPendingActivity const): (WebCore::IDBTransaction::stop): (WebCore::IDBTransaction::isActive const): (WebCore::IDBTransaction::isFinishedOrFinishing const): (WebCore::IDBTransaction::addRequest): (WebCore::IDBTransaction::removeRequest): (WebCore::IDBTransaction::scheduleOperation): (WebCore::IDBTransaction::schedulePendingOperationTimer): (WebCore::IDBTransaction::pendingOperationTimerFired): (WebCore::IDBTransaction::operationCompletedOnServer): (WebCore::IDBTransaction::scheduleCompletedOperationTimer): (WebCore::IDBTransaction::completedOperationTimerFired): (WebCore::IDBTransaction::commit): (WebCore::IDBTransaction::commitOnServer): (WebCore::IDBTransaction::finishAbortOrCommit): (WebCore::IDBTransaction::didStart): (WebCore::IDBTransaction::notifyDidAbort): (WebCore::IDBTransaction::didAbort): (WebCore::IDBTransaction::didCommit): (WebCore::IDBTransaction::fireOnComplete): (WebCore::IDBTransaction::fireOnAbort): (WebCore::IDBTransaction::enqueueEvent): (WebCore::IDBTransaction::dispatchEvent): (WebCore::IDBTransaction::createObjectStore): (WebCore::IDBTransaction::createObjectStoreOnServer): (WebCore::IDBTransaction::didCreateObjectStoreOnServer): (WebCore::IDBTransaction::renameObjectStore): (WebCore::IDBTransaction::renameObjectStoreOnServer): (WebCore::IDBTransaction::didRenameObjectStoreOnServer): (WebCore::IDBTransaction::createIndex): (WebCore::IDBTransaction::createIndexOnServer): (WebCore::IDBTransaction::didCreateIndexOnServer): (WebCore::IDBTransaction::renameIndex): (WebCore::IDBTransaction::renameIndexOnServer): (WebCore::IDBTransaction::didRenameIndexOnServer): (WebCore::IDBTransaction::requestOpenCursor): (WebCore::IDBTransaction::doRequestOpenCursor): (WebCore::IDBTransaction::openCursorOnServer): (WebCore::IDBTransaction::didOpenCursorOnServer): (WebCore::IDBTransaction::iterateCursor): (WebCore::IDBTransaction::iterateCursorOnServer): (WebCore::IDBTransaction::didIterateCursorOnServer): (WebCore::IDBTransaction::requestGetAllObjectStoreRecords): (WebCore::IDBTransaction::requestGetAllIndexRecords): (WebCore::IDBTransaction::getAllRecordsOnServer): (WebCore::IDBTransaction::didGetAllRecordsOnServer): (WebCore::IDBTransaction::requestGetRecord): (WebCore::IDBTransaction::requestGetValue): (WebCore::IDBTransaction::requestGetKey): (WebCore::IDBTransaction::requestIndexRecord): (WebCore::IDBTransaction::getRecordOnServer): (WebCore::IDBTransaction::didGetRecordOnServer): (WebCore::IDBTransaction::requestCount): (WebCore::IDBTransaction::getCountOnServer): (WebCore::IDBTransaction::didGetCountOnServer): (WebCore::IDBTransaction::requestDeleteRecord): (WebCore::IDBTransaction::deleteRecordOnServer): (WebCore::IDBTransaction::didDeleteRecordOnServer): (WebCore::IDBTransaction::requestClearObjectStore): (WebCore::IDBTransaction::clearObjectStoreOnServer): (WebCore::IDBTransaction::didClearObjectStoreOnServer): (WebCore::IDBTransaction::requestPutOrAdd): (WebCore::IDBTransaction::putOrAddOnServer): (WebCore::IDBTransaction::didPutOrAddOnServer): (WebCore::IDBTransaction::deleteObjectStore): (WebCore::IDBTransaction::deleteObjectStoreOnServer): (WebCore::IDBTransaction::didDeleteObjectStoreOnServer): (WebCore::IDBTransaction::deleteIndex): (WebCore::IDBTransaction::deleteIndexOnServer): (WebCore::IDBTransaction::didDeleteIndexOnServer): (WebCore::IDBTransaction::operationCompletedOnClient): (WebCore::IDBTransaction::establishOnServer): (WebCore::IDBTransaction::activate): (WebCore::IDBTransaction::deactivate): * Modules/indexeddb/client/IDBConnectionProxy.cpp: (WebCore::IDBClient::removeItemsMatchingCurrentThread): * Modules/indexeddb/client/TransactionOperation.h: (WebCore::IDBClient::TransactionOperation::~TransactionOperation): (WebCore::IDBClient::TransactionOperation::perform): (WebCore::IDBClient::TransactionOperation::transitionToCompleteOnThisThread): (WebCore::IDBClient::TransactionOperation::transitionToComplete): (WebCore::IDBClient::TransactionOperation::doComplete): (WebCore::IDBClient::TransactionOperation::originThread const): (WebCore::IDBClient::TransactionOperation::originThreadID const): Deleted. * Modules/webaudio/AudioContext.cpp: (WebCore::AudioContext::AudioContext): (WebCore::AudioContext::lock): (WebCore::AudioContext::tryLock): (WebCore::AudioContext::unlock): (WebCore::AudioContext::isAudioThread const): (WebCore::AudioContext::isGraphOwner const): * Modules/webaudio/AudioContext.h: (WebCore::AudioContext::setAudioThread): (WebCore::AudioContext::audioThread const): * Modules/webaudio/AudioDestinationNode.cpp: (WebCore::AudioDestinationNode::render): * Modules/webdatabase/Database.cpp: (WebCore::Database::performClose): (WebCore::Database::securityOrigin): * Modules/webdatabase/DatabaseDetails.h: (WebCore::DatabaseDetails::DatabaseDetails): (WebCore::DatabaseDetails::operator=): (WebCore::DatabaseDetails::thread const): (WebCore::DatabaseDetails::threadID const): Deleted. * Modules/webdatabase/DatabaseManager.cpp: (WebCore::DatabaseManager::detailsForNameAndOrigin): * Modules/webdatabase/DatabaseThread.cpp: (WebCore::DatabaseThread::databaseThread): (WebCore::DatabaseThread::recordDatabaseOpen): (WebCore::DatabaseThread::recordDatabaseClosed): * Modules/webdatabase/DatabaseThread.h: (WebCore::DatabaseThread::getThread): (WebCore::DatabaseThread::getThreadID): Deleted. * Modules/webdatabase/SQLTransaction.cpp: (WebCore::SQLTransaction::checkAndHandleClosedDatabase): * Modules/webdatabase/SQLTransactionBackend.cpp: (WebCore::SQLTransactionBackend::doCleanup): (WebCore::SQLTransactionBackend::notifyDatabaseThreadIsShuttingDown): * bindings/js/JSCallbackData.h: (WebCore::JSCallbackData::JSCallbackData): (WebCore::JSCallbackData::~JSCallbackData): * bindings/js/ScheduledAction.cpp: (WebCore::ScheduledAction::execute): * dom/ScriptExecutionContext.cpp: (WebCore::ScriptExecutionContext::createdMessagePort): (WebCore::ScriptExecutionContext::destroyedMessagePort): * page/ResourceUsageOverlay.h: * page/scrolling/ScrollingThread.cpp: (WebCore::ScrollingThread::isCurrentThread): * platform/Supplementable.h: (WebCore::Supplementable::provideSupplement): (WebCore::Supplementable::removeSupplement): (WebCore::Supplementable::requireSupplement): (WebCore::Supplementable::Supplementable): Deleted. * platform/Timer.cpp: (WebCore::TimerBase::TimerBase): (WebCore::TimerBase::start): (WebCore::TimerBase::stop): (WebCore::TimerBase::setNextFireTime): * platform/Timer.h: (WebCore::TimerBase::isActive const): * platform/graphics/cocoa/FontCacheCoreText.cpp: (WebCore::shouldAutoActivateFontIfNeeded): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.cpp: (WebCore::TextureMapperPlatformLayerProxy::activateOnCompositingThread): (WebCore::TextureMapperPlatformLayerProxy::invalidate): (WebCore::TextureMapperPlatformLayerProxy::getAvailableBuffer): (WebCore::TextureMapperPlatformLayerProxy::appendToUnusedBuffers): (WebCore::TextureMapperPlatformLayerProxy::swapBuffer): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.h: (): Deleted. * platform/ios/wak/WebCoreThread.mm: (RunWebThread): (StartWebThread): * platform/sql/SQLiteDatabase.cpp: (WebCore::SQLiteDatabase::open): (WebCore::SQLiteDatabase::close): * platform/sql/SQLiteDatabase.h: (WebCore::SQLiteDatabase::sqlite3Handle const): * workers/WorkerGlobalScope.cpp: (WebCore::WorkerGlobalScope::~WorkerGlobalScope): (WebCore::WorkerGlobalScope::isContextThread const): * workers/WorkerMessagingProxy.cpp: (WebCore::WorkerMessagingProxy::WorkerMessagingProxy): (WebCore::WorkerMessagingProxy::~WorkerMessagingProxy): * workers/WorkerRunLoop.cpp: (WebCore::WorkerRunLoop::runInMode): (WebCore::WorkerRunLoop::runCleanupTasks): * workers/WorkerThread.h: (WebCore::WorkerThread::thread const): (WebCore::WorkerThread::threadID const): Deleted. * workers/service/ServiceWorkerContainer.cpp: (WebCore::ServiceWorkerContainer::~ServiceWorkerContainer): (WebCore::ServiceWorkerContainer::scheduleJob): (WebCore::ServiceWorkerContainer::jobFailedWithException): (WebCore::ServiceWorkerContainer::scheduleTaskToFireUpdateFoundEvent): (WebCore::ServiceWorkerContainer::jobResolvedWithRegistration): (WebCore::ServiceWorkerContainer::jobResolvedWithUnregistrationResult): (WebCore::ServiceWorkerContainer::startScriptFetchForJob): (WebCore::ServiceWorkerContainer::jobFinishedLoadingScript): (WebCore::ServiceWorkerContainer::jobFailedLoadingScript): (WebCore::ServiceWorkerContainer::jobDidFinish): (WebCore::ServiceWorkerContainer::addRegistration): (WebCore::ServiceWorkerContainer::removeRegistration): (WebCore::ServiceWorkerContainer::scheduleTaskToFireControllerChangeEvent): (WebCore::ServiceWorkerContainer::contextIdentifier): * workers/service/ServiceWorkerContainer.h: * workers/service/ServiceWorkerJob.cpp: (WebCore::ServiceWorkerJob::~ServiceWorkerJob): (WebCore::ServiceWorkerJob::failedWithException): (WebCore::ServiceWorkerJob::resolvedWithRegistration): (WebCore::ServiceWorkerJob::resolvedWithUnregistrationResult): (WebCore::ServiceWorkerJob::startScriptFetch): (WebCore::ServiceWorkerJob::fetchScriptWithContext): (WebCore::ServiceWorkerJob::didReceiveResponse): (WebCore::ServiceWorkerJob::notifyFinished): * workers/service/ServiceWorkerJob.h: * xml/parser/XMLDocumentParserLibxml2.cpp: (WebCore::matchFunc): (WebCore::openFunc): (WebCore::initializeXMLParser): (WebCore::XMLParserContext::createStringParser): (WebCore::XMLParserContext::createMemoryParser): Source/WebKit: * UIProcess/API/glib/IconDatabase.cpp: * UIProcess/GenericCallback.h: (WebKit::GenericCallback::~GenericCallback): (WebKit::GenericCallback::performCallbackWithReturnValue): Source/WTF: We should use a pointer of WTF::Thread instead of ThreadIdentifier. One problem is that Windows support library uses WTF::createThread, which returns ThreadIdentifier. So we cannot drop ThreadIdentifier in Windows environment. This patch keeps ThreadIdentifier in Windows. * wtf/MainThread.cpp: (WTF::initializeMainThread): (WTF::isMainThread): (WTF::canAccessThreadLocalDataForThread): * wtf/MainThread.h: * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkCount): * wtf/RecursiveLockAdapter.h: (WTF::RecursiveLockAdapter::lock): (WTF::RecursiveLockAdapter::unlock): (WTF::RecursiveLockAdapter::tryLock): * wtf/Threading.cpp: (WTF::Thread::dump const): * wtf/Threading.h: (WTF::Thread::id const): (WTF::Thread::operator==): Deleted. (WTF::Thread::operator!=): Deleted. (WTF::currentThread): Deleted. * wtf/ThreadingPrimitives.h: * wtf/ThreadingPthreads.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::detach): (WTF::Thread::initializeCurrentTLS): (WTF::Thread::suspend): (WTF::Thread::establishPlatformSpecificHandle): (WTF::Thread::currentID): Deleted. * wtf/ThreadingWin.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::suspend): (WTF::Thread::currentDying): * wtf/mac/MainThreadMac.mm: (WTF::initializeApplicationUIThread): (WTF::initializeWebThreadPlatform): (WTF::canAccessThreadLocalDataForThread): (WTF::initializeApplicationUIThreadIdentifier): Deleted. (WTF::initializeWebThreadIdentifier): Deleted. Tools: * DumpRenderTree/mac/DumpRenderTree.mm: (dumpRenderTree): (runThread): Deleted. (runPthread): Deleted. (testThreadIdentifierMap): Deleted. * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: * TestWebKitAPI/Tests/WTF/Threading.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/196314@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@225470 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-12-04 06:13:05 +00:00
dataLog(toString(Thread::current(), ": unparking count = ", count, " from ", RawPointer(address), ".\n"));
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
Vector<RefPtr<ThreadData>, 8> threadDatas;
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
dequeue(
address,
JSC should support SharedArrayBuffer https://bugs.webkit.org/show_bug.cgi?id=163986 Reviewed by Keith Miller. JSTests: This adds our own test for the various corner cases of SharedArrayBuffer. This test is meant to check all of the things that don't require concurrency. * stress/SharedArrayBuffer.js: Added. (checkAtomics): (shouldFail): (Symbol): (runAtomic): Source/JavaScriptCore: This implements https://tc39.github.io/ecmascript_sharedmem/shmem.html. There is now a new SharedArrayBuffer type. In the JS runtime, which includes typed array types, the SharedArrayBuffer is a drop-in replacement for ArrayBuffer, even though they are distinct types (new SharedArrayBuffer() instanceof ArrayBuffer == false and vice versa). The DOM will not recognize SharedArrayBuffer, or any typed array that wraps it, to ensure safety. This matches what other browsers intend to do, see https://github.com/tc39/ecmascript_sharedmem/issues/38. API is provided for the DOM to opt into SharedArrayBuffer. One notable place is postMessage, which will share the SharedArrayBuffer's underlying data storage with other workers. This creates a pool of shared memory that the workers can use to talk to each other. There is also an Atomics object in global scope, which exposes sequentially consistent atomic operations: add, and, compareExchange, exchange, load, or, store, sub, and xor. Additionally it exposes a Atomics.isLockFree utility, which takes a byte amount and returns true or false. Also there is Atomics.wake/wait, which neatly map to ParkingLot. Accesses to typed arrays that wrap SharedArrayBuffer are optimized by JSC the same way as always. I believe that DFG and B3 already obey the following memory model, which I believe is a bit weaker than Cambridge and a bit stronger than what is being proposed for SharedArrayBuffer. To predict a program's behavior under the B3 memory model, imagine the space of all possible programs that would result from running an optimizer that adversarially follows B3's transformation rules. B3 transformations are correct if the newly created program is equivalent to the old one, assuming that any opaque effect in IR (like the reads and writes of a patchpoint/call/fence) could perform any load/store that satisfies the B3::Effects summary. Opaque effects are a way of describing an infinite set of programs: any program that only does the effects summarized in B3::Effects belongs to the set. For example, this prevents motion of operations across fences since fences are summarized as opaque effects that could read or write memory. This rule alone is not enough, because it leaves the door open for turning an atomic operation (like a load) into a non-atomic one (like a load followed by a store of the same value back to the same location or multiple loads). This is not an optimization that either our compiler or the CPU would want to do. One way to think of what exactly is forbidden is that B3 transformations that mess with memory accesses can only reorder them or remove them. This means that for any execution of the untransformed program, the corresponding execution of the transformed program (i.e. with the same input arguments and the same programs filled in for the opaque effects) must have the same loads and stores, with some removed and some reordered. This is a fairly simple mental model that B3 and DFG already follow and it's based on existing abstractions for the infinite set of programs inside an opaque effect (DFG's AbstractHeaps and B3's Effects). This patch makes all atomics operations intrinsic, but the DFG doesn't know about any of them yet. That's covered by bug 164108. This ought to be perf-neutral, but I am still running tests to confirm this. I'm also still writing new tests to cover all of the Atomics functionality and the behavior of SAB objects. * API/JSTypedArray.cpp: (JSObjectGetTypedArrayBytesPtr): (JSObjectGetTypedArrayBuffer): (JSObjectMakeArrayBufferWithBytesNoCopy): * API/tests/CompareAndSwapTest.cpp: (Bitmap::concurrentTestAndSet): * CMakeLists.txt: * JavaScriptCore.xcodeproj/project.pbxproj: * dfg/DFGDesiredWatchpoints.cpp: (JSC::DFG::ArrayBufferViewWatchpointAdaptor::add): * heap/Heap.cpp: (JSC::Heap::reportExtraMemoryVisited): (JSC::Heap::reportExternalMemoryVisited): * jsc.cpp: (functionTransferArrayBuffer): * runtime/ArrayBuffer.cpp: (JSC::SharedArrayBufferContents::SharedArrayBufferContents): (JSC::SharedArrayBufferContents::~SharedArrayBufferContents): (JSC::ArrayBufferContents::ArrayBufferContents): (JSC::ArrayBufferContents::operator=): (JSC::ArrayBufferContents::~ArrayBufferContents): (JSC::ArrayBufferContents::clear): (JSC::ArrayBufferContents::destroy): (JSC::ArrayBufferContents::reset): (JSC::ArrayBufferContents::tryAllocate): (JSC::ArrayBufferContents::makeShared): (JSC::ArrayBufferContents::transferTo): (JSC::ArrayBufferContents::copyTo): (JSC::ArrayBufferContents::shareWith): (JSC::ArrayBuffer::create): (JSC::ArrayBuffer::createAdopted): (JSC::ArrayBuffer::createFromBytes): (JSC::ArrayBuffer::tryCreate): (JSC::ArrayBuffer::createUninitialized): (JSC::ArrayBuffer::tryCreateUninitialized): (JSC::ArrayBuffer::createInternal): (JSC::ArrayBuffer::ArrayBuffer): (JSC::ArrayBuffer::slice): (JSC::ArrayBuffer::sliceImpl): (JSC::ArrayBuffer::makeShared): (JSC::ArrayBuffer::setSharingMode): (JSC::ArrayBuffer::transferTo): (JSC::ArrayBuffer::transfer): Deleted. * runtime/ArrayBuffer.h: (JSC::arrayBufferSharingModeName): (JSC::SharedArrayBufferContents::data): (JSC::ArrayBufferContents::data): (JSC::ArrayBufferContents::sizeInBytes): (JSC::ArrayBufferContents::isShared): (JSC::ArrayBuffer::sharingMode): (JSC::ArrayBuffer::isShared): (JSC::ArrayBuffer::gcSizeEstimateInBytes): (JSC::arrayBufferDestructorNull): Deleted. (JSC::arrayBufferDestructorDefault): Deleted. (JSC::ArrayBufferContents::ArrayBufferContents): Deleted. (JSC::ArrayBufferContents::transfer): Deleted. (JSC::ArrayBufferContents::copyTo): Deleted. (JSC::ArrayBuffer::create): Deleted. (JSC::ArrayBuffer::createAdopted): Deleted. (JSC::ArrayBuffer::createFromBytes): Deleted. (JSC::ArrayBuffer::tryCreate): Deleted. (JSC::ArrayBuffer::createUninitialized): Deleted. (JSC::ArrayBuffer::tryCreateUninitialized): Deleted. (JSC::ArrayBuffer::createInternal): Deleted. (JSC::ArrayBuffer::ArrayBuffer): Deleted. (JSC::ArrayBuffer::slice): Deleted. (JSC::ArrayBuffer::sliceImpl): Deleted. (JSC::ArrayBufferContents::tryAllocate): Deleted. (JSC::ArrayBufferContents::~ArrayBufferContents): Deleted. * runtime/ArrayBufferSharingMode.h: Added. * runtime/ArrayBufferView.h: (JSC::ArrayBufferView::possiblySharedBuffer): (JSC::ArrayBufferView::unsharedBuffer): (JSC::ArrayBufferView::isShared): (JSC::ArrayBufferView::buffer): Deleted. * runtime/AtomicsObject.cpp: Added. (JSC::AtomicsObject::AtomicsObject): (JSC::AtomicsObject::create): (JSC::AtomicsObject::createStructure): (JSC::AtomicsObject::finishCreation): (JSC::atomicsFuncAdd): (JSC::atomicsFuncAnd): (JSC::atomicsFuncCompareExchange): (JSC::atomicsFuncExchange): (JSC::atomicsFuncIsLockFree): (JSC::atomicsFuncLoad): (JSC::atomicsFuncOr): (JSC::atomicsFuncStore): (JSC::atomicsFuncSub): (JSC::atomicsFuncWait): (JSC::atomicsFuncWake): (JSC::atomicsFuncXor): * runtime/AtomicsObject.h: Added. * runtime/CommonIdentifiers.h: * runtime/DataView.cpp: (JSC::DataView::wrap): * runtime/GenericTypedArrayViewInlines.h: (JSC::GenericTypedArrayView<Adaptor>::subarray): * runtime/Intrinsic.h: * runtime/JSArrayBuffer.cpp: (JSC::JSArrayBuffer::finishCreation): (JSC::JSArrayBuffer::isShared): (JSC::JSArrayBuffer::sharingMode): * runtime/JSArrayBuffer.h: (JSC::toPossiblySharedArrayBuffer): (JSC::toUnsharedArrayBuffer): (JSC::JSArrayBuffer::toWrapped): (JSC::toArrayBuffer): Deleted. * runtime/JSArrayBufferConstructor.cpp: (JSC::JSArrayBufferConstructor::JSArrayBufferConstructor): (JSC::JSArrayBufferConstructor::finishCreation): (JSC::JSArrayBufferConstructor::create): (JSC::constructArrayBuffer): * runtime/JSArrayBufferConstructor.h: (JSC::JSArrayBufferConstructor::sharingMode): * runtime/JSArrayBufferPrototype.cpp: (JSC::arrayBufferProtoFuncSlice): (JSC::JSArrayBufferPrototype::JSArrayBufferPrototype): (JSC::JSArrayBufferPrototype::finishCreation): (JSC::JSArrayBufferPrototype::create): * runtime/JSArrayBufferPrototype.h: * runtime/JSArrayBufferView.cpp: (JSC::JSArrayBufferView::finishCreation): (JSC::JSArrayBufferView::visitChildren): (JSC::JSArrayBufferView::unsharedBuffer): (JSC::JSArrayBufferView::unsharedJSBuffer): (JSC::JSArrayBufferView::possiblySharedJSBuffer): (JSC::JSArrayBufferView::neuter): (JSC::JSArrayBufferView::toWrapped): Deleted. * runtime/JSArrayBufferView.h: (JSC::JSArrayBufferView::jsBuffer): Deleted. * runtime/JSArrayBufferViewInlines.h: (JSC::JSArrayBufferView::isShared): (JSC::JSArrayBufferView::possiblySharedBuffer): (JSC::JSArrayBufferView::possiblySharedImpl): (JSC::JSArrayBufferView::unsharedImpl): (JSC::JSArrayBufferView::byteOffset): (JSC::JSArrayBufferView::toWrapped): (JSC::JSArrayBufferView::buffer): Deleted. (JSC::JSArrayBufferView::impl): Deleted. (JSC::JSArrayBufferView::neuter): Deleted. * runtime/JSDataView.cpp: (JSC::JSDataView::possiblySharedTypedImpl): (JSC::JSDataView::unsharedTypedImpl): (JSC::JSDataView::getTypedArrayImpl): (JSC::JSDataView::typedImpl): Deleted. * runtime/JSDataView.h: (JSC::JSDataView::possiblySharedBuffer): (JSC::JSDataView::unsharedBuffer): (JSC::JSDataView::buffer): Deleted. * runtime/JSDataViewPrototype.cpp: (JSC::dataViewProtoGetterBuffer): * runtime/JSGenericTypedArrayView.h: (JSC::toPossiblySharedNativeTypedView): (JSC::toUnsharedNativeTypedView): (JSC::JSGenericTypedArrayView<Adaptor>::toWrapped): (JSC::JSGenericTypedArrayView::typedImpl): Deleted. (JSC::toNativeTypedView): Deleted. * runtime/JSGenericTypedArrayViewInlines.h: (JSC::JSGenericTypedArrayView<Adaptor>::create): (JSC::JSGenericTypedArrayView<Adaptor>::possiblySharedTypedImpl): (JSC::JSGenericTypedArrayView<Adaptor>::unsharedTypedImpl): (JSC::JSGenericTypedArrayView<Adaptor>::getTypedArrayImpl): * runtime/JSGenericTypedArrayViewPrototypeFunctions.h: (JSC::genericTypedArrayViewProtoGetterFuncBuffer): (JSC::genericTypedArrayViewPrivateFuncSubarrayCreate): * runtime/JSGlobalObject.cpp: (JSC::createAtomicsProperty): (JSC::JSGlobalObject::init): (JSC::JSGlobalObject::visitChildren): * runtime/JSGlobalObject.h: (JSC::JSGlobalObject::arrayBufferPrototype): (JSC::JSGlobalObject::arrayBufferStructure): * runtime/MathObject.cpp: * runtime/RuntimeFlags.h: * runtime/SimpleTypedArrayController.cpp: (JSC::SimpleTypedArrayController::toJS): * runtime/TypedArrayType.h: (JSC::typedArrayTypeForType): Source/WebCore: New tests added in the LayoutTests/workers/sab directory. This teaches WebCore that a typed array could be shared or not. By default, WebCore will reject shared typed arrays as if they were not typed arrays. This ensures that we don't get race conditions in code that can't handle it. If you postMessage a SharedArrayBuffer or something that wraps it, you will send the shared memory to the other worker. * Modules/encryptedmedia/CDMSessionClearKey.cpp: (WebCore::CDMSessionClearKey::cachedKeyForKeyID): * Modules/fetch/FetchBody.cpp: (WebCore::FetchBody::extract): * Modules/mediastream/RTCDataChannel.cpp: (WebCore::RTCDataChannel::send): * Modules/webaudio/AudioBuffer.cpp: (WebCore::AudioBuffer::getChannelData): * Modules/websockets/WebSocket.cpp: (WebCore::WebSocket::send): * bindings/js/JSBlobCustom.cpp: (WebCore::constructJSBlob): * bindings/js/JSCryptoAlgorithmDictionary.cpp: (WebCore::createRsaKeyGenParams): * bindings/js/JSCryptoCustom.cpp: (WebCore::JSCrypto::getRandomValues): * bindings/js/JSCryptoOperationData.cpp: (WebCore::cryptoOperationDataFromJSValue): * bindings/js/JSDOMBinding.h: (WebCore::toJS): (WebCore::toPossiblySharedArrayBufferView): (WebCore::toUnsharedArrayBufferView): (WebCore::toPossiblySharedInt8Array): (WebCore::toPossiblySharedInt16Array): (WebCore::toPossiblySharedInt32Array): (WebCore::toPossiblySharedUint8Array): (WebCore::toPossiblySharedUint8ClampedArray): (WebCore::toPossiblySharedUint16Array): (WebCore::toPossiblySharedUint32Array): (WebCore::toPossiblySharedFloat32Array): (WebCore::toPossiblySharedFloat64Array): (WebCore::toUnsharedInt8Array): (WebCore::toUnsharedInt16Array): (WebCore::toUnsharedInt32Array): (WebCore::toUnsharedUint8Array): (WebCore::toUnsharedUint8ClampedArray): (WebCore::toUnsharedUint16Array): (WebCore::toUnsharedUint32Array): (WebCore::toUnsharedFloat32Array): (WebCore::toUnsharedFloat64Array): (WebCore::toArrayBufferView): Deleted. (WebCore::toInt8Array): Deleted. (WebCore::toInt16Array): Deleted. (WebCore::toInt32Array): Deleted. (WebCore::toUint8Array): Deleted. (WebCore::toUint8ClampedArray): Deleted. (WebCore::toUint16Array): Deleted. (WebCore::toUint32Array): Deleted. (WebCore::toFloat32Array): Deleted. (WebCore::toFloat64Array): Deleted. * bindings/js/JSDataCueCustom.cpp: (WebCore::constructJSDataCue): * bindings/js/JSDictionary.cpp: (WebCore::JSDictionary::convertValue): * bindings/js/JSFileCustom.cpp: (WebCore::constructJSFile): * bindings/js/JSMessagePortCustom.cpp: (WebCore::extractTransferables): * bindings/js/JSWebGLRenderingContextBaseCustom.cpp: (WebCore::dataFunctionf): (WebCore::dataFunctioni): (WebCore::dataFunctionMatrix): * bindings/js/JSXMLHttpRequestCustom.cpp: (WebCore::JSXMLHttpRequest::send): * bindings/js/SerializedScriptValue.cpp: (WebCore::CloneSerializer::dumpArrayBufferView): (WebCore::CloneSerializer::dumpIfTerminal): (WebCore::CloneDeserializer::readArrayBufferView): (WebCore::CloneDeserializer::readTerminal): (WebCore::SerializedScriptValue::transferArrayBuffers): * bindings/js/StructuredClone.cpp: (WebCore::structuredCloneArrayBuffer): (WebCore::structuredCloneArrayBufferView): * bindings/scripts/CodeGeneratorJS.pm: (JSValueToNative): * css/FontFace.cpp: (WebCore::FontFace::create): * html/canvas/WebGL2RenderingContext.cpp: (WebCore::WebGL2RenderingContext::bufferData): (WebCore::WebGL2RenderingContext::bufferSubData): * platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp: (WebCore::MediaPlayerPrivateAVFoundation::extractKeyURIKeyIDAndCertificateFromInitData): Source/WebKit/mac: Support the RuntimeFlag. * WebView/WebPreferencesPrivate.h: Source/WebKit/win: Support the RuntimeFlag. * Interfaces/IWebPreferencesPrivate.idl: Source/WebKit2: Adds some small things we need for SharedArrayBuffer. * UIProcess/API/C/WKPreferencesRefPrivate.h: * UIProcess/API/Cocoa/WKPreferencesPrivate.h: * WebProcess/InjectedBundle/InjectedBundle.cpp: (WebKit::InjectedBundle::createWebDataFromUint8Array): Source/WTF: Adds some small things we need for SharedArrayBuffer. * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeakRelaxed): (WTF::Atomic::exchangeAdd): (WTF::Atomic::exchangeAnd): (WTF::Atomic::exchangeOr): (WTF::Atomic::exchangeSub): (WTF::Atomic::exchangeXor): (WTF::atomicLoad): (WTF::atomicStore): (WTF::atomicCompareExchangeWeak): (WTF::atomicCompareExchangeWeakRelaxed): (WTF::atomicCompareExchangeStrong): (WTF::atomicExchangeAdd): (WTF::atomicExchangeAnd): (WTF::atomicExchangeOr): (WTF::atomicExchangeSub): (WTF::atomicExchangeXor): (WTF::atomicExchange): (WTF::Atomic::exchangeAndAdd): Deleted. (WTF::weakCompareAndSwap): Deleted. We need to be able to do atomics operations on naked pointers. We also need to be able to do all of the things that std::atomic does. This adds those things and renames weakCompareAndSwap to atomicCompareExchangeWeakRelaxed so that we're using consistent terminology. * wtf/Bitmap.h: (WTF::WordType>::concurrentTestAndSet): Renamed weakCompareAndSwap. (WTF::WordType>::concurrentTestAndClear): Renamed weakCompareAndSwap. * wtf/FastBitVector.h: (WTF::FastBitVector::atomicSetAndCheck): Renamed weakCompareAndSwap. * wtf/ParkingLot.cpp: (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkCount): * wtf/ParkingLot.h: Added unparkCount(), which lets you unpark some bounded number of threads and returns the number of threads unparked. This is just a modest extension of unparkAll(). unparkAll() now just calls unparkCount(ptr, UINT_MAX). Tools: Use the right kind of typed array API. * DumpRenderTree/TestRunner.cpp: (setAudioResultCallback): LayoutTests: Adding tests. This is a work in progress. * workers/sab: Added. * workers/sab/simple-worker-1.js: Added. (onmessage): * workers/sab/simple-worker-2.js: Added. (onmessage): * workers/sab/simple.html: Added. Canonical link: https://commits.webkit.org/181984@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208209 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-11-01 03:10:00 +00:00
// FIXME: It seems like this ought to be EnsureNonEmpty if we follow what unparkOne() does,
// but that seems wrong.
WTF::Lock should not suffer from the thundering herd https://bugs.webkit.org/show_bug.cgi?id=147947 Reviewed by Geoffrey Garen. Source/WTF: This changes Lock::unlockSlow() to use unparkOne() instead of unparkAll(). The problem with doing this is that it's not obvious after calling unparkOne() if there are any other threads that are still parked on the lock's queue. If we assume that there are and leave the hasParkedBit set, then future calls to unlock() will take the slow path. We don't want that if there aren't actually any threads parked. On the other hand, if we assume that there aren't any threads parked and clear the hasParkedBit, then if there actually were some threads parked, then they may never be awoken since future calls to unlock() won't take slow path and so won't call unparkOne(). In other words, we need a way to be very precise about when we clear the hasParkedBit and we need to do it in a race-free way: it can't be the case that we clear the bit just as some thread gets parked on the queue. A similar problem arises in futexes, and one of the solutions is to have a thread that acquires a lock after parking sets the hasParkedBit. This is what Rusty Russel's usersem does. It's a subtle algorithm. Also, it means that if a thread barges in before the unparked thread runs, then that barging thread will not know that there are threads parked. This could increase the severity of barging. Since ParkingLot is a user-level API, we don't have to worry about the kernel-user security issues and so we can expose callbacks while ParkingLot is holding its internal locks. This change does exactly that for unparkOne(). The new variant of unparkOne() will call a user function while the queue from which we are unparking is locked. The callback is told basic stats about the queue: did we unpark a thread this time, and could there be more threads to unpark in the future. The callback runs while it's impossible for the queue state to change, since the ParkingLot's internal locks for the queue is held. This means that Lock::unlockSlow() can either clear, or leave, the hasParkedBit while releasing the lock inside the callback from unparkOne(). This takes care of the thundering herd problem while also reducing the greed that arises from barging threads. This required some careful reworking of the ParkingLot algorithm. The first thing I noticed was that the ThreadData::shouldPark flag was useless, since it's set exactly when ThreadData::address is non-null. Then I had to make sure that dequeue() could lazily create both hashtables and buckets, since the "callback is called while queue is locked" invariant requires that we didn't exit early due to the hashtable or bucket not being present. Note that all of this is done in such a way that the old unparkOne() and unparkAll() don't have to create any buckets, though they now may create the hashtable. We don't care as much about the hashtable being created by unpark since it's just such an unlikely scenario and it would only happen once. This change reduces the kernel CPU usage of WTF::Lock for the long critical section test by about 8x and makes it always perform as well as WTF::WordLock and WTF::Mutex for that benchmark. * benchmarks/LockSpeedTest.cpp: * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): * wtf/Lock.h: (WTF::LockBase::isLocked): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: * wtf/WordLock.h: (WTF::WordLock::isLocked): (WTF::WordLock::isFullyReset): Tools: Add testing that checks that locks return to a pristine state after contention is over. * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::LockInspector::isFullyReset): (TestWebKitAPI::runLockTest): (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/166072@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188374 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 03:51:25 +00:00
BucketMode::IgnoreEmpty,
WTF::Lock should be fair eventually https://bugs.webkit.org/show_bug.cgi?id=159384 Reviewed by Geoffrey Garen. Source/WTF: In https://webkit.org/blog/6161/locking-in-webkit/ we showed how relaxing the fairness of locks makes them fast. That post presented lock fairness as a trade-off between two extremes: - Barging. A barging lock, like WTF::Lock, releases the lock in unlock() even if there was a thread on the queue. If there was a thread on the queue, the lock is released and that thread is made runnable. That thread may then grab the lock, or some other thread may grab the lock first (it may barge). Usually, the barging thread is the thread that released the lock in the first place. This maximizes throughput but hurts fairness. There is no good theoretical bound on how unfair the lock may become, but empirical data suggests that it's fair enough for the cases we previously measured. - FIFO. A FIFO lock, like HandoffLock in ToyLocks.h, does not release the lock in unlock() if there is a thread waiting. If there is a thread waiting, unlock() will make that thread runnable and inform it that it now holds the lock. This ensures perfect round-robin fairness and allows us to reason theoretically about how long it may take for a thread to grab the lock. For example, if we know that only N threads are running and each one may contend on a critical section, and each one may hold the lock for at most S seconds, then the time it takes to grab the lock is N * S. Unfortunately, FIFO locks perform very badly in most cases. This is because for the common case of short critical sections, they force a context switch after each critical section if the lock is contended. This change makes WTF::Lock almost as fair as FIFO while still being as fast as barging. Thanks to this new algorithm, you can now have both of these things at the same time. This change makes WTF::Lock eventually fair. We can almost (more on the caveats below) guarantee that the time it takes to grab a lock is N * max(1ms, S). In other words, critical sections that are longer than 1ms are always fair. For shorter critical sections, the amount of time that any thread waits is 1ms times the number of threads. There are some caveats that arise from our use of randomness, but even then, in the limit as the critical section length goes to infinity, the lock becomes fair. The corner cases are unlikely to happen; our experiments show that the lock becomes exactly as fair as a FIFO lock for any critical section that is 1ms or longer. The fairness mechanism is broken into two parts. WTF::Lock can now choose to unlock a lock fairly or unfairly thanks to the new ParkingLot token mechanism. WTF::Lock knows when to use fair unlocking based on a timeout mechanism in ParkingLot called timeToBeFair. ParkingLot::unparkOne() and ParkingLot::parkConditionally() can now communicate with each other via a token. unparkOne() can pass a token, which parkConditionally() will return. This change also makes parkConditionally() a lot more precise about when it was unparked due to a call to unparkOne(). If unparkOne() is told that a thread was unparked then this thread is guaranteed to report that it was unparked rather than timing out, and that thread is guaranteed to get the token that unparkOne() passed. The token is an intptr_t. We use it as a boolean variable in WTF::Lock, but you could use it to pass arbitrary data structures. By default, the token is zero. WTF::Lock's unlock() will pass 1 as the token if it is doing fair unlocking. In that case, unlock() will not release the lock, and lock() will know that it holds the lock as soon as parkConditionally() returns. Note that this algorithm relies on unparkOne() invoking WTF::Lock's callback while the queue lock is held, so that WTF::Lock can make a decision about unlock strategy and inject a token while it has complete knowledge over the state of the queue. As such, it's not immediately obvious how to implement this algorithm on top of futexes. You really need ParkingLot! WTF::Lock does not use fair unlocking every time. We expose a new API, Lock::unlockFairly(), which forces the fair unlocking behavior. Additionally, ParkingLot now maintains a per-bucket stochastic fairness timeout. When the timeout fires, the unparkOne() callback sees UnparkResult::timeToBeFair = true. This timeout is set to be anywhere from 0ms to 1ms at random. When a dequeue happens and there are threads that actually get dequeued, we check if the time since the last unfair unlock (the last time timeToBeFair was set to true) is more than the timeout amount. If so, then we set timeToBeFair to true and reset the timeout. This means that in the absence of ParkingLot collisions, unfair unlocking is guaranteed to happen at least once per millisecond. It will happen at 2 KHz on average. If there are collisions, then each collision adds one millisecond to the worst case (and 0.5 ms to the average case). The reason why we don't just use a fixed 1ms timeout is that we want to avoid resonance. Imagine a program in which some thread acquires a lock at 1 KHz in-phase with the timeToBeFair timeout. Then this thread would be the benefactor of fairness to the detriment of everyone else. Randomness ensures that we aren't too fair to any one thread. Empirically, this is neutral on our major benchmarks like JetStream but it's an enormous improvement in LockFairnessTest. It's common for an unfair lock (either our BargingLock, the old WTF::Lock, any of the other futex-based locks that barge, or new os_unfair_lock) to allow only one thread to hold the lock during a whole second in which each thread is holding the lock for 1ms at a time. This is because in a barging lock, releasing a lock after holding it for 1ms and then reacquiring it immediately virtually ensures that none of the other threads can wake up in time to grab it before it's relocked. But the new WTF::Lock handles this case like a champ: each thread gets equal turns. Here's some data. If we launch 10 threads and have each of them run for 1 second while repeatedly holding a critical section for 1ms, then here's how many times each thread gets to hold the lock using the old WTF::Lock algorithm: 799, 6, 1, 1, 1, 1, 1, 1, 1, 1 One thread hogged the lock for almost the whole time! With the new WTF::Lock, the lock becomes totally fair: 80, 79, 79, 79, 79, 79, 79, 80, 80, 79 I don't know of anyone creating such an automatically-fair adaptive lock before, so I think that this is a pretty awesome advancement to the state of the art! This change is good for three reasons: - We do have long critical sections in WebKit and we don't want to have to worry about starvation. This reduces the likelihood that we will see starvation due to our lock strategy. - I was talking to ggaren about bmalloc's locking needs, and he wanted unlockFairly() or lockFairly() or some moral equivalent for the scavenger thread. - If we use a WTF::Lock to manage heap access in a multithreaded GC, we'll need the ability to unlock and relock without barging. * benchmarks/LockFairnessTest.cpp: (main): * benchmarks/ToyLocks.h: * wtf/Condition.h: (WTF::ConditionBase::waitUntil): (WTF::ConditionBase::notifyOne): * wtf/Lock.cpp: (WTF::LockBase::lockSlow): (WTF::LockBase::unlockSlow): (WTF::LockBase::unlockFairlySlow): (WTF::LockBase::unlockSlowImpl): * wtf/Lock.h: (WTF::LockBase::try_lock): (WTF::LockBase::unlock): (WTF::LockBase::unlockFairly): (WTF::LockBase::isHeld): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::compareAndPark): (WTF::ParkingLot::unparkOne): Tools: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Canonical link: https://commits.webkit.org/178039@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@203350 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-07-18 18:32:52 +00:00
[&] (ThreadData* element, bool) {
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
if (verbose)
WTF shouldn't have both Thread and ThreadIdentifier https://bugs.webkit.org/show_bug.cgi?id=180308 Reviewed by Darin Adler. Source/JavaScriptCore: * heap/MachineStackMarker.cpp: (JSC::MachineThreads::tryCopyOtherThreadStacks): * llint/LLIntSlowPaths.cpp: (JSC::LLInt::llint_trace_operand): (JSC::LLInt::llint_trace_value): (JSC::LLInt::LLINT_SLOW_PATH_DECL): (JSC::LLInt::traceFunctionPrologue): * runtime/ExceptionScope.cpp: (JSC::ExceptionScope::unexpectedExceptionMessage): * runtime/JSLock.h: (JSC::JSLock::currentThreadIsHoldingLock): * runtime/VM.cpp: (JSC::VM::throwException): * runtime/VM.h: (JSC::VM::throwingThread const): (JSC::VM::clearException): * tools/HeapVerifier.cpp: (JSC::HeapVerifier::printVerificationHeader): Source/WebCore: No behavior change. * Modules/indexeddb/IDBActiveDOMObject.h: (WebCore::IDBActiveDOMObject::originThread const): (WebCore::IDBActiveDOMObject::performCallbackOnOriginThread): (WebCore::IDBActiveDOMObject::callFunctionOnOriginThread): (WebCore::IDBActiveDOMObject::originThreadID const): Deleted. * Modules/indexeddb/IDBCursor.cpp: (WebCore::IDBCursor::IDBCursor): (WebCore::IDBCursor::~IDBCursor): (WebCore::IDBCursor::sourcesDeleted const): (WebCore::IDBCursor::transaction const): (WebCore::IDBCursor::update): (WebCore::IDBCursor::advance): (WebCore::IDBCursor::continueFunction): (WebCore::IDBCursor::uncheckedIterateCursor): (WebCore::IDBCursor::deleteFunction): (WebCore::IDBCursor::setGetResult): * Modules/indexeddb/IDBDatabase.cpp: (WebCore::IDBDatabase::~IDBDatabase): (WebCore::IDBDatabase::hasPendingActivity const): (WebCore::IDBDatabase::name const): (WebCore::IDBDatabase::version const): (WebCore::IDBDatabase::objectStoreNames const): (WebCore::IDBDatabase::renameObjectStore): (WebCore::IDBDatabase::renameIndex): (WebCore::IDBDatabase::createObjectStore): (WebCore::IDBDatabase::transaction): (WebCore::IDBDatabase::deleteObjectStore): (WebCore::IDBDatabase::close): (WebCore::IDBDatabase::connectionToServerLost): (WebCore::IDBDatabase::maybeCloseInServer): (WebCore::IDBDatabase::activeDOMObjectName const): (WebCore::IDBDatabase::canSuspendForDocumentSuspension const): (WebCore::IDBDatabase::stop): (WebCore::IDBDatabase::startVersionChangeTransaction): (WebCore::IDBDatabase::didStartTransaction): (WebCore::IDBDatabase::willCommitTransaction): (WebCore::IDBDatabase::didCommitTransaction): (WebCore::IDBDatabase::willAbortTransaction): (WebCore::IDBDatabase::didAbortTransaction): (WebCore::IDBDatabase::didCommitOrAbortTransaction): (WebCore::IDBDatabase::fireVersionChangeEvent): (WebCore::IDBDatabase::dispatchEvent): (WebCore::IDBDatabase::didCreateIndexInfo): (WebCore::IDBDatabase::didDeleteIndexInfo): * Modules/indexeddb/IDBIndex.cpp: (WebCore::IDBIndex::IDBIndex): (WebCore::IDBIndex::~IDBIndex): (WebCore::IDBIndex::name const): (WebCore::IDBIndex::setName): (WebCore::IDBIndex::objectStore): (WebCore::IDBIndex::keyPath const): (WebCore::IDBIndex::unique const): (WebCore::IDBIndex::multiEntry const): (WebCore::IDBIndex::rollbackInfoForVersionChangeAbort): (WebCore::IDBIndex::openCursor): (WebCore::IDBIndex::openKeyCursor): (WebCore::IDBIndex::doCount): (WebCore::IDBIndex::doGet): (WebCore::IDBIndex::doGetKey): (WebCore::IDBIndex::getAll): (WebCore::IDBIndex::getAllKeys): (WebCore::IDBIndex::markAsDeleted): * Modules/indexeddb/IDBObjectStore.cpp: (WebCore::IDBObjectStore::IDBObjectStore): (WebCore::IDBObjectStore::~IDBObjectStore): (WebCore::IDBObjectStore::name const): (WebCore::IDBObjectStore::setName): (WebCore::IDBObjectStore::keyPath const): (WebCore::IDBObjectStore::indexNames const): (WebCore::IDBObjectStore::transaction): (WebCore::IDBObjectStore::autoIncrement const): (WebCore::IDBObjectStore::openCursor): (WebCore::IDBObjectStore::openKeyCursor): (WebCore::IDBObjectStore::get): (WebCore::IDBObjectStore::getKey): (WebCore::IDBObjectStore::putOrAdd): (WebCore::IDBObjectStore::doDelete): (WebCore::IDBObjectStore::clear): (WebCore::IDBObjectStore::createIndex): (WebCore::IDBObjectStore::index): (WebCore::IDBObjectStore::deleteIndex): (WebCore::IDBObjectStore::doCount): (WebCore::IDBObjectStore::getAll): (WebCore::IDBObjectStore::getAllKeys): (WebCore::IDBObjectStore::markAsDeleted): (WebCore::IDBObjectStore::rollbackForVersionChangeAbort): * Modules/indexeddb/IDBOpenDBRequest.cpp: (WebCore::IDBOpenDBRequest::~IDBOpenDBRequest): (WebCore::IDBOpenDBRequest::onError): (WebCore::IDBOpenDBRequest::versionChangeTransactionDidFinish): (WebCore::IDBOpenDBRequest::fireSuccessAfterVersionChangeCommit): (WebCore::IDBOpenDBRequest::fireErrorAfterVersionChangeCompletion): (WebCore::IDBOpenDBRequest::dispatchEvent): (WebCore::IDBOpenDBRequest::onSuccess): (WebCore::IDBOpenDBRequest::onUpgradeNeeded): (WebCore::IDBOpenDBRequest::onDeleteDatabaseSuccess): (WebCore::IDBOpenDBRequest::requestCompleted): (WebCore::IDBOpenDBRequest::requestBlocked): * Modules/indexeddb/IDBRequest.cpp: (WebCore::IDBRequest::~IDBRequest): (WebCore:: const): (WebCore::IDBRequest::setSource): (WebCore::IDBRequest::setVersionChangeTransaction): (WebCore::IDBRequest::transaction const): (WebCore::IDBRequest::sourceObjectStoreIdentifier const): (WebCore::IDBRequest::sourceIndexIdentifier const): (WebCore::IDBRequest::requestedObjectStoreRecordType const): (WebCore::IDBRequest::requestedIndexRecordType const): (WebCore::IDBRequest::eventTargetInterface const): (WebCore::IDBRequest::activeDOMObjectName const): (WebCore::IDBRequest::canSuspendForDocumentSuspension const): (WebCore::IDBRequest::hasPendingActivity const): (WebCore::IDBRequest::stop): (WebCore::IDBRequest::enqueueEvent): (WebCore::IDBRequest::dispatchEvent): (WebCore::IDBRequest::uncaughtExceptionInEventHandler): (WebCore::IDBRequest::setResult): (WebCore::IDBRequest::setResultToStructuredClone): (WebCore::IDBRequest::setResultToUndefined): (WebCore::IDBRequest::resultCursor): (WebCore::IDBRequest::willIterateCursor): (WebCore::IDBRequest::didOpenOrIterateCursor): (WebCore::IDBRequest::completeRequestAndDispatchEvent): (WebCore::IDBRequest::onError): (WebCore::IDBRequest::onSuccess): * Modules/indexeddb/IDBTransaction.cpp: (WebCore::IDBTransaction::IDBTransaction): (WebCore::IDBTransaction::~IDBTransaction): (WebCore::IDBTransaction::objectStoreNames const): (WebCore::IDBTransaction::db): (WebCore::IDBTransaction::error const): (WebCore::IDBTransaction::objectStore): (WebCore::IDBTransaction::abortDueToFailedRequest): (WebCore::IDBTransaction::transitionedToFinishing): (WebCore::IDBTransaction::abort): (WebCore::IDBTransaction::internalAbort): (WebCore::IDBTransaction::abortOnServerAndCancelRequests): (WebCore::IDBTransaction::activeDOMObjectName const): (WebCore::IDBTransaction::canSuspendForDocumentSuspension const): (WebCore::IDBTransaction::hasPendingActivity const): (WebCore::IDBTransaction::stop): (WebCore::IDBTransaction::isActive const): (WebCore::IDBTransaction::isFinishedOrFinishing const): (WebCore::IDBTransaction::addRequest): (WebCore::IDBTransaction::removeRequest): (WebCore::IDBTransaction::scheduleOperation): (WebCore::IDBTransaction::schedulePendingOperationTimer): (WebCore::IDBTransaction::pendingOperationTimerFired): (WebCore::IDBTransaction::operationCompletedOnServer): (WebCore::IDBTransaction::scheduleCompletedOperationTimer): (WebCore::IDBTransaction::completedOperationTimerFired): (WebCore::IDBTransaction::commit): (WebCore::IDBTransaction::commitOnServer): (WebCore::IDBTransaction::finishAbortOrCommit): (WebCore::IDBTransaction::didStart): (WebCore::IDBTransaction::notifyDidAbort): (WebCore::IDBTransaction::didAbort): (WebCore::IDBTransaction::didCommit): (WebCore::IDBTransaction::fireOnComplete): (WebCore::IDBTransaction::fireOnAbort): (WebCore::IDBTransaction::enqueueEvent): (WebCore::IDBTransaction::dispatchEvent): (WebCore::IDBTransaction::createObjectStore): (WebCore::IDBTransaction::createObjectStoreOnServer): (WebCore::IDBTransaction::didCreateObjectStoreOnServer): (WebCore::IDBTransaction::renameObjectStore): (WebCore::IDBTransaction::renameObjectStoreOnServer): (WebCore::IDBTransaction::didRenameObjectStoreOnServer): (WebCore::IDBTransaction::createIndex): (WebCore::IDBTransaction::createIndexOnServer): (WebCore::IDBTransaction::didCreateIndexOnServer): (WebCore::IDBTransaction::renameIndex): (WebCore::IDBTransaction::renameIndexOnServer): (WebCore::IDBTransaction::didRenameIndexOnServer): (WebCore::IDBTransaction::requestOpenCursor): (WebCore::IDBTransaction::doRequestOpenCursor): (WebCore::IDBTransaction::openCursorOnServer): (WebCore::IDBTransaction::didOpenCursorOnServer): (WebCore::IDBTransaction::iterateCursor): (WebCore::IDBTransaction::iterateCursorOnServer): (WebCore::IDBTransaction::didIterateCursorOnServer): (WebCore::IDBTransaction::requestGetAllObjectStoreRecords): (WebCore::IDBTransaction::requestGetAllIndexRecords): (WebCore::IDBTransaction::getAllRecordsOnServer): (WebCore::IDBTransaction::didGetAllRecordsOnServer): (WebCore::IDBTransaction::requestGetRecord): (WebCore::IDBTransaction::requestGetValue): (WebCore::IDBTransaction::requestGetKey): (WebCore::IDBTransaction::requestIndexRecord): (WebCore::IDBTransaction::getRecordOnServer): (WebCore::IDBTransaction::didGetRecordOnServer): (WebCore::IDBTransaction::requestCount): (WebCore::IDBTransaction::getCountOnServer): (WebCore::IDBTransaction::didGetCountOnServer): (WebCore::IDBTransaction::requestDeleteRecord): (WebCore::IDBTransaction::deleteRecordOnServer): (WebCore::IDBTransaction::didDeleteRecordOnServer): (WebCore::IDBTransaction::requestClearObjectStore): (WebCore::IDBTransaction::clearObjectStoreOnServer): (WebCore::IDBTransaction::didClearObjectStoreOnServer): (WebCore::IDBTransaction::requestPutOrAdd): (WebCore::IDBTransaction::putOrAddOnServer): (WebCore::IDBTransaction::didPutOrAddOnServer): (WebCore::IDBTransaction::deleteObjectStore): (WebCore::IDBTransaction::deleteObjectStoreOnServer): (WebCore::IDBTransaction::didDeleteObjectStoreOnServer): (WebCore::IDBTransaction::deleteIndex): (WebCore::IDBTransaction::deleteIndexOnServer): (WebCore::IDBTransaction::didDeleteIndexOnServer): (WebCore::IDBTransaction::operationCompletedOnClient): (WebCore::IDBTransaction::establishOnServer): (WebCore::IDBTransaction::activate): (WebCore::IDBTransaction::deactivate): * Modules/indexeddb/client/IDBConnectionProxy.cpp: (WebCore::IDBClient::removeItemsMatchingCurrentThread): * Modules/indexeddb/client/TransactionOperation.h: (WebCore::IDBClient::TransactionOperation::~TransactionOperation): (WebCore::IDBClient::TransactionOperation::perform): (WebCore::IDBClient::TransactionOperation::transitionToCompleteOnThisThread): (WebCore::IDBClient::TransactionOperation::transitionToComplete): (WebCore::IDBClient::TransactionOperation::doComplete): (WebCore::IDBClient::TransactionOperation::originThread const): (WebCore::IDBClient::TransactionOperation::originThreadID const): Deleted. * Modules/webaudio/AudioContext.cpp: (WebCore::AudioContext::AudioContext): (WebCore::AudioContext::lock): (WebCore::AudioContext::tryLock): (WebCore::AudioContext::unlock): (WebCore::AudioContext::isAudioThread const): (WebCore::AudioContext::isGraphOwner const): * Modules/webaudio/AudioContext.h: (WebCore::AudioContext::setAudioThread): (WebCore::AudioContext::audioThread const): * Modules/webaudio/AudioDestinationNode.cpp: (WebCore::AudioDestinationNode::render): * Modules/webdatabase/Database.cpp: (WebCore::Database::performClose): (WebCore::Database::securityOrigin): * Modules/webdatabase/DatabaseDetails.h: (WebCore::DatabaseDetails::DatabaseDetails): (WebCore::DatabaseDetails::operator=): (WebCore::DatabaseDetails::thread const): (WebCore::DatabaseDetails::threadID const): Deleted. * Modules/webdatabase/DatabaseManager.cpp: (WebCore::DatabaseManager::detailsForNameAndOrigin): * Modules/webdatabase/DatabaseThread.cpp: (WebCore::DatabaseThread::databaseThread): (WebCore::DatabaseThread::recordDatabaseOpen): (WebCore::DatabaseThread::recordDatabaseClosed): * Modules/webdatabase/DatabaseThread.h: (WebCore::DatabaseThread::getThread): (WebCore::DatabaseThread::getThreadID): Deleted. * Modules/webdatabase/SQLTransaction.cpp: (WebCore::SQLTransaction::checkAndHandleClosedDatabase): * Modules/webdatabase/SQLTransactionBackend.cpp: (WebCore::SQLTransactionBackend::doCleanup): (WebCore::SQLTransactionBackend::notifyDatabaseThreadIsShuttingDown): * bindings/js/JSCallbackData.h: (WebCore::JSCallbackData::JSCallbackData): (WebCore::JSCallbackData::~JSCallbackData): * bindings/js/ScheduledAction.cpp: (WebCore::ScheduledAction::execute): * dom/ScriptExecutionContext.cpp: (WebCore::ScriptExecutionContext::createdMessagePort): (WebCore::ScriptExecutionContext::destroyedMessagePort): * page/ResourceUsageOverlay.h: * page/scrolling/ScrollingThread.cpp: (WebCore::ScrollingThread::isCurrentThread): * platform/Supplementable.h: (WebCore::Supplementable::provideSupplement): (WebCore::Supplementable::removeSupplement): (WebCore::Supplementable::requireSupplement): (WebCore::Supplementable::Supplementable): Deleted. * platform/Timer.cpp: (WebCore::TimerBase::TimerBase): (WebCore::TimerBase::start): (WebCore::TimerBase::stop): (WebCore::TimerBase::setNextFireTime): * platform/Timer.h: (WebCore::TimerBase::isActive const): * platform/graphics/cocoa/FontCacheCoreText.cpp: (WebCore::shouldAutoActivateFontIfNeeded): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.cpp: (WebCore::TextureMapperPlatformLayerProxy::activateOnCompositingThread): (WebCore::TextureMapperPlatformLayerProxy::invalidate): (WebCore::TextureMapperPlatformLayerProxy::getAvailableBuffer): (WebCore::TextureMapperPlatformLayerProxy::appendToUnusedBuffers): (WebCore::TextureMapperPlatformLayerProxy::swapBuffer): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.h: (): Deleted. * platform/ios/wak/WebCoreThread.mm: (RunWebThread): (StartWebThread): * platform/sql/SQLiteDatabase.cpp: (WebCore::SQLiteDatabase::open): (WebCore::SQLiteDatabase::close): * platform/sql/SQLiteDatabase.h: (WebCore::SQLiteDatabase::sqlite3Handle const): * workers/WorkerGlobalScope.cpp: (WebCore::WorkerGlobalScope::~WorkerGlobalScope): (WebCore::WorkerGlobalScope::isContextThread const): * workers/WorkerMessagingProxy.cpp: (WebCore::WorkerMessagingProxy::WorkerMessagingProxy): (WebCore::WorkerMessagingProxy::~WorkerMessagingProxy): * workers/WorkerRunLoop.cpp: (WebCore::WorkerRunLoop::runInMode): (WebCore::WorkerRunLoop::runCleanupTasks): * workers/WorkerThread.h: (WebCore::WorkerThread::thread const): (WebCore::WorkerThread::threadID const): Deleted. * workers/service/ServiceWorkerContainer.cpp: (WebCore::ServiceWorkerContainer::~ServiceWorkerContainer): (WebCore::ServiceWorkerContainer::scheduleJob): (WebCore::ServiceWorkerContainer::jobFailedWithException): (WebCore::ServiceWorkerContainer::scheduleTaskToFireUpdateFoundEvent): (WebCore::ServiceWorkerContainer::jobResolvedWithRegistration): (WebCore::ServiceWorkerContainer::jobResolvedWithUnregistrationResult): (WebCore::ServiceWorkerContainer::startScriptFetchForJob): (WebCore::ServiceWorkerContainer::jobFinishedLoadingScript): (WebCore::ServiceWorkerContainer::jobFailedLoadingScript): (WebCore::ServiceWorkerContainer::jobDidFinish): (WebCore::ServiceWorkerContainer::addRegistration): (WebCore::ServiceWorkerContainer::removeRegistration): (WebCore::ServiceWorkerContainer::scheduleTaskToFireControllerChangeEvent): (WebCore::ServiceWorkerContainer::contextIdentifier): * workers/service/ServiceWorkerContainer.h: * workers/service/ServiceWorkerJob.cpp: (WebCore::ServiceWorkerJob::~ServiceWorkerJob): (WebCore::ServiceWorkerJob::failedWithException): (WebCore::ServiceWorkerJob::resolvedWithRegistration): (WebCore::ServiceWorkerJob::resolvedWithUnregistrationResult): (WebCore::ServiceWorkerJob::startScriptFetch): (WebCore::ServiceWorkerJob::fetchScriptWithContext): (WebCore::ServiceWorkerJob::didReceiveResponse): (WebCore::ServiceWorkerJob::notifyFinished): * workers/service/ServiceWorkerJob.h: * xml/parser/XMLDocumentParserLibxml2.cpp: (WebCore::matchFunc): (WebCore::openFunc): (WebCore::initializeXMLParser): (WebCore::XMLParserContext::createStringParser): (WebCore::XMLParserContext::createMemoryParser): Source/WebKit: * UIProcess/API/glib/IconDatabase.cpp: * UIProcess/GenericCallback.h: (WebKit::GenericCallback::~GenericCallback): (WebKit::GenericCallback::performCallbackWithReturnValue): Source/WTF: We should use a pointer of WTF::Thread instead of ThreadIdentifier. One problem is that Windows support library uses WTF::createThread, which returns ThreadIdentifier. So we cannot drop ThreadIdentifier in Windows environment. This patch keeps ThreadIdentifier in Windows. * wtf/MainThread.cpp: (WTF::initializeMainThread): (WTF::isMainThread): (WTF::canAccessThreadLocalDataForThread): * wtf/MainThread.h: * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkCount): * wtf/RecursiveLockAdapter.h: (WTF::RecursiveLockAdapter::lock): (WTF::RecursiveLockAdapter::unlock): (WTF::RecursiveLockAdapter::tryLock): * wtf/Threading.cpp: (WTF::Thread::dump const): * wtf/Threading.h: (WTF::Thread::id const): (WTF::Thread::operator==): Deleted. (WTF::Thread::operator!=): Deleted. (WTF::currentThread): Deleted. * wtf/ThreadingPrimitives.h: * wtf/ThreadingPthreads.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::detach): (WTF::Thread::initializeCurrentTLS): (WTF::Thread::suspend): (WTF::Thread::establishPlatformSpecificHandle): (WTF::Thread::currentID): Deleted. * wtf/ThreadingWin.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::suspend): (WTF::Thread::currentDying): * wtf/mac/MainThreadMac.mm: (WTF::initializeApplicationUIThread): (WTF::initializeWebThreadPlatform): (WTF::canAccessThreadLocalDataForThread): (WTF::initializeApplicationUIThreadIdentifier): Deleted. (WTF::initializeWebThreadIdentifier): Deleted. Tools: * DumpRenderTree/mac/DumpRenderTree.mm: (dumpRenderTree): (runThread): Deleted. (runPthread): Deleted. (testThreadIdentifierMap): Deleted. * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: * TestWebKitAPI/Tests/WTF/Threading.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/196314@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@225470 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-12-04 06:13:05 +00:00
dataLog(toString(Thread::current(), ": Observing element with address = ", RawPointer(element->address), "\n"));
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
if (element->address != address)
return DequeueResult::Ignore;
threadDatas.append(element);
JSC should support SharedArrayBuffer https://bugs.webkit.org/show_bug.cgi?id=163986 Reviewed by Keith Miller. JSTests: This adds our own test for the various corner cases of SharedArrayBuffer. This test is meant to check all of the things that don't require concurrency. * stress/SharedArrayBuffer.js: Added. (checkAtomics): (shouldFail): (Symbol): (runAtomic): Source/JavaScriptCore: This implements https://tc39.github.io/ecmascript_sharedmem/shmem.html. There is now a new SharedArrayBuffer type. In the JS runtime, which includes typed array types, the SharedArrayBuffer is a drop-in replacement for ArrayBuffer, even though they are distinct types (new SharedArrayBuffer() instanceof ArrayBuffer == false and vice versa). The DOM will not recognize SharedArrayBuffer, or any typed array that wraps it, to ensure safety. This matches what other browsers intend to do, see https://github.com/tc39/ecmascript_sharedmem/issues/38. API is provided for the DOM to opt into SharedArrayBuffer. One notable place is postMessage, which will share the SharedArrayBuffer's underlying data storage with other workers. This creates a pool of shared memory that the workers can use to talk to each other. There is also an Atomics object in global scope, which exposes sequentially consistent atomic operations: add, and, compareExchange, exchange, load, or, store, sub, and xor. Additionally it exposes a Atomics.isLockFree utility, which takes a byte amount and returns true or false. Also there is Atomics.wake/wait, which neatly map to ParkingLot. Accesses to typed arrays that wrap SharedArrayBuffer are optimized by JSC the same way as always. I believe that DFG and B3 already obey the following memory model, which I believe is a bit weaker than Cambridge and a bit stronger than what is being proposed for SharedArrayBuffer. To predict a program's behavior under the B3 memory model, imagine the space of all possible programs that would result from running an optimizer that adversarially follows B3's transformation rules. B3 transformations are correct if the newly created program is equivalent to the old one, assuming that any opaque effect in IR (like the reads and writes of a patchpoint/call/fence) could perform any load/store that satisfies the B3::Effects summary. Opaque effects are a way of describing an infinite set of programs: any program that only does the effects summarized in B3::Effects belongs to the set. For example, this prevents motion of operations across fences since fences are summarized as opaque effects that could read or write memory. This rule alone is not enough, because it leaves the door open for turning an atomic operation (like a load) into a non-atomic one (like a load followed by a store of the same value back to the same location or multiple loads). This is not an optimization that either our compiler or the CPU would want to do. One way to think of what exactly is forbidden is that B3 transformations that mess with memory accesses can only reorder them or remove them. This means that for any execution of the untransformed program, the corresponding execution of the transformed program (i.e. with the same input arguments and the same programs filled in for the opaque effects) must have the same loads and stores, with some removed and some reordered. This is a fairly simple mental model that B3 and DFG already follow and it's based on existing abstractions for the infinite set of programs inside an opaque effect (DFG's AbstractHeaps and B3's Effects). This patch makes all atomics operations intrinsic, but the DFG doesn't know about any of them yet. That's covered by bug 164108. This ought to be perf-neutral, but I am still running tests to confirm this. I'm also still writing new tests to cover all of the Atomics functionality and the behavior of SAB objects. * API/JSTypedArray.cpp: (JSObjectGetTypedArrayBytesPtr): (JSObjectGetTypedArrayBuffer): (JSObjectMakeArrayBufferWithBytesNoCopy): * API/tests/CompareAndSwapTest.cpp: (Bitmap::concurrentTestAndSet): * CMakeLists.txt: * JavaScriptCore.xcodeproj/project.pbxproj: * dfg/DFGDesiredWatchpoints.cpp: (JSC::DFG::ArrayBufferViewWatchpointAdaptor::add): * heap/Heap.cpp: (JSC::Heap::reportExtraMemoryVisited): (JSC::Heap::reportExternalMemoryVisited): * jsc.cpp: (functionTransferArrayBuffer): * runtime/ArrayBuffer.cpp: (JSC::SharedArrayBufferContents::SharedArrayBufferContents): (JSC::SharedArrayBufferContents::~SharedArrayBufferContents): (JSC::ArrayBufferContents::ArrayBufferContents): (JSC::ArrayBufferContents::operator=): (JSC::ArrayBufferContents::~ArrayBufferContents): (JSC::ArrayBufferContents::clear): (JSC::ArrayBufferContents::destroy): (JSC::ArrayBufferContents::reset): (JSC::ArrayBufferContents::tryAllocate): (JSC::ArrayBufferContents::makeShared): (JSC::ArrayBufferContents::transferTo): (JSC::ArrayBufferContents::copyTo): (JSC::ArrayBufferContents::shareWith): (JSC::ArrayBuffer::create): (JSC::ArrayBuffer::createAdopted): (JSC::ArrayBuffer::createFromBytes): (JSC::ArrayBuffer::tryCreate): (JSC::ArrayBuffer::createUninitialized): (JSC::ArrayBuffer::tryCreateUninitialized): (JSC::ArrayBuffer::createInternal): (JSC::ArrayBuffer::ArrayBuffer): (JSC::ArrayBuffer::slice): (JSC::ArrayBuffer::sliceImpl): (JSC::ArrayBuffer::makeShared): (JSC::ArrayBuffer::setSharingMode): (JSC::ArrayBuffer::transferTo): (JSC::ArrayBuffer::transfer): Deleted. * runtime/ArrayBuffer.h: (JSC::arrayBufferSharingModeName): (JSC::SharedArrayBufferContents::data): (JSC::ArrayBufferContents::data): (JSC::ArrayBufferContents::sizeInBytes): (JSC::ArrayBufferContents::isShared): (JSC::ArrayBuffer::sharingMode): (JSC::ArrayBuffer::isShared): (JSC::ArrayBuffer::gcSizeEstimateInBytes): (JSC::arrayBufferDestructorNull): Deleted. (JSC::arrayBufferDestructorDefault): Deleted. (JSC::ArrayBufferContents::ArrayBufferContents): Deleted. (JSC::ArrayBufferContents::transfer): Deleted. (JSC::ArrayBufferContents::copyTo): Deleted. (JSC::ArrayBuffer::create): Deleted. (JSC::ArrayBuffer::createAdopted): Deleted. (JSC::ArrayBuffer::createFromBytes): Deleted. (JSC::ArrayBuffer::tryCreate): Deleted. (JSC::ArrayBuffer::createUninitialized): Deleted. (JSC::ArrayBuffer::tryCreateUninitialized): Deleted. (JSC::ArrayBuffer::createInternal): Deleted. (JSC::ArrayBuffer::ArrayBuffer): Deleted. (JSC::ArrayBuffer::slice): Deleted. (JSC::ArrayBuffer::sliceImpl): Deleted. (JSC::ArrayBufferContents::tryAllocate): Deleted. (JSC::ArrayBufferContents::~ArrayBufferContents): Deleted. * runtime/ArrayBufferSharingMode.h: Added. * runtime/ArrayBufferView.h: (JSC::ArrayBufferView::possiblySharedBuffer): (JSC::ArrayBufferView::unsharedBuffer): (JSC::ArrayBufferView::isShared): (JSC::ArrayBufferView::buffer): Deleted. * runtime/AtomicsObject.cpp: Added. (JSC::AtomicsObject::AtomicsObject): (JSC::AtomicsObject::create): (JSC::AtomicsObject::createStructure): (JSC::AtomicsObject::finishCreation): (JSC::atomicsFuncAdd): (JSC::atomicsFuncAnd): (JSC::atomicsFuncCompareExchange): (JSC::atomicsFuncExchange): (JSC::atomicsFuncIsLockFree): (JSC::atomicsFuncLoad): (JSC::atomicsFuncOr): (JSC::atomicsFuncStore): (JSC::atomicsFuncSub): (JSC::atomicsFuncWait): (JSC::atomicsFuncWake): (JSC::atomicsFuncXor): * runtime/AtomicsObject.h: Added. * runtime/CommonIdentifiers.h: * runtime/DataView.cpp: (JSC::DataView::wrap): * runtime/GenericTypedArrayViewInlines.h: (JSC::GenericTypedArrayView<Adaptor>::subarray): * runtime/Intrinsic.h: * runtime/JSArrayBuffer.cpp: (JSC::JSArrayBuffer::finishCreation): (JSC::JSArrayBuffer::isShared): (JSC::JSArrayBuffer::sharingMode): * runtime/JSArrayBuffer.h: (JSC::toPossiblySharedArrayBuffer): (JSC::toUnsharedArrayBuffer): (JSC::JSArrayBuffer::toWrapped): (JSC::toArrayBuffer): Deleted. * runtime/JSArrayBufferConstructor.cpp: (JSC::JSArrayBufferConstructor::JSArrayBufferConstructor): (JSC::JSArrayBufferConstructor::finishCreation): (JSC::JSArrayBufferConstructor::create): (JSC::constructArrayBuffer): * runtime/JSArrayBufferConstructor.h: (JSC::JSArrayBufferConstructor::sharingMode): * runtime/JSArrayBufferPrototype.cpp: (JSC::arrayBufferProtoFuncSlice): (JSC::JSArrayBufferPrototype::JSArrayBufferPrototype): (JSC::JSArrayBufferPrototype::finishCreation): (JSC::JSArrayBufferPrototype::create): * runtime/JSArrayBufferPrototype.h: * runtime/JSArrayBufferView.cpp: (JSC::JSArrayBufferView::finishCreation): (JSC::JSArrayBufferView::visitChildren): (JSC::JSArrayBufferView::unsharedBuffer): (JSC::JSArrayBufferView::unsharedJSBuffer): (JSC::JSArrayBufferView::possiblySharedJSBuffer): (JSC::JSArrayBufferView::neuter): (JSC::JSArrayBufferView::toWrapped): Deleted. * runtime/JSArrayBufferView.h: (JSC::JSArrayBufferView::jsBuffer): Deleted. * runtime/JSArrayBufferViewInlines.h: (JSC::JSArrayBufferView::isShared): (JSC::JSArrayBufferView::possiblySharedBuffer): (JSC::JSArrayBufferView::possiblySharedImpl): (JSC::JSArrayBufferView::unsharedImpl): (JSC::JSArrayBufferView::byteOffset): (JSC::JSArrayBufferView::toWrapped): (JSC::JSArrayBufferView::buffer): Deleted. (JSC::JSArrayBufferView::impl): Deleted. (JSC::JSArrayBufferView::neuter): Deleted. * runtime/JSDataView.cpp: (JSC::JSDataView::possiblySharedTypedImpl): (JSC::JSDataView::unsharedTypedImpl): (JSC::JSDataView::getTypedArrayImpl): (JSC::JSDataView::typedImpl): Deleted. * runtime/JSDataView.h: (JSC::JSDataView::possiblySharedBuffer): (JSC::JSDataView::unsharedBuffer): (JSC::JSDataView::buffer): Deleted. * runtime/JSDataViewPrototype.cpp: (JSC::dataViewProtoGetterBuffer): * runtime/JSGenericTypedArrayView.h: (JSC::toPossiblySharedNativeTypedView): (JSC::toUnsharedNativeTypedView): (JSC::JSGenericTypedArrayView<Adaptor>::toWrapped): (JSC::JSGenericTypedArrayView::typedImpl): Deleted. (JSC::toNativeTypedView): Deleted. * runtime/JSGenericTypedArrayViewInlines.h: (JSC::JSGenericTypedArrayView<Adaptor>::create): (JSC::JSGenericTypedArrayView<Adaptor>::possiblySharedTypedImpl): (JSC::JSGenericTypedArrayView<Adaptor>::unsharedTypedImpl): (JSC::JSGenericTypedArrayView<Adaptor>::getTypedArrayImpl): * runtime/JSGenericTypedArrayViewPrototypeFunctions.h: (JSC::genericTypedArrayViewProtoGetterFuncBuffer): (JSC::genericTypedArrayViewPrivateFuncSubarrayCreate): * runtime/JSGlobalObject.cpp: (JSC::createAtomicsProperty): (JSC::JSGlobalObject::init): (JSC::JSGlobalObject::visitChildren): * runtime/JSGlobalObject.h: (JSC::JSGlobalObject::arrayBufferPrototype): (JSC::JSGlobalObject::arrayBufferStructure): * runtime/MathObject.cpp: * runtime/RuntimeFlags.h: * runtime/SimpleTypedArrayController.cpp: (JSC::SimpleTypedArrayController::toJS): * runtime/TypedArrayType.h: (JSC::typedArrayTypeForType): Source/WebCore: New tests added in the LayoutTests/workers/sab directory. This teaches WebCore that a typed array could be shared or not. By default, WebCore will reject shared typed arrays as if they were not typed arrays. This ensures that we don't get race conditions in code that can't handle it. If you postMessage a SharedArrayBuffer or something that wraps it, you will send the shared memory to the other worker. * Modules/encryptedmedia/CDMSessionClearKey.cpp: (WebCore::CDMSessionClearKey::cachedKeyForKeyID): * Modules/fetch/FetchBody.cpp: (WebCore::FetchBody::extract): * Modules/mediastream/RTCDataChannel.cpp: (WebCore::RTCDataChannel::send): * Modules/webaudio/AudioBuffer.cpp: (WebCore::AudioBuffer::getChannelData): * Modules/websockets/WebSocket.cpp: (WebCore::WebSocket::send): * bindings/js/JSBlobCustom.cpp: (WebCore::constructJSBlob): * bindings/js/JSCryptoAlgorithmDictionary.cpp: (WebCore::createRsaKeyGenParams): * bindings/js/JSCryptoCustom.cpp: (WebCore::JSCrypto::getRandomValues): * bindings/js/JSCryptoOperationData.cpp: (WebCore::cryptoOperationDataFromJSValue): * bindings/js/JSDOMBinding.h: (WebCore::toJS): (WebCore::toPossiblySharedArrayBufferView): (WebCore::toUnsharedArrayBufferView): (WebCore::toPossiblySharedInt8Array): (WebCore::toPossiblySharedInt16Array): (WebCore::toPossiblySharedInt32Array): (WebCore::toPossiblySharedUint8Array): (WebCore::toPossiblySharedUint8ClampedArray): (WebCore::toPossiblySharedUint16Array): (WebCore::toPossiblySharedUint32Array): (WebCore::toPossiblySharedFloat32Array): (WebCore::toPossiblySharedFloat64Array): (WebCore::toUnsharedInt8Array): (WebCore::toUnsharedInt16Array): (WebCore::toUnsharedInt32Array): (WebCore::toUnsharedUint8Array): (WebCore::toUnsharedUint8ClampedArray): (WebCore::toUnsharedUint16Array): (WebCore::toUnsharedUint32Array): (WebCore::toUnsharedFloat32Array): (WebCore::toUnsharedFloat64Array): (WebCore::toArrayBufferView): Deleted. (WebCore::toInt8Array): Deleted. (WebCore::toInt16Array): Deleted. (WebCore::toInt32Array): Deleted. (WebCore::toUint8Array): Deleted. (WebCore::toUint8ClampedArray): Deleted. (WebCore::toUint16Array): Deleted. (WebCore::toUint32Array): Deleted. (WebCore::toFloat32Array): Deleted. (WebCore::toFloat64Array): Deleted. * bindings/js/JSDataCueCustom.cpp: (WebCore::constructJSDataCue): * bindings/js/JSDictionary.cpp: (WebCore::JSDictionary::convertValue): * bindings/js/JSFileCustom.cpp: (WebCore::constructJSFile): * bindings/js/JSMessagePortCustom.cpp: (WebCore::extractTransferables): * bindings/js/JSWebGLRenderingContextBaseCustom.cpp: (WebCore::dataFunctionf): (WebCore::dataFunctioni): (WebCore::dataFunctionMatrix): * bindings/js/JSXMLHttpRequestCustom.cpp: (WebCore::JSXMLHttpRequest::send): * bindings/js/SerializedScriptValue.cpp: (WebCore::CloneSerializer::dumpArrayBufferView): (WebCore::CloneSerializer::dumpIfTerminal): (WebCore::CloneDeserializer::readArrayBufferView): (WebCore::CloneDeserializer::readTerminal): (WebCore::SerializedScriptValue::transferArrayBuffers): * bindings/js/StructuredClone.cpp: (WebCore::structuredCloneArrayBuffer): (WebCore::structuredCloneArrayBufferView): * bindings/scripts/CodeGeneratorJS.pm: (JSValueToNative): * css/FontFace.cpp: (WebCore::FontFace::create): * html/canvas/WebGL2RenderingContext.cpp: (WebCore::WebGL2RenderingContext::bufferData): (WebCore::WebGL2RenderingContext::bufferSubData): * platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp: (WebCore::MediaPlayerPrivateAVFoundation::extractKeyURIKeyIDAndCertificateFromInitData): Source/WebKit/mac: Support the RuntimeFlag. * WebView/WebPreferencesPrivate.h: Source/WebKit/win: Support the RuntimeFlag. * Interfaces/IWebPreferencesPrivate.idl: Source/WebKit2: Adds some small things we need for SharedArrayBuffer. * UIProcess/API/C/WKPreferencesRefPrivate.h: * UIProcess/API/Cocoa/WKPreferencesPrivate.h: * WebProcess/InjectedBundle/InjectedBundle.cpp: (WebKit::InjectedBundle::createWebDataFromUint8Array): Source/WTF: Adds some small things we need for SharedArrayBuffer. * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeakRelaxed): (WTF::Atomic::exchangeAdd): (WTF::Atomic::exchangeAnd): (WTF::Atomic::exchangeOr): (WTF::Atomic::exchangeSub): (WTF::Atomic::exchangeXor): (WTF::atomicLoad): (WTF::atomicStore): (WTF::atomicCompareExchangeWeak): (WTF::atomicCompareExchangeWeakRelaxed): (WTF::atomicCompareExchangeStrong): (WTF::atomicExchangeAdd): (WTF::atomicExchangeAnd): (WTF::atomicExchangeOr): (WTF::atomicExchangeSub): (WTF::atomicExchangeXor): (WTF::atomicExchange): (WTF::Atomic::exchangeAndAdd): Deleted. (WTF::weakCompareAndSwap): Deleted. We need to be able to do atomics operations on naked pointers. We also need to be able to do all of the things that std::atomic does. This adds those things and renames weakCompareAndSwap to atomicCompareExchangeWeakRelaxed so that we're using consistent terminology. * wtf/Bitmap.h: (WTF::WordType>::concurrentTestAndSet): Renamed weakCompareAndSwap. (WTF::WordType>::concurrentTestAndClear): Renamed weakCompareAndSwap. * wtf/FastBitVector.h: (WTF::FastBitVector::atomicSetAndCheck): Renamed weakCompareAndSwap. * wtf/ParkingLot.cpp: (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkCount): * wtf/ParkingLot.h: Added unparkCount(), which lets you unpark some bounded number of threads and returns the number of threads unparked. This is just a modest extension of unparkAll(). unparkAll() now just calls unparkCount(ptr, UINT_MAX). Tools: Use the right kind of typed array API. * DumpRenderTree/TestRunner.cpp: (setAudioResultCallback): LayoutTests: Adding tests. This is a work in progress. * workers/sab: Added. * workers/sab/simple-worker-1.js: Added. (onmessage): * workers/sab/simple-worker-2.js: Added. (onmessage): * workers/sab/simple.html: Added. Canonical link: https://commits.webkit.org/181984@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208209 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-11-01 03:10:00 +00:00
if (threadDatas.size() == count)
return DequeueResult::RemoveAndStop;
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
return DequeueResult::RemoveAndContinue;
WTF::Lock should not suffer from the thundering herd https://bugs.webkit.org/show_bug.cgi?id=147947 Reviewed by Geoffrey Garen. Source/WTF: This changes Lock::unlockSlow() to use unparkOne() instead of unparkAll(). The problem with doing this is that it's not obvious after calling unparkOne() if there are any other threads that are still parked on the lock's queue. If we assume that there are and leave the hasParkedBit set, then future calls to unlock() will take the slow path. We don't want that if there aren't actually any threads parked. On the other hand, if we assume that there aren't any threads parked and clear the hasParkedBit, then if there actually were some threads parked, then they may never be awoken since future calls to unlock() won't take slow path and so won't call unparkOne(). In other words, we need a way to be very precise about when we clear the hasParkedBit and we need to do it in a race-free way: it can't be the case that we clear the bit just as some thread gets parked on the queue. A similar problem arises in futexes, and one of the solutions is to have a thread that acquires a lock after parking sets the hasParkedBit. This is what Rusty Russel's usersem does. It's a subtle algorithm. Also, it means that if a thread barges in before the unparked thread runs, then that barging thread will not know that there are threads parked. This could increase the severity of barging. Since ParkingLot is a user-level API, we don't have to worry about the kernel-user security issues and so we can expose callbacks while ParkingLot is holding its internal locks. This change does exactly that for unparkOne(). The new variant of unparkOne() will call a user function while the queue from which we are unparking is locked. The callback is told basic stats about the queue: did we unpark a thread this time, and could there be more threads to unpark in the future. The callback runs while it's impossible for the queue state to change, since the ParkingLot's internal locks for the queue is held. This means that Lock::unlockSlow() can either clear, or leave, the hasParkedBit while releasing the lock inside the callback from unparkOne(). This takes care of the thundering herd problem while also reducing the greed that arises from barging threads. This required some careful reworking of the ParkingLot algorithm. The first thing I noticed was that the ThreadData::shouldPark flag was useless, since it's set exactly when ThreadData::address is non-null. Then I had to make sure that dequeue() could lazily create both hashtables and buckets, since the "callback is called while queue is locked" invariant requires that we didn't exit early due to the hashtable or bucket not being present. Note that all of this is done in such a way that the old unparkOne() and unparkAll() don't have to create any buckets, though they now may create the hashtable. We don't care as much about the hashtable being created by unpark since it's just such an unlikely scenario and it would only happen once. This change reduces the kernel CPU usage of WTF::Lock for the long critical section test by about 8x and makes it always perform as well as WTF::WordLock and WTF::Mutex for that benchmark. * benchmarks/LockSpeedTest.cpp: * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): * wtf/Lock.h: (WTF::LockBase::isLocked): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: * wtf/WordLock.h: (WTF::WordLock::isLocked): (WTF::WordLock::isFullyReset): Tools: Add testing that checks that locks return to a pristine state after contention is over. * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::LockInspector::isFullyReset): (TestWebKitAPI::runLockTest): (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/166072@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188374 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 03:51:25 +00:00
},
[] (bool) { });
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
for (RefPtr<ThreadData>& threadData : threadDatas) {
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
if (verbose)
WTF shouldn't have both Thread and ThreadIdentifier https://bugs.webkit.org/show_bug.cgi?id=180308 Reviewed by Darin Adler. Source/JavaScriptCore: * heap/MachineStackMarker.cpp: (JSC::MachineThreads::tryCopyOtherThreadStacks): * llint/LLIntSlowPaths.cpp: (JSC::LLInt::llint_trace_operand): (JSC::LLInt::llint_trace_value): (JSC::LLInt::LLINT_SLOW_PATH_DECL): (JSC::LLInt::traceFunctionPrologue): * runtime/ExceptionScope.cpp: (JSC::ExceptionScope::unexpectedExceptionMessage): * runtime/JSLock.h: (JSC::JSLock::currentThreadIsHoldingLock): * runtime/VM.cpp: (JSC::VM::throwException): * runtime/VM.h: (JSC::VM::throwingThread const): (JSC::VM::clearException): * tools/HeapVerifier.cpp: (JSC::HeapVerifier::printVerificationHeader): Source/WebCore: No behavior change. * Modules/indexeddb/IDBActiveDOMObject.h: (WebCore::IDBActiveDOMObject::originThread const): (WebCore::IDBActiveDOMObject::performCallbackOnOriginThread): (WebCore::IDBActiveDOMObject::callFunctionOnOriginThread): (WebCore::IDBActiveDOMObject::originThreadID const): Deleted. * Modules/indexeddb/IDBCursor.cpp: (WebCore::IDBCursor::IDBCursor): (WebCore::IDBCursor::~IDBCursor): (WebCore::IDBCursor::sourcesDeleted const): (WebCore::IDBCursor::transaction const): (WebCore::IDBCursor::update): (WebCore::IDBCursor::advance): (WebCore::IDBCursor::continueFunction): (WebCore::IDBCursor::uncheckedIterateCursor): (WebCore::IDBCursor::deleteFunction): (WebCore::IDBCursor::setGetResult): * Modules/indexeddb/IDBDatabase.cpp: (WebCore::IDBDatabase::~IDBDatabase): (WebCore::IDBDatabase::hasPendingActivity const): (WebCore::IDBDatabase::name const): (WebCore::IDBDatabase::version const): (WebCore::IDBDatabase::objectStoreNames const): (WebCore::IDBDatabase::renameObjectStore): (WebCore::IDBDatabase::renameIndex): (WebCore::IDBDatabase::createObjectStore): (WebCore::IDBDatabase::transaction): (WebCore::IDBDatabase::deleteObjectStore): (WebCore::IDBDatabase::close): (WebCore::IDBDatabase::connectionToServerLost): (WebCore::IDBDatabase::maybeCloseInServer): (WebCore::IDBDatabase::activeDOMObjectName const): (WebCore::IDBDatabase::canSuspendForDocumentSuspension const): (WebCore::IDBDatabase::stop): (WebCore::IDBDatabase::startVersionChangeTransaction): (WebCore::IDBDatabase::didStartTransaction): (WebCore::IDBDatabase::willCommitTransaction): (WebCore::IDBDatabase::didCommitTransaction): (WebCore::IDBDatabase::willAbortTransaction): (WebCore::IDBDatabase::didAbortTransaction): (WebCore::IDBDatabase::didCommitOrAbortTransaction): (WebCore::IDBDatabase::fireVersionChangeEvent): (WebCore::IDBDatabase::dispatchEvent): (WebCore::IDBDatabase::didCreateIndexInfo): (WebCore::IDBDatabase::didDeleteIndexInfo): * Modules/indexeddb/IDBIndex.cpp: (WebCore::IDBIndex::IDBIndex): (WebCore::IDBIndex::~IDBIndex): (WebCore::IDBIndex::name const): (WebCore::IDBIndex::setName): (WebCore::IDBIndex::objectStore): (WebCore::IDBIndex::keyPath const): (WebCore::IDBIndex::unique const): (WebCore::IDBIndex::multiEntry const): (WebCore::IDBIndex::rollbackInfoForVersionChangeAbort): (WebCore::IDBIndex::openCursor): (WebCore::IDBIndex::openKeyCursor): (WebCore::IDBIndex::doCount): (WebCore::IDBIndex::doGet): (WebCore::IDBIndex::doGetKey): (WebCore::IDBIndex::getAll): (WebCore::IDBIndex::getAllKeys): (WebCore::IDBIndex::markAsDeleted): * Modules/indexeddb/IDBObjectStore.cpp: (WebCore::IDBObjectStore::IDBObjectStore): (WebCore::IDBObjectStore::~IDBObjectStore): (WebCore::IDBObjectStore::name const): (WebCore::IDBObjectStore::setName): (WebCore::IDBObjectStore::keyPath const): (WebCore::IDBObjectStore::indexNames const): (WebCore::IDBObjectStore::transaction): (WebCore::IDBObjectStore::autoIncrement const): (WebCore::IDBObjectStore::openCursor): (WebCore::IDBObjectStore::openKeyCursor): (WebCore::IDBObjectStore::get): (WebCore::IDBObjectStore::getKey): (WebCore::IDBObjectStore::putOrAdd): (WebCore::IDBObjectStore::doDelete): (WebCore::IDBObjectStore::clear): (WebCore::IDBObjectStore::createIndex): (WebCore::IDBObjectStore::index): (WebCore::IDBObjectStore::deleteIndex): (WebCore::IDBObjectStore::doCount): (WebCore::IDBObjectStore::getAll): (WebCore::IDBObjectStore::getAllKeys): (WebCore::IDBObjectStore::markAsDeleted): (WebCore::IDBObjectStore::rollbackForVersionChangeAbort): * Modules/indexeddb/IDBOpenDBRequest.cpp: (WebCore::IDBOpenDBRequest::~IDBOpenDBRequest): (WebCore::IDBOpenDBRequest::onError): (WebCore::IDBOpenDBRequest::versionChangeTransactionDidFinish): (WebCore::IDBOpenDBRequest::fireSuccessAfterVersionChangeCommit): (WebCore::IDBOpenDBRequest::fireErrorAfterVersionChangeCompletion): (WebCore::IDBOpenDBRequest::dispatchEvent): (WebCore::IDBOpenDBRequest::onSuccess): (WebCore::IDBOpenDBRequest::onUpgradeNeeded): (WebCore::IDBOpenDBRequest::onDeleteDatabaseSuccess): (WebCore::IDBOpenDBRequest::requestCompleted): (WebCore::IDBOpenDBRequest::requestBlocked): * Modules/indexeddb/IDBRequest.cpp: (WebCore::IDBRequest::~IDBRequest): (WebCore:: const): (WebCore::IDBRequest::setSource): (WebCore::IDBRequest::setVersionChangeTransaction): (WebCore::IDBRequest::transaction const): (WebCore::IDBRequest::sourceObjectStoreIdentifier const): (WebCore::IDBRequest::sourceIndexIdentifier const): (WebCore::IDBRequest::requestedObjectStoreRecordType const): (WebCore::IDBRequest::requestedIndexRecordType const): (WebCore::IDBRequest::eventTargetInterface const): (WebCore::IDBRequest::activeDOMObjectName const): (WebCore::IDBRequest::canSuspendForDocumentSuspension const): (WebCore::IDBRequest::hasPendingActivity const): (WebCore::IDBRequest::stop): (WebCore::IDBRequest::enqueueEvent): (WebCore::IDBRequest::dispatchEvent): (WebCore::IDBRequest::uncaughtExceptionInEventHandler): (WebCore::IDBRequest::setResult): (WebCore::IDBRequest::setResultToStructuredClone): (WebCore::IDBRequest::setResultToUndefined): (WebCore::IDBRequest::resultCursor): (WebCore::IDBRequest::willIterateCursor): (WebCore::IDBRequest::didOpenOrIterateCursor): (WebCore::IDBRequest::completeRequestAndDispatchEvent): (WebCore::IDBRequest::onError): (WebCore::IDBRequest::onSuccess): * Modules/indexeddb/IDBTransaction.cpp: (WebCore::IDBTransaction::IDBTransaction): (WebCore::IDBTransaction::~IDBTransaction): (WebCore::IDBTransaction::objectStoreNames const): (WebCore::IDBTransaction::db): (WebCore::IDBTransaction::error const): (WebCore::IDBTransaction::objectStore): (WebCore::IDBTransaction::abortDueToFailedRequest): (WebCore::IDBTransaction::transitionedToFinishing): (WebCore::IDBTransaction::abort): (WebCore::IDBTransaction::internalAbort): (WebCore::IDBTransaction::abortOnServerAndCancelRequests): (WebCore::IDBTransaction::activeDOMObjectName const): (WebCore::IDBTransaction::canSuspendForDocumentSuspension const): (WebCore::IDBTransaction::hasPendingActivity const): (WebCore::IDBTransaction::stop): (WebCore::IDBTransaction::isActive const): (WebCore::IDBTransaction::isFinishedOrFinishing const): (WebCore::IDBTransaction::addRequest): (WebCore::IDBTransaction::removeRequest): (WebCore::IDBTransaction::scheduleOperation): (WebCore::IDBTransaction::schedulePendingOperationTimer): (WebCore::IDBTransaction::pendingOperationTimerFired): (WebCore::IDBTransaction::operationCompletedOnServer): (WebCore::IDBTransaction::scheduleCompletedOperationTimer): (WebCore::IDBTransaction::completedOperationTimerFired): (WebCore::IDBTransaction::commit): (WebCore::IDBTransaction::commitOnServer): (WebCore::IDBTransaction::finishAbortOrCommit): (WebCore::IDBTransaction::didStart): (WebCore::IDBTransaction::notifyDidAbort): (WebCore::IDBTransaction::didAbort): (WebCore::IDBTransaction::didCommit): (WebCore::IDBTransaction::fireOnComplete): (WebCore::IDBTransaction::fireOnAbort): (WebCore::IDBTransaction::enqueueEvent): (WebCore::IDBTransaction::dispatchEvent): (WebCore::IDBTransaction::createObjectStore): (WebCore::IDBTransaction::createObjectStoreOnServer): (WebCore::IDBTransaction::didCreateObjectStoreOnServer): (WebCore::IDBTransaction::renameObjectStore): (WebCore::IDBTransaction::renameObjectStoreOnServer): (WebCore::IDBTransaction::didRenameObjectStoreOnServer): (WebCore::IDBTransaction::createIndex): (WebCore::IDBTransaction::createIndexOnServer): (WebCore::IDBTransaction::didCreateIndexOnServer): (WebCore::IDBTransaction::renameIndex): (WebCore::IDBTransaction::renameIndexOnServer): (WebCore::IDBTransaction::didRenameIndexOnServer): (WebCore::IDBTransaction::requestOpenCursor): (WebCore::IDBTransaction::doRequestOpenCursor): (WebCore::IDBTransaction::openCursorOnServer): (WebCore::IDBTransaction::didOpenCursorOnServer): (WebCore::IDBTransaction::iterateCursor): (WebCore::IDBTransaction::iterateCursorOnServer): (WebCore::IDBTransaction::didIterateCursorOnServer): (WebCore::IDBTransaction::requestGetAllObjectStoreRecords): (WebCore::IDBTransaction::requestGetAllIndexRecords): (WebCore::IDBTransaction::getAllRecordsOnServer): (WebCore::IDBTransaction::didGetAllRecordsOnServer): (WebCore::IDBTransaction::requestGetRecord): (WebCore::IDBTransaction::requestGetValue): (WebCore::IDBTransaction::requestGetKey): (WebCore::IDBTransaction::requestIndexRecord): (WebCore::IDBTransaction::getRecordOnServer): (WebCore::IDBTransaction::didGetRecordOnServer): (WebCore::IDBTransaction::requestCount): (WebCore::IDBTransaction::getCountOnServer): (WebCore::IDBTransaction::didGetCountOnServer): (WebCore::IDBTransaction::requestDeleteRecord): (WebCore::IDBTransaction::deleteRecordOnServer): (WebCore::IDBTransaction::didDeleteRecordOnServer): (WebCore::IDBTransaction::requestClearObjectStore): (WebCore::IDBTransaction::clearObjectStoreOnServer): (WebCore::IDBTransaction::didClearObjectStoreOnServer): (WebCore::IDBTransaction::requestPutOrAdd): (WebCore::IDBTransaction::putOrAddOnServer): (WebCore::IDBTransaction::didPutOrAddOnServer): (WebCore::IDBTransaction::deleteObjectStore): (WebCore::IDBTransaction::deleteObjectStoreOnServer): (WebCore::IDBTransaction::didDeleteObjectStoreOnServer): (WebCore::IDBTransaction::deleteIndex): (WebCore::IDBTransaction::deleteIndexOnServer): (WebCore::IDBTransaction::didDeleteIndexOnServer): (WebCore::IDBTransaction::operationCompletedOnClient): (WebCore::IDBTransaction::establishOnServer): (WebCore::IDBTransaction::activate): (WebCore::IDBTransaction::deactivate): * Modules/indexeddb/client/IDBConnectionProxy.cpp: (WebCore::IDBClient::removeItemsMatchingCurrentThread): * Modules/indexeddb/client/TransactionOperation.h: (WebCore::IDBClient::TransactionOperation::~TransactionOperation): (WebCore::IDBClient::TransactionOperation::perform): (WebCore::IDBClient::TransactionOperation::transitionToCompleteOnThisThread): (WebCore::IDBClient::TransactionOperation::transitionToComplete): (WebCore::IDBClient::TransactionOperation::doComplete): (WebCore::IDBClient::TransactionOperation::originThread const): (WebCore::IDBClient::TransactionOperation::originThreadID const): Deleted. * Modules/webaudio/AudioContext.cpp: (WebCore::AudioContext::AudioContext): (WebCore::AudioContext::lock): (WebCore::AudioContext::tryLock): (WebCore::AudioContext::unlock): (WebCore::AudioContext::isAudioThread const): (WebCore::AudioContext::isGraphOwner const): * Modules/webaudio/AudioContext.h: (WebCore::AudioContext::setAudioThread): (WebCore::AudioContext::audioThread const): * Modules/webaudio/AudioDestinationNode.cpp: (WebCore::AudioDestinationNode::render): * Modules/webdatabase/Database.cpp: (WebCore::Database::performClose): (WebCore::Database::securityOrigin): * Modules/webdatabase/DatabaseDetails.h: (WebCore::DatabaseDetails::DatabaseDetails): (WebCore::DatabaseDetails::operator=): (WebCore::DatabaseDetails::thread const): (WebCore::DatabaseDetails::threadID const): Deleted. * Modules/webdatabase/DatabaseManager.cpp: (WebCore::DatabaseManager::detailsForNameAndOrigin): * Modules/webdatabase/DatabaseThread.cpp: (WebCore::DatabaseThread::databaseThread): (WebCore::DatabaseThread::recordDatabaseOpen): (WebCore::DatabaseThread::recordDatabaseClosed): * Modules/webdatabase/DatabaseThread.h: (WebCore::DatabaseThread::getThread): (WebCore::DatabaseThread::getThreadID): Deleted. * Modules/webdatabase/SQLTransaction.cpp: (WebCore::SQLTransaction::checkAndHandleClosedDatabase): * Modules/webdatabase/SQLTransactionBackend.cpp: (WebCore::SQLTransactionBackend::doCleanup): (WebCore::SQLTransactionBackend::notifyDatabaseThreadIsShuttingDown): * bindings/js/JSCallbackData.h: (WebCore::JSCallbackData::JSCallbackData): (WebCore::JSCallbackData::~JSCallbackData): * bindings/js/ScheduledAction.cpp: (WebCore::ScheduledAction::execute): * dom/ScriptExecutionContext.cpp: (WebCore::ScriptExecutionContext::createdMessagePort): (WebCore::ScriptExecutionContext::destroyedMessagePort): * page/ResourceUsageOverlay.h: * page/scrolling/ScrollingThread.cpp: (WebCore::ScrollingThread::isCurrentThread): * platform/Supplementable.h: (WebCore::Supplementable::provideSupplement): (WebCore::Supplementable::removeSupplement): (WebCore::Supplementable::requireSupplement): (WebCore::Supplementable::Supplementable): Deleted. * platform/Timer.cpp: (WebCore::TimerBase::TimerBase): (WebCore::TimerBase::start): (WebCore::TimerBase::stop): (WebCore::TimerBase::setNextFireTime): * platform/Timer.h: (WebCore::TimerBase::isActive const): * platform/graphics/cocoa/FontCacheCoreText.cpp: (WebCore::shouldAutoActivateFontIfNeeded): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.cpp: (WebCore::TextureMapperPlatformLayerProxy::activateOnCompositingThread): (WebCore::TextureMapperPlatformLayerProxy::invalidate): (WebCore::TextureMapperPlatformLayerProxy::getAvailableBuffer): (WebCore::TextureMapperPlatformLayerProxy::appendToUnusedBuffers): (WebCore::TextureMapperPlatformLayerProxy::swapBuffer): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.h: (): Deleted. * platform/ios/wak/WebCoreThread.mm: (RunWebThread): (StartWebThread): * platform/sql/SQLiteDatabase.cpp: (WebCore::SQLiteDatabase::open): (WebCore::SQLiteDatabase::close): * platform/sql/SQLiteDatabase.h: (WebCore::SQLiteDatabase::sqlite3Handle const): * workers/WorkerGlobalScope.cpp: (WebCore::WorkerGlobalScope::~WorkerGlobalScope): (WebCore::WorkerGlobalScope::isContextThread const): * workers/WorkerMessagingProxy.cpp: (WebCore::WorkerMessagingProxy::WorkerMessagingProxy): (WebCore::WorkerMessagingProxy::~WorkerMessagingProxy): * workers/WorkerRunLoop.cpp: (WebCore::WorkerRunLoop::runInMode): (WebCore::WorkerRunLoop::runCleanupTasks): * workers/WorkerThread.h: (WebCore::WorkerThread::thread const): (WebCore::WorkerThread::threadID const): Deleted. * workers/service/ServiceWorkerContainer.cpp: (WebCore::ServiceWorkerContainer::~ServiceWorkerContainer): (WebCore::ServiceWorkerContainer::scheduleJob): (WebCore::ServiceWorkerContainer::jobFailedWithException): (WebCore::ServiceWorkerContainer::scheduleTaskToFireUpdateFoundEvent): (WebCore::ServiceWorkerContainer::jobResolvedWithRegistration): (WebCore::ServiceWorkerContainer::jobResolvedWithUnregistrationResult): (WebCore::ServiceWorkerContainer::startScriptFetchForJob): (WebCore::ServiceWorkerContainer::jobFinishedLoadingScript): (WebCore::ServiceWorkerContainer::jobFailedLoadingScript): (WebCore::ServiceWorkerContainer::jobDidFinish): (WebCore::ServiceWorkerContainer::addRegistration): (WebCore::ServiceWorkerContainer::removeRegistration): (WebCore::ServiceWorkerContainer::scheduleTaskToFireControllerChangeEvent): (WebCore::ServiceWorkerContainer::contextIdentifier): * workers/service/ServiceWorkerContainer.h: * workers/service/ServiceWorkerJob.cpp: (WebCore::ServiceWorkerJob::~ServiceWorkerJob): (WebCore::ServiceWorkerJob::failedWithException): (WebCore::ServiceWorkerJob::resolvedWithRegistration): (WebCore::ServiceWorkerJob::resolvedWithUnregistrationResult): (WebCore::ServiceWorkerJob::startScriptFetch): (WebCore::ServiceWorkerJob::fetchScriptWithContext): (WebCore::ServiceWorkerJob::didReceiveResponse): (WebCore::ServiceWorkerJob::notifyFinished): * workers/service/ServiceWorkerJob.h: * xml/parser/XMLDocumentParserLibxml2.cpp: (WebCore::matchFunc): (WebCore::openFunc): (WebCore::initializeXMLParser): (WebCore::XMLParserContext::createStringParser): (WebCore::XMLParserContext::createMemoryParser): Source/WebKit: * UIProcess/API/glib/IconDatabase.cpp: * UIProcess/GenericCallback.h: (WebKit::GenericCallback::~GenericCallback): (WebKit::GenericCallback::performCallbackWithReturnValue): Source/WTF: We should use a pointer of WTF::Thread instead of ThreadIdentifier. One problem is that Windows support library uses WTF::createThread, which returns ThreadIdentifier. So we cannot drop ThreadIdentifier in Windows environment. This patch keeps ThreadIdentifier in Windows. * wtf/MainThread.cpp: (WTF::initializeMainThread): (WTF::isMainThread): (WTF::canAccessThreadLocalDataForThread): * wtf/MainThread.h: * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkCount): * wtf/RecursiveLockAdapter.h: (WTF::RecursiveLockAdapter::lock): (WTF::RecursiveLockAdapter::unlock): (WTF::RecursiveLockAdapter::tryLock): * wtf/Threading.cpp: (WTF::Thread::dump const): * wtf/Threading.h: (WTF::Thread::id const): (WTF::Thread::operator==): Deleted. (WTF::Thread::operator!=): Deleted. (WTF::currentThread): Deleted. * wtf/ThreadingPrimitives.h: * wtf/ThreadingPthreads.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::detach): (WTF::Thread::initializeCurrentTLS): (WTF::Thread::suspend): (WTF::Thread::establishPlatformSpecificHandle): (WTF::Thread::currentID): Deleted. * wtf/ThreadingWin.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::suspend): (WTF::Thread::currentDying): * wtf/mac/MainThreadMac.mm: (WTF::initializeApplicationUIThread): (WTF::initializeWebThreadPlatform): (WTF::canAccessThreadLocalDataForThread): (WTF::initializeApplicationUIThreadIdentifier): Deleted. (WTF::initializeWebThreadIdentifier): Deleted. Tools: * DumpRenderTree/mac/DumpRenderTree.mm: (dumpRenderTree): (runThread): Deleted. (runPthread): Deleted. (testThreadIdentifierMap): Deleted. * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: * TestWebKitAPI/Tests/WTF/Threading.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/196314@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@225470 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-12-04 06:13:05 +00:00
dataLog(toString(Thread::current(), ": unparking ", RawPointer(threadData.get()), " with address ", RawPointer(threadData->address), "\n"));
WTF::Lock should not suffer from the thundering herd https://bugs.webkit.org/show_bug.cgi?id=147947 Reviewed by Geoffrey Garen. Source/WTF: This changes Lock::unlockSlow() to use unparkOne() instead of unparkAll(). The problem with doing this is that it's not obvious after calling unparkOne() if there are any other threads that are still parked on the lock's queue. If we assume that there are and leave the hasParkedBit set, then future calls to unlock() will take the slow path. We don't want that if there aren't actually any threads parked. On the other hand, if we assume that there aren't any threads parked and clear the hasParkedBit, then if there actually were some threads parked, then they may never be awoken since future calls to unlock() won't take slow path and so won't call unparkOne(). In other words, we need a way to be very precise about when we clear the hasParkedBit and we need to do it in a race-free way: it can't be the case that we clear the bit just as some thread gets parked on the queue. A similar problem arises in futexes, and one of the solutions is to have a thread that acquires a lock after parking sets the hasParkedBit. This is what Rusty Russel's usersem does. It's a subtle algorithm. Also, it means that if a thread barges in before the unparked thread runs, then that barging thread will not know that there are threads parked. This could increase the severity of barging. Since ParkingLot is a user-level API, we don't have to worry about the kernel-user security issues and so we can expose callbacks while ParkingLot is holding its internal locks. This change does exactly that for unparkOne(). The new variant of unparkOne() will call a user function while the queue from which we are unparking is locked. The callback is told basic stats about the queue: did we unpark a thread this time, and could there be more threads to unpark in the future. The callback runs while it's impossible for the queue state to change, since the ParkingLot's internal locks for the queue is held. This means that Lock::unlockSlow() can either clear, or leave, the hasParkedBit while releasing the lock inside the callback from unparkOne(). This takes care of the thundering herd problem while also reducing the greed that arises from barging threads. This required some careful reworking of the ParkingLot algorithm. The first thing I noticed was that the ThreadData::shouldPark flag was useless, since it's set exactly when ThreadData::address is non-null. Then I had to make sure that dequeue() could lazily create both hashtables and buckets, since the "callback is called while queue is locked" invariant requires that we didn't exit early due to the hashtable or bucket not being present. Note that all of this is done in such a way that the old unparkOne() and unparkAll() don't have to create any buckets, though they now may create the hashtable. We don't care as much about the hashtable being created by unpark since it's just such an unlikely scenario and it would only happen once. This change reduces the kernel CPU usage of WTF::Lock for the long critical section test by about 8x and makes it always perform as well as WTF::WordLock and WTF::Mutex for that benchmark. * benchmarks/LockSpeedTest.cpp: * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): * wtf/Lock.h: (WTF::LockBase::isLocked): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: * wtf/WordLock.h: (WTF::WordLock::isLocked): (WTF::WordLock::isFullyReset): Tools: Add testing that checks that locks return to a pristine state after contention is over. * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::LockInspector::isFullyReset): (TestWebKitAPI::runLockTest): (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/166072@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188374 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 03:51:25 +00:00
ASSERT(threadData->address);
{
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): Canonical link: https://commits.webkit.org/182152@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208415 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-11-05 03:02:39 +00:00
MutexLocker locker(threadData->parkingLock);
WTF::Lock should not suffer from the thundering herd https://bugs.webkit.org/show_bug.cgi?id=147947 Reviewed by Geoffrey Garen. Source/WTF: This changes Lock::unlockSlow() to use unparkOne() instead of unparkAll(). The problem with doing this is that it's not obvious after calling unparkOne() if there are any other threads that are still parked on the lock's queue. If we assume that there are and leave the hasParkedBit set, then future calls to unlock() will take the slow path. We don't want that if there aren't actually any threads parked. On the other hand, if we assume that there aren't any threads parked and clear the hasParkedBit, then if there actually were some threads parked, then they may never be awoken since future calls to unlock() won't take slow path and so won't call unparkOne(). In other words, we need a way to be very precise about when we clear the hasParkedBit and we need to do it in a race-free way: it can't be the case that we clear the bit just as some thread gets parked on the queue. A similar problem arises in futexes, and one of the solutions is to have a thread that acquires a lock after parking sets the hasParkedBit. This is what Rusty Russel's usersem does. It's a subtle algorithm. Also, it means that if a thread barges in before the unparked thread runs, then that barging thread will not know that there are threads parked. This could increase the severity of barging. Since ParkingLot is a user-level API, we don't have to worry about the kernel-user security issues and so we can expose callbacks while ParkingLot is holding its internal locks. This change does exactly that for unparkOne(). The new variant of unparkOne() will call a user function while the queue from which we are unparking is locked. The callback is told basic stats about the queue: did we unpark a thread this time, and could there be more threads to unpark in the future. The callback runs while it's impossible for the queue state to change, since the ParkingLot's internal locks for the queue is held. This means that Lock::unlockSlow() can either clear, or leave, the hasParkedBit while releasing the lock inside the callback from unparkOne(). This takes care of the thundering herd problem while also reducing the greed that arises from barging threads. This required some careful reworking of the ParkingLot algorithm. The first thing I noticed was that the ThreadData::shouldPark flag was useless, since it's set exactly when ThreadData::address is non-null. Then I had to make sure that dequeue() could lazily create both hashtables and buckets, since the "callback is called while queue is locked" invariant requires that we didn't exit early due to the hashtable or bucket not being present. Note that all of this is done in such a way that the old unparkOne() and unparkAll() don't have to create any buckets, though they now may create the hashtable. We don't care as much about the hashtable being created by unpark since it's just such an unlikely scenario and it would only happen once. This change reduces the kernel CPU usage of WTF::Lock for the long critical section test by about 8x and makes it always perform as well as WTF::WordLock and WTF::Mutex for that benchmark. * benchmarks/LockSpeedTest.cpp: * wtf/Lock.cpp: (WTF::LockBase::unlockSlow): * wtf/Lock.h: (WTF::LockBase::isLocked): (WTF::LockBase::isFullyReset): * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): * wtf/ParkingLot.h: * wtf/WordLock.h: (WTF::WordLock::isLocked): (WTF::WordLock::isFullyReset): Tools: Add testing that checks that locks return to a pristine state after contention is over. * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::LockInspector::isFullyReset): (TestWebKitAPI::runLockTest): (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/166072@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188374 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-13 03:51:25 +00:00
threadData->address = nullptr;
}
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): Canonical link: https://commits.webkit.org/182152@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208415 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-11-05 03:02:39 +00:00
threadData->parkingCondition.signal();
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
}
if (verbose)
WTF shouldn't have both Thread and ThreadIdentifier https://bugs.webkit.org/show_bug.cgi?id=180308 Reviewed by Darin Adler. Source/JavaScriptCore: * heap/MachineStackMarker.cpp: (JSC::MachineThreads::tryCopyOtherThreadStacks): * llint/LLIntSlowPaths.cpp: (JSC::LLInt::llint_trace_operand): (JSC::LLInt::llint_trace_value): (JSC::LLInt::LLINT_SLOW_PATH_DECL): (JSC::LLInt::traceFunctionPrologue): * runtime/ExceptionScope.cpp: (JSC::ExceptionScope::unexpectedExceptionMessage): * runtime/JSLock.h: (JSC::JSLock::currentThreadIsHoldingLock): * runtime/VM.cpp: (JSC::VM::throwException): * runtime/VM.h: (JSC::VM::throwingThread const): (JSC::VM::clearException): * tools/HeapVerifier.cpp: (JSC::HeapVerifier::printVerificationHeader): Source/WebCore: No behavior change. * Modules/indexeddb/IDBActiveDOMObject.h: (WebCore::IDBActiveDOMObject::originThread const): (WebCore::IDBActiveDOMObject::performCallbackOnOriginThread): (WebCore::IDBActiveDOMObject::callFunctionOnOriginThread): (WebCore::IDBActiveDOMObject::originThreadID const): Deleted. * Modules/indexeddb/IDBCursor.cpp: (WebCore::IDBCursor::IDBCursor): (WebCore::IDBCursor::~IDBCursor): (WebCore::IDBCursor::sourcesDeleted const): (WebCore::IDBCursor::transaction const): (WebCore::IDBCursor::update): (WebCore::IDBCursor::advance): (WebCore::IDBCursor::continueFunction): (WebCore::IDBCursor::uncheckedIterateCursor): (WebCore::IDBCursor::deleteFunction): (WebCore::IDBCursor::setGetResult): * Modules/indexeddb/IDBDatabase.cpp: (WebCore::IDBDatabase::~IDBDatabase): (WebCore::IDBDatabase::hasPendingActivity const): (WebCore::IDBDatabase::name const): (WebCore::IDBDatabase::version const): (WebCore::IDBDatabase::objectStoreNames const): (WebCore::IDBDatabase::renameObjectStore): (WebCore::IDBDatabase::renameIndex): (WebCore::IDBDatabase::createObjectStore): (WebCore::IDBDatabase::transaction): (WebCore::IDBDatabase::deleteObjectStore): (WebCore::IDBDatabase::close): (WebCore::IDBDatabase::connectionToServerLost): (WebCore::IDBDatabase::maybeCloseInServer): (WebCore::IDBDatabase::activeDOMObjectName const): (WebCore::IDBDatabase::canSuspendForDocumentSuspension const): (WebCore::IDBDatabase::stop): (WebCore::IDBDatabase::startVersionChangeTransaction): (WebCore::IDBDatabase::didStartTransaction): (WebCore::IDBDatabase::willCommitTransaction): (WebCore::IDBDatabase::didCommitTransaction): (WebCore::IDBDatabase::willAbortTransaction): (WebCore::IDBDatabase::didAbortTransaction): (WebCore::IDBDatabase::didCommitOrAbortTransaction): (WebCore::IDBDatabase::fireVersionChangeEvent): (WebCore::IDBDatabase::dispatchEvent): (WebCore::IDBDatabase::didCreateIndexInfo): (WebCore::IDBDatabase::didDeleteIndexInfo): * Modules/indexeddb/IDBIndex.cpp: (WebCore::IDBIndex::IDBIndex): (WebCore::IDBIndex::~IDBIndex): (WebCore::IDBIndex::name const): (WebCore::IDBIndex::setName): (WebCore::IDBIndex::objectStore): (WebCore::IDBIndex::keyPath const): (WebCore::IDBIndex::unique const): (WebCore::IDBIndex::multiEntry const): (WebCore::IDBIndex::rollbackInfoForVersionChangeAbort): (WebCore::IDBIndex::openCursor): (WebCore::IDBIndex::openKeyCursor): (WebCore::IDBIndex::doCount): (WebCore::IDBIndex::doGet): (WebCore::IDBIndex::doGetKey): (WebCore::IDBIndex::getAll): (WebCore::IDBIndex::getAllKeys): (WebCore::IDBIndex::markAsDeleted): * Modules/indexeddb/IDBObjectStore.cpp: (WebCore::IDBObjectStore::IDBObjectStore): (WebCore::IDBObjectStore::~IDBObjectStore): (WebCore::IDBObjectStore::name const): (WebCore::IDBObjectStore::setName): (WebCore::IDBObjectStore::keyPath const): (WebCore::IDBObjectStore::indexNames const): (WebCore::IDBObjectStore::transaction): (WebCore::IDBObjectStore::autoIncrement const): (WebCore::IDBObjectStore::openCursor): (WebCore::IDBObjectStore::openKeyCursor): (WebCore::IDBObjectStore::get): (WebCore::IDBObjectStore::getKey): (WebCore::IDBObjectStore::putOrAdd): (WebCore::IDBObjectStore::doDelete): (WebCore::IDBObjectStore::clear): (WebCore::IDBObjectStore::createIndex): (WebCore::IDBObjectStore::index): (WebCore::IDBObjectStore::deleteIndex): (WebCore::IDBObjectStore::doCount): (WebCore::IDBObjectStore::getAll): (WebCore::IDBObjectStore::getAllKeys): (WebCore::IDBObjectStore::markAsDeleted): (WebCore::IDBObjectStore::rollbackForVersionChangeAbort): * Modules/indexeddb/IDBOpenDBRequest.cpp: (WebCore::IDBOpenDBRequest::~IDBOpenDBRequest): (WebCore::IDBOpenDBRequest::onError): (WebCore::IDBOpenDBRequest::versionChangeTransactionDidFinish): (WebCore::IDBOpenDBRequest::fireSuccessAfterVersionChangeCommit): (WebCore::IDBOpenDBRequest::fireErrorAfterVersionChangeCompletion): (WebCore::IDBOpenDBRequest::dispatchEvent): (WebCore::IDBOpenDBRequest::onSuccess): (WebCore::IDBOpenDBRequest::onUpgradeNeeded): (WebCore::IDBOpenDBRequest::onDeleteDatabaseSuccess): (WebCore::IDBOpenDBRequest::requestCompleted): (WebCore::IDBOpenDBRequest::requestBlocked): * Modules/indexeddb/IDBRequest.cpp: (WebCore::IDBRequest::~IDBRequest): (WebCore:: const): (WebCore::IDBRequest::setSource): (WebCore::IDBRequest::setVersionChangeTransaction): (WebCore::IDBRequest::transaction const): (WebCore::IDBRequest::sourceObjectStoreIdentifier const): (WebCore::IDBRequest::sourceIndexIdentifier const): (WebCore::IDBRequest::requestedObjectStoreRecordType const): (WebCore::IDBRequest::requestedIndexRecordType const): (WebCore::IDBRequest::eventTargetInterface const): (WebCore::IDBRequest::activeDOMObjectName const): (WebCore::IDBRequest::canSuspendForDocumentSuspension const): (WebCore::IDBRequest::hasPendingActivity const): (WebCore::IDBRequest::stop): (WebCore::IDBRequest::enqueueEvent): (WebCore::IDBRequest::dispatchEvent): (WebCore::IDBRequest::uncaughtExceptionInEventHandler): (WebCore::IDBRequest::setResult): (WebCore::IDBRequest::setResultToStructuredClone): (WebCore::IDBRequest::setResultToUndefined): (WebCore::IDBRequest::resultCursor): (WebCore::IDBRequest::willIterateCursor): (WebCore::IDBRequest::didOpenOrIterateCursor): (WebCore::IDBRequest::completeRequestAndDispatchEvent): (WebCore::IDBRequest::onError): (WebCore::IDBRequest::onSuccess): * Modules/indexeddb/IDBTransaction.cpp: (WebCore::IDBTransaction::IDBTransaction): (WebCore::IDBTransaction::~IDBTransaction): (WebCore::IDBTransaction::objectStoreNames const): (WebCore::IDBTransaction::db): (WebCore::IDBTransaction::error const): (WebCore::IDBTransaction::objectStore): (WebCore::IDBTransaction::abortDueToFailedRequest): (WebCore::IDBTransaction::transitionedToFinishing): (WebCore::IDBTransaction::abort): (WebCore::IDBTransaction::internalAbort): (WebCore::IDBTransaction::abortOnServerAndCancelRequests): (WebCore::IDBTransaction::activeDOMObjectName const): (WebCore::IDBTransaction::canSuspendForDocumentSuspension const): (WebCore::IDBTransaction::hasPendingActivity const): (WebCore::IDBTransaction::stop): (WebCore::IDBTransaction::isActive const): (WebCore::IDBTransaction::isFinishedOrFinishing const): (WebCore::IDBTransaction::addRequest): (WebCore::IDBTransaction::removeRequest): (WebCore::IDBTransaction::scheduleOperation): (WebCore::IDBTransaction::schedulePendingOperationTimer): (WebCore::IDBTransaction::pendingOperationTimerFired): (WebCore::IDBTransaction::operationCompletedOnServer): (WebCore::IDBTransaction::scheduleCompletedOperationTimer): (WebCore::IDBTransaction::completedOperationTimerFired): (WebCore::IDBTransaction::commit): (WebCore::IDBTransaction::commitOnServer): (WebCore::IDBTransaction::finishAbortOrCommit): (WebCore::IDBTransaction::didStart): (WebCore::IDBTransaction::notifyDidAbort): (WebCore::IDBTransaction::didAbort): (WebCore::IDBTransaction::didCommit): (WebCore::IDBTransaction::fireOnComplete): (WebCore::IDBTransaction::fireOnAbort): (WebCore::IDBTransaction::enqueueEvent): (WebCore::IDBTransaction::dispatchEvent): (WebCore::IDBTransaction::createObjectStore): (WebCore::IDBTransaction::createObjectStoreOnServer): (WebCore::IDBTransaction::didCreateObjectStoreOnServer): (WebCore::IDBTransaction::renameObjectStore): (WebCore::IDBTransaction::renameObjectStoreOnServer): (WebCore::IDBTransaction::didRenameObjectStoreOnServer): (WebCore::IDBTransaction::createIndex): (WebCore::IDBTransaction::createIndexOnServer): (WebCore::IDBTransaction::didCreateIndexOnServer): (WebCore::IDBTransaction::renameIndex): (WebCore::IDBTransaction::renameIndexOnServer): (WebCore::IDBTransaction::didRenameIndexOnServer): (WebCore::IDBTransaction::requestOpenCursor): (WebCore::IDBTransaction::doRequestOpenCursor): (WebCore::IDBTransaction::openCursorOnServer): (WebCore::IDBTransaction::didOpenCursorOnServer): (WebCore::IDBTransaction::iterateCursor): (WebCore::IDBTransaction::iterateCursorOnServer): (WebCore::IDBTransaction::didIterateCursorOnServer): (WebCore::IDBTransaction::requestGetAllObjectStoreRecords): (WebCore::IDBTransaction::requestGetAllIndexRecords): (WebCore::IDBTransaction::getAllRecordsOnServer): (WebCore::IDBTransaction::didGetAllRecordsOnServer): (WebCore::IDBTransaction::requestGetRecord): (WebCore::IDBTransaction::requestGetValue): (WebCore::IDBTransaction::requestGetKey): (WebCore::IDBTransaction::requestIndexRecord): (WebCore::IDBTransaction::getRecordOnServer): (WebCore::IDBTransaction::didGetRecordOnServer): (WebCore::IDBTransaction::requestCount): (WebCore::IDBTransaction::getCountOnServer): (WebCore::IDBTransaction::didGetCountOnServer): (WebCore::IDBTransaction::requestDeleteRecord): (WebCore::IDBTransaction::deleteRecordOnServer): (WebCore::IDBTransaction::didDeleteRecordOnServer): (WebCore::IDBTransaction::requestClearObjectStore): (WebCore::IDBTransaction::clearObjectStoreOnServer): (WebCore::IDBTransaction::didClearObjectStoreOnServer): (WebCore::IDBTransaction::requestPutOrAdd): (WebCore::IDBTransaction::putOrAddOnServer): (WebCore::IDBTransaction::didPutOrAddOnServer): (WebCore::IDBTransaction::deleteObjectStore): (WebCore::IDBTransaction::deleteObjectStoreOnServer): (WebCore::IDBTransaction::didDeleteObjectStoreOnServer): (WebCore::IDBTransaction::deleteIndex): (WebCore::IDBTransaction::deleteIndexOnServer): (WebCore::IDBTransaction::didDeleteIndexOnServer): (WebCore::IDBTransaction::operationCompletedOnClient): (WebCore::IDBTransaction::establishOnServer): (WebCore::IDBTransaction::activate): (WebCore::IDBTransaction::deactivate): * Modules/indexeddb/client/IDBConnectionProxy.cpp: (WebCore::IDBClient::removeItemsMatchingCurrentThread): * Modules/indexeddb/client/TransactionOperation.h: (WebCore::IDBClient::TransactionOperation::~TransactionOperation): (WebCore::IDBClient::TransactionOperation::perform): (WebCore::IDBClient::TransactionOperation::transitionToCompleteOnThisThread): (WebCore::IDBClient::TransactionOperation::transitionToComplete): (WebCore::IDBClient::TransactionOperation::doComplete): (WebCore::IDBClient::TransactionOperation::originThread const): (WebCore::IDBClient::TransactionOperation::originThreadID const): Deleted. * Modules/webaudio/AudioContext.cpp: (WebCore::AudioContext::AudioContext): (WebCore::AudioContext::lock): (WebCore::AudioContext::tryLock): (WebCore::AudioContext::unlock): (WebCore::AudioContext::isAudioThread const): (WebCore::AudioContext::isGraphOwner const): * Modules/webaudio/AudioContext.h: (WebCore::AudioContext::setAudioThread): (WebCore::AudioContext::audioThread const): * Modules/webaudio/AudioDestinationNode.cpp: (WebCore::AudioDestinationNode::render): * Modules/webdatabase/Database.cpp: (WebCore::Database::performClose): (WebCore::Database::securityOrigin): * Modules/webdatabase/DatabaseDetails.h: (WebCore::DatabaseDetails::DatabaseDetails): (WebCore::DatabaseDetails::operator=): (WebCore::DatabaseDetails::thread const): (WebCore::DatabaseDetails::threadID const): Deleted. * Modules/webdatabase/DatabaseManager.cpp: (WebCore::DatabaseManager::detailsForNameAndOrigin): * Modules/webdatabase/DatabaseThread.cpp: (WebCore::DatabaseThread::databaseThread): (WebCore::DatabaseThread::recordDatabaseOpen): (WebCore::DatabaseThread::recordDatabaseClosed): * Modules/webdatabase/DatabaseThread.h: (WebCore::DatabaseThread::getThread): (WebCore::DatabaseThread::getThreadID): Deleted. * Modules/webdatabase/SQLTransaction.cpp: (WebCore::SQLTransaction::checkAndHandleClosedDatabase): * Modules/webdatabase/SQLTransactionBackend.cpp: (WebCore::SQLTransactionBackend::doCleanup): (WebCore::SQLTransactionBackend::notifyDatabaseThreadIsShuttingDown): * bindings/js/JSCallbackData.h: (WebCore::JSCallbackData::JSCallbackData): (WebCore::JSCallbackData::~JSCallbackData): * bindings/js/ScheduledAction.cpp: (WebCore::ScheduledAction::execute): * dom/ScriptExecutionContext.cpp: (WebCore::ScriptExecutionContext::createdMessagePort): (WebCore::ScriptExecutionContext::destroyedMessagePort): * page/ResourceUsageOverlay.h: * page/scrolling/ScrollingThread.cpp: (WebCore::ScrollingThread::isCurrentThread): * platform/Supplementable.h: (WebCore::Supplementable::provideSupplement): (WebCore::Supplementable::removeSupplement): (WebCore::Supplementable::requireSupplement): (WebCore::Supplementable::Supplementable): Deleted. * platform/Timer.cpp: (WebCore::TimerBase::TimerBase): (WebCore::TimerBase::start): (WebCore::TimerBase::stop): (WebCore::TimerBase::setNextFireTime): * platform/Timer.h: (WebCore::TimerBase::isActive const): * platform/graphics/cocoa/FontCacheCoreText.cpp: (WebCore::shouldAutoActivateFontIfNeeded): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.cpp: (WebCore::TextureMapperPlatformLayerProxy::activateOnCompositingThread): (WebCore::TextureMapperPlatformLayerProxy::invalidate): (WebCore::TextureMapperPlatformLayerProxy::getAvailableBuffer): (WebCore::TextureMapperPlatformLayerProxy::appendToUnusedBuffers): (WebCore::TextureMapperPlatformLayerProxy::swapBuffer): * platform/graphics/texmap/TextureMapperPlatformLayerProxy.h: (): Deleted. * platform/ios/wak/WebCoreThread.mm: (RunWebThread): (StartWebThread): * platform/sql/SQLiteDatabase.cpp: (WebCore::SQLiteDatabase::open): (WebCore::SQLiteDatabase::close): * platform/sql/SQLiteDatabase.h: (WebCore::SQLiteDatabase::sqlite3Handle const): * workers/WorkerGlobalScope.cpp: (WebCore::WorkerGlobalScope::~WorkerGlobalScope): (WebCore::WorkerGlobalScope::isContextThread const): * workers/WorkerMessagingProxy.cpp: (WebCore::WorkerMessagingProxy::WorkerMessagingProxy): (WebCore::WorkerMessagingProxy::~WorkerMessagingProxy): * workers/WorkerRunLoop.cpp: (WebCore::WorkerRunLoop::runInMode): (WebCore::WorkerRunLoop::runCleanupTasks): * workers/WorkerThread.h: (WebCore::WorkerThread::thread const): (WebCore::WorkerThread::threadID const): Deleted. * workers/service/ServiceWorkerContainer.cpp: (WebCore::ServiceWorkerContainer::~ServiceWorkerContainer): (WebCore::ServiceWorkerContainer::scheduleJob): (WebCore::ServiceWorkerContainer::jobFailedWithException): (WebCore::ServiceWorkerContainer::scheduleTaskToFireUpdateFoundEvent): (WebCore::ServiceWorkerContainer::jobResolvedWithRegistration): (WebCore::ServiceWorkerContainer::jobResolvedWithUnregistrationResult): (WebCore::ServiceWorkerContainer::startScriptFetchForJob): (WebCore::ServiceWorkerContainer::jobFinishedLoadingScript): (WebCore::ServiceWorkerContainer::jobFailedLoadingScript): (WebCore::ServiceWorkerContainer::jobDidFinish): (WebCore::ServiceWorkerContainer::addRegistration): (WebCore::ServiceWorkerContainer::removeRegistration): (WebCore::ServiceWorkerContainer::scheduleTaskToFireControllerChangeEvent): (WebCore::ServiceWorkerContainer::contextIdentifier): * workers/service/ServiceWorkerContainer.h: * workers/service/ServiceWorkerJob.cpp: (WebCore::ServiceWorkerJob::~ServiceWorkerJob): (WebCore::ServiceWorkerJob::failedWithException): (WebCore::ServiceWorkerJob::resolvedWithRegistration): (WebCore::ServiceWorkerJob::resolvedWithUnregistrationResult): (WebCore::ServiceWorkerJob::startScriptFetch): (WebCore::ServiceWorkerJob::fetchScriptWithContext): (WebCore::ServiceWorkerJob::didReceiveResponse): (WebCore::ServiceWorkerJob::notifyFinished): * workers/service/ServiceWorkerJob.h: * xml/parser/XMLDocumentParserLibxml2.cpp: (WebCore::matchFunc): (WebCore::openFunc): (WebCore::initializeXMLParser): (WebCore::XMLParserContext::createStringParser): (WebCore::XMLParserContext::createMemoryParser): Source/WebKit: * UIProcess/API/glib/IconDatabase.cpp: * UIProcess/GenericCallback.h: (WebKit::GenericCallback::~GenericCallback): (WebKit::GenericCallback::performCallbackWithReturnValue): Source/WTF: We should use a pointer of WTF::Thread instead of ThreadIdentifier. One problem is that Windows support library uses WTF::createThread, which returns ThreadIdentifier. So we cannot drop ThreadIdentifier in Windows environment. This patch keeps ThreadIdentifier in Windows. * wtf/MainThread.cpp: (WTF::initializeMainThread): (WTF::isMainThread): (WTF::canAccessThreadLocalDataForThread): * wtf/MainThread.h: * wtf/ParkingLot.cpp: (WTF::ParkingLot::parkConditionallyImpl): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkOneImpl): (WTF::ParkingLot::unparkCount): * wtf/RecursiveLockAdapter.h: (WTF::RecursiveLockAdapter::lock): (WTF::RecursiveLockAdapter::unlock): (WTF::RecursiveLockAdapter::tryLock): * wtf/Threading.cpp: (WTF::Thread::dump const): * wtf/Threading.h: (WTF::Thread::id const): (WTF::Thread::operator==): Deleted. (WTF::Thread::operator!=): Deleted. (WTF::currentThread): Deleted. * wtf/ThreadingPrimitives.h: * wtf/ThreadingPthreads.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::detach): (WTF::Thread::initializeCurrentTLS): (WTF::Thread::suspend): (WTF::Thread::establishPlatformSpecificHandle): (WTF::Thread::currentID): Deleted. * wtf/ThreadingWin.cpp: (WTF::Thread::waitForCompletion): (WTF::Thread::suspend): (WTF::Thread::currentDying): * wtf/mac/MainThreadMac.mm: (WTF::initializeApplicationUIThread): (WTF::initializeWebThreadPlatform): (WTF::canAccessThreadLocalDataForThread): (WTF::initializeApplicationUIThreadIdentifier): Deleted. (WTF::initializeWebThreadIdentifier): Deleted. Tools: * DumpRenderTree/mac/DumpRenderTree.mm: (dumpRenderTree): (runThread): Deleted. (runPthread): Deleted. (testThreadIdentifierMap): Deleted. * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: * TestWebKitAPI/Tests/WTF/Threading.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/196314@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@225470 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-12-04 06:13:05 +00:00
dataLog(toString(Thread::current(), ": done unparking.\n"));
JSC should support SharedArrayBuffer https://bugs.webkit.org/show_bug.cgi?id=163986 Reviewed by Keith Miller. JSTests: This adds our own test for the various corner cases of SharedArrayBuffer. This test is meant to check all of the things that don't require concurrency. * stress/SharedArrayBuffer.js: Added. (checkAtomics): (shouldFail): (Symbol): (runAtomic): Source/JavaScriptCore: This implements https://tc39.github.io/ecmascript_sharedmem/shmem.html. There is now a new SharedArrayBuffer type. In the JS runtime, which includes typed array types, the SharedArrayBuffer is a drop-in replacement for ArrayBuffer, even though they are distinct types (new SharedArrayBuffer() instanceof ArrayBuffer == false and vice versa). The DOM will not recognize SharedArrayBuffer, or any typed array that wraps it, to ensure safety. This matches what other browsers intend to do, see https://github.com/tc39/ecmascript_sharedmem/issues/38. API is provided for the DOM to opt into SharedArrayBuffer. One notable place is postMessage, which will share the SharedArrayBuffer's underlying data storage with other workers. This creates a pool of shared memory that the workers can use to talk to each other. There is also an Atomics object in global scope, which exposes sequentially consistent atomic operations: add, and, compareExchange, exchange, load, or, store, sub, and xor. Additionally it exposes a Atomics.isLockFree utility, which takes a byte amount and returns true or false. Also there is Atomics.wake/wait, which neatly map to ParkingLot. Accesses to typed arrays that wrap SharedArrayBuffer are optimized by JSC the same way as always. I believe that DFG and B3 already obey the following memory model, which I believe is a bit weaker than Cambridge and a bit stronger than what is being proposed for SharedArrayBuffer. To predict a program's behavior under the B3 memory model, imagine the space of all possible programs that would result from running an optimizer that adversarially follows B3's transformation rules. B3 transformations are correct if the newly created program is equivalent to the old one, assuming that any opaque effect in IR (like the reads and writes of a patchpoint/call/fence) could perform any load/store that satisfies the B3::Effects summary. Opaque effects are a way of describing an infinite set of programs: any program that only does the effects summarized in B3::Effects belongs to the set. For example, this prevents motion of operations across fences since fences are summarized as opaque effects that could read or write memory. This rule alone is not enough, because it leaves the door open for turning an atomic operation (like a load) into a non-atomic one (like a load followed by a store of the same value back to the same location or multiple loads). This is not an optimization that either our compiler or the CPU would want to do. One way to think of what exactly is forbidden is that B3 transformations that mess with memory accesses can only reorder them or remove them. This means that for any execution of the untransformed program, the corresponding execution of the transformed program (i.e. with the same input arguments and the same programs filled in for the opaque effects) must have the same loads and stores, with some removed and some reordered. This is a fairly simple mental model that B3 and DFG already follow and it's based on existing abstractions for the infinite set of programs inside an opaque effect (DFG's AbstractHeaps and B3's Effects). This patch makes all atomics operations intrinsic, but the DFG doesn't know about any of them yet. That's covered by bug 164108. This ought to be perf-neutral, but I am still running tests to confirm this. I'm also still writing new tests to cover all of the Atomics functionality and the behavior of SAB objects. * API/JSTypedArray.cpp: (JSObjectGetTypedArrayBytesPtr): (JSObjectGetTypedArrayBuffer): (JSObjectMakeArrayBufferWithBytesNoCopy): * API/tests/CompareAndSwapTest.cpp: (Bitmap::concurrentTestAndSet): * CMakeLists.txt: * JavaScriptCore.xcodeproj/project.pbxproj: * dfg/DFGDesiredWatchpoints.cpp: (JSC::DFG::ArrayBufferViewWatchpointAdaptor::add): * heap/Heap.cpp: (JSC::Heap::reportExtraMemoryVisited): (JSC::Heap::reportExternalMemoryVisited): * jsc.cpp: (functionTransferArrayBuffer): * runtime/ArrayBuffer.cpp: (JSC::SharedArrayBufferContents::SharedArrayBufferContents): (JSC::SharedArrayBufferContents::~SharedArrayBufferContents): (JSC::ArrayBufferContents::ArrayBufferContents): (JSC::ArrayBufferContents::operator=): (JSC::ArrayBufferContents::~ArrayBufferContents): (JSC::ArrayBufferContents::clear): (JSC::ArrayBufferContents::destroy): (JSC::ArrayBufferContents::reset): (JSC::ArrayBufferContents::tryAllocate): (JSC::ArrayBufferContents::makeShared): (JSC::ArrayBufferContents::transferTo): (JSC::ArrayBufferContents::copyTo): (JSC::ArrayBufferContents::shareWith): (JSC::ArrayBuffer::create): (JSC::ArrayBuffer::createAdopted): (JSC::ArrayBuffer::createFromBytes): (JSC::ArrayBuffer::tryCreate): (JSC::ArrayBuffer::createUninitialized): (JSC::ArrayBuffer::tryCreateUninitialized): (JSC::ArrayBuffer::createInternal): (JSC::ArrayBuffer::ArrayBuffer): (JSC::ArrayBuffer::slice): (JSC::ArrayBuffer::sliceImpl): (JSC::ArrayBuffer::makeShared): (JSC::ArrayBuffer::setSharingMode): (JSC::ArrayBuffer::transferTo): (JSC::ArrayBuffer::transfer): Deleted. * runtime/ArrayBuffer.h: (JSC::arrayBufferSharingModeName): (JSC::SharedArrayBufferContents::data): (JSC::ArrayBufferContents::data): (JSC::ArrayBufferContents::sizeInBytes): (JSC::ArrayBufferContents::isShared): (JSC::ArrayBuffer::sharingMode): (JSC::ArrayBuffer::isShared): (JSC::ArrayBuffer::gcSizeEstimateInBytes): (JSC::arrayBufferDestructorNull): Deleted. (JSC::arrayBufferDestructorDefault): Deleted. (JSC::ArrayBufferContents::ArrayBufferContents): Deleted. (JSC::ArrayBufferContents::transfer): Deleted. (JSC::ArrayBufferContents::copyTo): Deleted. (JSC::ArrayBuffer::create): Deleted. (JSC::ArrayBuffer::createAdopted): Deleted. (JSC::ArrayBuffer::createFromBytes): Deleted. (JSC::ArrayBuffer::tryCreate): Deleted. (JSC::ArrayBuffer::createUninitialized): Deleted. (JSC::ArrayBuffer::tryCreateUninitialized): Deleted. (JSC::ArrayBuffer::createInternal): Deleted. (JSC::ArrayBuffer::ArrayBuffer): Deleted. (JSC::ArrayBuffer::slice): Deleted. (JSC::ArrayBuffer::sliceImpl): Deleted. (JSC::ArrayBufferContents::tryAllocate): Deleted. (JSC::ArrayBufferContents::~ArrayBufferContents): Deleted. * runtime/ArrayBufferSharingMode.h: Added. * runtime/ArrayBufferView.h: (JSC::ArrayBufferView::possiblySharedBuffer): (JSC::ArrayBufferView::unsharedBuffer): (JSC::ArrayBufferView::isShared): (JSC::ArrayBufferView::buffer): Deleted. * runtime/AtomicsObject.cpp: Added. (JSC::AtomicsObject::AtomicsObject): (JSC::AtomicsObject::create): (JSC::AtomicsObject::createStructure): (JSC::AtomicsObject::finishCreation): (JSC::atomicsFuncAdd): (JSC::atomicsFuncAnd): (JSC::atomicsFuncCompareExchange): (JSC::atomicsFuncExchange): (JSC::atomicsFuncIsLockFree): (JSC::atomicsFuncLoad): (JSC::atomicsFuncOr): (JSC::atomicsFuncStore): (JSC::atomicsFuncSub): (JSC::atomicsFuncWait): (JSC::atomicsFuncWake): (JSC::atomicsFuncXor): * runtime/AtomicsObject.h: Added. * runtime/CommonIdentifiers.h: * runtime/DataView.cpp: (JSC::DataView::wrap): * runtime/GenericTypedArrayViewInlines.h: (JSC::GenericTypedArrayView<Adaptor>::subarray): * runtime/Intrinsic.h: * runtime/JSArrayBuffer.cpp: (JSC::JSArrayBuffer::finishCreation): (JSC::JSArrayBuffer::isShared): (JSC::JSArrayBuffer::sharingMode): * runtime/JSArrayBuffer.h: (JSC::toPossiblySharedArrayBuffer): (JSC::toUnsharedArrayBuffer): (JSC::JSArrayBuffer::toWrapped): (JSC::toArrayBuffer): Deleted. * runtime/JSArrayBufferConstructor.cpp: (JSC::JSArrayBufferConstructor::JSArrayBufferConstructor): (JSC::JSArrayBufferConstructor::finishCreation): (JSC::JSArrayBufferConstructor::create): (JSC::constructArrayBuffer): * runtime/JSArrayBufferConstructor.h: (JSC::JSArrayBufferConstructor::sharingMode): * runtime/JSArrayBufferPrototype.cpp: (JSC::arrayBufferProtoFuncSlice): (JSC::JSArrayBufferPrototype::JSArrayBufferPrototype): (JSC::JSArrayBufferPrototype::finishCreation): (JSC::JSArrayBufferPrototype::create): * runtime/JSArrayBufferPrototype.h: * runtime/JSArrayBufferView.cpp: (JSC::JSArrayBufferView::finishCreation): (JSC::JSArrayBufferView::visitChildren): (JSC::JSArrayBufferView::unsharedBuffer): (JSC::JSArrayBufferView::unsharedJSBuffer): (JSC::JSArrayBufferView::possiblySharedJSBuffer): (JSC::JSArrayBufferView::neuter): (JSC::JSArrayBufferView::toWrapped): Deleted. * runtime/JSArrayBufferView.h: (JSC::JSArrayBufferView::jsBuffer): Deleted. * runtime/JSArrayBufferViewInlines.h: (JSC::JSArrayBufferView::isShared): (JSC::JSArrayBufferView::possiblySharedBuffer): (JSC::JSArrayBufferView::possiblySharedImpl): (JSC::JSArrayBufferView::unsharedImpl): (JSC::JSArrayBufferView::byteOffset): (JSC::JSArrayBufferView::toWrapped): (JSC::JSArrayBufferView::buffer): Deleted. (JSC::JSArrayBufferView::impl): Deleted. (JSC::JSArrayBufferView::neuter): Deleted. * runtime/JSDataView.cpp: (JSC::JSDataView::possiblySharedTypedImpl): (JSC::JSDataView::unsharedTypedImpl): (JSC::JSDataView::getTypedArrayImpl): (JSC::JSDataView::typedImpl): Deleted. * runtime/JSDataView.h: (JSC::JSDataView::possiblySharedBuffer): (JSC::JSDataView::unsharedBuffer): (JSC::JSDataView::buffer): Deleted. * runtime/JSDataViewPrototype.cpp: (JSC::dataViewProtoGetterBuffer): * runtime/JSGenericTypedArrayView.h: (JSC::toPossiblySharedNativeTypedView): (JSC::toUnsharedNativeTypedView): (JSC::JSGenericTypedArrayView<Adaptor>::toWrapped): (JSC::JSGenericTypedArrayView::typedImpl): Deleted. (JSC::toNativeTypedView): Deleted. * runtime/JSGenericTypedArrayViewInlines.h: (JSC::JSGenericTypedArrayView<Adaptor>::create): (JSC::JSGenericTypedArrayView<Adaptor>::possiblySharedTypedImpl): (JSC::JSGenericTypedArrayView<Adaptor>::unsharedTypedImpl): (JSC::JSGenericTypedArrayView<Adaptor>::getTypedArrayImpl): * runtime/JSGenericTypedArrayViewPrototypeFunctions.h: (JSC::genericTypedArrayViewProtoGetterFuncBuffer): (JSC::genericTypedArrayViewPrivateFuncSubarrayCreate): * runtime/JSGlobalObject.cpp: (JSC::createAtomicsProperty): (JSC::JSGlobalObject::init): (JSC::JSGlobalObject::visitChildren): * runtime/JSGlobalObject.h: (JSC::JSGlobalObject::arrayBufferPrototype): (JSC::JSGlobalObject::arrayBufferStructure): * runtime/MathObject.cpp: * runtime/RuntimeFlags.h: * runtime/SimpleTypedArrayController.cpp: (JSC::SimpleTypedArrayController::toJS): * runtime/TypedArrayType.h: (JSC::typedArrayTypeForType): Source/WebCore: New tests added in the LayoutTests/workers/sab directory. This teaches WebCore that a typed array could be shared or not. By default, WebCore will reject shared typed arrays as if they were not typed arrays. This ensures that we don't get race conditions in code that can't handle it. If you postMessage a SharedArrayBuffer or something that wraps it, you will send the shared memory to the other worker. * Modules/encryptedmedia/CDMSessionClearKey.cpp: (WebCore::CDMSessionClearKey::cachedKeyForKeyID): * Modules/fetch/FetchBody.cpp: (WebCore::FetchBody::extract): * Modules/mediastream/RTCDataChannel.cpp: (WebCore::RTCDataChannel::send): * Modules/webaudio/AudioBuffer.cpp: (WebCore::AudioBuffer::getChannelData): * Modules/websockets/WebSocket.cpp: (WebCore::WebSocket::send): * bindings/js/JSBlobCustom.cpp: (WebCore::constructJSBlob): * bindings/js/JSCryptoAlgorithmDictionary.cpp: (WebCore::createRsaKeyGenParams): * bindings/js/JSCryptoCustom.cpp: (WebCore::JSCrypto::getRandomValues): * bindings/js/JSCryptoOperationData.cpp: (WebCore::cryptoOperationDataFromJSValue): * bindings/js/JSDOMBinding.h: (WebCore::toJS): (WebCore::toPossiblySharedArrayBufferView): (WebCore::toUnsharedArrayBufferView): (WebCore::toPossiblySharedInt8Array): (WebCore::toPossiblySharedInt16Array): (WebCore::toPossiblySharedInt32Array): (WebCore::toPossiblySharedUint8Array): (WebCore::toPossiblySharedUint8ClampedArray): (WebCore::toPossiblySharedUint16Array): (WebCore::toPossiblySharedUint32Array): (WebCore::toPossiblySharedFloat32Array): (WebCore::toPossiblySharedFloat64Array): (WebCore::toUnsharedInt8Array): (WebCore::toUnsharedInt16Array): (WebCore::toUnsharedInt32Array): (WebCore::toUnsharedUint8Array): (WebCore::toUnsharedUint8ClampedArray): (WebCore::toUnsharedUint16Array): (WebCore::toUnsharedUint32Array): (WebCore::toUnsharedFloat32Array): (WebCore::toUnsharedFloat64Array): (WebCore::toArrayBufferView): Deleted. (WebCore::toInt8Array): Deleted. (WebCore::toInt16Array): Deleted. (WebCore::toInt32Array): Deleted. (WebCore::toUint8Array): Deleted. (WebCore::toUint8ClampedArray): Deleted. (WebCore::toUint16Array): Deleted. (WebCore::toUint32Array): Deleted. (WebCore::toFloat32Array): Deleted. (WebCore::toFloat64Array): Deleted. * bindings/js/JSDataCueCustom.cpp: (WebCore::constructJSDataCue): * bindings/js/JSDictionary.cpp: (WebCore::JSDictionary::convertValue): * bindings/js/JSFileCustom.cpp: (WebCore::constructJSFile): * bindings/js/JSMessagePortCustom.cpp: (WebCore::extractTransferables): * bindings/js/JSWebGLRenderingContextBaseCustom.cpp: (WebCore::dataFunctionf): (WebCore::dataFunctioni): (WebCore::dataFunctionMatrix): * bindings/js/JSXMLHttpRequestCustom.cpp: (WebCore::JSXMLHttpRequest::send): * bindings/js/SerializedScriptValue.cpp: (WebCore::CloneSerializer::dumpArrayBufferView): (WebCore::CloneSerializer::dumpIfTerminal): (WebCore::CloneDeserializer::readArrayBufferView): (WebCore::CloneDeserializer::readTerminal): (WebCore::SerializedScriptValue::transferArrayBuffers): * bindings/js/StructuredClone.cpp: (WebCore::structuredCloneArrayBuffer): (WebCore::structuredCloneArrayBufferView): * bindings/scripts/CodeGeneratorJS.pm: (JSValueToNative): * css/FontFace.cpp: (WebCore::FontFace::create): * html/canvas/WebGL2RenderingContext.cpp: (WebCore::WebGL2RenderingContext::bufferData): (WebCore::WebGL2RenderingContext::bufferSubData): * platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp: (WebCore::MediaPlayerPrivateAVFoundation::extractKeyURIKeyIDAndCertificateFromInitData): Source/WebKit/mac: Support the RuntimeFlag. * WebView/WebPreferencesPrivate.h: Source/WebKit/win: Support the RuntimeFlag. * Interfaces/IWebPreferencesPrivate.idl: Source/WebKit2: Adds some small things we need for SharedArrayBuffer. * UIProcess/API/C/WKPreferencesRefPrivate.h: * UIProcess/API/Cocoa/WKPreferencesPrivate.h: * WebProcess/InjectedBundle/InjectedBundle.cpp: (WebKit::InjectedBundle::createWebDataFromUint8Array): Source/WTF: Adds some small things we need for SharedArrayBuffer. * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeakRelaxed): (WTF::Atomic::exchangeAdd): (WTF::Atomic::exchangeAnd): (WTF::Atomic::exchangeOr): (WTF::Atomic::exchangeSub): (WTF::Atomic::exchangeXor): (WTF::atomicLoad): (WTF::atomicStore): (WTF::atomicCompareExchangeWeak): (WTF::atomicCompareExchangeWeakRelaxed): (WTF::atomicCompareExchangeStrong): (WTF::atomicExchangeAdd): (WTF::atomicExchangeAnd): (WTF::atomicExchangeOr): (WTF::atomicExchangeSub): (WTF::atomicExchangeXor): (WTF::atomicExchange): (WTF::Atomic::exchangeAndAdd): Deleted. (WTF::weakCompareAndSwap): Deleted. We need to be able to do atomics operations on naked pointers. We also need to be able to do all of the things that std::atomic does. This adds those things and renames weakCompareAndSwap to atomicCompareExchangeWeakRelaxed so that we're using consistent terminology. * wtf/Bitmap.h: (WTF::WordType>::concurrentTestAndSet): Renamed weakCompareAndSwap. (WTF::WordType>::concurrentTestAndClear): Renamed weakCompareAndSwap. * wtf/FastBitVector.h: (WTF::FastBitVector::atomicSetAndCheck): Renamed weakCompareAndSwap. * wtf/ParkingLot.cpp: (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkCount): * wtf/ParkingLot.h: Added unparkCount(), which lets you unpark some bounded number of threads and returns the number of threads unparked. This is just a modest extension of unparkAll(). unparkAll() now just calls unparkCount(ptr, UINT_MAX). Tools: Use the right kind of typed array API. * DumpRenderTree/TestRunner.cpp: (setAudioResultCallback): LayoutTests: Adding tests. This is a work in progress. * workers/sab: Added. * workers/sab/simple-worker-1.js: Added. (onmessage): * workers/sab/simple-worker-2.js: Added. (onmessage): * workers/sab/simple.html: Added. Canonical link: https://commits.webkit.org/181984@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208209 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-11-01 03:10:00 +00:00
return threadDatas.size();
}
NEVER_INLINE void ParkingLot::unparkAll(const void* address)
{
unparkCount(address, UINT_MAX);
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
}
[WTF] Introduce Thread class and use RefPtr<Thread> and align Windows Threading implementation semantics to Pthread one https://bugs.webkit.org/show_bug.cgi?id=170502 Reviewed by Mark Lam. Source/JavaScriptCore: * API/tests/CompareAndSwapTest.cpp: (testCompareAndSwap): * JavaScriptCore.xcodeproj/project.pbxproj: * b3/air/testair.cpp: * b3/testb3.cpp: (JSC::B3::run): * bytecode/SuperSampler.cpp: (JSC::initializeSuperSampler): * dfg/DFGWorklist.cpp: * disassembler/Disassembler.cpp: * heap/Heap.cpp: (JSC::Heap::lastChanceToFinalize): (JSC::Heap::notifyIsSafeToCollect): * heap/Heap.h: * heap/MachineStackMarker.cpp: (JSC::MachineThreads::~MachineThreads): (JSC::MachineThreads::addCurrentThread): (JSC::MachineThreads::removeThread): (JSC::MachineThreads::removeThreadIfFound): (JSC::MachineThreads::MachineThread::MachineThread): (JSC::MachineThreads::MachineThread::getRegisters): (JSC::MachineThreads::MachineThread::Registers::stackPointer): (JSC::MachineThreads::MachineThread::Registers::framePointer): (JSC::MachineThreads::MachineThread::Registers::instructionPointer): (JSC::MachineThreads::MachineThread::Registers::llintPC): (JSC::MachineThreads::MachineThread::captureStack): (JSC::MachineThreads::tryCopyOtherThreadStack): (JSC::MachineThreads::tryCopyOtherThreadStacks): (pthreadSignalHandlerSuspendResume): Deleted. (JSC::threadData): Deleted. (JSC::MachineThreads::Thread::Thread): Deleted. (JSC::MachineThreads::Thread::createForCurrentThread): Deleted. (JSC::MachineThreads::Thread::operator==): Deleted. (JSC::MachineThreads::machineThreadForCurrentThread): Deleted. (JSC::MachineThreads::ThreadData::ThreadData): Deleted. (JSC::MachineThreads::ThreadData::~ThreadData): Deleted. (JSC::MachineThreads::ThreadData::suspend): Deleted. (JSC::MachineThreads::ThreadData::resume): Deleted. (JSC::MachineThreads::ThreadData::getRegisters): Deleted. (JSC::MachineThreads::ThreadData::Registers::stackPointer): Deleted. (JSC::MachineThreads::ThreadData::Registers::framePointer): Deleted. (JSC::MachineThreads::ThreadData::Registers::instructionPointer): Deleted. (JSC::MachineThreads::ThreadData::Registers::llintPC): Deleted. (JSC::MachineThreads::ThreadData::freeRegisters): Deleted. (JSC::MachineThreads::ThreadData::captureStack): Deleted. * heap/MachineStackMarker.h: (JSC::MachineThreads::MachineThread::suspend): (JSC::MachineThreads::MachineThread::resume): (JSC::MachineThreads::MachineThread::threadID): (JSC::MachineThreads::MachineThread::stackBase): (JSC::MachineThreads::MachineThread::stackEnd): (JSC::MachineThreads::threadsListHead): (JSC::MachineThreads::Thread::operator!=): Deleted. (JSC::MachineThreads::Thread::suspend): Deleted. (JSC::MachineThreads::Thread::resume): Deleted. (JSC::MachineThreads::Thread::getRegisters): Deleted. (JSC::MachineThreads::Thread::freeRegisters): Deleted. (JSC::MachineThreads::Thread::captureStack): Deleted. (JSC::MachineThreads::Thread::platformThread): Deleted. (JSC::MachineThreads::Thread::stackBase): Deleted. (JSC::MachineThreads::Thread::stackEnd): Deleted. * jit/ICStats.cpp: (JSC::ICStats::ICStats): (JSC::ICStats::~ICStats): * jit/ICStats.h: * jsc.cpp: (functionDollarAgentStart): (startTimeoutThreadIfNeeded): * runtime/JSLock.cpp: (JSC::JSLock::lock): * runtime/JSLock.h: (JSC::JSLock::ownerThread): (JSC::JSLock::currentThreadIsHoldingLock): * runtime/SamplingProfiler.cpp: (JSC::FrameWalker::isValidFramePointer): (JSC::SamplingProfiler::SamplingProfiler): (JSC::SamplingProfiler::createThreadIfNecessary): (JSC::SamplingProfiler::takeSample): * runtime/SamplingProfiler.h: * runtime/VM.h: (JSC::VM::ownerThread): * runtime/VMTraps.cpp: (JSC::findActiveVMAndStackBounds): (JSC::VMTraps::SignalSender::send): (JSC::VMTraps::fireTrap): Source/WebCore: Mechanical change. Use Thread:: APIs. * Modules/indexeddb/server/IDBServer.cpp: (WebCore::IDBServer::IDBServer::IDBServer): * Modules/indexeddb/server/IDBServer.h: * Modules/webaudio/AsyncAudioDecoder.cpp: (WebCore::AsyncAudioDecoder::AsyncAudioDecoder): (WebCore::AsyncAudioDecoder::~AsyncAudioDecoder): (WebCore::AsyncAudioDecoder::runLoop): * Modules/webaudio/AsyncAudioDecoder.h: * Modules/webaudio/OfflineAudioDestinationNode.cpp: (WebCore::OfflineAudioDestinationNode::OfflineAudioDestinationNode): (WebCore::OfflineAudioDestinationNode::uninitialize): (WebCore::OfflineAudioDestinationNode::startRendering): * Modules/webaudio/OfflineAudioDestinationNode.h: * Modules/webdatabase/Database.cpp: (WebCore::Database::securityOrigin): * Modules/webdatabase/DatabaseThread.cpp: (WebCore::DatabaseThread::start): (WebCore::DatabaseThread::databaseThread): (WebCore::DatabaseThread::recordDatabaseOpen): (WebCore::DatabaseThread::recordDatabaseClosed): * Modules/webdatabase/DatabaseThread.h: (WebCore::DatabaseThread::getThreadID): * bindings/js/GCController.cpp: (WebCore::GCController::garbageCollectOnAlternateThreadForDebugging): * fileapi/AsyncFileStream.cpp: (WebCore::callOnFileThread): * loader/icon/IconDatabase.cpp: (WebCore::IconDatabase::open): (WebCore::IconDatabase::close): * loader/icon/IconDatabase.h: * page/ResourceUsageThread.cpp: (WebCore::ResourceUsageThread::createThreadIfNeeded): * page/ResourceUsageThread.h: * page/scrolling/ScrollingThread.cpp: (WebCore::ScrollingThread::ScrollingThread): (WebCore::ScrollingThread::isCurrentThread): (WebCore::ScrollingThread::createThreadIfNeeded): (WebCore::ScrollingThread::threadCallback): * page/scrolling/ScrollingThread.h: * platform/audio/HRTFDatabaseLoader.cpp: (WebCore::HRTFDatabaseLoader::HRTFDatabaseLoader): (WebCore::HRTFDatabaseLoader::loadAsynchronously): (WebCore::HRTFDatabaseLoader::waitForLoaderThreadCompletion): * platform/audio/HRTFDatabaseLoader.h: * platform/audio/ReverbConvolver.cpp: (WebCore::ReverbConvolver::ReverbConvolver): (WebCore::ReverbConvolver::~ReverbConvolver): * platform/audio/ReverbConvolver.h: * platform/audio/gstreamer/AudioFileReaderGStreamer.cpp: (WebCore::createBusFromAudioFile): (WebCore::createBusFromInMemoryAudioFile): * platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp: (ResourceHandleStreamingClient::ResourceHandleStreamingClient): (ResourceHandleStreamingClient::~ResourceHandleStreamingClient): * platform/network/cf/LoaderRunLoopCF.cpp: (WebCore::loaderRunLoop): * platform/network/curl/CurlDownload.cpp: (WebCore::CurlDownloadManager::startThreadIfNeeded): (WebCore::CurlDownloadManager::stopThread): * platform/network/curl/CurlDownload.h: * platform/network/curl/SocketStreamHandleImpl.h: * platform/network/curl/SocketStreamHandleImplCurl.cpp: (WebCore::SocketStreamHandleImpl::startThread): (WebCore::SocketStreamHandleImpl::stopThread): * workers/WorkerThread.cpp: (WebCore::WorkerThread::WorkerThread): (WebCore::WorkerThread::start): (WebCore::WorkerThread::workerThread): * workers/WorkerThread.h: (WebCore::WorkerThread::threadID): Source/WebKit: Mechanical change. Use Thread:: APIs. * Storage/StorageThread.cpp: (WebCore::StorageThread::StorageThread): (WebCore::StorageThread::~StorageThread): (WebCore::StorageThread::start): (WebCore::StorageThread::dispatch): (WebCore::StorageThread::terminate): * Storage/StorageThread.h: Source/WebKit2: Mechanical change. Use Thread:: APIs. * NetworkProcess/NetworkProcess.cpp: (WebKit::NetworkProcess::initializeNetworkProcess): * NetworkProcess/cache/NetworkCacheIOChannelSoup.cpp: (WebKit::NetworkCache::IOChannel::readSyncInThread): * Platform/IPC/Connection.cpp: (IPC::Connection::processIncomingMessage): * Shared/EntryPointUtilities/mac/XPCService/XPCServiceEntryPoint.h: (WebKit::XPCServiceInitializer): * UIProcess/linux/MemoryPressureMonitor.cpp: (WebKit::MemoryPressureMonitor::MemoryPressureMonitor): * WebProcess/WebProcess.cpp: (WebKit::WebProcess::initializeWebProcess): Source/WTF: This patch is refactoring of WTF Threading mechanism to merge JavaScriptCore's threading extension to WTF Threading. Previously, JavaScriptCore requires richer threading features (such as suspending and resuming threads), and they are implemented for PlatformThread in JavaScriptCore. But these features should be implemented in WTF Threading side instead of maintaining JSC's own threading features too. This patch removes these features from JSC and move it to WTF Threading. However, current WTF Threading has one problem: Windows version of WTF Threading has different semantics from Pthreads one. In Windows WTF Threading, we cannot perform any operation after the target thread is detached: WTF Threading stop tracking the state of the thread once the thread is detached. But this is not the same to Pthreads one. In Pthreads, pthread_detach just means that the resource of the thread will be destroyed automatically. While some operations like pthread_join will be rejected, some operations like pthread_kill will be accepted. The problem is that detached thread can be suspended and resumed in JSC. For example, in jsc.cpp, we start the worker thread and detach it immediately. In worker thread, we will create VM and thus concurrent GC will suspend and resume the detached thread. However, in Windows WTF Threading, we have no reference to the detached thread. Thus we cannot perform suspend and resume operations onto the detached thread. To solve the problem, we change Windows Threading mechanism drastically to align it to the Pthread semantics. In the new Threading, we have RefPtr<Thread> class. It holds a handle to a platform thread. We can perform threading operations with this class. For example, Thread::suspend is offered. And we use destructor of the thread local variable to release the resources held by RefPtr<Thread>. In Windows, Thread::detach does nothing because the resource will be destroyed automatically by RefPtr<Thread>. To do so, we introduce ThreadHolder for Windows. This is similar to the previous ThreadIdentifierData for Pthreads. It holds RefPtr<Thread> in the thread local storage (technically, it is Fiber Local Storage in Windows). Thread::current() will return this reference. The problematic situation is that the order of the deallocation of the thread local storage is not defined. So we should not touch thread local storage in the destructor of the thread local storage. To avoid such edge cases, we have currentThread() / Thread::currentID() APIs. They are safe to be called even in the destructor of the other thread local storage. And in Windows, in the FLS destructor, we will create the thread_local variable to defer the destruction of the ThreadHolder. We ensure that this destructor is called after the other FLS destructors are called in Windows 10. This patch is performance neutral. * WTF.xcodeproj/project.pbxproj: * benchmarks/ConditionSpeedTest.cpp: * benchmarks/LockFairnessTest.cpp: * benchmarks/LockSpeedTest.cpp: * wtf/AutomaticThread.cpp: (WTF::AutomaticThread::start): * wtf/CMakeLists.txt: * wtf/MainThread.h: * wtf/MemoryPressureHandler.h: * wtf/ParallelJobsGeneric.cpp: (WTF::ParallelEnvironment::ThreadPrivate::tryLockFor): (WTF::ParallelEnvironment::ThreadPrivate::workerThread): * wtf/ParallelJobsGeneric.h: (WTF::ParallelEnvironment::ThreadPrivate::ThreadPrivate): Deleted. * wtf/ParkingLot.cpp: (WTF::ParkingLot::forEachImpl): * wtf/ParkingLot.h: (WTF::ParkingLot::forEach): * wtf/PlatformRegisters.h: Renamed from Source/JavaScriptCore/runtime/PlatformThread.h. * wtf/RefPtr.h: (WTF::RefPtr::RefPtr): * wtf/ThreadFunctionInvocation.h: (WTF::ThreadFunctionInvocation::ThreadFunctionInvocation): * wtf/ThreadHolder.cpp: Added. (WTF::ThreadHolder::~ThreadHolder): (WTF::ThreadHolder::initialize): * wtf/ThreadHolder.h: Renamed from Source/WTF/wtf/ThreadIdentifierDataPthreads.h. (WTF::ThreadHolder::thread): (WTF::ThreadHolder::ThreadHolder): * wtf/ThreadHolderPthreads.cpp: Renamed from Source/WTF/wtf/ThreadIdentifierDataPthreads.cpp. (WTF::ThreadHolder::initializeOnce): (WTF::ThreadHolder::current): (WTF::ThreadHolder::destruct): * wtf/ThreadHolderWin.cpp: Added. (WTF::threadMapMutex): (WTF::threadMap): (WTF::ThreadHolder::initializeOnce): (WTF::ThreadHolder::current): (WTF::ThreadHolder::destruct): * wtf/ThreadSpecific.h: * wtf/Threading.cpp: (WTF::Thread::normalizeThreadName): (WTF::threadEntryPoint): (WTF::Thread::create): (WTF::Thread::setCurrentThreadIsUserInteractive): (WTF::Thread::setCurrentThreadIsUserInitiated): (WTF::Thread::setGlobalMaxQOSClass): (WTF::Thread::adjustedQOSClass): (WTF::Thread::dump): (WTF::initializeThreading): (WTF::normalizeThreadName): Deleted. (WTF::createThread): Deleted. (WTF::setCurrentThreadIsUserInteractive): Deleted. (WTF::setCurrentThreadIsUserInitiated): Deleted. (WTF::setGlobalMaxQOSClass): Deleted. (WTF::adjustedQOSClass): Deleted. * wtf/Threading.h: (WTF::Thread::id): (WTF::Thread::operator==): (WTF::Thread::operator!=): (WTF::Thread::joinableState): (WTF::Thread::didBecomeDetached): (WTF::Thread::didJoin): (WTF::Thread::hasExited): (WTF::currentThread): * wtf/ThreadingPthreads.cpp: (WTF::Thread::Thread): (WTF::Thread::~Thread): (WTF::Thread::signalHandlerSuspendResume): (WTF::Thread::initializePlatformThreading): (WTF::initializeCurrentThreadEvenIfNonWTFCreated): (WTF::wtfThreadEntryPoint): (WTF::Thread::createInternal): (WTF::Thread::initializeCurrentThreadInternal): (WTF::Thread::changePriority): (WTF::Thread::waitForCompletion): (WTF::Thread::detach): (WTF::Thread::current): (WTF::Thread::currentID): (WTF::Thread::signal): (WTF::Thread::resume): (WTF::Thread::getRegisters): (WTF::Thread::didExit): (WTF::Thread::establish): (WTF::PthreadState::PthreadState): Deleted. (WTF::PthreadState::joinableState): Deleted. (WTF::PthreadState::pthreadHandle): Deleted. (WTF::PthreadState::didBecomeDetached): Deleted. (WTF::PthreadState::didExit): Deleted. (WTF::PthreadState::didJoin): Deleted. (WTF::PthreadState::hasExited): Deleted. (WTF::threadMapMutex): Deleted. (WTF::initializeThreading): Deleted. (WTF::threadMap): Deleted. (WTF::identifierByPthreadHandle): Deleted. (WTF::establishIdentifierForPthreadHandle): Deleted. (WTF::pthreadHandleForIdentifierWithLockAlreadyHeld): Deleted. (WTF::createThreadInternal): Deleted. (WTF::initializeCurrentThreadInternal): Deleted. (WTF::changeThreadPriority): Deleted. (WTF::waitForThreadCompletion): Deleted. (WTF::detachThread): Deleted. (WTF::threadDidExit): Deleted. (WTF::currentThread): Deleted. (WTF::signalThread): Deleted. * wtf/ThreadingWin.cpp: (WTF::Thread::Thread): (WTF::Thread::~Thread): (WTF::Thread::initializeCurrentThreadInternal): (WTF::Thread::initializePlatformThreading): (WTF::wtfThreadEntryPoint): (WTF::Thread::createInternal): (WTF::Thread::changePriority): (WTF::Thread::waitForCompletion): (WTF::Thread::detach): (WTF::Thread::resume): (WTF::Thread::getRegisters): (WTF::Thread::current): (WTF::Thread::currentID): (WTF::Thread::didExit): (WTF::Thread::establish): (WTF::initializeCurrentThreadInternal): Deleted. (WTF::threadMapMutex): Deleted. (WTF::initializeThreading): Deleted. (WTF::threadMap): Deleted. (WTF::storeThreadHandleByIdentifier): Deleted. (WTF::threadHandleForIdentifier): Deleted. (WTF::clearThreadHandleForIdentifier): Deleted. (WTF::createThreadInternal): Deleted. (WTF::changeThreadPriority): Deleted. (WTF::waitForThreadCompletion): Deleted. (WTF::detachThread): Deleted. (WTF::currentThread): Deleted. * wtf/WorkQueue.cpp: (WTF::WorkQueue::concurrentApply): * wtf/WorkQueue.h: * wtf/cocoa/WorkQueueCocoa.cpp: (WTF::dispatchQOSClass): * wtf/generic/WorkQueueGeneric.cpp: (WorkQueue::platformInitialize): (WorkQueue::platformInvalidate): * wtf/linux/MemoryPressureHandlerLinux.cpp: (WTF::MemoryPressureHandler::EventFDPoller::EventFDPoller): (WTF::MemoryPressureHandler::EventFDPoller::~EventFDPoller): * wtf/win/MainThreadWin.cpp: (WTF::initializeMainThreadPlatform): Tools: Mechanical change. Use Thread:: APIs. * DumpRenderTree/JavaScriptThreading.cpp: (runJavaScriptThread): (startJavaScriptThreads): (stopJavaScriptThreads): * DumpRenderTree/mac/DumpRenderTree.mm: (testThreadIdentifierMap): * TestWebKitAPI/Tests/WTF/Condition.cpp: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::runLockTest): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Canonical link: https://commits.webkit.org/187690@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@215265 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-04-12 12:08:29 +00:00
NEVER_INLINE void ParkingLot::forEachImpl(const ScopedLambda<void(Thread&, const void*)>& callback)
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
{
Vector<Bucket*> bucketsToUnlock = lockHashtable();
Hashtable* currentHashtable = hashtable.load();
for (unsigned i = currentHashtable->size; i--;) {
Bucket* bucket = currentHashtable->data[i].load();
if (!bucket)
continue;
for (ThreadData* currentThreadData = bucket->queueHead; currentThreadData; currentThreadData = currentThreadData->nextInQueue)
[WTF] Introduce Thread class and use RefPtr<Thread> and align Windows Threading implementation semantics to Pthread one https://bugs.webkit.org/show_bug.cgi?id=170502 Reviewed by Mark Lam. Source/JavaScriptCore: * API/tests/CompareAndSwapTest.cpp: (testCompareAndSwap): * JavaScriptCore.xcodeproj/project.pbxproj: * b3/air/testair.cpp: * b3/testb3.cpp: (JSC::B3::run): * bytecode/SuperSampler.cpp: (JSC::initializeSuperSampler): * dfg/DFGWorklist.cpp: * disassembler/Disassembler.cpp: * heap/Heap.cpp: (JSC::Heap::lastChanceToFinalize): (JSC::Heap::notifyIsSafeToCollect): * heap/Heap.h: * heap/MachineStackMarker.cpp: (JSC::MachineThreads::~MachineThreads): (JSC::MachineThreads::addCurrentThread): (JSC::MachineThreads::removeThread): (JSC::MachineThreads::removeThreadIfFound): (JSC::MachineThreads::MachineThread::MachineThread): (JSC::MachineThreads::MachineThread::getRegisters): (JSC::MachineThreads::MachineThread::Registers::stackPointer): (JSC::MachineThreads::MachineThread::Registers::framePointer): (JSC::MachineThreads::MachineThread::Registers::instructionPointer): (JSC::MachineThreads::MachineThread::Registers::llintPC): (JSC::MachineThreads::MachineThread::captureStack): (JSC::MachineThreads::tryCopyOtherThreadStack): (JSC::MachineThreads::tryCopyOtherThreadStacks): (pthreadSignalHandlerSuspendResume): Deleted. (JSC::threadData): Deleted. (JSC::MachineThreads::Thread::Thread): Deleted. (JSC::MachineThreads::Thread::createForCurrentThread): Deleted. (JSC::MachineThreads::Thread::operator==): Deleted. (JSC::MachineThreads::machineThreadForCurrentThread): Deleted. (JSC::MachineThreads::ThreadData::ThreadData): Deleted. (JSC::MachineThreads::ThreadData::~ThreadData): Deleted. (JSC::MachineThreads::ThreadData::suspend): Deleted. (JSC::MachineThreads::ThreadData::resume): Deleted. (JSC::MachineThreads::ThreadData::getRegisters): Deleted. (JSC::MachineThreads::ThreadData::Registers::stackPointer): Deleted. (JSC::MachineThreads::ThreadData::Registers::framePointer): Deleted. (JSC::MachineThreads::ThreadData::Registers::instructionPointer): Deleted. (JSC::MachineThreads::ThreadData::Registers::llintPC): Deleted. (JSC::MachineThreads::ThreadData::freeRegisters): Deleted. (JSC::MachineThreads::ThreadData::captureStack): Deleted. * heap/MachineStackMarker.h: (JSC::MachineThreads::MachineThread::suspend): (JSC::MachineThreads::MachineThread::resume): (JSC::MachineThreads::MachineThread::threadID): (JSC::MachineThreads::MachineThread::stackBase): (JSC::MachineThreads::MachineThread::stackEnd): (JSC::MachineThreads::threadsListHead): (JSC::MachineThreads::Thread::operator!=): Deleted. (JSC::MachineThreads::Thread::suspend): Deleted. (JSC::MachineThreads::Thread::resume): Deleted. (JSC::MachineThreads::Thread::getRegisters): Deleted. (JSC::MachineThreads::Thread::freeRegisters): Deleted. (JSC::MachineThreads::Thread::captureStack): Deleted. (JSC::MachineThreads::Thread::platformThread): Deleted. (JSC::MachineThreads::Thread::stackBase): Deleted. (JSC::MachineThreads::Thread::stackEnd): Deleted. * jit/ICStats.cpp: (JSC::ICStats::ICStats): (JSC::ICStats::~ICStats): * jit/ICStats.h: * jsc.cpp: (functionDollarAgentStart): (startTimeoutThreadIfNeeded): * runtime/JSLock.cpp: (JSC::JSLock::lock): * runtime/JSLock.h: (JSC::JSLock::ownerThread): (JSC::JSLock::currentThreadIsHoldingLock): * runtime/SamplingProfiler.cpp: (JSC::FrameWalker::isValidFramePointer): (JSC::SamplingProfiler::SamplingProfiler): (JSC::SamplingProfiler::createThreadIfNecessary): (JSC::SamplingProfiler::takeSample): * runtime/SamplingProfiler.h: * runtime/VM.h: (JSC::VM::ownerThread): * runtime/VMTraps.cpp: (JSC::findActiveVMAndStackBounds): (JSC::VMTraps::SignalSender::send): (JSC::VMTraps::fireTrap): Source/WebCore: Mechanical change. Use Thread:: APIs. * Modules/indexeddb/server/IDBServer.cpp: (WebCore::IDBServer::IDBServer::IDBServer): * Modules/indexeddb/server/IDBServer.h: * Modules/webaudio/AsyncAudioDecoder.cpp: (WebCore::AsyncAudioDecoder::AsyncAudioDecoder): (WebCore::AsyncAudioDecoder::~AsyncAudioDecoder): (WebCore::AsyncAudioDecoder::runLoop): * Modules/webaudio/AsyncAudioDecoder.h: * Modules/webaudio/OfflineAudioDestinationNode.cpp: (WebCore::OfflineAudioDestinationNode::OfflineAudioDestinationNode): (WebCore::OfflineAudioDestinationNode::uninitialize): (WebCore::OfflineAudioDestinationNode::startRendering): * Modules/webaudio/OfflineAudioDestinationNode.h: * Modules/webdatabase/Database.cpp: (WebCore::Database::securityOrigin): * Modules/webdatabase/DatabaseThread.cpp: (WebCore::DatabaseThread::start): (WebCore::DatabaseThread::databaseThread): (WebCore::DatabaseThread::recordDatabaseOpen): (WebCore::DatabaseThread::recordDatabaseClosed): * Modules/webdatabase/DatabaseThread.h: (WebCore::DatabaseThread::getThreadID): * bindings/js/GCController.cpp: (WebCore::GCController::garbageCollectOnAlternateThreadForDebugging): * fileapi/AsyncFileStream.cpp: (WebCore::callOnFileThread): * loader/icon/IconDatabase.cpp: (WebCore::IconDatabase::open): (WebCore::IconDatabase::close): * loader/icon/IconDatabase.h: * page/ResourceUsageThread.cpp: (WebCore::ResourceUsageThread::createThreadIfNeeded): * page/ResourceUsageThread.h: * page/scrolling/ScrollingThread.cpp: (WebCore::ScrollingThread::ScrollingThread): (WebCore::ScrollingThread::isCurrentThread): (WebCore::ScrollingThread::createThreadIfNeeded): (WebCore::ScrollingThread::threadCallback): * page/scrolling/ScrollingThread.h: * platform/audio/HRTFDatabaseLoader.cpp: (WebCore::HRTFDatabaseLoader::HRTFDatabaseLoader): (WebCore::HRTFDatabaseLoader::loadAsynchronously): (WebCore::HRTFDatabaseLoader::waitForLoaderThreadCompletion): * platform/audio/HRTFDatabaseLoader.h: * platform/audio/ReverbConvolver.cpp: (WebCore::ReverbConvolver::ReverbConvolver): (WebCore::ReverbConvolver::~ReverbConvolver): * platform/audio/ReverbConvolver.h: * platform/audio/gstreamer/AudioFileReaderGStreamer.cpp: (WebCore::createBusFromAudioFile): (WebCore::createBusFromInMemoryAudioFile): * platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp: (ResourceHandleStreamingClient::ResourceHandleStreamingClient): (ResourceHandleStreamingClient::~ResourceHandleStreamingClient): * platform/network/cf/LoaderRunLoopCF.cpp: (WebCore::loaderRunLoop): * platform/network/curl/CurlDownload.cpp: (WebCore::CurlDownloadManager::startThreadIfNeeded): (WebCore::CurlDownloadManager::stopThread): * platform/network/curl/CurlDownload.h: * platform/network/curl/SocketStreamHandleImpl.h: * platform/network/curl/SocketStreamHandleImplCurl.cpp: (WebCore::SocketStreamHandleImpl::startThread): (WebCore::SocketStreamHandleImpl::stopThread): * workers/WorkerThread.cpp: (WebCore::WorkerThread::WorkerThread): (WebCore::WorkerThread::start): (WebCore::WorkerThread::workerThread): * workers/WorkerThread.h: (WebCore::WorkerThread::threadID): Source/WebKit: Mechanical change. Use Thread:: APIs. * Storage/StorageThread.cpp: (WebCore::StorageThread::StorageThread): (WebCore::StorageThread::~StorageThread): (WebCore::StorageThread::start): (WebCore::StorageThread::dispatch): (WebCore::StorageThread::terminate): * Storage/StorageThread.h: Source/WebKit2: Mechanical change. Use Thread:: APIs. * NetworkProcess/NetworkProcess.cpp: (WebKit::NetworkProcess::initializeNetworkProcess): * NetworkProcess/cache/NetworkCacheIOChannelSoup.cpp: (WebKit::NetworkCache::IOChannel::readSyncInThread): * Platform/IPC/Connection.cpp: (IPC::Connection::processIncomingMessage): * Shared/EntryPointUtilities/mac/XPCService/XPCServiceEntryPoint.h: (WebKit::XPCServiceInitializer): * UIProcess/linux/MemoryPressureMonitor.cpp: (WebKit::MemoryPressureMonitor::MemoryPressureMonitor): * WebProcess/WebProcess.cpp: (WebKit::WebProcess::initializeWebProcess): Source/WTF: This patch is refactoring of WTF Threading mechanism to merge JavaScriptCore's threading extension to WTF Threading. Previously, JavaScriptCore requires richer threading features (such as suspending and resuming threads), and they are implemented for PlatformThread in JavaScriptCore. But these features should be implemented in WTF Threading side instead of maintaining JSC's own threading features too. This patch removes these features from JSC and move it to WTF Threading. However, current WTF Threading has one problem: Windows version of WTF Threading has different semantics from Pthreads one. In Windows WTF Threading, we cannot perform any operation after the target thread is detached: WTF Threading stop tracking the state of the thread once the thread is detached. But this is not the same to Pthreads one. In Pthreads, pthread_detach just means that the resource of the thread will be destroyed automatically. While some operations like pthread_join will be rejected, some operations like pthread_kill will be accepted. The problem is that detached thread can be suspended and resumed in JSC. For example, in jsc.cpp, we start the worker thread and detach it immediately. In worker thread, we will create VM and thus concurrent GC will suspend and resume the detached thread. However, in Windows WTF Threading, we have no reference to the detached thread. Thus we cannot perform suspend and resume operations onto the detached thread. To solve the problem, we change Windows Threading mechanism drastically to align it to the Pthread semantics. In the new Threading, we have RefPtr<Thread> class. It holds a handle to a platform thread. We can perform threading operations with this class. For example, Thread::suspend is offered. And we use destructor of the thread local variable to release the resources held by RefPtr<Thread>. In Windows, Thread::detach does nothing because the resource will be destroyed automatically by RefPtr<Thread>. To do so, we introduce ThreadHolder for Windows. This is similar to the previous ThreadIdentifierData for Pthreads. It holds RefPtr<Thread> in the thread local storage (technically, it is Fiber Local Storage in Windows). Thread::current() will return this reference. The problematic situation is that the order of the deallocation of the thread local storage is not defined. So we should not touch thread local storage in the destructor of the thread local storage. To avoid such edge cases, we have currentThread() / Thread::currentID() APIs. They are safe to be called even in the destructor of the other thread local storage. And in Windows, in the FLS destructor, we will create the thread_local variable to defer the destruction of the ThreadHolder. We ensure that this destructor is called after the other FLS destructors are called in Windows 10. This patch is performance neutral. * WTF.xcodeproj/project.pbxproj: * benchmarks/ConditionSpeedTest.cpp: * benchmarks/LockFairnessTest.cpp: * benchmarks/LockSpeedTest.cpp: * wtf/AutomaticThread.cpp: (WTF::AutomaticThread::start): * wtf/CMakeLists.txt: * wtf/MainThread.h: * wtf/MemoryPressureHandler.h: * wtf/ParallelJobsGeneric.cpp: (WTF::ParallelEnvironment::ThreadPrivate::tryLockFor): (WTF::ParallelEnvironment::ThreadPrivate::workerThread): * wtf/ParallelJobsGeneric.h: (WTF::ParallelEnvironment::ThreadPrivate::ThreadPrivate): Deleted. * wtf/ParkingLot.cpp: (WTF::ParkingLot::forEachImpl): * wtf/ParkingLot.h: (WTF::ParkingLot::forEach): * wtf/PlatformRegisters.h: Renamed from Source/JavaScriptCore/runtime/PlatformThread.h. * wtf/RefPtr.h: (WTF::RefPtr::RefPtr): * wtf/ThreadFunctionInvocation.h: (WTF::ThreadFunctionInvocation::ThreadFunctionInvocation): * wtf/ThreadHolder.cpp: Added. (WTF::ThreadHolder::~ThreadHolder): (WTF::ThreadHolder::initialize): * wtf/ThreadHolder.h: Renamed from Source/WTF/wtf/ThreadIdentifierDataPthreads.h. (WTF::ThreadHolder::thread): (WTF::ThreadHolder::ThreadHolder): * wtf/ThreadHolderPthreads.cpp: Renamed from Source/WTF/wtf/ThreadIdentifierDataPthreads.cpp. (WTF::ThreadHolder::initializeOnce): (WTF::ThreadHolder::current): (WTF::ThreadHolder::destruct): * wtf/ThreadHolderWin.cpp: Added. (WTF::threadMapMutex): (WTF::threadMap): (WTF::ThreadHolder::initializeOnce): (WTF::ThreadHolder::current): (WTF::ThreadHolder::destruct): * wtf/ThreadSpecific.h: * wtf/Threading.cpp: (WTF::Thread::normalizeThreadName): (WTF::threadEntryPoint): (WTF::Thread::create): (WTF::Thread::setCurrentThreadIsUserInteractive): (WTF::Thread::setCurrentThreadIsUserInitiated): (WTF::Thread::setGlobalMaxQOSClass): (WTF::Thread::adjustedQOSClass): (WTF::Thread::dump): (WTF::initializeThreading): (WTF::normalizeThreadName): Deleted. (WTF::createThread): Deleted. (WTF::setCurrentThreadIsUserInteractive): Deleted. (WTF::setCurrentThreadIsUserInitiated): Deleted. (WTF::setGlobalMaxQOSClass): Deleted. (WTF::adjustedQOSClass): Deleted. * wtf/Threading.h: (WTF::Thread::id): (WTF::Thread::operator==): (WTF::Thread::operator!=): (WTF::Thread::joinableState): (WTF::Thread::didBecomeDetached): (WTF::Thread::didJoin): (WTF::Thread::hasExited): (WTF::currentThread): * wtf/ThreadingPthreads.cpp: (WTF::Thread::Thread): (WTF::Thread::~Thread): (WTF::Thread::signalHandlerSuspendResume): (WTF::Thread::initializePlatformThreading): (WTF::initializeCurrentThreadEvenIfNonWTFCreated): (WTF::wtfThreadEntryPoint): (WTF::Thread::createInternal): (WTF::Thread::initializeCurrentThreadInternal): (WTF::Thread::changePriority): (WTF::Thread::waitForCompletion): (WTF::Thread::detach): (WTF::Thread::current): (WTF::Thread::currentID): (WTF::Thread::signal): (WTF::Thread::resume): (WTF::Thread::getRegisters): (WTF::Thread::didExit): (WTF::Thread::establish): (WTF::PthreadState::PthreadState): Deleted. (WTF::PthreadState::joinableState): Deleted. (WTF::PthreadState::pthreadHandle): Deleted. (WTF::PthreadState::didBecomeDetached): Deleted. (WTF::PthreadState::didExit): Deleted. (WTF::PthreadState::didJoin): Deleted. (WTF::PthreadState::hasExited): Deleted. (WTF::threadMapMutex): Deleted. (WTF::initializeThreading): Deleted. (WTF::threadMap): Deleted. (WTF::identifierByPthreadHandle): Deleted. (WTF::establishIdentifierForPthreadHandle): Deleted. (WTF::pthreadHandleForIdentifierWithLockAlreadyHeld): Deleted. (WTF::createThreadInternal): Deleted. (WTF::initializeCurrentThreadInternal): Deleted. (WTF::changeThreadPriority): Deleted. (WTF::waitForThreadCompletion): Deleted. (WTF::detachThread): Deleted. (WTF::threadDidExit): Deleted. (WTF::currentThread): Deleted. (WTF::signalThread): Deleted. * wtf/ThreadingWin.cpp: (WTF::Thread::Thread): (WTF::Thread::~Thread): (WTF::Thread::initializeCurrentThreadInternal): (WTF::Thread::initializePlatformThreading): (WTF::wtfThreadEntryPoint): (WTF::Thread::createInternal): (WTF::Thread::changePriority): (WTF::Thread::waitForCompletion): (WTF::Thread::detach): (WTF::Thread::resume): (WTF::Thread::getRegisters): (WTF::Thread::current): (WTF::Thread::currentID): (WTF::Thread::didExit): (WTF::Thread::establish): (WTF::initializeCurrentThreadInternal): Deleted. (WTF::threadMapMutex): Deleted. (WTF::initializeThreading): Deleted. (WTF::threadMap): Deleted. (WTF::storeThreadHandleByIdentifier): Deleted. (WTF::threadHandleForIdentifier): Deleted. (WTF::clearThreadHandleForIdentifier): Deleted. (WTF::createThreadInternal): Deleted. (WTF::changeThreadPriority): Deleted. (WTF::waitForThreadCompletion): Deleted. (WTF::detachThread): Deleted. (WTF::currentThread): Deleted. * wtf/WorkQueue.cpp: (WTF::WorkQueue::concurrentApply): * wtf/WorkQueue.h: * wtf/cocoa/WorkQueueCocoa.cpp: (WTF::dispatchQOSClass): * wtf/generic/WorkQueueGeneric.cpp: (WorkQueue::platformInitialize): (WorkQueue::platformInvalidate): * wtf/linux/MemoryPressureHandlerLinux.cpp: (WTF::MemoryPressureHandler::EventFDPoller::EventFDPoller): (WTF::MemoryPressureHandler::EventFDPoller::~EventFDPoller): * wtf/win/MainThreadWin.cpp: (WTF::initializeMainThreadPlatform): Tools: Mechanical change. Use Thread:: APIs. * DumpRenderTree/JavaScriptThreading.cpp: (runJavaScriptThread): (startJavaScriptThreads): (stopJavaScriptThreads): * DumpRenderTree/mac/DumpRenderTree.mm: (testThreadIdentifierMap): * TestWebKitAPI/Tests/WTF/Condition.cpp: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::runLockTest): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Canonical link: https://commits.webkit.org/187690@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@215265 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-04-12 12:08:29 +00:00
callback(currentThreadData->thread.get(), currentThreadData->address);
WTF should have a ParkingLot for parking sleeping threads, so that locks can fit in 1.6 bits https://bugs.webkit.org/show_bug.cgi?id=147665 Reviewed by Mark Lam. Source/JavaScriptCore: Replace ByteSpinLock with ByteLock. * runtime/ConcurrentJITLock.h: Source/WTF: This change adds a major new abstraction for concurrency algorithms in WebKit. It's called a ParkingLot, and it makes available a thread parking queue for each virtual address in memory. The queues are maintained by a data-access-parallel concurrent hashtable implementation. The memory usage is bounded at around half a KB per thread. The ParkingLot makes it easy to turn any spinlock-based concurrency protocol into one that parks threads after a while. Because queue state management is up to the ParkingLot and not the user's data structure, this patch uses it to implement a full adaptive mutex in one byte. In fact, only three states of that byte are used (0 = available, 1 = locked, 2 = locked and there are parked threads). Hence the joke that ParkingLot allows locks that fit in 1.6 bits. ByteLock is used as a replacement for ByteSpinLock in JavaScriptCore. The API tests for this also demo how to create a completely fair (FIFO) binary semamphore. The comment in Lock.h shows how we could accelerate Lock performance using ParkingLot. After we are sure that this code works, we can expand the use of ParkingLot. That's covered by https://bugs.webkit.org/show_bug.cgi?id=147841. * WTF.vcxproj/WTF.vcxproj: * WTF.xcodeproj/project.pbxproj: * benchmarks/LockSpeedTest.cpp: (main): * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeak): (WTF::Atomic::compareExchangeStrong): * wtf/ByteLock.cpp: Added. (WTF::ByteLock::lockSlow): (WTF::ByteLock::unlockSlow): * wtf/ByteLock.h: Added. (WTF::ByteLock::ByteLock): (WTF::ByteLock::lock): (WTF::ByteLock::unlock): (WTF::ByteLock::isHeld): (WTF::ByteLock::isLocked): * wtf/CMakeLists.txt: * wtf/Lock.h: * wtf/ParkingLot.cpp: Added. (WTF::ParkingLot::parkConditionally): (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkAll): (WTF::ParkingLot::forEach): * wtf/ParkingLot.h: Added. (WTF::ParkingLot::compareAndPark): Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/Lock.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WTF/ParkingLot.cpp: Added. (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/165996@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-11 19:51:35 +00:00
}
unlockHashtable(bucketsToUnlock);
}
} // namespace WTF