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