Changeset 188400 in webkit
- Timestamp:
- Aug 13, 2015 1:42:11 PM (9 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 12 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WTF/ChangeLog
r188386 r188400 1 2015-08-13 Filip Pizlo <fpizlo@apple.com> 2 3 WTF should have a compact Condition object to use with Lock 4 https://bugs.webkit.org/show_bug.cgi?id=147986 5 6 Reviewed by Geoffrey Garen. 7 8 Adds a condition variable implementation based on ParkingLot, called simply WTF::Condition. 9 It can be used with WTF::Lock or actually any lock implementation. It should even work with 10 WTF::SpinLock, WTF::Mutex, or std::mutex. Best of all, Condition only requires one byte. 11 12 ParkingLot almost contained all of the functionality needed to implemenet wait/notify. We 13 could have implemented Condition using a 32-bit (or even 64-bit) version that protects 14 against a notify that happens just before we park. But, this changes the ParkingLot API to 15 give us the ability to run some code between when ParkingLot enqueues the current thread 16 and when it actually sleeps. This callback is called with no locks held, so it can call 17 unlock() on any kind of lock, so long as that lock's unlock() method doesn't recurse into 18 ParkingLot::parkConditionally(). That seems unlikely; unlock() is more likely to call 19 ParkingLot::unparkOne() or unparkAll(). WTF::Lock will never call parkConditionally() 20 inside unlock(), so WTF::Lock is definitely appropriate for use with Condition. 21 22 Condition supports most of the API that std::condition_variable supports. It does some 23 things to try to reduce footgun potential. The preferred timeout form is waitUntil() which 24 takes an absolute time from the steady_clock. The only relative timeout form also takes a 25 predicate callback, so it's impossible to write the subtly incorrect 26 "while (...) wait_for(...)" idiom. 27 28 This patch doesn't actually introduce any uses of WTF::Condition other than the unit tests. 29 I'll start switching code over to using WTF::Condition in another patch. 30 31 * WTF.vcxproj/WTF.vcxproj: 32 * WTF.xcodeproj/project.pbxproj: 33 * wtf/CMakeLists.txt: 34 * wtf/Condition.h: Added. 35 (WTF::Condition::Condition): 36 (WTF::Condition::waitUntil): 37 (WTF::Condition::waitFor): 38 (WTF::Condition::wait): 39 (WTF::Condition::notifyOne): 40 (WTF::Condition::notifyAll): 41 * wtf/Lock.cpp: 42 (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. 43 * wtf/ParkingLot.cpp: 44 (WTF::ParkingLot::parkConditionally): Add the beforeSleep() callback. 45 (WTF::ParkingLot::unparkOne): 46 * wtf/ParkingLot.h: 47 (WTF::ParkingLot::compareAndPark): 48 1 49 2015-08-12 Anders Carlsson <andersca@apple.com> 2 50 -
trunk/Source/WTF/WTF.vcxproj/WTF.vcxproj
r188323 r188400 177 177 <ClInclude Include="..\wtf\CheckedBoolean.h" /> 178 178 <ClInclude Include="..\wtf\Compiler.h" /> 179 <ClInclude Include="..\wtf\Condition.h" /> 179 180 <ClInclude Include="..\wtf\CryptographicUtilities.h" /> 180 181 <ClInclude Include="..\wtf\CryptographicallyRandomNumber.h" /> -
trunk/Source/WTF/WTF.xcodeproj/project.pbxproj
r188323 r188400 41 41 0FC4EDE61696149600F65041 /* CommaPrinter.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FC4EDE51696149600F65041 /* CommaPrinter.h */; }; 42 42 0FD81AC5154FB22E00983E72 /* FastBitVector.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD81AC4154FB22E00983E72 /* FastBitVector.h */; settings = {ATTRIBUTES = (); }; }; 43 0FDB698E1B7C643A000C1078 /* Condition.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FDB698D1B7C643A000C1078 /* Condition.h */; }; 43 44 0FDDBFA71666DFA300C55FEF /* StringPrintStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FDDBFA51666DFA300C55FEF /* StringPrintStream.cpp */; }; 44 45 0FDDBFA81666DFA300C55FEF /* StringPrintStream.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FDDBFA61666DFA300C55FEF /* StringPrintStream.h */; }; … … 328 329 0FC4EDE51696149600F65041 /* CommaPrinter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CommaPrinter.h; sourceTree = "<group>"; }; 329 330 0FD81AC4154FB22E00983E72 /* FastBitVector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FastBitVector.h; sourceTree = "<group>"; }; 331 0FDB698D1B7C643A000C1078 /* Condition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Condition.h; sourceTree = "<group>"; }; 330 332 0FDDBFA51666DFA300C55FEF /* StringPrintStream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StringPrintStream.cpp; sourceTree = "<group>"; }; 331 333 0FDDBFA61666DFA300C55FEF /* StringPrintStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StringPrintStream.h; sourceTree = "<group>"; }; … … 731 733 0F8F2B90172E00F0007DBDA5 /* CompilationThread.h */, 732 734 A8A47270151A825A004123FF /* Compiler.h */, 735 0FDB698D1B7C643A000C1078 /* Condition.h */, 733 736 E15556F318A0CC18006F48FB /* CryptographicUtilities.cpp */, 734 737 E15556F418A0CC18006F48FB /* CryptographicUtilities.h */, … … 1186 1189 A8A47424151A825B004123FF /* SinglyLinkedList.h in Headers */, 1187 1190 A748745317A0BDAE00FA04CB /* SixCharacterHash.h in Headers */, 1191 0FDB698E1B7C643A000C1078 /* Condition.h in Headers */, 1188 1192 A8A47426151A825B004123FF /* Spectrum.h in Headers */, 1189 1193 A8A47428151A825B004123FF /* StackBounds.h in Headers */, -
trunk/Source/WTF/wtf/CMakeLists.txt
r188323 r188400 11 11 CompilationThread.h 12 12 Compiler.h 13 Condition.h 13 14 CryptographicUtilities.h 14 15 CryptographicallyRandomNumber.h -
trunk/Source/WTF/wtf/Lock.cpp
r188374 r188400 82 82 for (;;) { 83 83 uint8_t oldByteValue = m_byte.load(); 84 ASSERT(oldByteValue == isHeldBit || oldByteValue == (isHeldBit | hasParkedBit));84 RELEASE_ASSERT(oldByteValue == isHeldBit || oldByteValue == (isHeldBit | hasParkedBit)); 85 85 86 86 if (oldByteValue == isHeldBit) { -
trunk/Source/WTF/wtf/ParkingLot.cpp
r188374 r188400 508 508 } // anonymous namespace 509 509 510 bool ParkingLot::parkConditionally(const void* address, std::function<bool()> validation) 510 bool ParkingLot::parkConditionally( 511 const void* address, 512 std::function<bool()> validation, 513 std::function<void()> beforeSleep, 514 std::chrono::steady_clock::time_point timeout) 511 515 { 512 516 if (verbose) … … 514 518 515 519 ThreadData* me = myThreadData(); 520 521 // Guard against someone calling parkConditionally() recursively from beforeSleep(). 522 RELEASE_ASSERT(!me->address); 516 523 517 524 bool result = enqueue( … … 528 535 return false; 529 536 530 if (verbose) 531 dataLog(toString(currentThread(), ": parking self: ", RawPointer(me), "\n")); 537 beforeSleep(); 538 539 bool didGetDequeued; 532 540 { 533 541 std::unique_lock<std::mutex> locker(me->parkingLock); 534 while (me->address) 535 me->parkingCondition.wait(locker); 536 } 537 if (verbose) 538 dataLog(toString(currentThread(), ": unparked self: ", RawPointer(me), "\n")); 539 return true; 542 while (me->address && std::chrono::steady_clock::now() < timeout) 543 me->parkingCondition.wait_until(locker, timeout); 544 ASSERT(!me->address || me->address == address); 545 didGetDequeued = !me->address; 546 } 547 if (didGetDequeued) { 548 // Great! We actually got dequeued rather than the timeout expiring. 549 return true; 550 } 551 552 // Have to remove ourselves from the queue since we timed out and nobody has dequeued us yet. 553 554 // It's possible that we get unparked right here, just before dequeue() grabs a lock. It's 555 // probably worthwhile to detect when this happens, and return true in that case, to ensure 556 // that when we return false it really means that no unpark could have been responsible for us 557 // waking up, and that if an unpark call did happen, it woke someone else up. 558 bool didFind = false; 559 dequeue( 560 address, BucketMode::IgnoreEmpty, 561 [&] (ThreadData* element) { 562 if (element == me) { 563 didFind = true; 564 return DequeueResult::RemoveAndStop; 565 } 566 return DequeueResult::Ignore; 567 }, 568 [] (bool) { }); 569 570 ASSERT(!me->nextInQueue); 571 572 // Make sure that no matter what, me->address is null after this point. 573 { 574 std::lock_guard<std::mutex> locker(me->parkingLock); 575 me->address = nullptr; 576 } 577 578 // If we were not found in the search above, then we know that someone unparked us. 579 return !didFind; 540 580 } 541 581 -
trunk/Source/WTF/wtf/ParkingLot.h
r188374 r188400 27 27 #define WTF_ParkingLot_h 28 28 29 #include <chrono> 29 30 #include <functional> 30 31 #include <wtf/Atomics.h> … … 40 41 // Parks the thread in a queue associated with the given address, which cannot be null. The 41 42 // parking only succeeds if the validation function returns true while the queue lock is held. 42 // Returns true if the thread actually slept, or false if it returned quickly because of 43 // validation failure. 44 WTF_EXPORT_PRIVATE static bool parkConditionally(const void* address, std::function<bool()> validation); 43 // If validation returns false, it will unlock the internal parking queue and then it will 44 // return without doing anything else. If validation returns true, it will enqueue the thread, 45 // unlock the parking queue lock, call the beforeSleep function, and then it will sleep so long 46 // as the thread continues to be on the queue and the timeout hasn't fired. Finally, this 47 // returns true if we actually got unparked or false if the timeout was hit. Note that 48 // beforeSleep is called with no locks held, so it's OK to do pretty much anything so long as 49 // you don't recursively call parkConditionally(). You can call unparkOne()/unparkAll() though. 50 // It's useful to use beforeSleep() to unlock some mutex in the implementation of 51 // Condition::wait(). 52 WTF_EXPORT_PRIVATE static bool parkConditionally( 53 const void* address, 54 std::function<bool()> validation, 55 std::function<void()> beforeSleep, 56 std::chrono::steady_clock::time_point timeout); 45 57 58 // Simple version of parkConditionally() that covers the most common case: you want to park 59 // indefinitely so long as the value at the given address hasn't changed. 46 60 template<typename T, typename U> 47 61 static bool compareAndPark(const Atomic<T>* address, U expected) … … 52 66 U value = address->load(); 53 67 return value == expected; 54 }); 68 }, 69 [] () { }, 70 std::chrono::steady_clock::time_point::max()); 55 71 } 56 72 -
trunk/Tools/ChangeLog
r188387 r188400 1 2015-08-13 Filip Pizlo <fpizlo@apple.com> 2 3 WTF should have a compact Condition object to use with Lock 4 https://bugs.webkit.org/show_bug.cgi?id=147986 5 6 Reviewed by Geoffrey Garen. 7 8 Add a test for WTF::Condition. 9 10 * TestWebKitAPI/CMakeLists.txt: 11 * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj: 12 * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: 13 * TestWebKitAPI/Tests/WTF/Condition.cpp: Added. 14 (TestWebKitAPI::TEST): 15 * TestWebKitAPI/Tests/WTF/Lock.cpp: 16 (TestWebKitAPI::runLockTest): Change the name of the thread. 17 1 18 2015-08-13 Filip Pizlo <fpizlo@apple.com> 2 19 -
trunk/Tools/TestWebKitAPI/CMakeLists.txt
r188280 r188400 43 43 ${TESTWEBKITAPI_DIR}/Tests/WTF/AtomicString.cpp 44 44 ${TESTWEBKITAPI_DIR}/Tests/WTF/CString.cpp 45 ${TESTWEBKITAPI_DIR}/Tests/WTF/Condition.cpp 45 46 ${TESTWEBKITAPI_DIR}/Tests/WTF/CheckedArithmeticOperations.cpp 46 47 ${TESTWEBKITAPI_DIR}/Tests/WTF/DateMath.cpp -
trunk/Tools/TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj
r188291 r188400 1 <?xml version="1.0" encoding="utf-8"?>1 <?xml version="1.0" encoding="utf-8"?> 2 2 <Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 3 3 <ItemGroup Label="ProjectConfigurations"> … … 313 313 <ClCompile Include="..\Tests\WTF\cf\RetainPtrHashing.cpp" /> 314 314 <ClCompile Include="..\Tests\WTF\CheckedArithmeticOperations.cpp" /> 315 <ClCompile Include="..\Tests\WTF\Condition.cpp" /> 315 316 <ClCompile Include="..\Tests\WTF\CString.cpp" /> 316 317 <ClCompile Include="..\Tests\WTF\DateMath.cpp" /> -
trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
r188280 r188400 13 13 0F3B94A71A77267400DE3272 /* WKWebViewEvaluateJavaScript.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0F3B94A51A77266C00DE3272 /* WKWebViewEvaluateJavaScript.mm */; }; 14 14 0FE447991B76F1EB009498EB /* ParkingLot.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE447971B76F1E3009498EB /* ParkingLot.cpp */; }; 15 0FEAE3691B7D19D200CE17F2 /* Condition.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FEAE3671B7D19CB00CE17F2 /* Condition.cpp */; }; 15 16 0FFC45A61B73EBEB0085BD62 /* Lock.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FFC45A41B73EBE20085BD62 /* Lock.cpp */; }; 16 17 1A02C870125D4CFD00E3F4BD /* find.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 1A02C84B125D4A5E00E3F4BD /* find.html */; }; … … 432 433 0FC6C4CE141034AD005B7F0C /* MetaAllocator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MetaAllocator.cpp; sourceTree = "<group>"; }; 433 434 0FE447971B76F1E3009498EB /* ParkingLot.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParkingLot.cpp; sourceTree = "<group>"; }; 435 0FEAE3671B7D19CB00CE17F2 /* Condition.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Condition.cpp; sourceTree = "<group>"; }; 434 436 0FFC45A41B73EBE20085BD62 /* Lock.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Lock.cpp; sourceTree = "<group>"; }; 435 437 14464012167A8305000BD218 /* LayoutUnit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LayoutUnit.cpp; sourceTree = "<group>"; }; … … 1092 1094 26F1B44215CA434F00D1E4BF /* AtomicString.cpp */, 1093 1095 A7A966DA140ECCC8005EF9B4 /* CheckedArithmeticOperations.cpp */, 1096 0FEAE3671B7D19CB00CE17F2 /* Condition.cpp */, 1094 1097 26A2C72E15E2E73C005B1A14 /* CString.cpp */, 1095 1098 E40019301ACE9B5C001B0A2A /* BloomFilter.cpp */, … … 1495 1498 7CCE7EEF1A411AE600447C4C /* EphemeralSessionPushStateNoHistoryCallback.cpp in Sources */, 1496 1499 7CCE7EF01A411AE600447C4C /* EvaluateJavaScript.cpp in Sources */, 1500 0FEAE3691B7D19D200CE17F2 /* Condition.cpp in Sources */, 1497 1501 7CCE7EF11A411AE600447C4C /* FailedLoad.cpp in Sources */, 1498 1502 7CCE7EF31A411AE600447C4C /* Find.cpp in Sources */, -
trunk/Tools/TestWebKitAPI/Tests/WTF/Lock.cpp
r188387 r188400 54 54 for (unsigned threadIndex = numThreadsPerGroup; threadIndex--;) { 55 55 threads[threadGroupIndex * numThreadsPerGroup + threadIndex] = createThread( 56 " Benchmarkthread",56 "Lock test thread", 57 57 [threadGroupIndex, &locks, &words, numIterations, workPerCriticalSection] () { 58 58 for (unsigned i = numIterations; i--;) {
Note: See TracChangeset
for help on using the changeset viewer.