Changeset 259879 in webkit
- Timestamp:
- Apr 10, 2020 9:46:49 AM (4 years ago)
- Location:
- trunk
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WTF/ChangeLog
r259878 r259879 1 2020-04-10 Alicia Boya García <aboya@igalia.com> 2 3 [WTF] DataMutex: Add runUnlocked() 4 https://bugs.webkit.org/show_bug.cgi?id=209811 5 6 Reviewed by Xabier Rodriguez-Calvar. 7 8 This patch introduces a runUnlocked() method in WTF::DataMutex::LockedWrapper 9 to run a lambda function without the lock. This is intended to be used for 10 small sections of the code that need to be unlocked, in cases where using 11 scoping would prove non-ergonomic or where running the unlocked section is only 12 necessary or desired when a certain condition is met -- something that cannot 13 be done with C++ scoping. 14 15 Safety mechanisms are provided. First, because this is used with a lambda, all 16 variables to be used in the unlocked section have to be specified in the 17 capture (global capture is possible but not recommended to simplify analysis). 18 Second, additional checks have been added to DataMutex to detect unlocked 19 accesses among other conditions. This will detect among other things naive 20 access to protected members by means of capturing the LockedWrapper by 21 reference. 22 23 * wtf/DataMutex.h: 24 (WTF::OwnerAwareLockAdapter::lock): 25 (WTF::OwnerAwareLockAdapter::unlock): 26 (WTF::OwnerAwareLockAdapter::tryLock): 27 (WTF::OwnerAwareLockAdapter::isLocked const): 28 (WTF::DataMutex::LockedWrapper::operator->): 29 (WTF::DataMutex::LockedWrapper::operator*): 30 (WTF::DataMutex::LockedWrapper::mutex): 31 (WTF::DataMutex::LockedWrapper::lockHolder): 32 (WTF::DataMutex::LockedWrapper::runUnlocked): 33 1 34 2020-04-10 David Kilzer <ddkilzer@apple.com> 2 35 -
trunk/Source/WTF/wtf/DataMutex.h
r248546 r259879 22 22 23 23 #include <wtf/Lock.h> 24 #include <wtf/Threading.h> 24 25 25 26 namespace WTF { 26 27 27 template<typename T> 28 // By default invalid access checks are only done in Debug builds. 29 #if !defined(ENABLE_DATA_MUTEX_CHECKS) 30 #if defined(NDEBUG) 31 #define ENABLE_DATA_MUTEX_CHECKS 0 32 #else 33 #define ENABLE_DATA_MUTEX_CHECKS 1 34 #endif 35 #endif 36 37 #if ENABLE_DATA_MUTEX_CHECKS 38 #define DATA_MUTEX_CHECK(expr) RELEASE_ASSERT(expr) 39 #else 40 #define DATA_MUTEX_CHECK(expr) 41 #endif 42 43 template<typename LockType> 44 class OwnerAwareLockAdapter { 45 public: 46 void lock() 47 { 48 DATA_MUTEX_CHECK(m_owner != &Thread::current()); // Thread attempted recursive lock (unsupported). 49 m_lock.lock(); 50 #if ENABLE_DATA_MUTEX_CHECKS 51 ASSERT(!m_owner); 52 m_owner = &Thread::current(); 53 #endif 54 } 55 56 void unlock() 57 { 58 #if ENABLE_DATA_MUTEX_CHECKS 59 m_owner = nullptr; 60 #endif 61 m_lock.unlock(); 62 } 63 64 bool tryLock() 65 { 66 DATA_MUTEX_CHECK(m_owner != &Thread::current()); // Thread attempted recursive lock (unsupported). 67 if (!m_lock.tryLock()) 68 return false; 69 70 #if ENABLE_DATA_MUTEX_CHECKS 71 ASSERT(!m_owner); 72 m_owner = &Thread::current(); 73 #endif 74 return true; 75 } 76 77 bool isLocked() const 78 { 79 return m_lock.isLocked(); 80 } 81 82 private: 83 #if ENABLE_DATA_MUTEX_CHECKS 84 Thread* m_owner { nullptr }; // Use Thread* instead of RefPtr<Thread> since m_owner thread is always alive while m_owner is set. 85 #endif 86 LockType m_lock; 87 }; 88 89 using OwnerAwareLock = OwnerAwareLockAdapter<Lock>; 90 91 template<typename T, typename LockType = OwnerAwareLock> 28 92 class DataMutex { 29 93 WTF_MAKE_FAST_ALLOCATED; … … 45 109 T* operator->() 46 110 { 111 DATA_MUTEX_CHECK(m_mutex.isLocked()); 47 112 return &m_data; 48 113 } … … 50 115 T& operator*() 51 116 { 117 DATA_MUTEX_CHECK(m_mutex.isLocked()); 52 118 return m_data; 53 119 } 54 120 55 Lock & mutex()121 LockType& mutex() 56 122 { 57 123 return m_mutex; 58 124 } 59 125 60 Lock Holder& lockHolder()126 Locker<LockType>& lockHolder() 61 127 { 62 128 return m_lockHolder; 63 129 } 64 130 131 // Used to avoid excessive brace scoping when only small parts of the code need to be run unlocked. 132 // Please be mindful that accessing the wrapped data from the callback is unsafe and will fail on assertions. 133 // It's helpful to use a minimal lambda capture to be conscious of what data you're having access to in these sections. 134 void runUnlocked(WTF::Function<void()> callback) 135 { 136 m_mutex.unlock(); 137 callback(); 138 m_mutex.lock(); 139 } 140 65 141 private: 66 Lock & m_mutex;67 Lock Holderm_lockHolder;142 LockType& m_mutex; 143 Locker<LockType> m_lockHolder; 68 144 T& m_data; 69 145 }; 70 146 71 147 private: 72 Lock m_mutex;148 LockType m_mutex; 73 149 T m_data; 74 150 }; -
trunk/Tools/ChangeLog
r259873 r259879 1 2020-04-10 Alicia Boya García <aboya@igalia.com> 2 3 [WTF] DataMutex: Add runUnlocked() 4 https://bugs.webkit.org/show_bug.cgi?id=209811 5 6 Reviewed by Xabier Rodriguez-Calvar. 7 8 Tests for runUnlocked() and DataMutex checks are introduced. 9 10 * TestWebKitAPI/Tests/WTF/DataMutex.cpp: 11 (TestWebKitAPI::TEST): 12 1 13 == Rolled over to ChangeLog-2020-04-10 == -
trunk/Tools/TestWebKitAPI/Tests/WTF/DataMutex.cpp
r247723 r259879 26 26 27 27 #include "config.h" 28 29 // For this file, we force checks even if we're running on release. 30 #define ENABLE_DATA_MUTEX_CHECKS 1 28 31 #include <wtf/DataMutex.h> 29 32 … … 35 38 int number; 36 39 }; 37 DataMutex<MyStructure> myDataMutex;38 40 39 41 TEST(WTF_DataMutex, TakingTheMutex) 40 42 { 41 Lock* mutex; 43 DataMutex<MyStructure> myDataMutex; 44 45 OwnerAwareLock* mutex; 42 46 { 43 47 DataMutex<MyStructure>::LockedWrapper wrapper(myDataMutex); 44 48 mutex = &wrapper.mutex(); 45 ASSERT_TRUE(mutex->is Held());49 ASSERT_TRUE(mutex->isLocked()); 46 50 wrapper->number = 5; 51 52 wrapper.runUnlocked([mutex]() { 53 ASSERT_FALSE(mutex->isLocked()); 54 }); 55 ASSERT_TRUE(mutex->isLocked()); 47 56 } 48 ASSERT_FALSE(mutex->is Held());57 ASSERT_FALSE(mutex->isLocked()); 49 58 50 59 { … … 54 63 } 55 64 65 TEST(WTF_DataMutex, RunUnlockedIllegalAccessDeathTest) 66 { 67 ::testing::FLAGS_gtest_death_test_style = "threadsafe"; 68 DataMutex<MyStructure> myDataMutex; 69 DataMutex<MyStructure>::LockedWrapper wrapper(myDataMutex); 70 wrapper->number = 5; 71 72 ASSERT_DEATH(wrapper.runUnlocked([&]() { 73 wrapper->number++; 74 }), ""); 75 } 76 77 TEST(WTF_DataMutex, DoubleLockDeathTest) 78 { 79 ::testing::FLAGS_gtest_death_test_style = "threadsafe"; 80 DataMutex<MyStructure> myDataMutex; 81 DataMutex<MyStructure>::LockedWrapper wrapper1(myDataMutex); 82 ASSERT_DEATH(DataMutex<MyStructure>::LockedWrapper wrapper2(myDataMutex), ""); 83 } 84 56 85 } // namespace TestWebKitAPI
Note: See TracChangeset
for help on using the changeset viewer.