ysr@777: /* johnc@1525: * Copyright 2001-2009 Sun Microsystems, Inc. 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: * ysr@777: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, ysr@777: * CA 95054 USA or visit www.sun.com if you need additional information or ysr@777: * have any questions. ysr@777: * ysr@777: */ ysr@777: 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. ysr@777: 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. ysr@777: virtual bool do_card_ptr(jbyte* card_ptr, int 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) : ysr@777: PtrQueue(qset_, perm) ysr@777: { ysr@777: // Dirty card queues are always active. ysr@777: _active = true; ysr@777: } 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, ysr@777: size_t 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, ysr@777: int 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 { ysr@777: CardTableEntryClosure* _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: ysr@777: public: iveresov@1546: DirtyCardQueueSet(bool notify_when_complete = true); ysr@777: ysr@777: void initialize(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. ysr@777: static size_t num_par_ids(); ysr@777: ysr@777: static void handle_zero_index_for_thread(JavaThread* t); ysr@777: ysr@777: // Register "blk" as "the closure" for all queues. Only one such closure ysr@777: // is allowed. The "apply_closure_to_completed_buffer" method will apply ysr@777: // this closure to a completed buffer, and "iterate_closure_all_threads" ysr@777: // applies it to partially-filled buffers (the latter should only be done ysr@777: // with the world stopped). ysr@777: void set_closure(CardTableEntryClosure* closure); ysr@777: ysr@777: // If there is a registered closure for buffers, apply it to all entries ysr@777: // in all currently-active buffers. This should only be applied at a ysr@777: // safepoint. (Currently must not be called in parallel; this should ysr@777: // change in the future.) If "consume" is true, processed entries are ysr@777: // discarded. ysr@777: void iterate_closure_all_threads(bool consume = true, ysr@777: size_t worker_i = 0); ysr@777: ysr@777: // If there exists some completed buffer, pop it, then apply the ysr@777: // registered closure to all its elements, nulling out those elements ysr@777: // processed. If all elements are processed, returns "true". If no ysr@777: // completed buffers exist, returns false. If a completed buffer exists, ysr@777: // but is only partially completed before a "yield" happens, the ysr@777: // partially completed buffer (with its processed elements set to NULL) ysr@777: // is returned to the completed buffer set, and this call returns false. ysr@777: bool apply_closure_to_completed_buffer(int worker_i = 0, ysr@777: int stop_at = 0, johnc@1525: bool during_pause = false); johnc@1525: ysr@777: bool apply_closure_to_completed_buffer_helper(int 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. ysr@777: void apply_closure_to_all_completed_buffers(); ysr@777: ysr@777: DirtyCardQueue* shared_dirty_card_queue() { ysr@777: return &_shared_dirty_card_queue; ysr@777: } ysr@777: 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: };