| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 90 uint8_t ThreadState::s_mainThreadStateStorage[sizeof(ThreadState)]; | 90 uint8_t ThreadState::s_mainThreadStateStorage[sizeof(ThreadState)]; |
| 91 SafePointBarrier* ThreadState::s_safePointBarrier = 0; | 91 SafePointBarrier* ThreadState::s_safePointBarrier = 0; |
| 92 bool ThreadState::s_inGC = false; | 92 bool ThreadState::s_inGC = false; |
| 93 | 93 |
| 94 static Mutex& threadAttachMutex() | 94 static Mutex& threadAttachMutex() |
| 95 { | 95 { |
| 96 AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex); | 96 AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex); |
| 97 return mutex; | 97 return mutex; |
| 98 } | 98 } |
| 99 | 99 |
| 100 static double lockingTimeout() |
| 101 { |
| 102 // Wait time for parking all threads is at most 500 MS. |
| 103 return 0.100; |
| 104 } |
| 105 |
| 106 |
| 100 typedef void (*PushAllRegistersCallback)(SafePointBarrier*, ThreadState*, intptr
_t*); | 107 typedef void (*PushAllRegistersCallback)(SafePointBarrier*, ThreadState*, intptr
_t*); |
| 101 extern "C" void pushAllRegisters(SafePointBarrier*, ThreadState*, PushAllRegiste
rsCallback); | 108 extern "C" void pushAllRegisters(SafePointBarrier*, ThreadState*, PushAllRegiste
rsCallback); |
| 102 | 109 |
| 103 class SafePointBarrier { | 110 class SafePointBarrier { |
| 104 public: | 111 public: |
| 105 SafePointBarrier() : m_canResume(1), m_unparkedThreadCount(0) { } | 112 SafePointBarrier() : m_canResume(1), m_unparkedThreadCount(0) { } |
| 106 ~SafePointBarrier() { } | 113 ~SafePointBarrier() { } |
| 107 | 114 |
| 108 // Request other attached threads that are not at safe points to park themse
lves on safepoints. | 115 // Request other attached threads that are not at safe points to park themse
lves on safepoints. |
| 109 void parkOthers() | 116 bool parkOthers() |
| 110 { | 117 { |
| 111 ASSERT(ThreadState::current()->isAtSafePoint()); | 118 ASSERT(ThreadState::current()->isAtSafePoint()); |
| 112 | 119 |
| 113 // Lock threadAttachMutex() to prevent threads from attaching. | 120 // Lock threadAttachMutex() to prevent threads from attaching. |
| 114 threadAttachMutex().lock(); | 121 threadAttachMutex().lock(); |
| 115 | 122 |
| 116 ThreadState::AttachedThreadStateSet& threads = ThreadState::attachedThre
ads(); | 123 ThreadState::AttachedThreadStateSet& threads = ThreadState::attachedThre
ads(); |
| 117 | 124 |
| 118 MutexLocker locker(m_mutex); | 125 MutexLocker locker(m_mutex); |
| 119 atomicAdd(&m_unparkedThreadCount, threads.size()); | 126 atomicAdd(&m_unparkedThreadCount, threads.size()); |
| 120 releaseStore(&m_canResume, 0); | 127 releaseStore(&m_canResume, 0); |
| 121 | 128 |
| 122 ThreadState* current = ThreadState::current(); | 129 ThreadState* current = ThreadState::current(); |
| 123 for (ThreadState::AttachedThreadStateSet::iterator it = threads.begin(),
end = threads.end(); it != end; ++it) { | 130 for (ThreadState::AttachedThreadStateSet::iterator it = threads.begin(),
end = threads.end(); it != end; ++it) { |
| 124 if (*it == current) | 131 if (*it == current) |
| 125 continue; | 132 continue; |
| 126 | 133 |
| 127 const Vector<ThreadState::Interruptor*>& interruptors = (*it)->inter
ruptors(); | 134 const Vector<ThreadState::Interruptor*>& interruptors = (*it)->inter
ruptors(); |
| 128 for (size_t i = 0; i < interruptors.size(); i++) | 135 for (size_t i = 0; i < interruptors.size(); i++) |
| 129 interruptors[i]->requestInterrupt(); | 136 interruptors[i]->requestInterrupt(); |
| 130 } | 137 } |
| 131 | 138 |
| 132 while (acquireLoad(&m_unparkedThreadCount) > 0) | 139 while (acquireLoad(&m_unparkedThreadCount) > 0) { |
| 133 m_parked.wait(m_mutex); | 140 double expirationTime = currentTime() + lockingTimeout(); |
| 141 if (!m_parked.timedWait(m_mutex, expirationTime)) { |
| 142 // One of the other threads did not return to a safepoint within
the maximum |
| 143 // time we allow for threads to be parked. Abandon the GC and re
sume the |
| 144 // currently parked threads. |
| 145 resumeOthers(true); |
| 146 return false; |
| 147 } |
| 148 } |
| 149 return true; |
| 134 } | 150 } |
| 135 | 151 |
| 136 void resumeOthers() | 152 void resumeOthers(bool barrierLocked = false) |
| 137 { | 153 { |
| 138 ThreadState::AttachedThreadStateSet& threads = ThreadState::attachedThre
ads(); | 154 ThreadState::AttachedThreadStateSet& threads = ThreadState::attachedThre
ads(); |
| 139 atomicSubtract(&m_unparkedThreadCount, threads.size()); | 155 atomicSubtract(&m_unparkedThreadCount, threads.size()); |
| 140 releaseStore(&m_canResume, 1); | 156 releaseStore(&m_canResume, 1); |
| 141 { | 157 |
| 158 // FIXME: Resumed threads will all contend for m_mutex just to unlock it |
| 159 // later which is a waste of resources. |
| 160 if (UNLIKELY(barrierLocked)) { |
| 161 m_resume.broadcast(); |
| 162 } else { |
| 142 // FIXME: Resumed threads will all contend for | 163 // FIXME: Resumed threads will all contend for |
| 143 // m_mutex just to unlock it later which is a waste of | 164 // m_mutex just to unlock it later which is a waste of |
| 144 // resources. | 165 // resources. |
| 145 MutexLocker locker(m_mutex); | 166 MutexLocker locker(m_mutex); |
| 146 m_resume.broadcast(); | 167 m_resume.broadcast(); |
| 147 } | 168 } |
| 148 | 169 |
| 149 ThreadState* current = ThreadState::current(); | 170 ThreadState* current = ThreadState::current(); |
| 150 for (ThreadState::AttachedThreadStateSet::iterator it = threads.begin(),
end = threads.end(); it != end; ++it) { | 171 for (ThreadState::AttachedThreadStateSet::iterator it = threads.begin(),
end = threads.end(); it != end; ++it) { |
| 151 if (*it == current) | 172 if (*it == current) |
| 152 continue; | 173 continue; |
| 153 | 174 |
| 154 const Vector<ThreadState::Interruptor*>& interruptors = (*it)->inter
ruptors(); | 175 const Vector<ThreadState::Interruptor*>& interruptors = (*it)->inter
ruptors(); |
| 155 for (size_t i = 0; i < interruptors.size(); i++) | 176 for (size_t i = 0; i < interruptors.size(); i++) |
| 156 interruptors[i]->clearInterrupt(); | 177 interruptors[i]->clearInterrupt(); |
| 157 } | 178 } |
| 158 | 179 |
| 159 threadAttachMutex().unlock(); | 180 threadAttachMutex().unlock(); |
| 160 ASSERT(ThreadState::current()->isAtSafePoint()); | 181 ASSERT(ThreadState::current()->isAtSafePoint()); |
| 161 } | 182 } |
| 162 | 183 |
| 184 void checkAndPark(ThreadState* state) |
| 185 { |
| 186 ASSERT(!state->isSweepInProgress()); |
| 187 if (!acquireLoad(&m_canResume)) { |
| 188 pushAllRegisters(this, state, parkAfterPushRegisters); |
| 189 state->performPendingSweep(); |
| 190 } |
| 191 } |
| 192 |
| 193 void enterSafePoint(ThreadState* state) |
| 194 { |
| 195 ASSERT(!state->isSweepInProgress()); |
| 196 pushAllRegisters(this, state, enterSafePointAfterPushRegisters); |
| 197 } |
| 198 |
| 199 void leaveSafePoint(ThreadState* state) |
| 200 { |
| 201 if (atomicIncrement(&m_unparkedThreadCount) > 0) |
| 202 checkAndPark(state); |
| 203 } |
| 204 |
| 205 private: |
| 163 void doPark(ThreadState* state, intptr_t* stackEnd) | 206 void doPark(ThreadState* state, intptr_t* stackEnd) |
| 164 { | 207 { |
| 165 state->recordStackEnd(stackEnd); | 208 state->recordStackEnd(stackEnd); |
| 166 MutexLocker locker(m_mutex); | 209 MutexLocker locker(m_mutex); |
| 167 if (!atomicDecrement(&m_unparkedThreadCount)) | 210 if (!atomicDecrement(&m_unparkedThreadCount)) |
| 168 m_parked.signal(); | 211 m_parked.signal(); |
| 169 while (!acquireLoad(&m_canResume)) | 212 while (!acquireLoad(&m_canResume)) |
| 170 m_resume.wait(m_mutex); | 213 m_resume.wait(m_mutex); |
| 171 atomicIncrement(&m_unparkedThreadCount); | 214 atomicIncrement(&m_unparkedThreadCount); |
| 172 } | 215 } |
| 173 | 216 |
| 174 void checkAndPark(ThreadState* state) | 217 static void parkAfterPushRegisters(SafePointBarrier* barrier, ThreadState* s
tate, intptr_t* stackEnd) |
| 175 { | 218 { |
| 176 ASSERT(!state->isSweepInProgress()); | 219 barrier->doPark(state, stackEnd); |
| 177 if (!acquireLoad(&m_canResume)) { | |
| 178 pushAllRegisters(this, state, parkAfterPushRegisters); | |
| 179 state->performPendingSweep(); | |
| 180 } | |
| 181 } | 220 } |
| 182 | 221 |
| 183 void doEnterSafePoint(ThreadState* state, intptr_t* stackEnd) | 222 void doEnterSafePoint(ThreadState* state, intptr_t* stackEnd) |
| 184 { | 223 { |
| 185 state->recordStackEnd(stackEnd); | 224 state->recordStackEnd(stackEnd); |
| 186 state->copyStackUntilSafePointScope(); | 225 state->copyStackUntilSafePointScope(); |
| 187 // m_unparkedThreadCount tracks amount of unparked threads. It is | 226 // m_unparkedThreadCount tracks amount of unparked threads. It is |
| 188 // positive if and only if we have requested other threads to park | 227 // positive if and only if we have requested other threads to park |
| 189 // at safe-points in preparation for GC. The last thread to park | 228 // at safe-points in preparation for GC. The last thread to park |
| 190 // itself will make the counter hit zero and should notify GC thread | 229 // itself will make the counter hit zero and should notify GC thread |
| 191 // that it is safe to proceed. | 230 // that it is safe to proceed. |
| 192 // If no other thread is waiting for other threads to park then | 231 // If no other thread is waiting for other threads to park then |
| 193 // this counter can be negative: if N threads are at safe-points | 232 // this counter can be negative: if N threads are at safe-points |
| 194 // the counter will be -N. | 233 // the counter will be -N. |
| 195 if (!atomicDecrement(&m_unparkedThreadCount)) { | 234 if (!atomicDecrement(&m_unparkedThreadCount)) { |
| 196 MutexLocker locker(m_mutex); | 235 MutexLocker locker(m_mutex); |
| 197 m_parked.signal(); // Safe point reached. | 236 m_parked.signal(); // Safe point reached. |
| 198 } | 237 } |
| 199 } | 238 } |
| 200 | 239 |
| 201 void enterSafePoint(ThreadState* state) | |
| 202 { | |
| 203 ASSERT(!state->isSweepInProgress()); | |
| 204 pushAllRegisters(this, state, enterSafePointAfterPushRegisters); | |
| 205 } | |
| 206 | |
| 207 void leaveSafePoint(ThreadState* state) | |
| 208 { | |
| 209 if (atomicIncrement(&m_unparkedThreadCount) > 0) | |
| 210 checkAndPark(state); | |
| 211 } | |
| 212 | |
| 213 private: | |
| 214 static void parkAfterPushRegisters(SafePointBarrier* barrier, ThreadState* s
tate, intptr_t* stackEnd) | |
| 215 { | |
| 216 barrier->doPark(state, stackEnd); | |
| 217 } | |
| 218 | |
| 219 static void enterSafePointAfterPushRegisters(SafePointBarrier* barrier, Thre
adState* state, intptr_t* stackEnd) | 240 static void enterSafePointAfterPushRegisters(SafePointBarrier* barrier, Thre
adState* state, intptr_t* stackEnd) |
| 220 { | 241 { |
| 221 barrier->doEnterSafePoint(state, stackEnd); | 242 barrier->doEnterSafePoint(state, stackEnd); |
| 222 } | 243 } |
| 223 | 244 |
| 224 volatile int m_canResume; | 245 volatile int m_canResume; |
| 225 volatile int m_unparkedThreadCount; | 246 volatile int m_unparkedThreadCount; |
| 226 Mutex m_mutex; | 247 Mutex m_mutex; |
| 227 ThreadCondition m_parked; | 248 ThreadCondition m_parked; |
| 228 ThreadCondition m_resume; | 249 ThreadCondition m_resume; |
| (...skipping 466 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 695 if (isConsistentForGC()) { | 716 if (isConsistentForGC()) { |
| 696 HeapStats scannedStats; | 717 HeapStats scannedStats; |
| 697 scannedStats.clear(); | 718 scannedStats.clear(); |
| 698 for (int i = 0; i < NumberOfHeaps; i++) | 719 for (int i = 0; i < NumberOfHeaps; i++) |
| 699 m_heaps[i]->getScannedStats(scannedStats); | 720 m_heaps[i]->getScannedStats(scannedStats); |
| 700 ASSERT(scannedStats == stats); | 721 ASSERT(scannedStats == stats); |
| 701 } | 722 } |
| 702 #endif | 723 #endif |
| 703 } | 724 } |
| 704 | 725 |
| 705 void ThreadState::stopThreads() | 726 bool ThreadState::stopThreads() |
| 706 { | 727 { |
| 707 s_safePointBarrier->parkOthers(); | 728 return s_safePointBarrier->parkOthers(); |
| 708 } | 729 } |
| 709 | 730 |
| 710 void ThreadState::resumeThreads() | 731 void ThreadState::resumeThreads() |
| 711 { | 732 { |
| 712 s_safePointBarrier->resumeOthers(); | 733 s_safePointBarrier->resumeOthers(); |
| 713 } | 734 } |
| 714 | 735 |
| 715 void ThreadState::safePoint(StackState stackState) | 736 void ThreadState::safePoint(StackState stackState) |
| 716 { | 737 { |
| 717 checkThread(); | 738 checkThread(); |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 850 state->safePoint(HeapPointersOnStack); | 871 state->safePoint(HeapPointersOnStack); |
| 851 } | 872 } |
| 852 | 873 |
| 853 ThreadState::AttachedThreadStateSet& ThreadState::attachedThreads() | 874 ThreadState::AttachedThreadStateSet& ThreadState::attachedThreads() |
| 854 { | 875 { |
| 855 DEFINE_STATIC_LOCAL(AttachedThreadStateSet, threads, ()); | 876 DEFINE_STATIC_LOCAL(AttachedThreadStateSet, threads, ()); |
| 856 return threads; | 877 return threads; |
| 857 } | 878 } |
| 858 | 879 |
| 859 } | 880 } |
| OLD | NEW |