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. |
Mads Ager (chromium)
2013/12/05 09:22:24
Request other attached threads that are not at saf
haraken
2013/12/05 09:37:40
Done.
| |
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; |
Mads Ager (chromium)
2013/12/05 09:22:24
wasAtSafePoint?
| |
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 |