Wed, 13 Jan 2010 15:45:47 -0800
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
src/share/vm/gc_implementation/g1/ptrQueue.cpp | file | annotate | diff | comparison | revisions | |
src/share/vm/gc_implementation/g1/ptrQueue.inline.hpp | file | annotate | diff | comparison | revisions |
1.1 --- a/src/share/vm/gc_implementation/g1/ptrQueue.cpp Thu Jan 14 09:20:13 2010 -0800 1.2 +++ b/src/share/vm/gc_implementation/g1/ptrQueue.cpp Wed Jan 13 15:45:47 2010 -0800 1.3 @@ -73,7 +73,12 @@ 1.4 1.5 void PtrQueue::locking_enqueue_completed_buffer(void** buf) { 1.6 assert(_lock->owned_by_self(), "Required."); 1.7 + 1.8 + // We have to unlock _lock (which may be Shared_DirtyCardQ_lock) before 1.9 + // we acquire DirtyCardQ_CBL_mon inside enqeue_complete_buffer as they 1.10 + // have the same rank and we may get the "possible deadlock" message 1.11 _lock->unlock(); 1.12 + 1.13 qset()->enqueue_complete_buffer(buf); 1.14 // We must relock only because the caller will unlock, for the normal 1.15 // case. 1.16 @@ -140,7 +145,36 @@ 1.17 // holding the lock if there is one). 1.18 if (_buf != NULL) { 1.19 if (_lock) { 1.20 - locking_enqueue_completed_buffer(_buf); 1.21 + assert(_lock->owned_by_self(), "Required."); 1.22 + 1.23 + // The current PtrQ may be the shared dirty card queue and 1.24 + // may be being manipulated by more than one worker thread 1.25 + // during a pause. Since the enqueuing of the completed 1.26 + // buffer unlocks the Shared_DirtyCardQ_lock more than one 1.27 + // worker thread can 'race' on reading the shared queue attributes 1.28 + // (_buf and _index) and multiple threads can call into this 1.29 + // routine for the same buffer. This will cause the completed 1.30 + // buffer to be added to the CBL multiple times. 1.31 + 1.32 + // We "claim" the current buffer by caching value of _buf in 1.33 + // a local and clearing the field while holding _lock. When 1.34 + // _lock is released (while enqueueing the completed buffer) 1.35 + // the thread that acquires _lock will skip this code, 1.36 + // preventing the subsequent the multiple enqueue, and 1.37 + // install a newly allocated buffer below. 1.38 + 1.39 + void** buf = _buf; // local pointer to completed buffer 1.40 + _buf = NULL; // clear shared _buf field 1.41 + 1.42 + locking_enqueue_completed_buffer(buf); // enqueue completed buffer 1.43 + 1.44 + // While the current thread was enqueuing the buffer another thread 1.45 + // may have a allocated a new buffer and inserted it into this pointer 1.46 + // queue. If that happens then we just return so that the current 1.47 + // thread doesn't overwrite the buffer allocated by the other thread 1.48 + // and potentially losing some dirtied cards. 1.49 + 1.50 + if (_buf != NULL) return; 1.51 } else { 1.52 if (qset()->process_or_enqueue_complete_buffer(_buf)) { 1.53 // Recycle the buffer. No allocation.
2.1 --- a/src/share/vm/gc_implementation/g1/ptrQueue.inline.hpp Thu Jan 14 09:20:13 2010 -0800 2.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 2.3 @@ -1,41 +0,0 @@ 2.4 -/* 2.5 - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. 2.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 2.7 - * 2.8 - * This code is free software; you can redistribute it and/or modify it 2.9 - * under the terms of the GNU General Public License version 2 only, as 2.10 - * published by the Free Software Foundation. 2.11 - * 2.12 - * This code is distributed in the hope that it will be useful, but WITHOUT 2.13 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 2.14 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 2.15 - * version 2 for more details (a copy is included in the LICENSE file that 2.16 - * accompanied this code). 2.17 - * 2.18 - * You should have received a copy of the GNU General Public License version 2.19 - * 2 along with this work; if not, write to the Free Software Foundation, 2.20 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2.21 - * 2.22 - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 2.23 - * CA 95054 USA or visit www.sun.com if you need additional information or 2.24 - * have any questions. 2.25 - * 2.26 - */ 2.27 - 2.28 -void PtrQueue::handle_zero_index() { 2.29 - assert(0 == _index, "Precondition."); 2.30 - // This thread records the full buffer and allocates a new one (while 2.31 - // holding the lock if there is one). 2.32 - void** buf = _buf; 2.33 - _buf = qset()->allocate_buffer(); 2.34 - _sz = qset()->buffer_size(); 2.35 - _index = _sz; 2.36 - assert(0 <= _index && _index <= _sz, "Invariant."); 2.37 - if (buf != NULL) { 2.38 - if (_lock) { 2.39 - locking_enqueue_completed_buffer(buf); 2.40 - } else { 2.41 - qset()->enqueue_complete_buffer(buf); 2.42 - } 2.43 - } 2.44 -}