Chromium Code Reviews| Index: Source/platform/heap/ThreadState.cpp |
| diff --git a/Source/platform/heap/ThreadState.cpp b/Source/platform/heap/ThreadState.cpp |
| index a8a66cb67fced14b8a90e6cafc677c3325ace37f..b6601b666d59a32f3c5fe813c44827169fcd1b1f 100644 |
| --- a/Source/platform/heap/ThreadState.cpp |
| +++ b/Source/platform/heap/ThreadState.cpp |
| @@ -96,6 +96,13 @@ static Mutex& threadAttachMutex() |
| return mutex; |
| } |
| +static double lockingTimeout() |
| +{ |
| + // Wait time for parking all threads is at most 10 MS. |
| + return 0.01; |
| +} |
| + |
| + |
| typedef void (*PushAllRegistersCallback)(SafePointBarrier*, ThreadState*, intptr_t*); |
| extern "C" void pushAllRegisters(SafePointBarrier*, ThreadState*, PushAllRegistersCallback); |
| @@ -105,7 +112,7 @@ public: |
| ~SafePointBarrier() { } |
| // Request other attached threads that are not at safe points to park themselves on safepoints. |
| - void parkOthers() |
| + bool parkOthers() |
| { |
| ASSERT(ThreadState::current()->isAtSafePoint()); |
| @@ -128,16 +135,30 @@ public: |
| interruptors[i]->requestInterrupt(); |
| } |
| - while (acquireLoad(&m_unparkedThreadCount) > 0) |
| - m_parked.wait(m_mutex); |
| + while (acquireLoad(&m_unparkedThreadCount) > 0) { |
| + double expirationTime = currentTime() + lockingTimeout(); |
| + if (!m_parked.timedWait(m_mutex, expirationTime)) { |
| + // One of the other threads did not return to a safepoint within the maximum |
| + // time we allow for threads to be parked. Abandon the GC and resume the |
| + // currently parked threads. |
| + resumeOthers(true); |
|
haraken
2014/05/01 04:03:56
Nit: It would be more consistent if you can remove
wibling-chromium
2014/05/01 06:51:48
Yes, that would be nice. However I am worried that
haraken
2014/05/01 07:33:50
Yes, but is it problematic that we allow another t
wibling-chromium
2014/05/01 08:25:18
No, that should be okay. However previously we wou
haraken
2014/05/01 08:36:31
Thanks for the clarification, makes sense!
|
| + return false; |
| + } |
| + } |
| + return true; |
| } |
| - void resumeOthers() |
| + void resumeOthers(bool barrierLocked = false) |
| { |
| ThreadState::AttachedThreadStateSet& threads = ThreadState::attachedThreads(); |
| atomicSubtract(&m_unparkedThreadCount, threads.size()); |
|
haraken
2014/05/01 04:03:56
I guess this will confuse m_unparkedThreadCount. A
wibling-chromium
2014/05/01 06:51:48
I initially read the code the same way, but parkOt
haraken
2014/05/01 07:33:50
Thanks for the clarification. Your explanation sou
|
| releaseStore(&m_canResume, 1); |
| - { |
| + |
| + // FIXME: Resumed threads will all contend for m_mutex just to unlock it |
| + // later which is a waste of resources. |
| + if (UNLIKELY(barrierLocked)) { |
| + m_resume.broadcast(); |
| + } else { |
| // FIXME: Resumed threads will all contend for |
| // m_mutex just to unlock it later which is a waste of |
| // resources. |
| @@ -159,6 +180,28 @@ public: |
| ASSERT(ThreadState::current()->isAtSafePoint()); |
| } |
| + void checkAndPark(ThreadState* state) |
|
zerny-chromium
2014/05/01 07:05:38
Nit: avoid reordering/formatting for unchanged cod
wibling-chromium
2014/05/01 08:25:18
Done. I will revert that and do it in a separate c
|
| + { |
| + ASSERT(!state->isSweepInProgress()); |
| + if (!acquireLoad(&m_canResume)) { |
| + pushAllRegisters(this, state, parkAfterPushRegisters); |
| + state->performPendingSweep(); |
| + } |
| + } |
| + |
| + void enterSafePoint(ThreadState* state) |
| + { |
| + ASSERT(!state->isSweepInProgress()); |
| + pushAllRegisters(this, state, enterSafePointAfterPushRegisters); |
| + } |
| + |
| + void leaveSafePoint(ThreadState* state) |
| + { |
| + if (atomicIncrement(&m_unparkedThreadCount) > 0) |
| + checkAndPark(state); |
| + } |
| + |
| +private: |
| void doPark(ThreadState* state, intptr_t* stackEnd) |
| { |
| state->recordStackEnd(stackEnd); |
| @@ -170,13 +213,9 @@ public: |
| atomicIncrement(&m_unparkedThreadCount); |
| } |
| - void checkAndPark(ThreadState* state) |
| + static void parkAfterPushRegisters(SafePointBarrier* barrier, ThreadState* state, intptr_t* stackEnd) |
| { |
| - ASSERT(!state->isSweepInProgress()); |
| - if (!acquireLoad(&m_canResume)) { |
| - pushAllRegisters(this, state, parkAfterPushRegisters); |
| - state->performPendingSweep(); |
| - } |
| + barrier->doPark(state, stackEnd); |
| } |
| void doEnterSafePoint(ThreadState* state, intptr_t* stackEnd) |
| @@ -197,24 +236,6 @@ public: |
| } |
| } |
| - void enterSafePoint(ThreadState* state) |
| - { |
| - ASSERT(!state->isSweepInProgress()); |
| - pushAllRegisters(this, state, enterSafePointAfterPushRegisters); |
| - } |
| - |
| - void leaveSafePoint(ThreadState* state) |
| - { |
| - if (atomicIncrement(&m_unparkedThreadCount) > 0) |
| - checkAndPark(state); |
| - } |
| - |
| -private: |
| - static void parkAfterPushRegisters(SafePointBarrier* barrier, ThreadState* state, intptr_t* stackEnd) |
| - { |
| - barrier->doPark(state, stackEnd); |
| - } |
| - |
| static void enterSafePointAfterPushRegisters(SafePointBarrier* barrier, ThreadState* state, intptr_t* stackEnd) |
| { |
| barrier->doEnterSafePoint(state, stackEnd); |
| @@ -701,9 +722,9 @@ void ThreadState::getStats(HeapStats& stats) |
| #endif |
| } |
| -void ThreadState::stopThreads() |
| +bool ThreadState::stopThreads() |
| { |
| - s_safePointBarrier->parkOthers(); |
| + return s_safePointBarrier->parkOthers(); |
| } |
| void ThreadState::resumeThreads() |