Mercurial > hg > graal-jvmci-8
comparison src/share/vm/gc_implementation/g1/vm_operations_g1.cpp @ 5963:64bf7c8270cb
7147724: G1: hang in SurrogateLockerThread::manipulatePLL
Summary: Attempting to initiate a marking cycle when allocating a humongous object can, if a marking cycle is successfully initiated by another thread, result in the allocating thread spinning until the marking cycle is complete. Eliminate a deadlock between the main ConcurrentMarkThread, the SurrogateLocker thread, the VM thread, and a mutator thread waiting on the SecondaryFreeList_lock (while free regions are going to become available) by not manipulating the pending list lock during the prologue and epilogue of the cleanup pause.
Reviewed-by: brutisso, jcoomes, tonyp
author | johnc |
---|---|
date | Mon, 12 Mar 2012 14:59:00 -0700 |
parents | 9509c20bba28 |
children | 5c86f8211d1e |
comparison
equal
deleted
inserted
replaced
5962:8a729074feae | 5963:64bf7c8270cb |
---|---|
32 #include "runtime/interfaceSupport.hpp" | 32 #include "runtime/interfaceSupport.hpp" |
33 | 33 |
34 VM_G1CollectForAllocation::VM_G1CollectForAllocation( | 34 VM_G1CollectForAllocation::VM_G1CollectForAllocation( |
35 unsigned int gc_count_before, | 35 unsigned int gc_count_before, |
36 size_t word_size) | 36 size_t word_size) |
37 : VM_G1OperationWithAllocRequest(gc_count_before, word_size) { | 37 : VM_G1OperationWithAllocRequest(gc_count_before, word_size, |
38 GCCause::_allocation_failure) { | |
38 guarantee(word_size > 0, "an allocation should always be requested"); | 39 guarantee(word_size > 0, "an allocation should always be requested"); |
39 } | 40 } |
40 | 41 |
41 void VM_G1CollectForAllocation::doit() { | 42 void VM_G1CollectForAllocation::doit() { |
42 G1CollectedHeap* g1h = G1CollectedHeap::heap(); | 43 G1CollectedHeap* g1h = G1CollectedHeap::heap(); |
55 unsigned int gc_count_before, | 56 unsigned int gc_count_before, |
56 size_t word_size, | 57 size_t word_size, |
57 bool should_initiate_conc_mark, | 58 bool should_initiate_conc_mark, |
58 double target_pause_time_ms, | 59 double target_pause_time_ms, |
59 GCCause::Cause gc_cause) | 60 GCCause::Cause gc_cause) |
60 : VM_G1OperationWithAllocRequest(gc_count_before, word_size), | 61 : VM_G1OperationWithAllocRequest(gc_count_before, word_size, gc_cause), |
61 _should_initiate_conc_mark(should_initiate_conc_mark), | 62 _should_initiate_conc_mark(should_initiate_conc_mark), |
62 _target_pause_time_ms(target_pause_time_ms), | 63 _target_pause_time_ms(target_pause_time_ms), |
64 _should_retry_gc(false), | |
63 _full_collections_completed_before(0) { | 65 _full_collections_completed_before(0) { |
64 guarantee(target_pause_time_ms > 0.0, | 66 guarantee(target_pause_time_ms > 0.0, |
65 err_msg("target_pause_time_ms = %1.6lf should be positive", | 67 err_msg("target_pause_time_ms = %1.6lf should be positive", |
66 target_pause_time_ms)); | 68 target_pause_time_ms)); |
67 guarantee(word_size == 0 || gc_cause == GCCause::_g1_inc_collection_pause, | 69 guarantee(word_size == 0 || gc_cause == GCCause::_g1_inc_collection_pause, |
68 "we can only request an allocation if the GC cause is for " | 70 "we can only request an allocation if the GC cause is for " |
69 "an incremental GC pause"); | 71 "an incremental GC pause"); |
70 _gc_cause = gc_cause; | 72 _gc_cause = gc_cause; |
73 } | |
74 | |
75 bool VM_G1IncCollectionPause::doit_prologue() { | |
76 bool res = VM_GC_Operation::doit_prologue(); | |
77 if (!res) { | |
78 if (_should_initiate_conc_mark) { | |
79 // The prologue can fail for a couple of reasons. The first is that another GC | |
80 // got scheduled and prevented the scheduling of the initial mark GC. The | |
81 // second is that the GC locker may be active and the heap can't be expanded. | |
82 // In both cases we want to retry the GC so that the initial mark pause is | |
83 // actually scheduled. In the second case, however, we should stall until | |
84 // until the GC locker is no longer active and then retry the initial mark GC. | |
85 _should_retry_gc = true; | |
86 } | |
87 } | |
88 return res; | |
71 } | 89 } |
72 | 90 |
73 void VM_G1IncCollectionPause::doit() { | 91 void VM_G1IncCollectionPause::doit() { |
74 G1CollectedHeap* g1h = G1CollectedHeap::heap(); | 92 G1CollectedHeap* g1h = G1CollectedHeap::heap(); |
75 assert(!_should_initiate_conc_mark || | 93 assert(!_should_initiate_conc_mark || |
104 | 122 |
105 // The above routine returns true if we were able to force the | 123 // The above routine returns true if we were able to force the |
106 // next GC pause to be an initial mark; it returns false if a | 124 // next GC pause to be an initial mark; it returns false if a |
107 // marking cycle is already in progress. | 125 // marking cycle is already in progress. |
108 // | 126 // |
109 // If a marking cycle is already in progress just return and skip | 127 // If a marking cycle is already in progress just return and skip the |
110 // the pause - the requesting thread should block in doit_epilogue | 128 // pause below - if the reason for requesting this initial mark pause |
111 // until the marking cycle is complete. | 129 // was due to a System.gc() then the requesting thread should block in |
130 // doit_epilogue() until the marking cycle is complete. | |
131 // | |
132 // If this initial mark pause was requested as part of a humongous | |
133 // allocation then we know that the marking cycle must just have | |
134 // been started by another thread (possibly also allocating a humongous | |
135 // object) as there was no active marking cycle when the requesting | |
136 // thread checked before calling collect() in | |
137 // attempt_allocation_humongous(). Retrying the GC, in this case, | |
138 // will cause the requesting thread to spin inside collect() until the | |
139 // just started marking cycle is complete - which may be a while. So | |
140 // we do NOT retry the GC. | |
112 if (!res) { | 141 if (!res) { |
113 assert(_word_size == 0, "ExplicitGCInvokesConcurrent shouldn't be allocating"); | 142 assert(_word_size == 0, "Concurrent Full GC/Humongous Object IM shouldn't be allocating"); |
143 if (_gc_cause != GCCause::_g1_humongous_allocation) { | |
144 _should_retry_gc = true; | |
145 } | |
114 return; | 146 return; |
115 } | 147 } |
116 } | 148 } |
117 | 149 |
118 _pause_succeeded = | 150 _pause_succeeded = |
121 // An allocation had been requested. | 153 // An allocation had been requested. |
122 _result = g1h->attempt_allocation_at_safepoint(_word_size, | 154 _result = g1h->attempt_allocation_at_safepoint(_word_size, |
123 true /* expect_null_cur_alloc_region */); | 155 true /* expect_null_cur_alloc_region */); |
124 } else { | 156 } else { |
125 assert(_result == NULL, "invariant"); | 157 assert(_result == NULL, "invariant"); |
158 if (!_pause_succeeded) { | |
159 // Another possible reason reason for the pause to not be successful | |
160 // is that, again, the GC locker is active (and has become active | |
161 // since the prologue was executed). In this case we should retry | |
162 // the pause after waiting for the GC locker to become inactive. | |
163 _should_retry_gc = true; | |
164 } | |
126 } | 165 } |
127 } | 166 } |
128 | 167 |
129 void VM_G1IncCollectionPause::doit_epilogue() { | 168 void VM_G1IncCollectionPause::doit_epilogue() { |
130 VM_GC_Operation::doit_epilogue(); | 169 VM_GC_Operation::doit_epilogue(); |
166 } | 205 } |
167 } | 206 } |
168 } | 207 } |
169 | 208 |
170 void VM_CGC_Operation::acquire_pending_list_lock() { | 209 void VM_CGC_Operation::acquire_pending_list_lock() { |
210 assert(_needs_pll, "don't call this otherwise"); | |
171 // The caller may block while communicating | 211 // The caller may block while communicating |
172 // with the SLT thread in order to acquire/release the PLL. | 212 // with the SLT thread in order to acquire/release the PLL. |
173 ConcurrentMarkThread::slt()-> | 213 ConcurrentMarkThread::slt()-> |
174 manipulatePLL(SurrogateLockerThread::acquirePLL); | 214 manipulatePLL(SurrogateLockerThread::acquirePLL); |
175 } | 215 } |
176 | 216 |
177 void VM_CGC_Operation::release_and_notify_pending_list_lock() { | 217 void VM_CGC_Operation::release_and_notify_pending_list_lock() { |
218 assert(_needs_pll, "don't call this otherwise"); | |
178 // The caller may block while communicating | 219 // The caller may block while communicating |
179 // with the SLT thread in order to acquire/release the PLL. | 220 // with the SLT thread in order to acquire/release the PLL. |
180 ConcurrentMarkThread::slt()-> | 221 ConcurrentMarkThread::slt()-> |
181 manipulatePLL(SurrogateLockerThread::releaseAndNotifyPLL); | 222 manipulatePLL(SurrogateLockerThread::releaseAndNotifyPLL); |
182 } | 223 } |
196 } | 237 } |
197 | 238 |
198 bool VM_CGC_Operation::doit_prologue() { | 239 bool VM_CGC_Operation::doit_prologue() { |
199 // Note the relative order of the locks must match that in | 240 // Note the relative order of the locks must match that in |
200 // VM_GC_Operation::doit_prologue() or deadlocks can occur | 241 // VM_GC_Operation::doit_prologue() or deadlocks can occur |
201 acquire_pending_list_lock(); | 242 if (_needs_pll) { |
243 acquire_pending_list_lock(); | |
244 } | |
202 | 245 |
203 Heap_lock->lock(); | 246 Heap_lock->lock(); |
204 SharedHeap::heap()->_thread_holds_heap_lock_for_gc = true; | 247 SharedHeap::heap()->_thread_holds_heap_lock_for_gc = true; |
205 return true; | 248 return true; |
206 } | 249 } |
208 void VM_CGC_Operation::doit_epilogue() { | 251 void VM_CGC_Operation::doit_epilogue() { |
209 // Note the relative order of the unlocks must match that in | 252 // Note the relative order of the unlocks must match that in |
210 // VM_GC_Operation::doit_epilogue() | 253 // VM_GC_Operation::doit_epilogue() |
211 SharedHeap::heap()->_thread_holds_heap_lock_for_gc = false; | 254 SharedHeap::heap()->_thread_holds_heap_lock_for_gc = false; |
212 Heap_lock->unlock(); | 255 Heap_lock->unlock(); |
213 release_and_notify_pending_list_lock(); | 256 if (_needs_pll) { |
214 } | 257 release_and_notify_pending_list_lock(); |
258 } | |
259 } |