comparison src/share/vm/gc_implementation/g1/ptrQueue.cpp @ 1169:09646c4656ca

6915005: G1: Hang in PtrQueueSet::completed_buffers_list_length with gcl001 Summary: When enqueuing a completed PtrQueue buffer, cache a local pointer to the buffer and clear the field in the PtrQueue prior to unlocking the mutex referenced by the _lock field and pass the cached local value to the enqueuing routine. This will prevent the same completed buffer being enqueued multiple times, which causes the hang. Reviewed-by: ysr
author johnc
date Wed, 13 Jan 2010 15:45:47 -0800
parents 44f61c24ddab
children d4197f8d516a
comparison
equal deleted inserted replaced
1168:22e27cceb7d8 1169:09646c4656ca
71 assert(0 <= _index && _index <= _sz, "Invariant."); 71 assert(0 <= _index && _index <= _sz, "Invariant.");
72 } 72 }
73 73
74 void PtrQueue::locking_enqueue_completed_buffer(void** buf) { 74 void PtrQueue::locking_enqueue_completed_buffer(void** buf) {
75 assert(_lock->owned_by_self(), "Required."); 75 assert(_lock->owned_by_self(), "Required.");
76
77 // We have to unlock _lock (which may be Shared_DirtyCardQ_lock) before
78 // we acquire DirtyCardQ_CBL_mon inside enqeue_complete_buffer as they
79 // have the same rank and we may get the "possible deadlock" message
76 _lock->unlock(); 80 _lock->unlock();
81
77 qset()->enqueue_complete_buffer(buf); 82 qset()->enqueue_complete_buffer(buf);
78 // We must relock only because the caller will unlock, for the normal 83 // We must relock only because the caller will unlock, for the normal
79 // case. 84 // case.
80 _lock->lock_without_safepoint_check(); 85 _lock->lock_without_safepoint_check();
81 } 86 }
138 assert(0 == _index, "Precondition."); 143 assert(0 == _index, "Precondition.");
139 // This thread records the full buffer and allocates a new one (while 144 // This thread records the full buffer and allocates a new one (while
140 // holding the lock if there is one). 145 // holding the lock if there is one).
141 if (_buf != NULL) { 146 if (_buf != NULL) {
142 if (_lock) { 147 if (_lock) {
143 locking_enqueue_completed_buffer(_buf); 148 assert(_lock->owned_by_self(), "Required.");
149
150 // The current PtrQ may be the shared dirty card queue and
151 // may be being manipulated by more than one worker thread
152 // during a pause. Since the enqueuing of the completed
153 // buffer unlocks the Shared_DirtyCardQ_lock more than one
154 // worker thread can 'race' on reading the shared queue attributes
155 // (_buf and _index) and multiple threads can call into this
156 // routine for the same buffer. This will cause the completed
157 // buffer to be added to the CBL multiple times.
158
159 // We "claim" the current buffer by caching value of _buf in
160 // a local and clearing the field while holding _lock. When
161 // _lock is released (while enqueueing the completed buffer)
162 // the thread that acquires _lock will skip this code,
163 // preventing the subsequent the multiple enqueue, and
164 // install a newly allocated buffer below.
165
166 void** buf = _buf; // local pointer to completed buffer
167 _buf = NULL; // clear shared _buf field
168
169 locking_enqueue_completed_buffer(buf); // enqueue completed buffer
170
171 // While the current thread was enqueuing the buffer another thread
172 // may have a allocated a new buffer and inserted it into this pointer
173 // queue. If that happens then we just return so that the current
174 // thread doesn't overwrite the buffer allocated by the other thread
175 // and potentially losing some dirtied cards.
176
177 if (_buf != NULL) return;
144 } else { 178 } else {
145 if (qset()->process_or_enqueue_complete_buffer(_buf)) { 179 if (qset()->process_or_enqueue_complete_buffer(_buf)) {
146 // Recycle the buffer. No allocation. 180 // Recycle the buffer. No allocation.
147 _sz = qset()->buffer_size(); 181 _sz = qset()->buffer_size();
148 _index = _sz; 182 _index = _sz;