| 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 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 52 typedef void (*PushAllRegistersCallback)(SafePointBarrier*, ThreadState*, intptr
_t*); | 52 typedef void (*PushAllRegistersCallback)(SafePointBarrier*, ThreadState*, intptr
_t*); |
| 53 extern "C" void pushAllRegisters(SafePointBarrier*, ThreadState*, PushAllRegiste
rsCallback); | 53 extern "C" void pushAllRegisters(SafePointBarrier*, ThreadState*, PushAllRegiste
rsCallback); |
| 54 | 54 |
| 55 static Mutex& threadAttachMutex() | 55 static Mutex& threadAttachMutex() |
| 56 { | 56 { |
| 57 AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex); | 57 AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex); |
| 58 return mutex; | 58 return mutex; |
| 59 } | 59 } |
| 60 | 60 |
| 61 static void parkAfterPushRegisters(SafePointBarrier*, ThreadState*, intptr_t* st
ackEnd); | 61 static void parkAfterPushRegisters(SafePointBarrier*, ThreadState*, intptr_t* st
ackEnd); |
| 62 static void notifyPausedAfterPushRegisters(SafePointBarrier*, ThreadState*, intp
tr_t* stackEnd); | 62 static void enterSafePointAfterPushRegisters(SafePointBarrier*, ThreadState*, in
tptr_t* stackEnd); |
| 63 | 63 |
| 64 class SafePointBarrier { | 64 class SafePointBarrier { |
| 65 public: | 65 public: |
| 66 SafePointBarrier() | 66 SafePointBarrier() |
| 67 { | 67 { |
| 68 NoBarrier_Store(&m_unparkedThreadCount, 0); | 68 NoBarrier_Store(&m_unparkedThreadCount, 0); |
| 69 Release_Store(&m_canResume, 1); | 69 Release_Store(&m_canResume, 1); |
| 70 } | 70 } |
| 71 | 71 |
| 72 ~SafePointBarrier() | 72 ~SafePointBarrier() |
| 73 { | 73 { |
| 74 } | 74 } |
| 75 | 75 |
| 76 // Request other attached and non-paused threads to park themselves on safep
oints. | 76 // Request other attached and not-in-safe-point threads to park themselves o
n safepoints. |
| 77 void parkOthers(ThreadState::StackState stackState) | 77 void parkOthers(ThreadState::StackState stackState) |
| 78 { | 78 { |
| 79 // Mark current thread as paused before attempting to lock the threadAtt
achMutex(). This will | 79 // Enter safe point before attempting to lock the threadAttachMutex(). T
his will |
| 80 // allow to avoid dead-lock if two threads arrive into parkOthers() simu
ltaneously. | 80 // allow to avoid dead-lock if two threads arrive into parkOthers() simu
ltaneously. |
| 81 ThreadState::Current()->paused(stackState); | 81 ThreadState::Current()->enterSafePoint(stackState); |
| 82 | 82 |
| 83 // Lock threadAttachMutex() to prevent threads from attaching. | 83 // Lock threadAttachMutex() to prevent threads from attaching. |
| 84 threadAttachMutex().lock(); | 84 threadAttachMutex().lock(); |
| 85 | 85 |
| 86 ThreadState::AttachedThreadStateSet& threads = ThreadState::attachedThre
ads(); | 86 ThreadState::AttachedThreadStateSet& threads = ThreadState::attachedThre
ads(); |
| 87 | 87 |
| 88 MutexLocker locker(m_mutex); | 88 MutexLocker locker(m_mutex); |
| 89 NoBarrier_AtomicIncrement(&m_unparkedThreadCount, threads.size()); | 89 NoBarrier_AtomicIncrement(&m_unparkedThreadCount, threads.size()); |
| 90 Release_Store(&m_canResume, 0); | 90 Release_Store(&m_canResume, 0); |
| 91 | 91 |
| 92 for (ThreadState::AttachedThreadStateSet::iterator it = threads.begin(),
end = threads.end(); it != end; ++it) { | 92 for (ThreadState::AttachedThreadStateSet::iterator it = threads.begin(),
end = threads.end(); it != end; ++it) { |
| 93 if ((*it)->interruptor()) | 93 if ((*it)->interruptor()) |
| 94 (*it)->interruptor()->requestInterrupt(); | 94 (*it)->interruptor()->requestInterrupt(); |
| 95 } | 95 } |
| 96 | 96 |
| 97 while (NoBarrier_Load(&m_unparkedThreadCount) > 0) | 97 while (NoBarrier_Load(&m_unparkedThreadCount) > 0) |
| 98 m_parked.wait(m_mutex); | 98 m_parked.wait(m_mutex); |
| 99 } | 99 } |
| 100 | 100 |
| 101 void resumeOthers() | 101 void resumeOthers() |
| 102 { | 102 { |
| 103 ThreadState::AttachedThreadStateSet& threads = ThreadState::attachedThre
ads(); | 103 ThreadState::AttachedThreadStateSet& threads = ThreadState::attachedThre
ads(); |
| 104 NoBarrier_AtomicIncrement(&m_unparkedThreadCount, -threads.size()); | 104 NoBarrier_AtomicIncrement(&m_unparkedThreadCount, -threads.size()); |
| 105 Release_Store(&m_canResume, 1); | 105 Release_Store(&m_canResume, 1); |
| 106 { | 106 { |
| 107 // FIXME(oilpan) resumed threads will all contend for | 107 // FIXME(oilpan): Resumed threads will all contend for |
| 108 // m_mutex just to unlock it later which is a waste of | 108 // m_mutex just to unlock it later which is a waste of |
| 109 // resources. | 109 // resources. |
| 110 MutexLocker locker(m_mutex); | 110 MutexLocker locker(m_mutex); |
| 111 m_resume.broadcast(); | 111 m_resume.broadcast(); |
| 112 } | 112 } |
| 113 | 113 |
| 114 for (ThreadState::AttachedThreadStateSet::iterator it = threads.begin(),
end = threads.end(); it != end; ++it) { | 114 for (ThreadState::AttachedThreadStateSet::iterator it = threads.begin(),
end = threads.end(); it != end; ++it) { |
| 115 if ((*it)->interruptor()) | 115 if ((*it)->interruptor()) |
| 116 (*it)->interruptor()->clearInterrupt(); | 116 (*it)->interruptor()->clearInterrupt(); |
| 117 } | 117 } |
| 118 | 118 |
| 119 threadAttachMutex().unlock(); | 119 threadAttachMutex().unlock(); |
| 120 ThreadState::Current()->resumed(); | 120 ThreadState::Current()->leaveSafePoint(); |
| 121 } | 121 } |
| 122 | 122 |
| 123 void doPark(ThreadState* state, intptr_t* stackEnd) | 123 void doPark(ThreadState* state, intptr_t* stackEnd) |
| 124 { | 124 { |
| 125 state->recordStackEnd(stackEnd); | 125 state->recordStackEnd(stackEnd); |
| 126 MutexLocker locker(m_mutex); | 126 MutexLocker locker(m_mutex); |
| 127 if (!NoBarrier_AtomicIncrement(&m_unparkedThreadCount, -1)) | 127 if (!NoBarrier_AtomicIncrement(&m_unparkedThreadCount, -1)) |
| 128 m_parked.signal(); | 128 m_parked.signal(); |
| 129 while (!NoBarrier_Load(&m_canResume)) | 129 while (!NoBarrier_Load(&m_canResume)) |
| 130 m_resume.wait(m_mutex); | 130 m_resume.wait(m_mutex); |
| 131 NoBarrier_AtomicIncrement(&m_unparkedThreadCount, 1); | 131 NoBarrier_AtomicIncrement(&m_unparkedThreadCount, 1); |
| 132 } | 132 } |
| 133 | 133 |
| 134 void checkAndPark(ThreadState* state) | 134 void checkAndPark(ThreadState* state) |
| 135 { | 135 { |
| 136 ASSERT(!state->isSweepInProgress()); | 136 ASSERT(!state->isSweepInProgress()); |
| 137 if (!Acquire_Load(&m_canResume)) { | 137 if (!Acquire_Load(&m_canResume)) { |
| 138 pushAllRegisters(this, state, parkAfterPushRegisters); | 138 pushAllRegisters(this, state, parkAfterPushRegisters); |
| 139 state->executePendingAction(); | 139 state->executePendingAction(); |
| 140 } | 140 } |
| 141 } | 141 } |
| 142 | 142 |
| 143 void doNotifyPaused(ThreadState* state, intptr_t* stackEnd) | 143 void doEnterSafePoint(ThreadState* state, intptr_t* stackEnd) |
| 144 { | 144 { |
| 145 state->recordStackEnd(stackEnd); | 145 state->recordStackEnd(stackEnd); |
| 146 if (!NoBarrier_AtomicIncrement(&m_unparkedThreadCount, -1)) { | 146 if (!NoBarrier_AtomicIncrement(&m_unparkedThreadCount, -1)) { |
| 147 MutexLocker locker(m_mutex); | 147 MutexLocker locker(m_mutex); |
| 148 m_parked.signal(); // Safe point reached. | 148 m_parked.signal(); // Safe point reached. |
| 149 } | 149 } |
| 150 } | 150 } |
| 151 | 151 |
| 152 void notifyPaused(ThreadState* state) | 152 void enterSafePoint(ThreadState* state) |
| 153 { | 153 { |
| 154 ASSERT(!state->isSweepInProgress()); | 154 ASSERT(!state->isSweepInProgress()); |
| 155 pushAllRegisters(this, state, notifyPausedAfterPushRegisters); | 155 pushAllRegisters(this, state, enterSafePointAfterPushRegisters); |
| 156 } | 156 } |
| 157 | 157 |
| 158 void notifyResumed(ThreadState* state) | 158 void leaveSafePoint(ThreadState* state) |
| 159 { | 159 { |
| 160 if (NoBarrier_AtomicIncrement(&m_unparkedThreadCount, 1) > 0) | 160 if (NoBarrier_AtomicIncrement(&m_unparkedThreadCount, 1) > 0) |
| 161 checkAndPark(state); | 161 checkAndPark(state); |
| 162 state->executePendingAction(); | 162 state->executePendingAction(); |
| 163 } | 163 } |
| 164 | 164 |
| 165 private: | 165 private: |
| 166 volatile Atomic32 m_canResume; | 166 volatile Atomic32 m_canResume; |
| 167 volatile Atomic32 m_unparkedThreadCount; | 167 volatile Atomic32 m_unparkedThreadCount; |
| 168 Mutex m_mutex; | 168 Mutex m_mutex; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 204 { | 204 { |
| 205 MutexLocker locker(threadAttachMutex()); | 205 MutexLocker locker(threadAttachMutex()); |
| 206 ThreadState* state = new ThreadState(); | 206 ThreadState* state = new ThreadState(); |
| 207 state->create(startOfStack); | 207 state->create(startOfStack); |
| 208 attachedThreads().add(state); | 208 attachedThreads().add(state); |
| 209 } | 209 } |
| 210 | 210 |
| 211 void ThreadState::detach() | 211 void ThreadState::detach() |
| 212 { | 212 { |
| 213 ThreadState* current = Current(); | 213 ThreadState* current = Current(); |
| 214 // Mark current thread as paused before trying to acquire threadAttachMutex | 214 // Enter safe point before trying to acquire threadAttachMutex |
| 215 // to avoid dead lock if another thread is preparing for GC, has acquired | 215 // to avoid dead lock if another thread is preparing for GC, has acquired |
| 216 // threadAttachMutex and waiting for other threads to pause or reach a | 216 // threadAttachMutex and waiting for other threads to pause or reach a |
| 217 // safepoint. | 217 // safepoint. |
| 218 if (!current->isPaused()) | 218 if (!current->isInSafePoint()) |
| 219 current->paused(NoHeapPointersOnStack); | 219 current->enterSafePoint(NoHeapPointersOnStack); |
| 220 MutexLocker locker(threadAttachMutex()); | 220 MutexLocker locker(threadAttachMutex()); |
| 221 current->resumed(); | 221 current->leaveSafePoint(); |
| 222 current->destroy(); | 222 current->destroy(); |
| 223 attachedThreads().remove(current); | 223 attachedThreads().remove(current); |
| 224 delete current; | 224 delete current; |
| 225 } | 225 } |
| 226 | 226 |
| 227 void ThreadState::create(intptr_t* startOfStack) | 227 void ThreadState::create(intptr_t* startOfStack) |
| 228 { | 228 { |
| 229 ASSERT(!**s_threadSpecific); | 229 ASSERT(!**s_threadSpecific); |
| 230 m_thread = currentThread(); | 230 m_thread = currentThread(); |
| 231 **s_threadSpecific = this; | 231 **s_threadSpecific = this; |
| (...skipping 28 matching lines...) Expand all Loading... |
| 260 checkThread(); | 260 checkThread(); |
| 261 delete m_heaps[GeneralHeap]; | 261 delete m_heaps[GeneralHeap]; |
| 262 for (int i = GeneralHeap + 1; i < NumberOfHeaps; i++) | 262 for (int i = GeneralHeap + 1; i < NumberOfHeaps; i++) |
| 263 delete m_heaps[i]; | 263 delete m_heaps[i]; |
| 264 delete m_persistents; | 264 delete m_persistents; |
| 265 m_persistents = 0; | 265 m_persistents = 0; |
| 266 delete m_interruptor; | 266 delete m_interruptor; |
| 267 m_interruptor = 0; | 267 m_interruptor = 0; |
| 268 } | 268 } |
| 269 | 269 |
| 270 void ThreadState::paused(StackState stackState) | 270 void ThreadState::enterSafePoint(StackState stackState) |
| 271 { | 271 { |
| 272 if (stackState == NoHeapPointersOnStack && gcRequested()) | 272 if (stackState == NoHeapPointersOnStack && gcRequested()) |
| 273 Heap::collectGarbage(NoHeapPointersOnStack); | 273 Heap::collectGarbage(NoHeapPointersOnStack); |
| 274 checkThread(); | 274 checkThread(); |
| 275 ASSERT(!m_isPaused); | 275 ASSERT(!m_inSafePoint); |
| 276 m_isPaused = true; | 276 m_inSafePoint = true; |
| 277 m_stackState = stackState; | 277 m_stackState = stackState; |
| 278 s_safePointBarrier->notifyPaused(this); | 278 s_safePointBarrier->enterSafePoint(this); |
| 279 } | 279 } |
| 280 | 280 |
| 281 void ThreadState::resumed() | 281 void ThreadState::leaveSafePoint() |
| 282 { | 282 { |
| 283 checkThread(); | 283 checkThread(); |
| 284 ASSERT(m_isPaused); | 284 ASSERT(m_inSafePoint); |
| 285 m_isPaused = false; | 285 m_inSafePoint = false; |
| 286 m_stackState = HeapPointersOnStack; | 286 m_stackState = HeapPointersOnStack; |
| 287 s_safePointBarrier->notifyResumed(this); | 287 s_safePointBarrier->leaveSafePoint(this); |
| 288 } | 288 } |
| 289 | 289 |
| 290 void ThreadState::visitRoots(Visitor* visitor) | 290 void ThreadState::visitRoots(Visitor* visitor) |
| 291 { | 291 { |
| 292 AttachedThreadStateSet& threads = attachedThreads(); | 292 AttachedThreadStateSet& threads = attachedThreads(); |
| 293 for (AttachedThreadStateSet::iterator it = threads.begin(), end = threads.en
d(); it != end; ++it) | 293 for (AttachedThreadStateSet::iterator it = threads.begin(), end = threads.en
d(); it != end; ++it) |
| 294 (*it)->trace(visitor); | 294 (*it)->trace(visitor); |
| 295 } | 295 } |
| 296 | 296 |
| 297 void ThreadState::visitPersistents(Visitor* visitor) | 297 void ThreadState::visitPersistents(Visitor* visitor) |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 440 return Acquire_Load(&m_gcRequested); | 440 return Acquire_Load(&m_gcRequested); |
| 441 } | 441 } |
| 442 | 442 |
| 443 void ThreadState::setGCRequested(bool gcRequested) | 443 void ThreadState::setGCRequested(bool gcRequested) |
| 444 { | 444 { |
| 445 Release_Store(&m_gcRequested, gcRequested); | 445 Release_Store(&m_gcRequested, gcRequested); |
| 446 } | 446 } |
| 447 | 447 |
| 448 void ThreadState::setInterruptor(Interruptor* interruptor) | 448 void ThreadState::setInterruptor(Interruptor* interruptor) |
| 449 { | 449 { |
| 450 bool wasPaused = false; | 450 bool wasInSafePoint = false; |
| 451 if (!isPaused()) { | 451 if (!isInSafePoint()) { |
| 452 paused(HeapPointersOnStack); | 452 enterSafePoint(HeapPointersOnStack); |
| 453 wasPaused = true; | 453 wasInSafePoint = true; |
| 454 } | 454 } |
| 455 | 455 |
| 456 { | 456 { |
| 457 MutexLocker locker(threadAttachMutex()); | 457 MutexLocker locker(threadAttachMutex()); |
| 458 delete m_interruptor; | 458 delete m_interruptor; |
| 459 m_interruptor = interruptor; | 459 m_interruptor = interruptor; |
| 460 } | 460 } |
| 461 | 461 |
| 462 if (wasPaused) | 462 if (wasInSafePoint) |
| 463 resumed(); | 463 leaveSafePoint(); |
| 464 } | 464 } |
| 465 | 465 |
| 466 bool ThreadState::inFinalizeAll() | 466 bool ThreadState::inFinalizeAll() |
| 467 { | 467 { |
| 468 for (int i = 0; i < NumberOfHeaps; i++) { | 468 for (int i = 0; i < NumberOfHeaps; i++) { |
| 469 if (m_heaps[i]->inFinalizeAll()) | 469 if (m_heaps[i]->inFinalizeAll()) |
| 470 return true; | 470 return true; |
| 471 } | 471 } |
| 472 return false; | 472 return false; |
| 473 } | 473 } |
| (...skipping 20 matching lines...) Expand all Loading... |
| 494 m_sweepInProgress = false; | 494 m_sweepInProgress = false; |
| 495 setGCRequested(false); | 495 setGCRequested(false); |
| 496 setSweepRequested(false); | 496 setSweepRequested(false); |
| 497 } | 497 } |
| 498 } | 498 } |
| 499 | 499 |
| 500 void ThreadState::Interruptor::onInterrupted() | 500 void ThreadState::Interruptor::onInterrupted() |
| 501 { | 501 { |
| 502 ThreadState* state = ThreadState::Current(); | 502 ThreadState* state = ThreadState::Current(); |
| 503 ASSERT(state); | 503 ASSERT(state); |
| 504 ASSERT(!state->isPaused()); | 504 ASSERT(!state->isInSafePoint()); |
| 505 state->safePoint(); | 505 state->safePoint(); |
| 506 } | 506 } |
| 507 | 507 |
| 508 // Trigger on a 50% increase in size, but not for less than 2 pages. | 508 // Trigger on a 50% increase in size, but not for less than 2 pages. |
| 509 static bool increasedEnough(size_t newSize, size_t oldSize) | 509 static bool increasedEnough(size_t newSize, size_t oldSize) |
| 510 { | 510 { |
| 511 if (newSize < 2 * writablePageSize()) | 511 if (newSize < 2 * writablePageSize()) |
| 512 return false; | 512 return false; |
| 513 return newSize > oldSize + (oldSize >> 1); | 513 return newSize > oldSize + (oldSize >> 1); |
| 514 } | 514 } |
| (...skipping 24 matching lines...) Expand all Loading... |
| 539 { | 539 { |
| 540 return m_totalAllocatedSpace == other.m_totalAllocatedSpace | 540 return m_totalAllocatedSpace == other.m_totalAllocatedSpace |
| 541 && m_totalObjectSpace == other.m_totalObjectSpace; | 541 && m_totalObjectSpace == other.m_totalObjectSpace; |
| 542 } | 542 } |
| 543 | 543 |
| 544 static void parkAfterPushRegisters(SafePointBarrier* barrier, ThreadState* state
, intptr_t* stackEnd) | 544 static void parkAfterPushRegisters(SafePointBarrier* barrier, ThreadState* state
, intptr_t* stackEnd) |
| 545 { | 545 { |
| 546 barrier->doPark(state, stackEnd); | 546 barrier->doPark(state, stackEnd); |
| 547 } | 547 } |
| 548 | 548 |
| 549 static void notifyPausedAfterPushRegisters(SafePointBarrier* barrier, ThreadStat
e* state, intptr_t* stackEnd) | 549 static void enterSafePointAfterPushRegisters(SafePointBarrier* barrier, ThreadSt
ate* state, intptr_t* stackEnd) |
| 550 { | 550 { |
| 551 barrier->doNotifyPaused(state, stackEnd); | 551 barrier->doEnterSafePoint(state, stackEnd); |
| 552 } | 552 } |
| 553 | 553 |
| 554 | 554 |
| 555 } | 555 } |
| OLD | NEW |