Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/share/vm/gc_implementation/parallelScavenge/gcTaskManager.hpp
38920 views
/*1* Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#ifndef SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_GCTASKMANAGER_HPP25#define SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_GCTASKMANAGER_HPP2627#include "runtime/mutex.hpp"28#include "utilities/growableArray.hpp"2930//31// The GCTaskManager is a queue of GCTasks, and accessors32// to allow the queue to be accessed from many threads.33//3435// Forward declarations of types defined in this file.36class GCTask;37class GCTaskQueue;38class SynchronizedGCTaskQueue;39class GCTaskManager;40class NotifyDoneClosure;41// Some useful subclasses of GCTask. You can also make up your own.42class NoopGCTask;43class BarrierGCTask;44class ReleasingBarrierGCTask;45class NotifyingBarrierGCTask;46class WaitForBarrierGCTask;47class IdleGCTask;48// A free list of Monitor*'s.49class MonitorSupply;5051// Forward declarations of classes referenced in this file via pointer.52class GCTaskThread;53class Mutex;54class Monitor;55class ThreadClosure;5657// The abstract base GCTask.58class GCTask : public ResourceObj {59public:60// Known kinds of GCTasks, for predicates.61class Kind : AllStatic {62public:63enum kind {64unknown_task,65ordinary_task,66barrier_task,67noop_task,68idle_task69};70static const char* to_string(kind value);71};72private:73// Instance state.74const Kind::kind _kind; // For runtime type checking.75const uint _affinity; // Which worker should run task.76GCTask* _newer; // Tasks are on doubly-linked ...77GCTask* _older; // ... lists.78public:79virtual char* name() { return (char *)"task"; }8081// Abstract do_it method82virtual void do_it(GCTaskManager* manager, uint which) = 0;83// Accessors84Kind::kind kind() const {85return _kind;86}87uint affinity() const {88return _affinity;89}90GCTask* newer() const {91return _newer;92}93void set_newer(GCTask* n) {94_newer = n;95}96GCTask* older() const {97return _older;98}99void set_older(GCTask* p) {100_older = p;101}102// Predicates.103bool is_ordinary_task() const {104return kind()==Kind::ordinary_task;105}106bool is_barrier_task() const {107return kind()==Kind::barrier_task;108}109bool is_noop_task() const {110return kind()==Kind::noop_task;111}112bool is_idle_task() const {113return kind()==Kind::idle_task;114}115void print(const char* message) const PRODUCT_RETURN;116protected:117// Constructors: Only create subclasses.118// An ordinary GCTask.119GCTask();120// A GCTask of a particular kind, usually barrier or noop.121GCTask(Kind::kind kind);122// An ordinary GCTask with an affinity.123GCTask(uint affinity);124// A GCTask of a particular kind, with and affinity.125GCTask(Kind::kind kind, uint affinity);126// We want a virtual destructor because virtual methods,127// but since ResourceObj's don't have their destructors128// called, we don't have one at all. Instead we have129// this method, which gets called by subclasses to clean up.130virtual void destruct();131// Methods.132void initialize();133};134135// A doubly-linked list of GCTasks.136// The list is not synchronized, because sometimes we want to137// build up a list and then make it available to other threads.138// See also: SynchronizedGCTaskQueue.139class GCTaskQueue : public ResourceObj {140private:141// Instance state.142GCTask* _insert_end; // Tasks are enqueued at this end.143GCTask* _remove_end; // Tasks are dequeued from this end.144uint _length; // The current length of the queue.145const bool _is_c_heap_obj; // Is this a CHeapObj?146public:147// Factory create and destroy methods.148// Create as ResourceObj.149static GCTaskQueue* create();150// Create as CHeapObj.151static GCTaskQueue* create_on_c_heap();152// Destroyer.153static void destroy(GCTaskQueue* that);154// Accessors.155// These just examine the state of the queue.156bool is_empty() const {157assert(((insert_end() == NULL && remove_end() == NULL) ||158(insert_end() != NULL && remove_end() != NULL)),159"insert_end and remove_end don't match");160assert((insert_end() != NULL) || (_length == 0), "Not empty");161return insert_end() == NULL;162}163uint length() const {164return _length;165}166// Methods.167// Enqueue one task.168void enqueue(GCTask* task);169// Enqueue a list of tasks. Empties the argument list.170void enqueue(GCTaskQueue* list);171// Dequeue one task.172GCTask* dequeue();173// Dequeue one task, preferring one with affinity.174GCTask* dequeue(uint affinity);175protected:176// Constructor. Clients use factory, but there might be subclasses.177GCTaskQueue(bool on_c_heap);178// Destructor-like method.179// Because ResourceMark doesn't call destructors.180// This method cleans up like one.181virtual void destruct();182// Accessors.183GCTask* insert_end() const {184return _insert_end;185}186void set_insert_end(GCTask* value) {187_insert_end = value;188}189GCTask* remove_end() const {190return _remove_end;191}192void set_remove_end(GCTask* value) {193_remove_end = value;194}195void increment_length() {196_length += 1;197}198void decrement_length() {199_length -= 1;200}201void set_length(uint value) {202_length = value;203}204bool is_c_heap_obj() const {205return _is_c_heap_obj;206}207// Methods.208void initialize();209GCTask* remove(); // Remove from remove end.210GCTask* remove(GCTask* task); // Remove from the middle.211void print(const char* message) const PRODUCT_RETURN;212// Debug support213void verify_length() const PRODUCT_RETURN;214};215216// A GCTaskQueue that can be synchronized.217// This "has-a" GCTaskQueue and a mutex to do the exclusion.218class SynchronizedGCTaskQueue : public CHeapObj<mtGC> {219private:220// Instance state.221GCTaskQueue* _unsynchronized_queue; // Has-a unsynchronized queue.222Monitor * _lock; // Lock to control access.223public:224// Factory create and destroy methods.225static SynchronizedGCTaskQueue* create(GCTaskQueue* queue, Monitor * lock) {226return new SynchronizedGCTaskQueue(queue, lock);227}228static void destroy(SynchronizedGCTaskQueue* that) {229if (that != NULL) {230delete that;231}232}233// Accessors234GCTaskQueue* unsynchronized_queue() const {235return _unsynchronized_queue;236}237Monitor * lock() const {238return _lock;239}240// GCTaskQueue wrapper methods.241// These check that you hold the lock242// and then call the method on the queue.243bool is_empty() const {244guarantee(own_lock(), "don't own the lock");245return unsynchronized_queue()->is_empty();246}247void enqueue(GCTask* task) {248guarantee(own_lock(), "don't own the lock");249unsynchronized_queue()->enqueue(task);250}251void enqueue(GCTaskQueue* list) {252guarantee(own_lock(), "don't own the lock");253unsynchronized_queue()->enqueue(list);254}255GCTask* dequeue() {256guarantee(own_lock(), "don't own the lock");257return unsynchronized_queue()->dequeue();258}259GCTask* dequeue(uint affinity) {260guarantee(own_lock(), "don't own the lock");261return unsynchronized_queue()->dequeue(affinity);262}263uint length() const {264guarantee(own_lock(), "don't own the lock");265return unsynchronized_queue()->length();266}267// For guarantees.268bool own_lock() const {269return lock()->owned_by_self();270}271protected:272// Constructor. Clients use factory, but there might be subclasses.273SynchronizedGCTaskQueue(GCTaskQueue* queue, Monitor * lock);274// Destructor. Not virtual because no virtuals.275~SynchronizedGCTaskQueue();276};277278// This is an abstract base class for getting notifications279// when a GCTaskManager is done.280class NotifyDoneClosure : public CHeapObj<mtGC> {281public:282// The notification callback method.283virtual void notify(GCTaskManager* manager) = 0;284protected:285// Constructor.286NotifyDoneClosure() {287// Nothing to do.288}289// Virtual destructor because virtual methods.290virtual ~NotifyDoneClosure() {291// Nothing to do.292}293};294295// Dynamic number of GC threads296//297// GC threads wait in get_task() for work (i.e., a task) to perform.298// When the number of GC threads was static, the number of tasks299// created to do a job was equal to or greater than the maximum300// number of GC threads (ParallelGCThreads). The job might be divided301// into a number of tasks greater than the number of GC threads for302// load balancing (i.e., over partitioning). The last task to be303// executed by a GC thread in a job is a work stealing task. A304// GC thread that gets a work stealing task continues to execute305// that task until the job is done. In the static number of GC theads306// case, tasks are added to a queue (FIFO). The work stealing tasks are307// the last to be added. Once the tasks are added, the GC threads grab308// a task and go. A single thread can do all the non-work stealing tasks309// and then execute a work stealing and wait for all the other GC threads310// to execute their work stealing task.311// In the dynamic number of GC threads implementation, idle-tasks are312// created to occupy the non-participating or "inactive" threads. An313// idle-task makes the GC thread wait on a barrier that is part of the314// GCTaskManager. The GC threads that have been "idled" in a IdleGCTask315// are released once all the active GC threads have finished their work316// stealing tasks. The GCTaskManager does not wait for all the "idled"317// GC threads to resume execution. When those GC threads do resume318// execution in the course of the thread scheduling, they call get_tasks()319// as all the other GC threads do. Because all the "idled" threads are320// not required to execute in order to finish a job, it is possible for321// a GC thread to still be "idled" when the next job is started. Such322// a thread stays "idled" for the next job. This can result in a new323// job not having all the expected active workers. For example if on324// job requests 4 active workers out of a total of 10 workers so the325// remaining 6 are "idled", if the next job requests 6 active workers326// but all 6 of the "idled" workers are still idle, then the next job327// will only get 4 active workers.328// The implementation for the parallel old compaction phase has an329// added complication. In the static case parold partitions the chunks330// ready to be filled into stacks, one for each GC thread. A GC thread331// executing a draining task (drains the stack of ready chunks)332// claims a stack according to it's id (the unique ordinal value assigned333// to each GC thread). In the dynamic case not all GC threads will334// actively participate so stacks with ready to fill chunks can only be335// given to the active threads. An initial implementation chose stacks336// number 1-n to get the ready chunks and required that GC threads337// 1-n be the active workers. This was undesirable because it required338// certain threads to participate. In the final implementation a339// list of stacks equal in number to the active workers are filled340// with ready chunks. GC threads that participate get a stack from341// the task (DrainStacksCompactionTask), empty the stack, and then add it to a342// recycling list at the end of the task. If the same GC thread gets343// a second task, it gets a second stack to drain and returns it. The344// stacks are added to a recycling list so that later stealing tasks345// for this tasks can get a stack from the recycling list. Stealing tasks346// use the stacks in its work in a way similar to the draining tasks.347// A thread is not guaranteed to get anything but a stealing task and348// a thread that only gets a stealing task has to get a stack. A failed349// implementation tried to have the GC threads keep the stack they used350// during a draining task for later use in the stealing task but that didn't351// work because as noted a thread is not guaranteed to get a draining task.352//353// For PSScavenge and ParCompactionManager the GC threads are354// held in the GCTaskThread** _thread array in GCTaskManager.355356357class GCTaskManager : public CHeapObj<mtGC> {358friend class ParCompactionManager;359friend class PSParallelCompact;360friend class PSScavenge;361friend class PSRefProcTaskExecutor;362friend class RefProcTaskExecutor;363friend class GCTaskThread;364friend class IdleGCTask;365private:366// Instance state.367NotifyDoneClosure* _ndc; // Notify on completion.368const uint _workers; // Number of workers.369Monitor* _monitor; // Notification of changes.370SynchronizedGCTaskQueue* _queue; // Queue of tasks.371GCTaskThread** _thread; // Array of worker threads.372uint _active_workers; // Number of active workers.373uint _busy_workers; // Number of busy workers.374uint _blocking_worker; // The worker that's blocking.375bool* _resource_flag; // Array of flag per threads.376uint _delivered_tasks; // Count of delivered tasks.377uint _completed_tasks; // Count of completed tasks.378uint _barriers; // Count of barrier tasks.379uint _emptied_queue; // Times we emptied the queue.380NoopGCTask* _noop_task; // The NoopGCTask instance.381uint _noop_tasks; // Count of noop tasks.382WaitForBarrierGCTask* _idle_inactive_task;// Task for inactive workers383volatile uint _idle_workers; // Number of idled workers384public:385// Factory create and destroy methods.386static GCTaskManager* create(uint workers) {387return new GCTaskManager(workers);388}389static GCTaskManager* create(uint workers, NotifyDoneClosure* ndc) {390return new GCTaskManager(workers, ndc);391}392static void destroy(GCTaskManager* that) {393if (that != NULL) {394delete that;395}396}397// Accessors.398uint busy_workers() const {399return _busy_workers;400}401volatile uint idle_workers() const {402return _idle_workers;403}404// Pun between Monitor* and Mutex*405Monitor* monitor() const {406return _monitor;407}408Monitor * lock() const {409return _monitor;410}411WaitForBarrierGCTask* idle_inactive_task() {412return _idle_inactive_task;413}414// Methods.415// Add the argument task to be run.416void add_task(GCTask* task);417// Add a list of tasks. Removes task from the argument list.418void add_list(GCTaskQueue* list);419// Claim a task for argument worker.420GCTask* get_task(uint which);421// Note the completion of a task by the argument worker.422void note_completion(uint which);423// Is the queue blocked from handing out new tasks?424bool is_blocked() const {425return (blocking_worker() != sentinel_worker());426}427// Request that all workers release their resources.428void release_all_resources();429// Ask if a particular worker should release its resources.430bool should_release_resources(uint which); // Predicate.431// Note the release of resources by the argument worker.432void note_release(uint which);433// Create IdleGCTasks for inactive workers and start workers434void task_idle_workers();435// Release the workers in IdleGCTasks436void release_idle_workers();437// Constants.438// A sentinel worker identifier.439static uint sentinel_worker() {440return (uint) -1; // Why isn't there a max_uint?441}442443// Execute the task queue and wait for the completion.444void execute_and_wait(GCTaskQueue* list);445446void print_task_time_stamps();447void print_threads_on(outputStream* st);448void threads_do(ThreadClosure* tc);449450protected:451// Constructors. Clients use factory, but there might be subclasses.452// Create a GCTaskManager with the appropriate number of workers.453GCTaskManager(uint workers);454// Create a GCTaskManager that calls back when there's no more work.455GCTaskManager(uint workers, NotifyDoneClosure* ndc);456// Make virtual if necessary.457~GCTaskManager();458// Accessors.459uint workers() const {460return _workers;461}462void set_active_workers(uint v) {463assert(v <= _workers, "Trying to set more workers active than there are");464_active_workers = MIN2(v, _workers);465assert(v != 0, "Trying to set active workers to 0");466_active_workers = MAX2(1U, _active_workers);467}468// Sets the number of threads that will be used in a collection469void set_active_gang();470471NotifyDoneClosure* notify_done_closure() const {472return _ndc;473}474SynchronizedGCTaskQueue* queue() const {475return _queue;476}477NoopGCTask* noop_task() const {478return _noop_task;479}480// Bounds-checking per-thread data accessors.481GCTaskThread* thread(uint which);482void set_thread(uint which, GCTaskThread* value);483bool resource_flag(uint which);484void set_resource_flag(uint which, bool value);485// Modifier methods with some semantics.486// Is any worker blocking handing out new tasks?487uint blocking_worker() const {488return _blocking_worker;489}490void set_blocking_worker(uint value) {491_blocking_worker = value;492}493void set_unblocked() {494set_blocking_worker(sentinel_worker());495}496// Count of busy workers.497void reset_busy_workers() {498_busy_workers = 0;499}500uint increment_busy_workers();501uint decrement_busy_workers();502// Count of tasks delivered to workers.503uint delivered_tasks() const {504return _delivered_tasks;505}506void increment_delivered_tasks() {507_delivered_tasks += 1;508}509void reset_delivered_tasks() {510_delivered_tasks = 0;511}512// Count of tasks completed by workers.513uint completed_tasks() const {514return _completed_tasks;515}516void increment_completed_tasks() {517_completed_tasks += 1;518}519void reset_completed_tasks() {520_completed_tasks = 0;521}522// Count of barrier tasks completed.523uint barriers() const {524return _barriers;525}526void increment_barriers() {527_barriers += 1;528}529void reset_barriers() {530_barriers = 0;531}532// Count of how many times the queue has emptied.533uint emptied_queue() const {534return _emptied_queue;535}536void increment_emptied_queue() {537_emptied_queue += 1;538}539void reset_emptied_queue() {540_emptied_queue = 0;541}542// Count of the number of noop tasks we've handed out,543// e.g., to handle resource release requests.544uint noop_tasks() const {545return _noop_tasks;546}547void increment_noop_tasks() {548_noop_tasks += 1;549}550void reset_noop_tasks() {551_noop_tasks = 0;552}553void increment_idle_workers() {554_idle_workers++;555}556void decrement_idle_workers() {557_idle_workers--;558}559// Other methods.560void initialize();561562public:563// Return true if all workers are currently active.564bool all_workers_active() { return workers() == active_workers(); }565uint active_workers() const {566return _active_workers;567}568};569570//571// Some exemplary GCTasks.572//573574// A noop task that does nothing,575// except take us around the GCTaskThread loop.576class NoopGCTask : public GCTask {577private:578const bool _is_c_heap_obj; // Is this a CHeapObj?579public:580// Factory create and destroy methods.581static NoopGCTask* create();582static NoopGCTask* create_on_c_heap();583static void destroy(NoopGCTask* that);584585virtual char* name() { return (char *)"noop task"; }586// Methods from GCTask.587void do_it(GCTaskManager* manager, uint which) {588// Nothing to do.589}590protected:591// Constructor.592NoopGCTask(bool on_c_heap) :593GCTask(GCTask::Kind::noop_task),594_is_c_heap_obj(on_c_heap) {595// Nothing to do.596}597// Destructor-like method.598void destruct();599// Accessors.600bool is_c_heap_obj() const {601return _is_c_heap_obj;602}603};604605// A BarrierGCTask blocks other tasks from starting,606// and waits until it is the only task running.607class BarrierGCTask : public GCTask {608public:609// Factory create and destroy methods.610static BarrierGCTask* create() {611return new BarrierGCTask();612}613static void destroy(BarrierGCTask* that) {614if (that != NULL) {615that->destruct();616delete that;617}618}619// Methods from GCTask.620void do_it(GCTaskManager* manager, uint which);621protected:622// Constructor. Clients use factory, but there might be subclasses.623BarrierGCTask() :624GCTask(GCTask::Kind::barrier_task) {625// Nothing to do.626}627// Destructor-like method.628void destruct();629630virtual char* name() { return (char *)"barrier task"; }631// Methods.632// Wait for this to be the only task running.633void do_it_internal(GCTaskManager* manager, uint which);634};635636// A ReleasingBarrierGCTask is a BarrierGCTask637// that tells all the tasks to release their resource areas.638class ReleasingBarrierGCTask : public BarrierGCTask {639public:640// Factory create and destroy methods.641static ReleasingBarrierGCTask* create() {642return new ReleasingBarrierGCTask();643}644static void destroy(ReleasingBarrierGCTask* that) {645if (that != NULL) {646that->destruct();647delete that;648}649}650// Methods from GCTask.651void do_it(GCTaskManager* manager, uint which);652protected:653// Constructor. Clients use factory, but there might be subclasses.654ReleasingBarrierGCTask() :655BarrierGCTask() {656// Nothing to do.657}658// Destructor-like method.659void destruct();660};661662// A NotifyingBarrierGCTask is a BarrierGCTask663// that calls a notification method when it is the only task running.664class NotifyingBarrierGCTask : public BarrierGCTask {665private:666// Instance state.667NotifyDoneClosure* _ndc; // The callback object.668public:669// Factory create and destroy methods.670static NotifyingBarrierGCTask* create(NotifyDoneClosure* ndc) {671return new NotifyingBarrierGCTask(ndc);672}673static void destroy(NotifyingBarrierGCTask* that) {674if (that != NULL) {675that->destruct();676delete that;677}678}679// Methods from GCTask.680void do_it(GCTaskManager* manager, uint which);681protected:682// Constructor. Clients use factory, but there might be subclasses.683NotifyingBarrierGCTask(NotifyDoneClosure* ndc) :684BarrierGCTask(),685_ndc(ndc) {686assert(notify_done_closure() != NULL, "can't notify on NULL");687}688// Destructor-like method.689void destruct();690// Accessor.691NotifyDoneClosure* notify_done_closure() const { return _ndc; }692};693694// A WaitForBarrierGCTask is a BarrierGCTask695// with a method you can call to wait until696// the BarrierGCTask is done.697// This may cover many of the uses of NotifyingBarrierGCTasks.698class WaitForBarrierGCTask : public BarrierGCTask {699friend class GCTaskManager;700friend class IdleGCTask;701private:702// Instance state.703Monitor* _monitor; // Guard and notify changes.704volatile bool _should_wait; // true=>wait, false=>proceed.705const bool _is_c_heap_obj; // Was allocated on the heap.706public:707virtual char* name() { return (char *) "waitfor-barrier-task"; }708709// Factory create and destroy methods.710static WaitForBarrierGCTask* create();711static WaitForBarrierGCTask* create_on_c_heap();712static void destroy(WaitForBarrierGCTask* that);713// Methods.714void do_it(GCTaskManager* manager, uint which);715void wait_for(bool reset);716void set_should_wait(bool value) {717_should_wait = value;718}719protected:720// Constructor. Clients use factory, but there might be subclasses.721WaitForBarrierGCTask(bool on_c_heap);722// Destructor-like method.723void destruct();724// Accessors.725Monitor* monitor() const {726return _monitor;727}728bool should_wait() const {729return _should_wait;730}731bool is_c_heap_obj() {732return _is_c_heap_obj;733}734};735736// Task that is used to idle a GC task when fewer than737// the maximum workers are wanted.738class IdleGCTask : public GCTask {739const bool _is_c_heap_obj; // Was allocated on the heap.740public:741bool is_c_heap_obj() {742return _is_c_heap_obj;743}744// Factory create and destroy methods.745static IdleGCTask* create();746static IdleGCTask* create_on_c_heap();747static void destroy(IdleGCTask* that);748749virtual char* name() { return (char *)"idle task"; }750// Methods from GCTask.751virtual void do_it(GCTaskManager* manager, uint which);752protected:753// Constructor.754IdleGCTask(bool on_c_heap) :755GCTask(GCTask::Kind::idle_task),756_is_c_heap_obj(on_c_heap) {757// Nothing to do.758}759// Destructor-like method.760void destruct();761};762763class MonitorSupply : public AllStatic {764private:765// State.766// Control multi-threaded access.767static Mutex* _lock;768// The list of available Monitor*'s.769static GrowableArray<Monitor*>* _freelist;770public:771// Reserve a Monitor*.772static Monitor* reserve();773// Release a Monitor*.774static void release(Monitor* instance);775private:776// Accessors.777static Mutex* lock() {778return _lock;779}780static GrowableArray<Monitor*>* freelist() {781return _freelist;782}783};784785#endif // SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_GCTASKMANAGER_HPP786787788