| 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 100 MS. | |
| 103 return 0.100; | |
| 104 } | |
| 105 | |
| 106 | |
| 107 typedef void (*PushAllRegistersCallback)(SafePointBarrier*, ThreadState*, intptr
_t*); | |
| 108 extern "C" void pushAllRegisters(SafePointBarrier*, ThreadState*, PushAllRegiste
rsCallback); | |
| 109 | |
| 110 class SafePointBarrier { | 100 class SafePointBarrier { |
| 111 public: | 101 public: |
| 112 SafePointBarrier() : m_canResume(1), m_unparkedThreadCount(0) { } | 102 SafePointBarrier() : m_canResume(1), m_unparkedThreadCount(0) { } |
| 113 ~SafePointBarrier() { } | 103 ~SafePointBarrier() { } |
| 114 | 104 |
| 115 // Request other attached threads that are not at safe points to park themse
lves on safepoints. | 105 // Request other attached threads that are not at safe points to park themse
lves on safepoints. |
| 116 bool parkOthers() | 106 bool parkOthers() |
| 117 { | 107 { |
| 118 ASSERT(ThreadState::current()->isAtSafePoint()); | |
| 119 | |
| 120 // Lock threadAttachMutex() to prevent threads from attaching. | |
| 121 threadAttachMutex().lock(); | |
| 122 | |
| 123 ThreadState::AttachedThreadStateSet& threads = ThreadState::attachedThre
ads(); | |
| 124 | |
| 125 MutexLocker locker(m_mutex); | |
| 126 atomicAdd(&m_unparkedThreadCount, threads.size()); | |
| 127 releaseStore(&m_canResume, 0); | |
| 128 | |
| 129 ThreadState* current = ThreadState::current(); | |
| 130 for (ThreadState::AttachedThreadStateSet::iterator it = threads.begin(),
end = threads.end(); it != end; ++it) { | |
| 131 if (*it == current) | |
| 132 continue; | |
| 133 | |
| 134 const Vector<ThreadState::Interruptor*>& interruptors = (*it)->inter
ruptors(); | |
| 135 for (size_t i = 0; i < interruptors.size(); i++) | |
| 136 interruptors[i]->requestInterrupt(); | |
| 137 } | |
| 138 | |
| 139 while (acquireLoad(&m_unparkedThreadCount) > 0) { | |
| 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; | 108 return true; |
| 150 } | 109 } |
| 151 | 110 |
| 152 void resumeOthers(bool barrierLocked = false) | 111 void resumeOthers(bool barrierLocked = false) |
| 153 { | 112 { |
| 154 ThreadState::AttachedThreadStateSet& threads = ThreadState::attachedThre
ads(); | |
| 155 atomicSubtract(&m_unparkedThreadCount, threads.size()); | |
| 156 releaseStore(&m_canResume, 1); | |
| 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 { | |
| 163 // FIXME: Resumed threads will all contend for | |
| 164 // m_mutex just to unlock it later which is a waste of | |
| 165 // resources. | |
| 166 MutexLocker locker(m_mutex); | |
| 167 m_resume.broadcast(); | |
| 168 } | |
| 169 | |
| 170 ThreadState* current = ThreadState::current(); | |
| 171 for (ThreadState::AttachedThreadStateSet::iterator it = threads.begin(),
end = threads.end(); it != end; ++it) { | |
| 172 if (*it == current) | |
| 173 continue; | |
| 174 | |
| 175 const Vector<ThreadState::Interruptor*>& interruptors = (*it)->inter
ruptors(); | |
| 176 for (size_t i = 0; i < interruptors.size(); i++) | |
| 177 interruptors[i]->clearInterrupt(); | |
| 178 } | |
| 179 | |
| 180 threadAttachMutex().unlock(); | |
| 181 ASSERT(ThreadState::current()->isAtSafePoint()); | |
| 182 } | 113 } |
| 183 | 114 |
| 184 void checkAndPark(ThreadState* state, SafePointAwareMutexLocker* locker = 0) | 115 void checkAndPark(ThreadState* state, SafePointAwareMutexLocker* locker = 0) |
| 185 { | 116 { |
| 186 ASSERT(!state->isSweepInProgress()); | |
| 187 if (!acquireLoad(&m_canResume)) { | |
| 188 // If we are leaving the safepoint from a SafePointAwareMutexLocker | |
| 189 // call out to release the lock before going to sleep. This enables
the | |
| 190 // lock to be acquired in the sweep phase, e.g. during weak processi
ng | |
| 191 // or finalization. The SafePointAwareLocker will reenter the safepo
int | |
| 192 // and reacquire the lock after leaving this safepoint. | |
| 193 if (locker) | |
| 194 locker->reset(); | |
| 195 pushAllRegisters(this, state, parkAfterPushRegisters); | |
| 196 } | |
| 197 } | 117 } |
| 198 | 118 |
| 199 void enterSafePoint(ThreadState* state) | 119 void enterSafePoint(ThreadState* state) |
| 200 { | 120 { |
| 201 ASSERT(!state->isSweepInProgress()); | |
| 202 pushAllRegisters(this, state, enterSafePointAfterPushRegisters); | |
| 203 } | 121 } |
| 204 | 122 |
| 205 void leaveSafePoint(ThreadState* state, SafePointAwareMutexLocker* locker =
0) | 123 void leaveSafePoint(ThreadState* state, SafePointAwareMutexLocker* locker =
0) |
| 206 { | 124 { |
| 207 if (atomicIncrement(&m_unparkedThreadCount) > 0) | |
| 208 checkAndPark(state, locker); | |
| 209 } | 125 } |
| 210 | 126 |
| 211 private: | 127 private: |
| 212 void doPark(ThreadState* state, intptr_t* stackEnd) | 128 void doPark(ThreadState* state, intptr_t* stackEnd) |
| 213 { | 129 { |
| 214 state->recordStackEnd(stackEnd); | 130 state->recordStackEnd(stackEnd); |
| 215 MutexLocker locker(m_mutex); | 131 MutexLocker locker(m_mutex); |
| 216 if (!atomicDecrement(&m_unparkedThreadCount)) | 132 if (!atomicDecrement(&m_unparkedThreadCount)) |
| 217 m_parked.signal(); | 133 m_parked.signal(); |
| 218 while (!acquireLoad(&m_canResume)) | 134 while (!acquireLoad(&m_canResume)) |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 323 WrapperPersistentRegion* region = WrapperPersistentRegion::removeHead(&m
_liveWrapperPersistents); | 239 WrapperPersistentRegion* region = WrapperPersistentRegion::removeHead(&m
_liveWrapperPersistents); |
| 324 delete region; | 240 delete region; |
| 325 } | 241 } |
| 326 while (m_pooledWrapperPersistents) { | 242 while (m_pooledWrapperPersistents) { |
| 327 WrapperPersistentRegion* region = WrapperPersistentRegion::removeHead(&m
_pooledWrapperPersistents); | 243 WrapperPersistentRegion* region = WrapperPersistentRegion::removeHead(&m
_pooledWrapperPersistents); |
| 328 delete region; | 244 delete region; |
| 329 } | 245 } |
| 330 **s_threadSpecific = 0; | 246 **s_threadSpecific = 0; |
| 331 } | 247 } |
| 332 | 248 |
| 333 void ThreadState::init() | |
| 334 { | |
| 335 s_threadSpecific = new WTF::ThreadSpecific<ThreadState*>(); | |
| 336 s_safePointBarrier = new SafePointBarrier; | |
| 337 } | |
| 338 | |
| 339 void ThreadState::shutdown() | |
| 340 { | |
| 341 delete s_safePointBarrier; | |
| 342 s_safePointBarrier = 0; | |
| 343 | |
| 344 // Thread-local storage shouldn't be disposed, so we don't call ~ThreadSpeci
fic(). | |
| 345 } | |
| 346 | |
| 347 void ThreadState::attachMainThread() | |
| 348 { | |
| 349 RELEASE_ASSERT(!Heap::s_shutdownCalled); | |
| 350 MutexLocker locker(threadAttachMutex()); | |
| 351 ThreadState* state = new(s_mainThreadStateStorage) ThreadState(); | |
| 352 attachedThreads().add(state); | |
| 353 } | |
| 354 | |
| 355 void ThreadState::detachMainThread() | |
| 356 { | |
| 357 // Enter a safe point before trying to acquire threadAttachMutex | |
| 358 // to avoid dead lock if another thread is preparing for GC, has acquired | |
| 359 // threadAttachMutex and waiting for other threads to pause or reach a | |
| 360 // safepoint. | |
| 361 ThreadState* state = mainThreadState(); | |
| 362 | |
| 363 { | |
| 364 SafePointAwareMutexLocker locker(threadAttachMutex(), NoHeapPointersOnSt
ack); | |
| 365 | |
| 366 // First add the main thread's heap pages to the orphaned pool. | |
| 367 state->cleanupPages(); | |
| 368 | |
| 369 // Second detach thread. | |
| 370 ASSERT(attachedThreads().contains(state)); | |
| 371 attachedThreads().remove(state); | |
| 372 state->~ThreadState(); | |
| 373 } | |
| 374 shutdownHeapIfNecessary(); | |
| 375 } | |
| 376 | |
| 377 void ThreadState::shutdownHeapIfNecessary() | |
| 378 { | |
| 379 // We don't need to enter a safe point before acquiring threadAttachMutex | |
| 380 // because this thread is already detached. | |
| 381 | |
| 382 MutexLocker locker(threadAttachMutex()); | |
| 383 // We start shutting down the heap if there is no running thread | |
| 384 // and Heap::shutdown() is already called. | |
| 385 if (!attachedThreads().size() && Heap::s_shutdownCalled) | |
| 386 Heap::doShutdown(); | |
| 387 } | |
| 388 | |
| 389 void ThreadState::attach() | 249 void ThreadState::attach() |
| 390 { | 250 { |
| 391 RELEASE_ASSERT(!Heap::s_shutdownCalled); | 251 RELEASE_ASSERT(!Heap::s_shutdownCalled); |
| 392 MutexLocker locker(threadAttachMutex()); | 252 MutexLocker locker(threadAttachMutex()); |
| 393 ThreadState* state = new ThreadState(); | 253 ThreadState* state = new ThreadState(); |
| 394 attachedThreads().add(state); | 254 attachedThreads().add(state); |
| 395 } | 255 } |
| 396 | 256 |
| 397 void ThreadState::cleanupPages() | 257 void ThreadState::cleanupPages() |
| 398 { | 258 { |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 445 ASSERT(attachedThreads().contains(this)); | 305 ASSERT(attachedThreads().contains(this)); |
| 446 attachedThreads().remove(this); | 306 attachedThreads().remove(this); |
| 447 } | 307 } |
| 448 | 308 |
| 449 for (size_t i = 0; i < m_cleanupTasks.size(); i++) | 309 for (size_t i = 0; i < m_cleanupTasks.size(); i++) |
| 450 m_cleanupTasks[i]->postCleanup(); | 310 m_cleanupTasks[i]->postCleanup(); |
| 451 m_cleanupTasks.clear(); | 311 m_cleanupTasks.clear(); |
| 452 } | 312 } |
| 453 | 313 |
| 454 | 314 |
| 455 void ThreadState::detach() | |
| 456 { | |
| 457 ThreadState* state = current(); | |
| 458 state->cleanup(); | |
| 459 delete state; | |
| 460 shutdownHeapIfNecessary(); | |
| 461 } | |
| 462 | |
| 463 void ThreadState::visitPersistentRoots(Visitor* visitor) | 315 void ThreadState::visitPersistentRoots(Visitor* visitor) |
| 464 { | 316 { |
| 465 { | 317 { |
| 466 // All threads are at safepoints so this is not strictly necessary. | 318 // All threads are at safepoints so this is not strictly necessary. |
| 467 // However we acquire the mutex to make mutation and traversal of this | 319 // However we acquire the mutex to make mutation and traversal of this |
| 468 // list symmetrical. | 320 // list symmetrical. |
| 469 MutexLocker locker(globalRootsMutex()); | 321 MutexLocker locker(globalRootsMutex()); |
| 470 globalRoots()->trace(visitor); | 322 globalRoots()->trace(visitor); |
| 471 } | 323 } |
| 472 | 324 |
| (...skipping 608 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1081 return gcInfo; | 933 return gcInfo; |
| 1082 } | 934 } |
| 1083 } | 935 } |
| 1084 if (needLockForIteration) | 936 if (needLockForIteration) |
| 1085 threadAttachMutex().unlock(); | 937 threadAttachMutex().unlock(); |
| 1086 return 0; | 938 return 0; |
| 1087 } | 939 } |
| 1088 #endif | 940 #endif |
| 1089 | 941 |
| 1090 } | 942 } |
| OLD | NEW |