Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "platform/heap/SafePoint.h" | 5 #include "platform/heap/SafePoint.h" |
| 6 | 6 |
| 7 #include "platform/heap/Heap.h" | |
| 7 #include "wtf/Atomics.h" | 8 #include "wtf/Atomics.h" |
| 8 #include "wtf/CurrentTime.h" | 9 #include "wtf/CurrentTime.h" |
| 9 | 10 |
| 10 namespace blink { | 11 namespace blink { |
| 11 | 12 |
| 12 using PushAllRegistersCallback = void (*)(SafePointBarrier*, ThreadState*, intpt r_t*); | 13 using PushAllRegistersCallback = void (*)(SafePointBarrier*, ThreadState*, intpt r_t*); |
| 13 extern "C" void pushAllRegisters(SafePointBarrier*, ThreadState*, PushAllRegiste rsCallback); | 14 extern "C" void pushAllRegisters(SafePointBarrier*, ThreadState*, PushAllRegiste rsCallback); |
| 14 | 15 |
| 15 static double lockingTimeout() | 16 static double lockingTimeout() |
| 16 { | 17 { |
| 17 // Wait time for parking all threads is at most 100 ms. | 18 // Wait time for parking all threads is at most 100 ms. |
| 18 return 0.100; | 19 return 0.100; |
| 19 } | 20 } |
| 20 | 21 |
| 21 SafePointBarrier::SafePointBarrier() | 22 SafePointBarrier::SafePointBarrier(Heap* heap) |
| 22 : m_canResume(1) | 23 : m_canResume(1) |
| 23 , m_unparkedThreadCount(0) | 24 , m_unparkedThreadCount(0) |
| 25 , m_heap(heap) | |
| 24 { | 26 { |
| 25 } | 27 } |
| 26 | 28 |
| 27 SafePointBarrier::~SafePointBarrier() | 29 SafePointBarrier::~SafePointBarrier() |
| 28 { | 30 { |
| 29 } | 31 } |
| 30 | 32 |
| 31 bool SafePointBarrier::parkOthers() | 33 bool SafePointBarrier::parkOthers() |
| 32 { | 34 { |
| 33 ASSERT(ThreadState::current()->isAtSafePoint()); | 35 ASSERT(ThreadState::current()->isAtSafePoint()); |
| 34 | 36 |
| 35 ThreadState* current = ThreadState::current(); | 37 ThreadState* current = ThreadState::current(); |
| 36 // Lock threadAttachMutex() to prevent threads from attaching. | 38 // Lock threadAttachMutex() to prevent threads from attaching. |
| 37 ThreadState::lockThreadAttachMutex(); | 39 m_heap->lockThreadAttachMutex(); |
| 38 ThreadState::AttachedThreadStateSet& threads = ThreadState::attachedThreads( ); | 40 const ThreadStateSet& threads = m_heap->threads(); |
|
haraken
2016/02/29 11:17:45
It would be better to move lockThreadAttachMutex()
keishi
2016/03/02 06:01:03
Done.
| |
| 39 | 41 |
| 40 MutexLocker locker(m_mutex); | 42 MutexLocker locker(m_mutex); |
| 41 atomicAdd(&m_unparkedThreadCount, threads.size()); | 43 atomicAdd(&m_unparkedThreadCount, threads.size()); |
| 42 releaseStore(&m_canResume, 0); | 44 releaseStore(&m_canResume, 0); |
| 43 | 45 |
| 44 for (ThreadState* state : threads) { | 46 for (ThreadState* state : threads) { |
| 45 if (state == current) | 47 if (state == current) |
| 46 continue; | 48 continue; |
| 47 | 49 |
| 48 for (auto& interruptor : state->interruptors()) | 50 for (auto& interruptor : state->interruptors()) |
| 49 interruptor->requestInterrupt(); | 51 interruptor->requestInterrupt(); |
| 50 } | 52 } |
| 51 | 53 |
| 52 while (acquireLoad(&m_unparkedThreadCount) > 0) { | 54 while (acquireLoad(&m_unparkedThreadCount) > 0) { |
| 53 double expirationTime = currentTime() + lockingTimeout(); | 55 double expirationTime = currentTime() + lockingTimeout(); |
| 54 if (!m_parked.timedWait(m_mutex, expirationTime)) { | 56 if (!m_parked.timedWait(m_mutex, expirationTime)) { |
| 55 // One of the other threads did not return to a safepoint within the maximum | 57 // One of the other threads did not return to a safepoint within the maximum |
| 56 // time we allow for threads to be parked. Abandon the GC and resume the | 58 // time we allow for threads to be parked. Abandon the GC and resume the |
| 57 // currently parked threads. | 59 // currently parked threads. |
| 58 resumeOthers(true); | 60 resumeOthers(true); |
| 59 return false; | 61 return false; |
| 60 } | 62 } |
| 61 } | 63 } |
| 62 return true; | 64 return true; |
| 63 } | 65 } |
| 64 | 66 |
| 65 void SafePointBarrier::resumeOthers(bool barrierLocked) | 67 void SafePointBarrier::resumeOthers(bool barrierLocked) |
| 66 { | 68 { |
| 67 ThreadState::AttachedThreadStateSet& threads = ThreadState::attachedThreads( ); | 69 const ThreadStateSet& threads = m_heap->threads(); |
| 68 atomicSubtract(&m_unparkedThreadCount, threads.size()); | 70 atomicSubtract(&m_unparkedThreadCount, threads.size()); |
| 69 releaseStore(&m_canResume, 1); | 71 releaseStore(&m_canResume, 1); |
| 70 | 72 |
| 71 if (UNLIKELY(barrierLocked)) { | 73 if (UNLIKELY(barrierLocked)) { |
| 72 m_resume.broadcast(); | 74 m_resume.broadcast(); |
| 73 } else { | 75 } else { |
| 74 // FIXME: Resumed threads will all contend for m_mutex just | 76 // FIXME: Resumed threads will all contend for m_mutex just |
| 75 // to unlock it later which is a waste of resources. | 77 // to unlock it later which is a waste of resources. |
| 76 MutexLocker locker(m_mutex); | 78 MutexLocker locker(m_mutex); |
| 77 m_resume.broadcast(); | 79 m_resume.broadcast(); |
| 78 } | 80 } |
| 79 | 81 |
| 80 ThreadState::unlockThreadAttachMutex(); | 82 m_heap->unlockThreadAttachMutex(); |
| 81 ASSERT(ThreadState::current()->isAtSafePoint()); | 83 ASSERT(ThreadState::current()->isAtSafePoint()); |
| 82 } | 84 } |
| 83 | 85 |
| 84 void SafePointBarrier::checkAndPark(ThreadState* state, SafePointAwareMutexLocke r* locker) | 86 void SafePointBarrier::checkAndPark(ThreadState* state, SafePointAwareMutexLocke r* locker) |
| 85 { | 87 { |
| 86 ASSERT(!state->sweepForbidden()); | 88 ASSERT(!state->sweepForbidden()); |
| 87 if (!acquireLoad(&m_canResume)) { | 89 if (!acquireLoad(&m_canResume)) { |
| 88 // If we are leaving the safepoint from a SafePointAwareMutexLocker | 90 // If we are leaving the safepoint from a SafePointAwareMutexLocker |
| 89 // call out to release the lock before going to sleep. This enables the | 91 // call out to release the lock before going to sleep. This enables the |
| 90 // lock to be acquired in the sweep phase, e.g. during weak processing | 92 // lock to be acquired in the sweep phase, e.g. during weak processing |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 131 // If no other thread is waiting for other threads to park then | 133 // If no other thread is waiting for other threads to park then |
| 132 // this counter can be negative: if N threads are at safe-points | 134 // this counter can be negative: if N threads are at safe-points |
| 133 // the counter will be -N. | 135 // the counter will be -N. |
| 134 if (!atomicDecrement(&m_unparkedThreadCount)) { | 136 if (!atomicDecrement(&m_unparkedThreadCount)) { |
| 135 MutexLocker locker(m_mutex); | 137 MutexLocker locker(m_mutex); |
| 136 m_parked.signal(); // Safe point reached. | 138 m_parked.signal(); // Safe point reached. |
| 137 } | 139 } |
| 138 } | 140 } |
| 139 | 141 |
| 140 } // namespace blink | 142 } // namespace blink |
| OLD | NEW |