duke@435: /* mikael@4153: * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. duke@435: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@435: * duke@435: * This code is free software; you can redistribute it and/or modify it duke@435: * under the terms of the GNU General Public License version 2 only, as duke@435: * published by the Free Software Foundation. duke@435: * duke@435: * This code is distributed in the hope that it will be useful, but WITHOUT duke@435: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@435: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@435: * version 2 for more details (a copy is included in the LICENSE file that duke@435: * accompanied this code). duke@435: * duke@435: * You should have received a copy of the GNU General Public License version duke@435: * 2 along with this work; if not, write to the Free Software Foundation, duke@435: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@435: * 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. duke@435: * duke@435: */ duke@435: stefank@2314: #ifndef SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_GCTASKMANAGER_HPP stefank@2314: #define SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_GCTASKMANAGER_HPP stefank@2314: stefank@2314: #include "runtime/mutex.hpp" stefank@2314: #include "utilities/growableArray.hpp" stefank@2314: duke@435: // duke@435: // The GCTaskManager is a queue of GCTasks, and accessors duke@435: // to allow the queue to be accessed from many threads. duke@435: // duke@435: duke@435: // Forward declarations of types defined in this file. duke@435: class GCTask; duke@435: class GCTaskQueue; duke@435: class SynchronizedGCTaskQueue; duke@435: class GCTaskManager; duke@435: class NotifyDoneClosure; duke@435: // Some useful subclasses of GCTask. You can also make up your own. duke@435: class NoopGCTask; duke@435: class BarrierGCTask; duke@435: class ReleasingBarrierGCTask; duke@435: class NotifyingBarrierGCTask; duke@435: class WaitForBarrierGCTask; jmasa@3294: class IdleGCTask; duke@435: // A free list of Monitor*'s. duke@435: class MonitorSupply; duke@435: duke@435: // Forward declarations of classes referenced in this file via pointer. duke@435: class GCTaskThread; duke@435: class Mutex; duke@435: class Monitor; duke@435: class ThreadClosure; duke@435: duke@435: // The abstract base GCTask. duke@435: class GCTask : public ResourceObj { duke@435: public: duke@435: // Known kinds of GCTasks, for predicates. duke@435: class Kind : AllStatic { duke@435: public: duke@435: enum kind { duke@435: unknown_task, duke@435: ordinary_task, duke@435: barrier_task, jmasa@3294: noop_task, jmasa@3294: idle_task duke@435: }; duke@435: static const char* to_string(kind value); duke@435: }; duke@435: private: duke@435: // Instance state. duke@435: const Kind::kind _kind; // For runtime type checking. duke@435: const uint _affinity; // Which worker should run task. duke@435: GCTask* _newer; // Tasks are on doubly-linked ... duke@435: GCTask* _older; // ... lists. duke@435: public: duke@435: virtual char* name() { return (char *)"task"; } duke@435: duke@435: // Abstract do_it method duke@435: virtual void do_it(GCTaskManager* manager, uint which) = 0; duke@435: // Accessors duke@435: Kind::kind kind() const { duke@435: return _kind; duke@435: } duke@435: uint affinity() const { duke@435: return _affinity; duke@435: } duke@435: GCTask* newer() const { duke@435: return _newer; duke@435: } duke@435: void set_newer(GCTask* n) { duke@435: _newer = n; duke@435: } duke@435: GCTask* older() const { duke@435: return _older; duke@435: } duke@435: void set_older(GCTask* p) { duke@435: _older = p; duke@435: } duke@435: // Predicates. duke@435: bool is_ordinary_task() const { duke@435: return kind()==Kind::ordinary_task; duke@435: } duke@435: bool is_barrier_task() const { duke@435: return kind()==Kind::barrier_task; duke@435: } duke@435: bool is_noop_task() const { duke@435: return kind()==Kind::noop_task; duke@435: } jmasa@3294: bool is_idle_task() const { jmasa@3294: return kind()==Kind::idle_task; jmasa@3294: } duke@435: void print(const char* message) const PRODUCT_RETURN; duke@435: protected: duke@435: // Constructors: Only create subclasses. duke@435: // An ordinary GCTask. duke@435: GCTask(); duke@435: // A GCTask of a particular kind, usually barrier or noop. duke@435: GCTask(Kind::kind kind); duke@435: // An ordinary GCTask with an affinity. duke@435: GCTask(uint affinity); duke@435: // A GCTask of a particular kind, with and affinity. duke@435: GCTask(Kind::kind kind, uint affinity); duke@435: // We want a virtual destructor because virtual methods, duke@435: // but since ResourceObj's don't have their destructors duke@435: // called, we don't have one at all. Instead we have duke@435: // this method, which gets called by subclasses to clean up. duke@435: virtual void destruct(); duke@435: // Methods. duke@435: void initialize(); duke@435: }; duke@435: duke@435: // A doubly-linked list of GCTasks. duke@435: // The list is not synchronized, because sometimes we want to duke@435: // build up a list and then make it available to other threads. duke@435: // See also: SynchronizedGCTaskQueue. duke@435: class GCTaskQueue : public ResourceObj { duke@435: private: duke@435: // Instance state. duke@435: GCTask* _insert_end; // Tasks are enqueued at this end. duke@435: GCTask* _remove_end; // Tasks are dequeued from this end. duke@435: uint _length; // The current length of the queue. duke@435: const bool _is_c_heap_obj; // Is this a CHeapObj? duke@435: public: duke@435: // Factory create and destroy methods. duke@435: // Create as ResourceObj. duke@435: static GCTaskQueue* create(); duke@435: // Create as CHeapObj. duke@435: static GCTaskQueue* create_on_c_heap(); duke@435: // Destroyer. duke@435: static void destroy(GCTaskQueue* that); duke@435: // Accessors. duke@435: // These just examine the state of the queue. duke@435: bool is_empty() const { duke@435: assert(((insert_end() == NULL && remove_end() == NULL) || duke@435: (insert_end() != NULL && remove_end() != NULL)), duke@435: "insert_end and remove_end don't match"); jmasa@3294: assert((insert_end() != NULL) || (_length == 0), "Not empty"); duke@435: return insert_end() == NULL; duke@435: } duke@435: uint length() const { duke@435: return _length; duke@435: } duke@435: // Methods. duke@435: // Enqueue one task. duke@435: void enqueue(GCTask* task); duke@435: // Enqueue a list of tasks. Empties the argument list. duke@435: void enqueue(GCTaskQueue* list); duke@435: // Dequeue one task. duke@435: GCTask* dequeue(); duke@435: // Dequeue one task, preferring one with affinity. duke@435: GCTask* dequeue(uint affinity); duke@435: protected: duke@435: // Constructor. Clients use factory, but there might be subclasses. duke@435: GCTaskQueue(bool on_c_heap); duke@435: // Destructor-like method. duke@435: // Because ResourceMark doesn't call destructors. duke@435: // This method cleans up like one. duke@435: virtual void destruct(); duke@435: // Accessors. duke@435: GCTask* insert_end() const { duke@435: return _insert_end; duke@435: } duke@435: void set_insert_end(GCTask* value) { duke@435: _insert_end = value; duke@435: } duke@435: GCTask* remove_end() const { duke@435: return _remove_end; duke@435: } duke@435: void set_remove_end(GCTask* value) { duke@435: _remove_end = value; duke@435: } duke@435: void increment_length() { duke@435: _length += 1; duke@435: } duke@435: void decrement_length() { duke@435: _length -= 1; duke@435: } duke@435: void set_length(uint value) { duke@435: _length = value; duke@435: } duke@435: bool is_c_heap_obj() const { duke@435: return _is_c_heap_obj; duke@435: } duke@435: // Methods. duke@435: void initialize(); duke@435: GCTask* remove(); // Remove from remove end. duke@435: GCTask* remove(GCTask* task); // Remove from the middle. duke@435: void print(const char* message) const PRODUCT_RETURN; jmasa@3294: // Debug support jmasa@3294: void verify_length() const PRODUCT_RETURN; duke@435: }; duke@435: duke@435: // A GCTaskQueue that can be synchronized. duke@435: // This "has-a" GCTaskQueue and a mutex to do the exclusion. zgu@3900: class SynchronizedGCTaskQueue : public CHeapObj { duke@435: private: duke@435: // Instance state. duke@435: GCTaskQueue* _unsynchronized_queue; // Has-a unsynchronized queue. duke@435: Monitor * _lock; // Lock to control access. duke@435: public: duke@435: // Factory create and destroy methods. duke@435: static SynchronizedGCTaskQueue* create(GCTaskQueue* queue, Monitor * lock) { duke@435: return new SynchronizedGCTaskQueue(queue, lock); duke@435: } duke@435: static void destroy(SynchronizedGCTaskQueue* that) { duke@435: if (that != NULL) { duke@435: delete that; duke@435: } duke@435: } duke@435: // Accessors duke@435: GCTaskQueue* unsynchronized_queue() const { duke@435: return _unsynchronized_queue; duke@435: } duke@435: Monitor * lock() const { duke@435: return _lock; duke@435: } duke@435: // GCTaskQueue wrapper methods. duke@435: // These check that you hold the lock duke@435: // and then call the method on the queue. duke@435: bool is_empty() const { duke@435: guarantee(own_lock(), "don't own the lock"); duke@435: return unsynchronized_queue()->is_empty(); duke@435: } duke@435: void enqueue(GCTask* task) { duke@435: guarantee(own_lock(), "don't own the lock"); duke@435: unsynchronized_queue()->enqueue(task); duke@435: } duke@435: void enqueue(GCTaskQueue* list) { duke@435: guarantee(own_lock(), "don't own the lock"); duke@435: unsynchronized_queue()->enqueue(list); duke@435: } duke@435: GCTask* dequeue() { duke@435: guarantee(own_lock(), "don't own the lock"); duke@435: return unsynchronized_queue()->dequeue(); duke@435: } duke@435: GCTask* dequeue(uint affinity) { duke@435: guarantee(own_lock(), "don't own the lock"); duke@435: return unsynchronized_queue()->dequeue(affinity); duke@435: } duke@435: uint length() const { duke@435: guarantee(own_lock(), "don't own the lock"); duke@435: return unsynchronized_queue()->length(); duke@435: } duke@435: // For guarantees. duke@435: bool own_lock() const { duke@435: return lock()->owned_by_self(); duke@435: } duke@435: protected: duke@435: // Constructor. Clients use factory, but there might be subclasses. duke@435: SynchronizedGCTaskQueue(GCTaskQueue* queue, Monitor * lock); duke@435: // Destructor. Not virtual because no virtuals. duke@435: ~SynchronizedGCTaskQueue(); duke@435: }; duke@435: duke@435: // This is an abstract base class for getting notifications duke@435: // when a GCTaskManager is done. zgu@3900: class NotifyDoneClosure : public CHeapObj { duke@435: public: duke@435: // The notification callback method. duke@435: virtual void notify(GCTaskManager* manager) = 0; duke@435: protected: duke@435: // Constructor. duke@435: NotifyDoneClosure() { duke@435: // Nothing to do. duke@435: } duke@435: // Virtual destructor because virtual methods. duke@435: virtual ~NotifyDoneClosure() { duke@435: // Nothing to do. duke@435: } duke@435: }; duke@435: jmasa@3294: // Dynamic number of GC threads jmasa@3294: // jmasa@3294: // GC threads wait in get_task() for work (i.e., a task) to perform. jmasa@3294: // When the number of GC threads was static, the number of tasks jmasa@3294: // created to do a job was equal to or greater than the maximum jmasa@3294: // number of GC threads (ParallelGCThreads). The job might be divided jmasa@3294: // into a number of tasks greater than the number of GC threads for jmasa@3294: // load balancing (i.e., over partitioning). The last task to be jmasa@3294: // executed by a GC thread in a job is a work stealing task. A jmasa@3294: // GC thread that gets a work stealing task continues to execute jmasa@3294: // that task until the job is done. In the static number of GC theads jmasa@3294: // case, tasks are added to a queue (FIFO). The work stealing tasks are jmasa@3294: // the last to be added. Once the tasks are added, the GC threads grab jmasa@3294: // a task and go. A single thread can do all the non-work stealing tasks jmasa@3294: // and then execute a work stealing and wait for all the other GC threads jmasa@3294: // to execute their work stealing task. jmasa@3294: // In the dynamic number of GC threads implementation, idle-tasks are jmasa@3294: // created to occupy the non-participating or "inactive" threads. An jmasa@3294: // idle-task makes the GC thread wait on a barrier that is part of the jmasa@3294: // GCTaskManager. The GC threads that have been "idled" in a IdleGCTask jmasa@3294: // are released once all the active GC threads have finished their work jmasa@3294: // stealing tasks. The GCTaskManager does not wait for all the "idled" jmasa@3294: // GC threads to resume execution. When those GC threads do resume jmasa@3294: // execution in the course of the thread scheduling, they call get_tasks() jmasa@3294: // as all the other GC threads do. Because all the "idled" threads are jmasa@3294: // not required to execute in order to finish a job, it is possible for jmasa@3294: // a GC thread to still be "idled" when the next job is started. Such jmasa@3294: // a thread stays "idled" for the next job. This can result in a new jmasa@3294: // job not having all the expected active workers. For example if on jmasa@3294: // job requests 4 active workers out of a total of 10 workers so the jmasa@3294: // remaining 6 are "idled", if the next job requests 6 active workers jmasa@3294: // but all 6 of the "idled" workers are still idle, then the next job jmasa@3294: // will only get 4 active workers. jmasa@3294: // The implementation for the parallel old compaction phase has an jmasa@3294: // added complication. In the static case parold partitions the chunks jmasa@3294: // ready to be filled into stacks, one for each GC thread. A GC thread jmasa@3294: // executing a draining task (drains the stack of ready chunks) jmasa@3294: // claims a stack according to it's id (the unique ordinal value assigned jmasa@3294: // to each GC thread). In the dynamic case not all GC threads will jmasa@3294: // actively participate so stacks with ready to fill chunks can only be jmasa@3294: // given to the active threads. An initial implementation chose stacks jmasa@3294: // number 1-n to get the ready chunks and required that GC threads jmasa@3294: // 1-n be the active workers. This was undesirable because it required jmasa@3294: // certain threads to participate. In the final implementation a jmasa@3294: // list of stacks equal in number to the active workers are filled jmasa@3294: // with ready chunks. GC threads that participate get a stack from jmasa@3294: // the task (DrainStacksCompactionTask), empty the stack, and then add it to a jmasa@3294: // recycling list at the end of the task. If the same GC thread gets jmasa@3294: // a second task, it gets a second stack to drain and returns it. The jmasa@3294: // stacks are added to a recycling list so that later stealing tasks jmasa@3294: // for this tasks can get a stack from the recycling list. Stealing tasks jmasa@3294: // use the stacks in its work in a way similar to the draining tasks. jmasa@3294: // A thread is not guaranteed to get anything but a stealing task and jmasa@3294: // a thread that only gets a stealing task has to get a stack. A failed jmasa@3294: // implementation tried to have the GC threads keep the stack they used jmasa@3294: // during a draining task for later use in the stealing task but that didn't jmasa@3294: // work because as noted a thread is not guaranteed to get a draining task. jmasa@3294: // jmasa@3294: // For PSScavenge and ParCompactionManager the GC threads are jmasa@3294: // held in the GCTaskThread** _thread array in GCTaskManager. jmasa@3294: jmasa@3294: zgu@3900: class GCTaskManager : public CHeapObj { duke@435: friend class ParCompactionManager; duke@435: friend class PSParallelCompact; duke@435: friend class PSScavenge; duke@435: friend class PSRefProcTaskExecutor; duke@435: friend class RefProcTaskExecutor; jmasa@3294: friend class GCTaskThread; jmasa@3294: friend class IdleGCTask; duke@435: private: duke@435: // Instance state. duke@435: NotifyDoneClosure* _ndc; // Notify on completion. duke@435: const uint _workers; // Number of workers. duke@435: Monitor* _monitor; // Notification of changes. duke@435: SynchronizedGCTaskQueue* _queue; // Queue of tasks. duke@435: GCTaskThread** _thread; // Array of worker threads. jmasa@3294: uint _active_workers; // Number of active workers. duke@435: uint _busy_workers; // Number of busy workers. duke@435: uint _blocking_worker; // The worker that's blocking. duke@435: bool* _resource_flag; // Array of flag per threads. duke@435: uint _delivered_tasks; // Count of delivered tasks. duke@435: uint _completed_tasks; // Count of completed tasks. duke@435: uint _barriers; // Count of barrier tasks. duke@435: uint _emptied_queue; // Times we emptied the queue. duke@435: NoopGCTask* _noop_task; // The NoopGCTask instance. duke@435: uint _noop_tasks; // Count of noop tasks. jmasa@3294: WaitForBarrierGCTask* _idle_inactive_task;// Task for inactive workers jmasa@3294: volatile uint _idle_workers; // Number of idled workers duke@435: public: duke@435: // Factory create and destroy methods. duke@435: static GCTaskManager* create(uint workers) { duke@435: return new GCTaskManager(workers); duke@435: } duke@435: static GCTaskManager* create(uint workers, NotifyDoneClosure* ndc) { duke@435: return new GCTaskManager(workers, ndc); duke@435: } duke@435: static void destroy(GCTaskManager* that) { duke@435: if (that != NULL) { duke@435: delete that; duke@435: } duke@435: } duke@435: // Accessors. duke@435: uint busy_workers() const { duke@435: return _busy_workers; duke@435: } jmasa@3294: volatile uint idle_workers() const { jmasa@3294: return _idle_workers; jmasa@3294: } duke@435: // Pun between Monitor* and Mutex* duke@435: Monitor* monitor() const { duke@435: return _monitor; duke@435: } duke@435: Monitor * lock() const { duke@435: return _monitor; duke@435: } jmasa@3294: WaitForBarrierGCTask* idle_inactive_task() { jmasa@3294: return _idle_inactive_task; jmasa@3294: } duke@435: // Methods. duke@435: // Add the argument task to be run. duke@435: void add_task(GCTask* task); duke@435: // Add a list of tasks. Removes task from the argument list. duke@435: void add_list(GCTaskQueue* list); duke@435: // Claim a task for argument worker. duke@435: GCTask* get_task(uint which); duke@435: // Note the completion of a task by the argument worker. duke@435: void note_completion(uint which); duke@435: // Is the queue blocked from handing out new tasks? duke@435: bool is_blocked() const { duke@435: return (blocking_worker() != sentinel_worker()); duke@435: } duke@435: // Request that all workers release their resources. duke@435: void release_all_resources(); duke@435: // Ask if a particular worker should release its resources. duke@435: bool should_release_resources(uint which); // Predicate. duke@435: // Note the release of resources by the argument worker. duke@435: void note_release(uint which); jmasa@3294: // Create IdleGCTasks for inactive workers and start workers jmasa@3294: void task_idle_workers(); jmasa@3294: // Release the workers in IdleGCTasks jmasa@3294: void release_idle_workers(); duke@435: // Constants. duke@435: // A sentinel worker identifier. duke@435: static uint sentinel_worker() { duke@435: return (uint) -1; // Why isn't there a max_uint? duke@435: } duke@435: duke@435: // Execute the task queue and wait for the completion. duke@435: void execute_and_wait(GCTaskQueue* list); duke@435: duke@435: void print_task_time_stamps(); duke@435: void print_threads_on(outputStream* st); duke@435: void threads_do(ThreadClosure* tc); duke@435: duke@435: protected: duke@435: // Constructors. Clients use factory, but there might be subclasses. duke@435: // Create a GCTaskManager with the appropriate number of workers. duke@435: GCTaskManager(uint workers); duke@435: // Create a GCTaskManager that calls back when there's no more work. duke@435: GCTaskManager(uint workers, NotifyDoneClosure* ndc); duke@435: // Make virtual if necessary. duke@435: ~GCTaskManager(); duke@435: // Accessors. duke@435: uint workers() const { duke@435: return _workers; duke@435: } jmasa@3294: void set_active_workers(uint v) { jmasa@3294: assert(v <= _workers, "Trying to set more workers active than there are"); jmasa@3294: _active_workers = MIN2(v, _workers); jmasa@3294: assert(v != 0, "Trying to set active workers to 0"); jmasa@3294: _active_workers = MAX2(1U, _active_workers); jmasa@3294: } jmasa@3294: // Sets the number of threads that will be used in a collection jmasa@3294: void set_active_gang(); jmasa@3294: duke@435: NotifyDoneClosure* notify_done_closure() const { duke@435: return _ndc; duke@435: } duke@435: SynchronizedGCTaskQueue* queue() const { duke@435: return _queue; duke@435: } duke@435: NoopGCTask* noop_task() const { duke@435: return _noop_task; duke@435: } duke@435: // Bounds-checking per-thread data accessors. duke@435: GCTaskThread* thread(uint which); duke@435: void set_thread(uint which, GCTaskThread* value); duke@435: bool resource_flag(uint which); duke@435: void set_resource_flag(uint which, bool value); duke@435: // Modifier methods with some semantics. duke@435: // Is any worker blocking handing out new tasks? duke@435: uint blocking_worker() const { duke@435: return _blocking_worker; duke@435: } duke@435: void set_blocking_worker(uint value) { duke@435: _blocking_worker = value; duke@435: } duke@435: void set_unblocked() { duke@435: set_blocking_worker(sentinel_worker()); duke@435: } duke@435: // Count of busy workers. duke@435: void reset_busy_workers() { duke@435: _busy_workers = 0; duke@435: } duke@435: uint increment_busy_workers(); duke@435: uint decrement_busy_workers(); duke@435: // Count of tasks delivered to workers. duke@435: uint delivered_tasks() const { duke@435: return _delivered_tasks; duke@435: } duke@435: void increment_delivered_tasks() { duke@435: _delivered_tasks += 1; duke@435: } duke@435: void reset_delivered_tasks() { duke@435: _delivered_tasks = 0; duke@435: } duke@435: // Count of tasks completed by workers. duke@435: uint completed_tasks() const { duke@435: return _completed_tasks; duke@435: } duke@435: void increment_completed_tasks() { duke@435: _completed_tasks += 1; duke@435: } duke@435: void reset_completed_tasks() { duke@435: _completed_tasks = 0; duke@435: } duke@435: // Count of barrier tasks completed. duke@435: uint barriers() const { duke@435: return _barriers; duke@435: } duke@435: void increment_barriers() { duke@435: _barriers += 1; duke@435: } duke@435: void reset_barriers() { duke@435: _barriers = 0; duke@435: } duke@435: // Count of how many times the queue has emptied. duke@435: uint emptied_queue() const { duke@435: return _emptied_queue; duke@435: } duke@435: void increment_emptied_queue() { duke@435: _emptied_queue += 1; duke@435: } duke@435: void reset_emptied_queue() { duke@435: _emptied_queue = 0; duke@435: } duke@435: // Count of the number of noop tasks we've handed out, duke@435: // e.g., to handle resource release requests. duke@435: uint noop_tasks() const { duke@435: return _noop_tasks; duke@435: } duke@435: void increment_noop_tasks() { duke@435: _noop_tasks += 1; duke@435: } duke@435: void reset_noop_tasks() { duke@435: _noop_tasks = 0; duke@435: } jmasa@3294: void increment_idle_workers() { jmasa@3294: _idle_workers++; jmasa@3294: } jmasa@3294: void decrement_idle_workers() { jmasa@3294: _idle_workers--; jmasa@3294: } duke@435: // Other methods. duke@435: void initialize(); jmasa@3294: jmasa@3294: public: jmasa@3294: // Return true if all workers are currently active. jmasa@3294: bool all_workers_active() { return workers() == active_workers(); } jmasa@3294: uint active_workers() const { jmasa@3294: return _active_workers; jmasa@3294: } duke@435: }; duke@435: duke@435: // duke@435: // Some exemplary GCTasks. duke@435: // duke@435: duke@435: // A noop task that does nothing, duke@435: // except take us around the GCTaskThread loop. duke@435: class NoopGCTask : public GCTask { duke@435: private: duke@435: const bool _is_c_heap_obj; // Is this a CHeapObj? duke@435: public: duke@435: // Factory create and destroy methods. duke@435: static NoopGCTask* create(); duke@435: static NoopGCTask* create_on_c_heap(); duke@435: static void destroy(NoopGCTask* that); jmasa@3294: jmasa@3294: virtual char* name() { return (char *)"noop task"; } duke@435: // Methods from GCTask. duke@435: void do_it(GCTaskManager* manager, uint which) { duke@435: // Nothing to do. duke@435: } duke@435: protected: duke@435: // Constructor. duke@435: NoopGCTask(bool on_c_heap) : duke@435: GCTask(GCTask::Kind::noop_task), duke@435: _is_c_heap_obj(on_c_heap) { duke@435: // Nothing to do. duke@435: } duke@435: // Destructor-like method. duke@435: void destruct(); duke@435: // Accessors. duke@435: bool is_c_heap_obj() const { duke@435: return _is_c_heap_obj; duke@435: } duke@435: }; duke@435: duke@435: // A BarrierGCTask blocks other tasks from starting, duke@435: // and waits until it is the only task running. duke@435: class BarrierGCTask : public GCTask { duke@435: public: duke@435: // Factory create and destroy methods. duke@435: static BarrierGCTask* create() { duke@435: return new BarrierGCTask(); duke@435: } duke@435: static void destroy(BarrierGCTask* that) { duke@435: if (that != NULL) { duke@435: that->destruct(); duke@435: delete that; duke@435: } duke@435: } duke@435: // Methods from GCTask. duke@435: void do_it(GCTaskManager* manager, uint which); duke@435: protected: duke@435: // Constructor. Clients use factory, but there might be subclasses. duke@435: BarrierGCTask() : duke@435: GCTask(GCTask::Kind::barrier_task) { duke@435: // Nothing to do. duke@435: } duke@435: // Destructor-like method. duke@435: void destruct(); jmasa@3294: jmasa@3294: virtual char* name() { return (char *)"barrier task"; } duke@435: // Methods. duke@435: // Wait for this to be the only task running. duke@435: void do_it_internal(GCTaskManager* manager, uint which); duke@435: }; duke@435: duke@435: // A ReleasingBarrierGCTask is a BarrierGCTask duke@435: // that tells all the tasks to release their resource areas. duke@435: class ReleasingBarrierGCTask : public BarrierGCTask { duke@435: public: duke@435: // Factory create and destroy methods. duke@435: static ReleasingBarrierGCTask* create() { duke@435: return new ReleasingBarrierGCTask(); duke@435: } duke@435: static void destroy(ReleasingBarrierGCTask* that) { duke@435: if (that != NULL) { duke@435: that->destruct(); duke@435: delete that; duke@435: } duke@435: } duke@435: // Methods from GCTask. duke@435: void do_it(GCTaskManager* manager, uint which); duke@435: protected: duke@435: // Constructor. Clients use factory, but there might be subclasses. duke@435: ReleasingBarrierGCTask() : duke@435: BarrierGCTask() { duke@435: // Nothing to do. duke@435: } duke@435: // Destructor-like method. duke@435: void destruct(); duke@435: }; duke@435: duke@435: // A NotifyingBarrierGCTask is a BarrierGCTask duke@435: // that calls a notification method when it is the only task running. duke@435: class NotifyingBarrierGCTask : public BarrierGCTask { duke@435: private: duke@435: // Instance state. duke@435: NotifyDoneClosure* _ndc; // The callback object. duke@435: public: duke@435: // Factory create and destroy methods. duke@435: static NotifyingBarrierGCTask* create(NotifyDoneClosure* ndc) { duke@435: return new NotifyingBarrierGCTask(ndc); duke@435: } duke@435: static void destroy(NotifyingBarrierGCTask* that) { duke@435: if (that != NULL) { duke@435: that->destruct(); duke@435: delete that; duke@435: } duke@435: } duke@435: // Methods from GCTask. duke@435: void do_it(GCTaskManager* manager, uint which); duke@435: protected: duke@435: // Constructor. Clients use factory, but there might be subclasses. duke@435: NotifyingBarrierGCTask(NotifyDoneClosure* ndc) : duke@435: BarrierGCTask(), duke@435: _ndc(ndc) { duke@435: assert(notify_done_closure() != NULL, "can't notify on NULL"); duke@435: } duke@435: // Destructor-like method. duke@435: void destruct(); duke@435: // Accessor. duke@435: NotifyDoneClosure* notify_done_closure() const { return _ndc; } duke@435: }; duke@435: duke@435: // A WaitForBarrierGCTask is a BarrierGCTask duke@435: // with a method you can call to wait until duke@435: // the BarrierGCTask is done. duke@435: // This may cover many of the uses of NotifyingBarrierGCTasks. duke@435: class WaitForBarrierGCTask : public BarrierGCTask { jmasa@3294: friend class GCTaskManager; jmasa@3294: friend class IdleGCTask; duke@435: private: duke@435: // Instance state. jmasa@3294: Monitor* _monitor; // Guard and notify changes. jmasa@3294: volatile bool _should_wait; // true=>wait, false=>proceed. jmasa@3294: const bool _is_c_heap_obj; // Was allocated on the heap. duke@435: public: duke@435: virtual char* name() { return (char *) "waitfor-barrier-task"; } duke@435: duke@435: // Factory create and destroy methods. duke@435: static WaitForBarrierGCTask* create(); duke@435: static WaitForBarrierGCTask* create_on_c_heap(); duke@435: static void destroy(WaitForBarrierGCTask* that); duke@435: // Methods. duke@435: void do_it(GCTaskManager* manager, uint which); jmasa@3294: void wait_for(bool reset); jmasa@3294: void set_should_wait(bool value) { jmasa@3294: _should_wait = value; jmasa@3294: } duke@435: protected: duke@435: // Constructor. Clients use factory, but there might be subclasses. duke@435: WaitForBarrierGCTask(bool on_c_heap); duke@435: // Destructor-like method. duke@435: void destruct(); duke@435: // Accessors. duke@435: Monitor* monitor() const { duke@435: return _monitor; duke@435: } duke@435: bool should_wait() const { duke@435: return _should_wait; duke@435: } duke@435: bool is_c_heap_obj() { duke@435: return _is_c_heap_obj; duke@435: } duke@435: }; duke@435: jmasa@3294: // Task that is used to idle a GC task when fewer than jmasa@3294: // the maximum workers are wanted. jmasa@3294: class IdleGCTask : public GCTask { jmasa@3294: const bool _is_c_heap_obj; // Was allocated on the heap. jmasa@3294: public: jmasa@3294: bool is_c_heap_obj() { jmasa@3294: return _is_c_heap_obj; jmasa@3294: } jmasa@3294: // Factory create and destroy methods. jmasa@3294: static IdleGCTask* create(); jmasa@3294: static IdleGCTask* create_on_c_heap(); jmasa@3294: static void destroy(IdleGCTask* that); jmasa@3294: jmasa@3294: virtual char* name() { return (char *)"idle task"; } jmasa@3294: // Methods from GCTask. jmasa@3294: virtual void do_it(GCTaskManager* manager, uint which); jmasa@3294: protected: jmasa@3294: // Constructor. jmasa@3294: IdleGCTask(bool on_c_heap) : jmasa@3294: GCTask(GCTask::Kind::idle_task), jmasa@3294: _is_c_heap_obj(on_c_heap) { jmasa@3294: // Nothing to do. jmasa@3294: } jmasa@3294: // Destructor-like method. jmasa@3294: void destruct(); jmasa@3294: }; jmasa@3294: duke@435: class MonitorSupply : public AllStatic { duke@435: private: duke@435: // State. duke@435: // Control multi-threaded access. duke@435: static Mutex* _lock; duke@435: // The list of available Monitor*'s. duke@435: static GrowableArray* _freelist; duke@435: public: duke@435: // Reserve a Monitor*. duke@435: static Monitor* reserve(); duke@435: // Release a Monitor*. duke@435: static void release(Monitor* instance); duke@435: private: duke@435: // Accessors. duke@435: static Mutex* lock() { duke@435: return _lock; duke@435: } duke@435: static GrowableArray* freelist() { duke@435: return _freelist; duke@435: } duke@435: }; stefank@2314: stefank@2314: #endif // SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_GCTASKMANAGER_HPP