aoqi@0: /* aoqi@0: * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: * aoqi@0: */ aoqi@0: aoqi@0: #ifndef SHARE_VM_GC_IMPLEMENTATION_G1_DIRTYCARDQUEUE_HPP aoqi@0: #define SHARE_VM_GC_IMPLEMENTATION_G1_DIRTYCARDQUEUE_HPP aoqi@0: aoqi@0: #include "gc_implementation/g1/ptrQueue.hpp" aoqi@0: #include "memory/allocation.hpp" aoqi@0: aoqi@0: class FreeIdSet; aoqi@0: aoqi@0: // A closure class for processing card table entries. Note that we don't aoqi@0: // require these closure objects to be stack-allocated. aoqi@0: class CardTableEntryClosure: public CHeapObj { aoqi@0: public: aoqi@0: // Process the card whose card table entry is "card_ptr". If returns aoqi@0: // "false", terminate the iteration early. aoqi@0: virtual bool do_card_ptr(jbyte* card_ptr, uint worker_i = 0) = 0; aoqi@0: }; aoqi@0: aoqi@0: // A ptrQueue whose elements are "oops", pointers to object heads. aoqi@0: class DirtyCardQueue: public PtrQueue { aoqi@0: public: aoqi@0: DirtyCardQueue(PtrQueueSet* qset_, bool perm = false) : aoqi@0: // Dirty card queues are always active, so we create them with their aoqi@0: // active field set to true. aoqi@0: PtrQueue(qset_, perm, true /* active */) { } aoqi@0: aoqi@0: // Apply the closure to all elements, and reset the index to make the aoqi@0: // buffer empty. If a closure application returns "false", return aoqi@0: // "false" immediately, halting the iteration. If "consume" is true, aoqi@0: // deletes processed entries from logs. aoqi@0: bool apply_closure(CardTableEntryClosure* cl, aoqi@0: bool consume = true, aoqi@0: uint worker_i = 0); aoqi@0: aoqi@0: // Apply the closure to all elements of "buf", down to "index" aoqi@0: // (inclusive.) If returns "false", then a closure application returned aoqi@0: // "false", and we return immediately. If "consume" is true, entries are aoqi@0: // set to NULL as they are processed, so they will not be processed again aoqi@0: // later. aoqi@0: static bool apply_closure_to_buffer(CardTableEntryClosure* cl, aoqi@0: void** buf, size_t index, size_t sz, aoqi@0: bool consume = true, aoqi@0: uint worker_i = 0); aoqi@0: void **get_buf() { return _buf;} aoqi@0: void set_buf(void **buf) {_buf = buf;} aoqi@0: size_t get_index() { return _index;} aoqi@0: void reinitialize() { _buf = 0; _sz = 0; _index = 0;} aoqi@0: }; aoqi@0: aoqi@0: aoqi@0: aoqi@0: class DirtyCardQueueSet: public PtrQueueSet { aoqi@0: CardTableEntryClosure* _closure; aoqi@0: aoqi@0: DirtyCardQueue _shared_dirty_card_queue; aoqi@0: aoqi@0: // Override. aoqi@0: bool mut_process_buffer(void** buf); aoqi@0: aoqi@0: // Protected by the _cbl_mon. aoqi@0: FreeIdSet* _free_ids; aoqi@0: aoqi@0: // The number of completed buffers processed by mutator and rs thread, aoqi@0: // respectively. aoqi@0: jint _processed_buffers_mut; aoqi@0: jint _processed_buffers_rs_thread; aoqi@0: aoqi@0: public: aoqi@0: DirtyCardQueueSet(bool notify_when_complete = true); aoqi@0: aoqi@0: void initialize(Monitor* cbl_mon, Mutex* fl_lock, aoqi@0: int process_completed_threshold, aoqi@0: int max_completed_queue, aoqi@0: Mutex* lock, PtrQueueSet* fl_owner = NULL); aoqi@0: aoqi@0: // The number of parallel ids that can be claimed to allow collector or aoqi@0: // mutator threads to do card-processing work. aoqi@0: static uint num_par_ids(); aoqi@0: aoqi@0: static void handle_zero_index_for_thread(JavaThread* t); aoqi@0: aoqi@0: // Register "blk" as "the closure" for all queues. Only one such closure aoqi@0: // is allowed. The "apply_closure_to_completed_buffer" method will apply aoqi@0: // this closure to a completed buffer, and "iterate_closure_all_threads" aoqi@0: // applies it to partially-filled buffers (the latter should only be done aoqi@0: // with the world stopped). aoqi@0: void set_closure(CardTableEntryClosure* closure); aoqi@0: aoqi@0: // If there is a registered closure for buffers, apply it to all entries aoqi@0: // in all currently-active buffers. This should only be applied at a aoqi@0: // safepoint. (Currently must not be called in parallel; this should aoqi@0: // change in the future.) If "consume" is true, processed entries are aoqi@0: // discarded. aoqi@0: void iterate_closure_all_threads(bool consume = true, aoqi@0: uint worker_i = 0); aoqi@0: aoqi@0: // If there exists some completed buffer, pop it, then apply the aoqi@0: // registered closure to all its elements, nulling out those elements aoqi@0: // processed. If all elements are processed, returns "true". If no aoqi@0: // completed buffers exist, returns false. If a completed buffer exists, aoqi@0: // but is only partially completed before a "yield" happens, the aoqi@0: // partially completed buffer (with its processed elements set to NULL) aoqi@0: // is returned to the completed buffer set, and this call returns false. aoqi@0: bool apply_closure_to_completed_buffer(uint worker_i = 0, aoqi@0: int stop_at = 0, aoqi@0: bool during_pause = false); aoqi@0: aoqi@0: // If there exists some completed buffer, pop it, then apply the aoqi@0: // specified closure to all its elements, nulling out those elements aoqi@0: // processed. If all elements are processed, returns "true". If no aoqi@0: // completed buffers exist, returns false. If a completed buffer exists, aoqi@0: // but is only partially completed before a "yield" happens, the aoqi@0: // partially completed buffer (with its processed elements set to NULL) aoqi@0: // is returned to the completed buffer set, and this call returns false. aoqi@0: bool apply_closure_to_completed_buffer(CardTableEntryClosure* cl, aoqi@0: uint worker_i = 0, aoqi@0: int stop_at = 0, aoqi@0: bool during_pause = false); aoqi@0: aoqi@0: // Helper routine for the above. aoqi@0: bool apply_closure_to_completed_buffer_helper(CardTableEntryClosure* cl, aoqi@0: uint worker_i, aoqi@0: BufferNode* nd); aoqi@0: aoqi@0: BufferNode* get_completed_buffer(int stop_at); aoqi@0: aoqi@0: // Applies the current closure to all completed buffers, aoqi@0: // non-consumptively. aoqi@0: void apply_closure_to_all_completed_buffers(); aoqi@0: aoqi@0: DirtyCardQueue* shared_dirty_card_queue() { aoqi@0: return &_shared_dirty_card_queue; aoqi@0: } aoqi@0: aoqi@0: // Deallocate any completed log buffers aoqi@0: void clear(); aoqi@0: aoqi@0: // If a full collection is happening, reset partial logs, and ignore aoqi@0: // completed ones: the full collection will make them all irrelevant. aoqi@0: void abandon_logs(); aoqi@0: aoqi@0: // If any threads have partial logs, add them to the global list of logs. aoqi@0: void concatenate_logs(); aoqi@0: void clear_n_completed_buffers() { _n_completed_buffers = 0;} aoqi@0: aoqi@0: jint processed_buffers_mut() { aoqi@0: return _processed_buffers_mut; aoqi@0: } aoqi@0: jint processed_buffers_rs_thread() { aoqi@0: return _processed_buffers_rs_thread; aoqi@0: } aoqi@0: aoqi@0: }; aoqi@0: aoqi@0: #endif // SHARE_VM_GC_IMPLEMENTATION_G1_DIRTYCARDQUEUE_HPP