src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp

Mon, 22 Sep 2008 09:56:49 -0400

author
tonyp
date
Mon, 22 Sep 2008 09:56:49 -0400
changeset 799
919e7959392a
parent 777
37f87013dfd8
child 905
ad8c8ca4ab0f
permissions
-rw-r--r--

6742641: G1: NullPointerException during GCOld
Summary: An update buffer is not processed correctly, which causes roots into the collection set not to be scanned and, hence, for the heap to be corrupted. The cause is that an object is accessed after it has been explicitly deleted, which causes a race.
Reviewed-by: jcoomes, ysr

     1 /*
     2  * Copyright 2001-2007 Sun Microsystems, Inc.  All Rights Reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.
     8  *
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    12  * version 2 for more details (a copy is included in the LICENSE file that
    13  * accompanied this code).
    14  *
    15  * You should have received a copy of the GNU General Public License version
    16  * 2 along with this work; if not, write to the Free Software Foundation,
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    18  *
    19  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
    20  * CA 95054 USA or visit www.sun.com if you need additional information or
    21  * have any questions.
    22  *
    23  */
    25 # include "incls/_precompiled.incl"
    26 # include "incls/_dirtyCardQueue.cpp.incl"
    28 bool DirtyCardQueue::apply_closure(CardTableEntryClosure* cl,
    29                                    bool consume,
    30                                    size_t worker_i) {
    31   bool res = true;
    32   if (_buf != NULL) {
    33     res = apply_closure_to_buffer(cl, _buf, _index, _sz,
    34                                   consume,
    35                                   (int) worker_i);
    36     if (res && consume) _index = _sz;
    37   }
    38   return res;
    39 }
    41 bool DirtyCardQueue::apply_closure_to_buffer(CardTableEntryClosure* cl,
    42                                              void** buf,
    43                                              size_t index, size_t sz,
    44                                              bool consume,
    45                                              int worker_i) {
    46   if (cl == NULL) return true;
    47   for (size_t i = index; i < sz; i += oopSize) {
    48     int ind = byte_index_to_index((int)i);
    49     jbyte* card_ptr = (jbyte*)buf[ind];
    50     if (card_ptr != NULL) {
    51       // Set the entry to null, so we don't do it again (via the test
    52       // above) if we reconsider this buffer.
    53       if (consume) buf[ind] = NULL;
    54       if (!cl->do_card_ptr(card_ptr, worker_i)) return false;
    55     }
    56   }
    57   return true;
    58 }
    60 #ifdef _MSC_VER // the use of 'this' below gets a warning, make it go away
    61 #pragma warning( disable:4355 ) // 'this' : used in base member initializer list
    62 #endif // _MSC_VER
    64 DirtyCardQueueSet::DirtyCardQueueSet() :
    65   PtrQueueSet(true /*notify_when_complete*/),
    66   _closure(NULL),
    67   _shared_dirty_card_queue(this, true /*perm*/),
    68   _free_ids(NULL),
    69   _processed_buffers_mut(0), _processed_buffers_rs_thread(0)
    70 {
    71   _all_active = true;
    72 }
    74 size_t DirtyCardQueueSet::num_par_ids() {
    75   return MAX2(ParallelGCThreads, (size_t)2);
    76 }
    79 void DirtyCardQueueSet::initialize(Monitor* cbl_mon, Mutex* fl_lock,
    80                                    int max_completed_queue,
    81                                    Mutex* lock) {
    82   PtrQueueSet::initialize(cbl_mon, fl_lock, max_completed_queue);
    83   set_buffer_size(DCQBarrierQueueBufferSize);
    84   set_process_completed_threshold(DCQBarrierProcessCompletedThreshold);
    86   _shared_dirty_card_queue.set_lock(lock);
    87   _free_ids = new FreeIdSet((int) num_par_ids(), _cbl_mon);
    88   bool b = _free_ids->claim_perm_id(0);
    89   guarantee(b, "Must reserve id zero for concurrent refinement thread.");
    90 }
    92 void DirtyCardQueueSet::handle_zero_index_for_thread(JavaThread* t) {
    93   t->dirty_card_queue().handle_zero_index();
    94 }
    96 void DirtyCardQueueSet::set_closure(CardTableEntryClosure* closure) {
    97   _closure = closure;
    98 }
   100 void DirtyCardQueueSet::iterate_closure_all_threads(bool consume,
   101                                                     size_t worker_i) {
   102   assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint.");
   103   for(JavaThread* t = Threads::first(); t; t = t->next()) {
   104     bool b = t->dirty_card_queue().apply_closure(_closure, consume);
   105     guarantee(b, "Should not be interrupted.");
   106   }
   107   bool b = shared_dirty_card_queue()->apply_closure(_closure,
   108                                                     consume,
   109                                                     worker_i);
   110   guarantee(b, "Should not be interrupted.");
   111 }
   113 bool DirtyCardQueueSet::mut_process_buffer(void** buf) {
   115   // Used to determine if we had already claimed a par_id
   116   // before entering this method.
   117   bool already_claimed = false;
   119   // We grab the current JavaThread.
   120   JavaThread* thread = JavaThread::current();
   122   // We get the the number of any par_id that this thread
   123   // might have already claimed.
   124   int worker_i = thread->get_claimed_par_id();
   126   // If worker_i is not -1 then the thread has already claimed
   127   // a par_id. We make note of it using the already_claimed value
   128   if (worker_i != -1) {
   129     already_claimed = true;
   130   } else {
   132     // Otherwise we need to claim a par id
   133     worker_i = _free_ids->claim_par_id();
   135     // And store the par_id value in the thread
   136     thread->set_claimed_par_id(worker_i);
   137   }
   139   bool b = false;
   140   if (worker_i != -1) {
   141     b = DirtyCardQueue::apply_closure_to_buffer(_closure, buf, 0,
   142                                                 _sz, true, worker_i);
   143     if (b) Atomic::inc(&_processed_buffers_mut);
   145     // If we had not claimed an id before entering the method
   146     // then we must release the id.
   147     if (!already_claimed) {
   149       // we release the id
   150       _free_ids->release_par_id(worker_i);
   152       // and set the claimed_id in the thread to -1
   153       thread->set_claimed_par_id(-1);
   154     }
   155   }
   156   return b;
   157 }
   159 DirtyCardQueueSet::CompletedBufferNode*
   160 DirtyCardQueueSet::get_completed_buffer_lock(int stop_at) {
   161   CompletedBufferNode* nd = NULL;
   162   MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);
   164   if ((int)_n_completed_buffers <= stop_at) {
   165     _process_completed = false;
   166     return NULL;
   167   }
   169   if (_completed_buffers_head != NULL) {
   170     nd = _completed_buffers_head;
   171     _completed_buffers_head = nd->next;
   172     if (_completed_buffers_head == NULL)
   173       _completed_buffers_tail = NULL;
   174     _n_completed_buffers--;
   175   }
   176   debug_only(assert_completed_buffer_list_len_correct_locked());
   177   return nd;
   178 }
   180 // We only do this in contexts where there is no concurrent enqueueing.
   181 DirtyCardQueueSet::CompletedBufferNode*
   182 DirtyCardQueueSet::get_completed_buffer_CAS() {
   183   CompletedBufferNode* nd = _completed_buffers_head;
   185   while (nd != NULL) {
   186     CompletedBufferNode* next = nd->next;
   187     CompletedBufferNode* result =
   188       (CompletedBufferNode*)Atomic::cmpxchg_ptr(next,
   189                                                 &_completed_buffers_head,
   190                                                 nd);
   191     if (result == nd) {
   192       return result;
   193     } else {
   194       nd = _completed_buffers_head;
   195     }
   196   }
   197   assert(_completed_buffers_head == NULL, "Loop post");
   198   _completed_buffers_tail = NULL;
   199   return NULL;
   200 }
   202 bool DirtyCardQueueSet::
   203 apply_closure_to_completed_buffer_helper(int worker_i,
   204                                          CompletedBufferNode* nd) {
   205   if (nd != NULL) {
   206     bool b =
   207       DirtyCardQueue::apply_closure_to_buffer(_closure, nd->buf,
   208                                               nd->index, _sz,
   209                                               true, worker_i);
   210     void** buf = nd->buf;
   211     size_t index = nd->index;
   212     delete nd;
   213     if (b) {
   214       deallocate_buffer(buf);
   215       return true;  // In normal case, go on to next buffer.
   216     } else {
   217       enqueue_complete_buffer(buf, index, true);
   218       return false;
   219     }
   220   } else {
   221     return false;
   222   }
   223 }
   225 bool DirtyCardQueueSet::apply_closure_to_completed_buffer(int worker_i,
   226                                                           int stop_at,
   227                                                           bool with_CAS)
   228 {
   229   CompletedBufferNode* nd = NULL;
   230   if (with_CAS) {
   231     guarantee(stop_at == 0, "Precondition");
   232     nd = get_completed_buffer_CAS();
   233   } else {
   234     nd = get_completed_buffer_lock(stop_at);
   235   }
   236   bool res = apply_closure_to_completed_buffer_helper(worker_i, nd);
   237   if (res) _processed_buffers_rs_thread++;
   238   return res;
   239 }
   241 void DirtyCardQueueSet::apply_closure_to_all_completed_buffers() {
   242   CompletedBufferNode* nd = _completed_buffers_head;
   243   while (nd != NULL) {
   244     bool b =
   245       DirtyCardQueue::apply_closure_to_buffer(_closure, nd->buf, 0, _sz,
   246                                               false);
   247     guarantee(b, "Should not stop early.");
   248     nd = nd->next;
   249   }
   250 }
   252 void DirtyCardQueueSet::abandon_logs() {
   253   assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint.");
   254   CompletedBufferNode* buffers_to_delete = NULL;
   255   {
   256     MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);
   257     while (_completed_buffers_head != NULL) {
   258       CompletedBufferNode* nd = _completed_buffers_head;
   259       _completed_buffers_head = nd->next;
   260       nd->next = buffers_to_delete;
   261       buffers_to_delete = nd;
   262     }
   263     _n_completed_buffers = 0;
   264     _completed_buffers_tail = NULL;
   265     debug_only(assert_completed_buffer_list_len_correct_locked());
   266   }
   267   while (buffers_to_delete != NULL) {
   268     CompletedBufferNode* nd = buffers_to_delete;
   269     buffers_to_delete = nd->next;
   270     deallocate_buffer(nd->buf);
   271     delete nd;
   272   }
   273   // Since abandon is done only at safepoints, we can safely manipulate
   274   // these queues.
   275   for (JavaThread* t = Threads::first(); t; t = t->next()) {
   276     t->dirty_card_queue().reset();
   277   }
   278   shared_dirty_card_queue()->reset();
   279 }
   282 void DirtyCardQueueSet::concatenate_logs() {
   283   // Iterate over all the threads, if we find a partial log add it to
   284   // the global list of logs.  Temporarily turn off the limit on the number
   285   // of outstanding buffers.
   286   int save_max_completed_queue = _max_completed_queue;
   287   _max_completed_queue = max_jint;
   288   assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint.");
   289   for (JavaThread* t = Threads::first(); t; t = t->next()) {
   290     DirtyCardQueue& dcq = t->dirty_card_queue();
   291     if (dcq.size() != 0) {
   292       void **buf = t->dirty_card_queue().get_buf();
   293       // We must NULL out the unused entries, then enqueue.
   294       for (size_t i = 0; i < t->dirty_card_queue().get_index(); i += oopSize) {
   295         buf[PtrQueue::byte_index_to_index((int)i)] = NULL;
   296       }
   297       enqueue_complete_buffer(dcq.get_buf(), dcq.get_index());
   298       dcq.reinitialize();
   299     }
   300   }
   301   if (_shared_dirty_card_queue.size() != 0) {
   302     enqueue_complete_buffer(_shared_dirty_card_queue.get_buf(),
   303                             _shared_dirty_card_queue.get_index());
   304     _shared_dirty_card_queue.reinitialize();
   305   }
   306   // Restore the completed buffer queue limit.
   307   _max_completed_queue = save_max_completed_queue;
   308 }

mercurial