Modified: trunk/Source/WTF/wtf/Condition.h (278256 => 278257)
--- trunk/Source/WTF/wtf/Condition.h 2021-05-30 19:45:09 UTC (rev 278256)
+++ trunk/Source/WTF/wtf/Condition.h 2021-05-30 20:35:59 UTC (rev 278257)
@@ -40,16 +40,16 @@
// notifyAll() require just a load and branch for the fast case where no thread is waiting.
// This condition variable, when used with WTF::Lock, can outperform a system condition variable
// and lock by up to 58x.
-class UncheckedCondition final {
- WTF_MAKE_NONCOPYABLE(UncheckedCondition);
+class Condition final {
+ WTF_MAKE_NONCOPYABLE(Condition);
WTF_MAKE_FAST_ALLOCATED;
public:
- // UncheckedCondition will accept any kind of time and convert it internally, but this typedef tells
- // you what kind of time UncheckedCondition would be able to use without conversions. However, if you
+ // Condition will accept any kind of time and convert it internally, but this typedef tells
+ // you what kind of time Condition would be able to use without conversions. However, if you
// are unlikely to be affected by the cost of conversions, it is better to use MonotonicTime.
using Time = ParkingLot::Time;
- constexpr UncheckedCondition() = default;
+ constexpr Condition() = default;
// Wait on a parking queue while releasing the given lock. It will unlock the lock just before
// parking, and relock it upon wakeup. Returns true if we woke up due to some call to
@@ -69,47 +69,41 @@
template<typename LockType>
bool waitUntil(LockType& lock, const TimeWithDynamicClockType& timeout)
{
- bool result;
- if (timeout < timeout.nowWithSameClock()) {
- lock.unlock();
- result = false;
- } else {
- result = ParkingLot::parkConditionally(
- &m_hasWaiters,
- [this] () -> bool {
- // Let everyone know that we will be waiting. Do this while we hold the queue lock,
- // to prevent races with notifyOne().
- m_hasWaiters.store(true);
- return true;
- },
- [&lock] () { lock.unlock(); },
- timeout).wasUnparked;
- }
- lock.lock();
- return result;
+ return waitUntilUnchecked(lock, timeout);
}
+ bool waitUntil(Lock& lock, const TimeWithDynamicClockType& timeout) WTF_REQUIRES_LOCK(lock)
+ {
+ return waitUntilUnchecked(lock, timeout);
+ }
+
// Wait until the given predicate is satisfied. Returns true if it is satisfied in the end.
// May return early due to timeout.
template<typename LockType, typename Functor>
- bool waitUntil(
- LockType& lock, const TimeWithDynamicClockType& timeout, const Functor& predicate)
+ bool waitUntil(LockType& lock, const TimeWithDynamicClockType& timeout, const Functor& predicate)
{
- while (!predicate()) {
- if (!waitUntil(lock, timeout))
- return predicate();
- }
- return true;
+ return waitUntilUnchecked(lock, timeout, predicate);
}
+ template<typename Functor>
+ bool waitUntil(Lock& lock, const TimeWithDynamicClockType& timeout, const Functor& predicate) WTF_REQUIRES_LOCK(lock)
+ {
+ return waitUntilUnchecked(lock, timeout, predicate);
+ }
+
// Wait until the given predicate is satisfied. Returns true if it is satisfied in the end.
// May return early due to timeout.
template<typename LockType, typename Functor>
- bool waitFor(
- LockType& lock, Seconds relativeTimeout, const Functor& predicate)
+ bool waitFor(LockType& lock, Seconds relativeTimeout, const Functor& predicate)
{
return waitUntil(lock, MonotonicTime::now() + relativeTimeout, predicate);
}
+
+ template<typename Functor>
+ bool waitFor(Lock& lock, Seconds relativeTimeout, const Functor& predicate) WTF_REQUIRES_LOCK(lock)
+ {
+ return waitUntil(lock, MonotonicTime::now() + relativeTimeout, predicate);
+ }
template<typename LockType>
bool waitFor(LockType& lock, Seconds relativeTimeout)
@@ -117,6 +111,11 @@
return waitUntil(lock, MonotonicTime::now() + relativeTimeout);
}
+ bool waitFor(Lock& lock, Seconds relativeTimeout) WTF_REQUIRES_LOCK(lock)
+ {
+ return waitUntil(lock, MonotonicTime::now() + relativeTimeout);
+ }
+
template<typename LockType>
void wait(LockType& lock)
{
@@ -123,6 +122,11 @@
waitUntil(lock, Time::infinity());
}
+ void wait(Lock& lock) WTF_REQUIRES_LOCK(lock)
+ {
+ waitUntil(lock, Time::infinity());
+ }
+
template<typename LockType, typename Functor>
void wait(LockType& lock, const Functor& predicate)
{
@@ -130,6 +134,13 @@
wait(lock);
}
+ template<typename Functor>
+ void wait(Lock& lock, const Functor& predicate) WTF_REQUIRES_LOCK(lock)
+ {
+ while (!predicate())
+ wait(lock);
+ }
+
// Note that this method is extremely fast when nobody is waiting. It is not necessary to try to
// avoid calling this method. This returns true if someone was actually woken up.
bool notifyOne()
@@ -170,64 +181,47 @@
}
private:
- Atomic<bool> m_hasWaiters { false };
-};
-
-// A condition variable type for Lock.
-// For predicates that access the guarded variables, use assertIsHeld(lock).
-class Condition final {
- WTF_MAKE_NONCOPYABLE(Condition);
- WTF_MAKE_FAST_ALLOCATED;
-public:
- constexpr Condition() = default;
-
- bool waitUntil(Lock& lock, const TimeWithDynamicClockType& timeout) WTF_REQUIRES_LOCK(lock)
+ template<typename LockType>
+ bool waitUntilUnchecked(LockType& lock, const TimeWithDynamicClockType& timeout) WTF_IGNORES_THREAD_SAFETY_ANALYSIS
{
- return m_condition.waitUntil(uncheckedCast(lock), timeout);
+ bool result;
+ if (timeout < timeout.nowWithSameClock()) {
+ lock.unlock();
+ result = false;
+ } else {
+ result = ParkingLot::parkConditionally(
+ &m_hasWaiters,
+ [this] () -> bool {
+ // Let everyone know that we will be waiting. Do this while we hold the queue lock,
+ // to prevent races with notifyOne().
+ m_hasWaiters.store(true);
+ return true;
+ },
+ [&lock] () WTF_IGNORES_THREAD_SAFETY_ANALYSIS {
+ lock.unlock();
+ },
+ timeout).wasUnparked;
+ }
+ lock.lock();
+ return result;
}
- template<typename Functor>
- bool waitUntil(Lock& lock, const TimeWithDynamicClockType& timeout, const Functor& predicate) WTF_REQUIRES_LOCK(lock)
+
+ template<typename LockType, typename Functor>
+ bool waitUntilUnchecked(LockType& lock, const TimeWithDynamicClockType& timeout, const Functor& predicate) WTF_IGNORES_THREAD_SAFETY_ANALYSIS
{
- return m_condition.waitUntil(uncheckedCast(lock), timeout, predicate);
+ while (!predicate()) {
+ if (!waitUntil(lock, timeout))
+ return predicate();
+ }
+ return true;
}
- template<typename Functor>
- bool waitFor(Lock& lock, Seconds relativeTimeout, const Functor& predicate) WTF_REQUIRES_LOCK(lock)
- {
- return m_condition.waitFor(uncheckedCast(lock), relativeTimeout, predicate);
- }
- bool waitFor(Lock& lock, Seconds relativeTimeout) WTF_REQUIRES_LOCK(lock)
- {
- return m_condition.waitFor(uncheckedCast(lock), relativeTimeout);
- }
- void wait(Lock& lock) WTF_REQUIRES_LOCK(lock)
- {
- m_condition.wait(uncheckedCast(lock));
- }
- template<typename Functor>
- void wait(Lock& lock, const Functor& predicate) WTF_REQUIRES_LOCK(lock)
- {
- m_condition.wait(uncheckedCast(lock), predicate);
- }
- bool notifyOne()
- {
- return m_condition.notifyOne();
- }
- void notifyAll()
- {
- m_condition.notifyAll();
- }
-private:
- static UncheckedLock& uncheckedCast(Lock& lock) { return static_cast<UncheckedLock&>(lock); }
- UncheckedCondition m_condition;
+
+ Atomic<bool> m_hasWaiters { false };
};
-using StaticUncheckedCondition = UncheckedCondition;
using StaticCondition = Condition;
} // namespace WTF
using WTF::Condition;
-using WTF::UncheckedCondition;
using WTF::StaticCondition;
-using WTF::StaticUncheckedCondition;
-
Modified: trunk/Source/WTF/wtf/Lock.cpp (278256 => 278257)
--- trunk/Source/WTF/wtf/Lock.cpp 2021-05-30 19:45:09 UTC (rev 278256)
+++ trunk/Source/WTF/wtf/Lock.cpp 2021-05-30 20:35:59 UTC (rev 278257)
@@ -39,7 +39,7 @@
static constexpr bool profileLockContention = false;
-void UncheckedLock::lockSlow()
+void Lock::lockSlow()
{
if (profileLockContention)
STACK_SHOT_PROFILE(4, 2, 5);
@@ -46,7 +46,7 @@
DefaultLockAlgorithm::lockSlow(m_byte);
}
-void UncheckedLock::unlockSlow()
+void Lock::unlockSlow()
{
// Heap allocations are forbidden on the certain threads (e.g. audio rendering thread) for performance reasons so we need to
// explicitly allow the following allocation(s). In some rare cases, the unlockSlow() algorith may cause allocations.
@@ -55,7 +55,7 @@
DefaultLockAlgorithm::unlockSlow(m_byte, DefaultLockAlgorithm::Unfair);
}
-void UncheckedLock::unlockFairlySlow()
+void Lock::unlockFairlySlow()
{
// Heap allocations are forbidden on the certain threads (e.g. audio rendering thread) for performance reasons so we need to
// explicitly allow the following allocation(s). In some rare cases, the unlockSlow() algorith may cause allocations.
@@ -64,7 +64,7 @@
DefaultLockAlgorithm::unlockSlow(m_byte, DefaultLockAlgorithm::Fair);
}
-void UncheckedLock::safepointSlow()
+void Lock::safepointSlow()
{
DefaultLockAlgorithm::safepointSlow(m_byte);
}
Modified: trunk/Source/WTF/wtf/Lock.h (278256 => 278257)
--- trunk/Source/WTF/wtf/Lock.h 2021-05-30 19:45:09 UTC (rev 278256)
+++ trunk/Source/WTF/wtf/Lock.h 2021-05-30 20:35:59 UTC (rev 278257)
@@ -50,29 +50,35 @@
// at worst one call to unlock() per millisecond will do a direct hand-off to the thread that is at
// the head of the queue. When there are collisions, each collision increases the fair unlock delay
// by one millisecond in the worst case.
-class UncheckedLock {
- WTF_MAKE_NONCOPYABLE(UncheckedLock);
+//
+// This lock type supports thread safety analysis.
+// To annotate a member variable or a global variable with thread ownership information,
+// use lock capability annotations defined in ThreadSafetyAnalysis.h.
+class WTF_CAPABILITY_LOCK Lock {
+ WTF_MAKE_NONCOPYABLE(Lock);
WTF_MAKE_FAST_ALLOCATED;
public:
- constexpr UncheckedLock() = default;
+ constexpr Lock() = default;
- void lock()
+ void lock() WTF_ACQUIRES_LOCK()
{
if (UNLIKELY(!DefaultLockAlgorithm::lockFastAssumingZero(m_byte)))
lockSlow();
}
- bool tryLock()
+ bool tryLock() WTF_ACQUIRES_LOCK_IF(true) // NOLINT: Intentional deviation to support std::scoped_lock.
{
return DefaultLockAlgorithm::tryLock(m_byte);
}
// Need this version for std::unique_lock.
- bool try_lock()
+ bool try_lock() WTF_ACQUIRES_LOCK_IF(true)
{
return tryLock();
}
+ WTF_EXPORT_PRIVATE bool tryLockWithTimeout(Seconds timeout) WTF_ACQUIRES_LOCK_IF(true);
+
// Relinquish the lock. Either one of the threads that were waiting for the lock, or some other
// thread that happens to be running, will be able to grab the lock. This bit of unfairness is
// called barging, and we allow it because it maximizes throughput. However, we bound how unfair
@@ -81,7 +87,7 @@
// we check if the last time that we did a fair unlock was more than roughly 1ms ago; if so, we
// unlock fairly. Fairness matters most for long critical sections, and this virtually
// guarantees that long critical sections always get a fair lock.
- void unlock()
+ void unlock() WTF_RELEASES_LOCK()
{
if (UNLIKELY(!DefaultLockAlgorithm::unlockFastAssumingZero(m_byte)))
unlockSlow();
@@ -92,7 +98,7 @@
// to be fair anyway. However, if you plan to relock the lock right after unlocking and you want
// to ensure that some other thread runs in the meantime, this is probably the function you
// want.
- void unlockFairly()
+ void unlockFairly() WTF_RELEASES_LOCK()
{
if (UNLIKELY(!DefaultLockAlgorithm::unlockFastAssumingZero(m_byte)))
unlockFairlySlow();
@@ -134,45 +140,6 @@
Atomic<uint8_t> m_byte { 0 };
};
-// A lock type with support for thread safety analysis.
-// To annotate a member variable or a global variable with thread ownership information,
-// use lock capability annotations defined in ThreadSafetyAnalysis.h.
-//
-// Example:
-// class MyValue : public ThreadSafeRefCounted<MyValue>
-// {
-// public:
-// void setValue(int value) { Locker holdLock { m_lock }; m_value = value; }
-// void maybeSetOtherValue(int value)
-// {
-// if (!m_lock.tryLock())
-// return;
-// Locker locker { AdoptLock, m_otherLock };
-// m_otherValue = value;
-// }
-// private:
-// Lock m_lock;
-// int m_value WTF_GUARDED_BY_LOCK(m_lock) { 77 };
-// int m_otherValue WTF_GUARDED_BY_LOCK(m_lock) { 88 };
-// };
-class WTF_CAPABILITY_LOCK Lock : UncheckedLock {
- WTF_MAKE_NONCOPYABLE(Lock);
- WTF_MAKE_FAST_ALLOCATED;
-public:
- constexpr Lock() = default;
- void lock() WTF_ACQUIRES_LOCK() { UncheckedLock::lock(); }
- bool tryLock() WTF_ACQUIRES_LOCK_IF(true) { return UncheckedLock::tryLock(); }
- bool try_lock() WTF_ACQUIRES_LOCK_IF(true) { return UncheckedLock::try_lock(); } // NOLINT: Intentional deviation to support std::scoped_lock.
- WTF_EXPORT_PRIVATE bool tryLockWithTimeout(Seconds timeout) WTF_ACQUIRES_LOCK_IF(true);
- void unlock() WTF_RELEASES_LOCK() { UncheckedLock::unlock(); }
- void unlockFairly() WTF_RELEASES_LOCK() { UncheckedLock::unlockFairly(); }
- void safepoint() { UncheckedLock::safepoint(); }
- bool isHeld() const { return UncheckedLock::isHeld(); }
- bool isLocked() const { return UncheckedLock::isLocked(); }
- friend class Condition;
- friend struct TestWebKitAPI::LockInspector;
-};
-
// Asserts that the lock is held.
// This can be used in cases where the annotations cannot be added to the function
// declaration.
@@ -234,11 +201,8 @@
Locker(AdoptLockTag, Lock&) -> Locker<Lock>;
using LockHolder = Locker<Lock>;
-using UncheckedLockHolder = Locker<UncheckedLock>;
} // namespace WTF
-using WTF::UncheckedLock;
using WTF::Lock;
using WTF::LockHolder;
-using WTF::UncheckedLockHolder;