Tue, 24 Nov 2009 15:19:30 -0800
6899058: G1: Internal error in ptrQueue.cpp:201 in nightly tests
Summary: Fixes a race on the dirty card queue completed buffer list between worker thread(s) performing a flush of a deferred store barrier (enqueueing a newly completed buffer) and worker thread(s) in the RSet updating code claiming completed buffers. Removed the routine that removes elements from the completed update buffer queue using a CAS.
Reviewed-by: ysr, tonyp
1.1 --- a/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp Fri Nov 20 14:47:01 2009 -0500 1.2 +++ b/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp Tue Nov 24 15:19:30 2009 -0800 1.3 @@ -155,7 +155,7 @@ 1.4 } 1.5 1.6 DirtyCardQueueSet::CompletedBufferNode* 1.7 -DirtyCardQueueSet::get_completed_buffer_lock(int stop_at) { 1.8 +DirtyCardQueueSet::get_completed_buffer(int stop_at) { 1.9 CompletedBufferNode* nd = NULL; 1.10 MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag); 1.11 1.12 @@ -175,28 +175,6 @@ 1.13 return nd; 1.14 } 1.15 1.16 -// We only do this in contexts where there is no concurrent enqueueing. 1.17 -DirtyCardQueueSet::CompletedBufferNode* 1.18 -DirtyCardQueueSet::get_completed_buffer_CAS() { 1.19 - CompletedBufferNode* nd = _completed_buffers_head; 1.20 - 1.21 - while (nd != NULL) { 1.22 - CompletedBufferNode* next = nd->next; 1.23 - CompletedBufferNode* result = 1.24 - (CompletedBufferNode*)Atomic::cmpxchg_ptr(next, 1.25 - &_completed_buffers_head, 1.26 - nd); 1.27 - if (result == nd) { 1.28 - return result; 1.29 - } else { 1.30 - nd = _completed_buffers_head; 1.31 - } 1.32 - } 1.33 - assert(_completed_buffers_head == NULL, "Loop post"); 1.34 - _completed_buffers_tail = NULL; 1.35 - return NULL; 1.36 -} 1.37 - 1.38 bool DirtyCardQueueSet:: 1.39 apply_closure_to_completed_buffer_helper(int worker_i, 1.40 CompletedBufferNode* nd) { 1.41 @@ -222,15 +200,10 @@ 1.42 1.43 bool DirtyCardQueueSet::apply_closure_to_completed_buffer(int worker_i, 1.44 int stop_at, 1.45 - bool with_CAS) 1.46 + bool during_pause) 1.47 { 1.48 - CompletedBufferNode* nd = NULL; 1.49 - if (with_CAS) { 1.50 - guarantee(stop_at == 0, "Precondition"); 1.51 - nd = get_completed_buffer_CAS(); 1.52 - } else { 1.53 - nd = get_completed_buffer_lock(stop_at); 1.54 - } 1.55 + assert(!during_pause || stop_at == 0, "Should not leave any completed buffers during a pause"); 1.56 + CompletedBufferNode* nd = get_completed_buffer(stop_at); 1.57 bool res = apply_closure_to_completed_buffer_helper(worker_i, nd); 1.58 if (res) Atomic::inc(&_processed_buffers_rs_thread); 1.59 return res;
2.1 --- a/src/share/vm/gc_implementation/g1/dirtyCardQueue.hpp Fri Nov 20 14:47:01 2009 -0500 2.2 +++ b/src/share/vm/gc_implementation/g1/dirtyCardQueue.hpp Tue Nov 24 15:19:30 2009 -0800 2.3 @@ -1,5 +1,5 @@ 2.4 /* 2.5 - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. 2.6 + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. 2.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 2.8 * 2.9 * This code is free software; you can redistribute it and/or modify it 2.10 @@ -120,12 +120,13 @@ 2.11 // is returned to the completed buffer set, and this call returns false. 2.12 bool apply_closure_to_completed_buffer(int worker_i = 0, 2.13 int stop_at = 0, 2.14 - bool with_CAS = false); 2.15 + bool during_pause = false); 2.16 + 2.17 bool apply_closure_to_completed_buffer_helper(int worker_i, 2.18 CompletedBufferNode* nd); 2.19 2.20 - CompletedBufferNode* get_completed_buffer_CAS(); 2.21 - CompletedBufferNode* get_completed_buffer_lock(int stop_at); 2.22 + CompletedBufferNode* get_completed_buffer(int stop_at); 2.23 + 2.24 // Applies the current closure to all completed buffers, 2.25 // non-consumptively. 2.26 void apply_closure_to_all_completed_buffers();