Changeset 209938 in webkit
- Timestamp:
- Dec 16, 2016 2:26:09 PM (7 years ago)
- Location:
- trunk/Source/WTF
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WTF/ChangeLog
r209913 r209938 1 2016-12-16 Michael Saboff <msaboff@apple.com> 2 3 REGRESSION: HipChat and Mail sometimes hang beneath JSC::Heap::lastChanceToFinalize() 4 https://bugs.webkit.org/show_bug.cgi?id=165962 5 6 Reviewed by Filip Pizlo. 7 8 There is an inherent race in Condition::waitFor() where the timeout can happen just before 9 a notify from another thread. 10 11 Fixed this by adding a condition variable and flag to each AutomaticThread. The flag 12 is used to signify to a notifying thread that the thread is waiting. That flag is set 13 in the waiting thread before calling waitFor() and cleared by another thread when it 14 notifies the thread. The access to that flag happens when the lock is held. 15 Now the waiting thread checks if the flag after a timeout to see that it in fact should 16 proceed like a normal notification. 17 18 The added condition variable allows us to target a specific thread. We used to keep a list 19 of waiting threads, now we keep a list of all threads. To notify one thread, we look for 20 a waiting thread and notify it directly. If we can't find a waiting thread, we start a 21 sleeping thread. 22 23 We notify all threads by waking all waiting threads and starting all sleeping threads. 24 25 * wtf/AutomaticThread.cpp: 26 (WTF::AutomaticThreadCondition::notifyOne): 27 (WTF::AutomaticThreadCondition::notifyAll): 28 (WTF::AutomaticThread::isWaiting): 29 (WTF::AutomaticThread::notify): 30 (WTF::AutomaticThread::start): 31 * wtf/AutomaticThread.h: 32 1 33 2016-12-15 Myles C. Maxfield <mmaxfield@apple.com> 2 34 -
trunk/Source/WTF/wtf/AutomaticThread.cpp
r208982 r209938 48 48 void AutomaticThreadCondition::notifyOne(const LockHolder& locker) 49 49 { 50 if (m_condition.notifyOne()) 51 return; 52 53 if (m_threads.isEmpty()) 54 return; 55 56 m_threads.takeLast()->start(locker); 50 for (AutomaticThread* thread : m_threads) { 51 if (thread->isWaiting(locker)) { 52 thread->notify(locker); 53 return; 54 } 55 } 56 57 for (AutomaticThread* thread : m_threads) { 58 if (!thread->hasUnderlyingThread(locker)) { 59 thread->start(locker); 60 return; 61 } 62 } 63 64 m_condition.notifyOne(); 57 65 } 58 66 … … 60 68 { 61 69 m_condition.notifyAll(); 62 63 for (AutomaticThread* thread : m_threads) 64 thread->start(locker); 65 m_threads.clear(); 70 71 for (AutomaticThread* thread : m_threads) { 72 if (thread->isWaiting(locker)) 73 thread->notify(locker); 74 else if (!thread->hasUnderlyingThread(locker)) 75 thread->start(locker); 76 } 66 77 } 67 78 … … 116 127 m_isRunning = false; 117 128 return true; 129 } 130 131 bool AutomaticThread::isWaiting(const LockHolder& locker) 132 { 133 return hasUnderlyingThread(locker) && m_isWaiting; 134 } 135 136 bool AutomaticThread::notify(const LockHolder& locker) 137 { 138 ASSERT_UNUSED(locker, hasUnderlyingThread(locker)); 139 m_isWaiting = false; 140 return m_waitCondition.notifyOne(); 118 141 } 119 142 … … 162 185 if (!ASSERT_DISABLED) { 163 186 LockHolder locker(*m_lock); 164 ASSERT( !m_condition->contains(locker, this));187 ASSERT(m_condition->contains(locker, this)); 165 188 } 166 189 … … 181 204 RELEASE_ASSERT(result == PollResult::Wait); 182 205 // Shut the thread down after one second. 206 m_isWaiting = true; 183 207 bool awokenByNotify = 184 m_condition->m_condition.waitFor(*m_lock, 1_s); 185 if (!awokenByNotify) { 208 m_waitCondition.waitFor(*m_lock, 1_s); 209 if (verbose && !awokenByNotify && !m_isWaiting) 210 dataLog(RawPointer(this), ": waitFor timed out, but notified via m_isWaiting flag!\n"); 211 if (m_isWaiting) { 212 m_isWaiting = false; 186 213 if (verbose) 187 214 dataLog(RawPointer(this), ": Going to sleep!\n"); 188 m_condition->add(locker, this);189 215 return; 190 216 } -
trunk/Source/WTF/wtf/AutomaticThread.h
r208306 r209938 121 121 // mechanism (set some flag and then notify the condition). 122 122 bool tryStop(const LockHolder&); 123 123 124 bool isWaiting(const LockHolder&); 125 126 bool notify(const LockHolder&); 127 124 128 void join(); 125 129 … … 178 182 RefPtr<AutomaticThreadCondition> m_condition; 179 183 bool m_isRunning { true }; 184 bool m_isWaiting { false }; 180 185 bool m_hasUnderlyingThread { false }; 186 Condition m_waitCondition; 181 187 Condition m_isRunningCondition; 182 188 };
Note: See TracChangeset
for help on using the changeset viewer.