--- old/src/share/vm/utilities/workgroup.hpp 2015-05-13 13:59:03.226614387 +0200 +++ /dev/null 2015-03-18 17:10:38.111854831 +0100 @@ -1,531 +0,0 @@ -/* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_VM_UTILITIES_WORKGROUP_HPP -#define SHARE_VM_UTILITIES_WORKGROUP_HPP - -#include "runtime/thread.inline.hpp" -#include "utilities/taskqueue.hpp" - -// Task class hierarchy: -// AbstractGangTask -// AbstractGangTaskWOopQueues -// -// Gang/Group class hierarchy: -// AbstractWorkGang -// WorkGang -// FlexibleWorkGang -// YieldingFlexibleWorkGang (defined in another file) -// -// Worker class hierarchy: -// GangWorker (subclass of WorkerThread) -// YieldingFlexibleGangWorker (defined in another file) - -// Forward declarations of classes defined here - -class WorkGang; -class GangWorker; -class YieldingFlexibleGangWorker; -class YieldingFlexibleGangTask; -class WorkData; -class AbstractWorkGang; - -// An abstract task to be worked on by a gang. -// You subclass this to supply your own work() method -class AbstractGangTask VALUE_OBJ_CLASS_SPEC { -public: - // The abstract work method. - // The argument tells you which member of the gang you are. - virtual void work(uint worker_id) = 0; - - // This method configures the task for proper termination. - // Some tasks do not have any requirements on termination - // and may inherit this method that does nothing. Some - // tasks do some coordination on termination and override - // this method to implement that coordination. - virtual void set_for_termination(uint active_workers) {}; - - // Debugging accessor for the name. - const char* name() const PRODUCT_RETURN_(return NULL;); - int counter() { return _counter; } - void set_counter(int value) { _counter = value; } - int *address_of_counter() { return &_counter; } - - // RTTI - NOT_PRODUCT(virtual bool is_YieldingFlexibleGang_task() const { - return false; - }) - -private: - NOT_PRODUCT(const char* _name;) - // ??? Should a task have a priority associated with it? - // ??? Or can the run method adjust priority as needed? - int _counter; - -protected: - // Constructor and desctructor: only construct subclasses. - AbstractGangTask(const char* name) - { - NOT_PRODUCT(_name = name); - _counter = 0; - } - ~AbstractGangTask() { } - -public: -}; - -class AbstractGangTaskWOopQueues : public AbstractGangTask { - OopTaskQueueSet* _queues; - ParallelTaskTerminator _terminator; - public: - AbstractGangTaskWOopQueues(const char* name, OopTaskQueueSet* queues) : - AbstractGangTask(name), _queues(queues), _terminator(0, _queues) {} - ParallelTaskTerminator* terminator() { return &_terminator; } - virtual void set_for_termination(uint active_workers) { - terminator()->reset_for_reuse(active_workers); - } - OopTaskQueueSet* queues() { return _queues; } -}; - - -// Class AbstractWorkGang: -// An abstract class representing a gang of workers. -// You subclass this to supply an implementation of run_task(). -class AbstractWorkGang: public CHeapObj { - // Here's the public interface to this class. -public: - // Constructor and destructor. - AbstractWorkGang(const char* name, bool are_GC_task_threads, - bool are_ConcurrentGC_threads); - ~AbstractWorkGang(); - // Run a task, returns when the task is done (or terminated). - virtual void run_task(AbstractGangTask* task) = 0; - // Stop and terminate all workers. - virtual void stop(); - // Return true if more workers should be applied to the task. - virtual bool needs_more_workers() const { return true; } -public: - // Debugging. - const char* name() const; -protected: - // Initialize only instance data. - const bool _are_GC_task_threads; - const bool _are_ConcurrentGC_threads; - // Printing support. - const char* _name; - // The monitor which protects these data, - // and notifies of changes in it. - Monitor* _monitor; - // The count of the number of workers in the gang. - uint _total_workers; - // Whether the workers should terminate. - bool _terminate; - // The array of worker threads for this gang. - // This is only needed for cleaning up. - GangWorker** _gang_workers; - // The task for this gang. - AbstractGangTask* _task; - // A sequence number for the current task. - int _sequence_number; - // The number of started workers. - uint _started_workers; - // The number of finished workers. - uint _finished_workers; -public: - // Accessors for fields - Monitor* monitor() const { - return _monitor; - } - uint total_workers() const { - return _total_workers; - } - virtual uint active_workers() const { - return _total_workers; - } - bool terminate() const { - return _terminate; - } - GangWorker** gang_workers() const { - return _gang_workers; - } - AbstractGangTask* task() const { - return _task; - } - int sequence_number() const { - return _sequence_number; - } - uint started_workers() const { - return _started_workers; - } - uint finished_workers() const { - return _finished_workers; - } - bool are_GC_task_threads() const { - return _are_GC_task_threads; - } - bool are_ConcurrentGC_threads() const { - return _are_ConcurrentGC_threads; - } - // Predicates. - bool is_idle() const { - return (task() == NULL); - } - // Return the Ith gang worker. - GangWorker* gang_worker(uint i) const; - - void threads_do(ThreadClosure* tc) const; - - // Printing - void print_worker_threads_on(outputStream *st) const; - void print_worker_threads() const { - print_worker_threads_on(tty); - } - -protected: - friend class GangWorker; - friend class YieldingFlexibleGangWorker; - // Note activation and deactivation of workers. - // These methods should only be called with the mutex held. - void internal_worker_poll(WorkData* data) const; - void internal_note_start(); - void internal_note_finish(); -}; - -class WorkData: public StackObj { - // This would be a struct, but I want accessor methods. -private: - bool _terminate; - AbstractGangTask* _task; - int _sequence_number; -public: - // Constructor and destructor - WorkData() { - _terminate = false; - _task = NULL; - _sequence_number = 0; - } - ~WorkData() { - } - // Accessors and modifiers - bool terminate() const { return _terminate; } - void set_terminate(bool value) { _terminate = value; } - AbstractGangTask* task() const { return _task; } - void set_task(AbstractGangTask* value) { _task = value; } - int sequence_number() const { return _sequence_number; } - void set_sequence_number(int value) { _sequence_number = value; } - - YieldingFlexibleGangTask* yf_task() const { - return (YieldingFlexibleGangTask*)_task; - } -}; - -// Class WorkGang: -class WorkGang: public AbstractWorkGang { -public: - // Constructor - WorkGang(const char* name, uint workers, - bool are_GC_task_threads, bool are_ConcurrentGC_threads); - // Run a task, returns when the task is done (or terminated). - virtual void run_task(AbstractGangTask* task); - void run_task(AbstractGangTask* task, uint no_of_parallel_workers); - // Allocate a worker and return a pointer to it. - virtual GangWorker* allocate_worker(uint which); - // Initialize workers in the gang. Return true if initialization - // succeeded. The type of the worker can be overridden in a derived - // class with the appropriate implementation of allocate_worker(). - bool initialize_workers(); -}; - -// Class GangWorker: -// Several instances of this class run in parallel as workers for a gang. -class GangWorker: public WorkerThread { -public: - // Constructors and destructor. - GangWorker(AbstractWorkGang* gang, uint id); - - // The only real method: run a task for the gang. - virtual void run(); - // Predicate for Thread - virtual bool is_GC_task_thread() const; - virtual bool is_ConcurrentGC_thread() const; - // Printing - void print_on(outputStream* st) const; - virtual void print() const { print_on(tty); } -protected: - AbstractWorkGang* _gang; - - virtual void initialize(); - virtual void loop(); - -public: - AbstractWorkGang* gang() const { return _gang; } -}; - -// Dynamic number of worker threads -// -// This type of work gang is used to run different numbers of -// worker threads at different times. The -// number of workers run for a task is "_active_workers" -// instead of "_total_workers" in a WorkGang. The method -// "needs_more_workers()" returns true until "_active_workers" -// have been started and returns false afterwards. The -// implementation of "needs_more_workers()" in WorkGang always -// returns true so that all workers are started. The method -// "loop()" in GangWorker was modified to ask "needs_more_workers()" -// in its loop to decide if it should start working on a task. -// A worker in "loop()" waits for notification on the WorkGang -// monitor and execution of each worker as it checks for work -// is serialized via the same monitor. The "needs_more_workers()" -// call is serialized and additionally the calculation for the -// "part" (effectively the worker id for executing the task) is -// serialized to give each worker a unique "part". Workers that -// are not needed for this tasks (i.e., "_active_workers" have -// been started before it, continue to wait for work. - -class FlexibleWorkGang: public WorkGang { - // The currently active workers in this gang. - // This is a number that is dynamically adjusted - // and checked in the run_task() method at each invocation. - // As described above _active_workers determines the number - // of threads started on a task. It must also be used to - // determine completion. - - protected: - uint _active_workers; - public: - // Constructor and destructor. - // Initialize active_workers to a minimum value. Setting it to - // the parameter "workers" will initialize it to a maximum - // value which is not desirable. - FlexibleWorkGang(const char* name, uint workers, - bool are_GC_task_threads, - bool are_ConcurrentGC_threads) : - WorkGang(name, workers, are_GC_task_threads, are_ConcurrentGC_threads), - _active_workers(UseDynamicNumberOfGCThreads ? 1U : ParallelGCThreads) {} - // Accessors for fields - virtual uint active_workers() const { return _active_workers; } - void set_active_workers(uint v) { - assert(v <= _total_workers, - "Trying to set more workers active than there are"); - _active_workers = MIN2(v, _total_workers); - assert(v != 0, "Trying to set active workers to 0"); - _active_workers = MAX2(1U, _active_workers); - assert(UseDynamicNumberOfGCThreads || _active_workers == _total_workers, - "Unless dynamic should use total workers"); - } - virtual void run_task(AbstractGangTask* task); - virtual bool needs_more_workers() const { - return _started_workers < _active_workers; - } -}; - -// A class that acts as a synchronisation barrier. Workers enter -// the barrier and must wait until all other workers have entered -// before any of them may leave. - -class WorkGangBarrierSync : public StackObj { -protected: - Monitor _monitor; - uint _n_workers; - uint _n_completed; - bool _should_reset; - bool _aborted; - - Monitor* monitor() { return &_monitor; } - uint n_workers() { return _n_workers; } - uint n_completed() { return _n_completed; } - bool should_reset() { return _should_reset; } - bool aborted() { return _aborted; } - - void zero_completed() { _n_completed = 0; } - void inc_completed() { _n_completed++; } - void set_aborted() { _aborted = true; } - void set_should_reset(bool v) { _should_reset = v; } - -public: - WorkGangBarrierSync(); - WorkGangBarrierSync(uint n_workers, const char* name); - - // Set the number of workers that will use the barrier. - // Must be called before any of the workers start running. - void set_n_workers(uint n_workers); - - // Enter the barrier. A worker that enters the barrier will - // not be allowed to leave until all other threads have - // also entered the barrier or the barrier is aborted. - // Returns false if the barrier was aborted. - bool enter(); - - // Aborts the barrier and wakes up any threads waiting for - // the barrier to complete. The barrier will remain in the - // aborted state until the next call to set_n_workers(). - void abort(); -}; - -// A class to manage claiming of subtasks within a group of tasks. The -// subtasks will be identified by integer indices, usually elements of an -// enumeration type. - -class SubTasksDone: public CHeapObj { - uint* _tasks; - uint _n_tasks; - // _n_threads is used to determine when a sub task is done. - // It does not control how many threads will execute the subtask - // but must be initialized to the number that do execute the task - // in order to correctly decide when the subtask is done (all the - // threads working on the task have finished). - uint _n_threads; - uint _threads_completed; -#ifdef ASSERT - volatile uint _claimed; -#endif - - // Set all tasks to unclaimed. - void clear(); - -public: - // Initializes "this" to a state in which there are "n" tasks to be - // processed, none of the which are originally claimed. The number of - // threads doing the tasks is initialized 1. - SubTasksDone(uint n); - - // True iff the object is in a valid state. - bool valid(); - - // Get/set the number of parallel threads doing the tasks to "t". Can only - // be called before tasks start or after they are complete. - uint n_threads() { return _n_threads; } - void set_n_threads(uint t); - - // Returns "false" if the task "t" is unclaimed, and ensures that task is - // claimed. The task "t" is required to be within the range of "this". - bool is_task_claimed(uint t); - - // The calling thread asserts that it has attempted to claim all the - // tasks that it will try to claim. Every thread in the parallel task - // must execute this. (When the last thread does so, the task array is - // cleared.) - void all_tasks_completed(); - - // Destructor. - ~SubTasksDone(); -}; - -// As above, but for sequential tasks, i.e. instead of claiming -// sub-tasks from a set (possibly an enumeration), claim sub-tasks -// in sequential order. This is ideal for claiming dynamically -// partitioned tasks (like striding in the parallel remembered -// set scanning). Note that unlike the above class this is -// a stack object - is there any reason for it not to be? - -class SequentialSubTasksDone : public StackObj { -protected: - uint _n_tasks; // Total number of tasks available. - uint _n_claimed; // Number of tasks claimed. - // _n_threads is used to determine when a sub task is done. - // See comments on SubTasksDone::_n_threads - uint _n_threads; // Total number of parallel threads. - uint _n_completed; // Number of completed threads. - - void clear(); - -public: - SequentialSubTasksDone() { - clear(); - } - ~SequentialSubTasksDone() {} - - // True iff the object is in a valid state. - bool valid(); - - // number of tasks - uint n_tasks() const { return _n_tasks; } - - // Get/set the number of parallel threads doing the tasks to t. - // Should be called before the task starts but it is safe - // to call this once a task is running provided that all - // threads agree on the number of threads. - uint n_threads() { return _n_threads; } - void set_n_threads(uint t) { _n_threads = t; } - - // Set the number of tasks to be claimed to t. As above, - // should be called before the tasks start but it is safe - // to call this once a task is running provided all threads - // agree on the number of tasks. - void set_n_tasks(uint t) { _n_tasks = t; } - - // Returns false if the next task in the sequence is unclaimed, - // and ensures that it is claimed. Will set t to be the index - // of the claimed task in the sequence. Will return true if - // the task cannot be claimed and there are none left to claim. - bool is_task_claimed(uint& t); - - // The calling thread asserts that it has attempted to claim - // all the tasks it possibly can in the sequence. Every thread - // claiming tasks must promise call this. Returns true if this - // is the last thread to complete so that the thread can perform - // cleanup if necessary. - bool all_tasks_completed(); -}; - -// Represents a set of free small integer ids. -class FreeIdSet : public CHeapObj { - enum { - end_of_list = -1, - claimed = -2 - }; - - int _sz; - Monitor* _mon; - - int* _ids; - int _hd; - int _waiters; - int _claimed; - - static bool _safepoint; - typedef FreeIdSet* FreeIdSetPtr; - static const int NSets = 10; - static FreeIdSetPtr _sets[NSets]; - static bool _stat_init; - int _index; - -public: - FreeIdSet(int sz, Monitor* mon); - ~FreeIdSet(); - - static void set_safepoint(bool b); - - // Attempt to claim the given id permanently. Returns "true" iff - // successful. - bool claim_perm_id(int i); - - // Returns an unclaimed parallel id (waiting for one to be released if - // necessary). Returns "-1" if a GC wakes up a wait for an id. - int claim_par_id(); - - void release_par_id(int id); -}; - -#endif // SHARE_VM_UTILITIES_WORKGROUP_HPP --- /dev/null 2015-03-18 17:10:38.111854831 +0100 +++ new/src/share/vm/gc/shared/workgroup.hpp 2015-05-13 13:59:03.018605745 +0200 @@ -0,0 +1,531 @@ +/* + * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_GC_SHARED_WORKGROUP_HPP +#define SHARE_VM_GC_SHARED_WORKGROUP_HPP + +#include "gc/shared/taskqueue.hpp" +#include "runtime/thread.inline.hpp" + +// Task class hierarchy: +// AbstractGangTask +// AbstractGangTaskWOopQueues +// +// Gang/Group class hierarchy: +// AbstractWorkGang +// WorkGang +// FlexibleWorkGang +// YieldingFlexibleWorkGang (defined in another file) +// +// Worker class hierarchy: +// GangWorker (subclass of WorkerThread) +// YieldingFlexibleGangWorker (defined in another file) + +// Forward declarations of classes defined here + +class WorkGang; +class GangWorker; +class YieldingFlexibleGangWorker; +class YieldingFlexibleGangTask; +class WorkData; +class AbstractWorkGang; + +// An abstract task to be worked on by a gang. +// You subclass this to supply your own work() method +class AbstractGangTask VALUE_OBJ_CLASS_SPEC { +public: + // The abstract work method. + // The argument tells you which member of the gang you are. + virtual void work(uint worker_id) = 0; + + // This method configures the task for proper termination. + // Some tasks do not have any requirements on termination + // and may inherit this method that does nothing. Some + // tasks do some coordination on termination and override + // this method to implement that coordination. + virtual void set_for_termination(uint active_workers) {}; + + // Debugging accessor for the name. + const char* name() const PRODUCT_RETURN_(return NULL;); + int counter() { return _counter; } + void set_counter(int value) { _counter = value; } + int *address_of_counter() { return &_counter; } + + // RTTI + NOT_PRODUCT(virtual bool is_YieldingFlexibleGang_task() const { + return false; + }) + +private: + NOT_PRODUCT(const char* _name;) + // ??? Should a task have a priority associated with it? + // ??? Or can the run method adjust priority as needed? + int _counter; + +protected: + // Constructor and desctructor: only construct subclasses. + AbstractGangTask(const char* name) + { + NOT_PRODUCT(_name = name); + _counter = 0; + } + ~AbstractGangTask() { } + +public: +}; + +class AbstractGangTaskWOopQueues : public AbstractGangTask { + OopTaskQueueSet* _queues; + ParallelTaskTerminator _terminator; + public: + AbstractGangTaskWOopQueues(const char* name, OopTaskQueueSet* queues) : + AbstractGangTask(name), _queues(queues), _terminator(0, _queues) {} + ParallelTaskTerminator* terminator() { return &_terminator; } + virtual void set_for_termination(uint active_workers) { + terminator()->reset_for_reuse(active_workers); + } + OopTaskQueueSet* queues() { return _queues; } +}; + + +// Class AbstractWorkGang: +// An abstract class representing a gang of workers. +// You subclass this to supply an implementation of run_task(). +class AbstractWorkGang: public CHeapObj { + // Here's the public interface to this class. +public: + // Constructor and destructor. + AbstractWorkGang(const char* name, bool are_GC_task_threads, + bool are_ConcurrentGC_threads); + ~AbstractWorkGang(); + // Run a task, returns when the task is done (or terminated). + virtual void run_task(AbstractGangTask* task) = 0; + // Stop and terminate all workers. + virtual void stop(); + // Return true if more workers should be applied to the task. + virtual bool needs_more_workers() const { return true; } +public: + // Debugging. + const char* name() const; +protected: + // Initialize only instance data. + const bool _are_GC_task_threads; + const bool _are_ConcurrentGC_threads; + // Printing support. + const char* _name; + // The monitor which protects these data, + // and notifies of changes in it. + Monitor* _monitor; + // The count of the number of workers in the gang. + uint _total_workers; + // Whether the workers should terminate. + bool _terminate; + // The array of worker threads for this gang. + // This is only needed for cleaning up. + GangWorker** _gang_workers; + // The task for this gang. + AbstractGangTask* _task; + // A sequence number for the current task. + int _sequence_number; + // The number of started workers. + uint _started_workers; + // The number of finished workers. + uint _finished_workers; +public: + // Accessors for fields + Monitor* monitor() const { + return _monitor; + } + uint total_workers() const { + return _total_workers; + } + virtual uint active_workers() const { + return _total_workers; + } + bool terminate() const { + return _terminate; + } + GangWorker** gang_workers() const { + return _gang_workers; + } + AbstractGangTask* task() const { + return _task; + } + int sequence_number() const { + return _sequence_number; + } + uint started_workers() const { + return _started_workers; + } + uint finished_workers() const { + return _finished_workers; + } + bool are_GC_task_threads() const { + return _are_GC_task_threads; + } + bool are_ConcurrentGC_threads() const { + return _are_ConcurrentGC_threads; + } + // Predicates. + bool is_idle() const { + return (task() == NULL); + } + // Return the Ith gang worker. + GangWorker* gang_worker(uint i) const; + + void threads_do(ThreadClosure* tc) const; + + // Printing + void print_worker_threads_on(outputStream *st) const; + void print_worker_threads() const { + print_worker_threads_on(tty); + } + +protected: + friend class GangWorker; + friend class YieldingFlexibleGangWorker; + // Note activation and deactivation of workers. + // These methods should only be called with the mutex held. + void internal_worker_poll(WorkData* data) const; + void internal_note_start(); + void internal_note_finish(); +}; + +class WorkData: public StackObj { + // This would be a struct, but I want accessor methods. +private: + bool _terminate; + AbstractGangTask* _task; + int _sequence_number; +public: + // Constructor and destructor + WorkData() { + _terminate = false; + _task = NULL; + _sequence_number = 0; + } + ~WorkData() { + } + // Accessors and modifiers + bool terminate() const { return _terminate; } + void set_terminate(bool value) { _terminate = value; } + AbstractGangTask* task() const { return _task; } + void set_task(AbstractGangTask* value) { _task = value; } + int sequence_number() const { return _sequence_number; } + void set_sequence_number(int value) { _sequence_number = value; } + + YieldingFlexibleGangTask* yf_task() const { + return (YieldingFlexibleGangTask*)_task; + } +}; + +// Class WorkGang: +class WorkGang: public AbstractWorkGang { +public: + // Constructor + WorkGang(const char* name, uint workers, + bool are_GC_task_threads, bool are_ConcurrentGC_threads); + // Run a task, returns when the task is done (or terminated). + virtual void run_task(AbstractGangTask* task); + void run_task(AbstractGangTask* task, uint no_of_parallel_workers); + // Allocate a worker and return a pointer to it. + virtual GangWorker* allocate_worker(uint which); + // Initialize workers in the gang. Return true if initialization + // succeeded. The type of the worker can be overridden in a derived + // class with the appropriate implementation of allocate_worker(). + bool initialize_workers(); +}; + +// Class GangWorker: +// Several instances of this class run in parallel as workers for a gang. +class GangWorker: public WorkerThread { +public: + // Constructors and destructor. + GangWorker(AbstractWorkGang* gang, uint id); + + // The only real method: run a task for the gang. + virtual void run(); + // Predicate for Thread + virtual bool is_GC_task_thread() const; + virtual bool is_ConcurrentGC_thread() const; + // Printing + void print_on(outputStream* st) const; + virtual void print() const { print_on(tty); } +protected: + AbstractWorkGang* _gang; + + virtual void initialize(); + virtual void loop(); + +public: + AbstractWorkGang* gang() const { return _gang; } +}; + +// Dynamic number of worker threads +// +// This type of work gang is used to run different numbers of +// worker threads at different times. The +// number of workers run for a task is "_active_workers" +// instead of "_total_workers" in a WorkGang. The method +// "needs_more_workers()" returns true until "_active_workers" +// have been started and returns false afterwards. The +// implementation of "needs_more_workers()" in WorkGang always +// returns true so that all workers are started. The method +// "loop()" in GangWorker was modified to ask "needs_more_workers()" +// in its loop to decide if it should start working on a task. +// A worker in "loop()" waits for notification on the WorkGang +// monitor and execution of each worker as it checks for work +// is serialized via the same monitor. The "needs_more_workers()" +// call is serialized and additionally the calculation for the +// "part" (effectively the worker id for executing the task) is +// serialized to give each worker a unique "part". Workers that +// are not needed for this tasks (i.e., "_active_workers" have +// been started before it, continue to wait for work. + +class FlexibleWorkGang: public WorkGang { + // The currently active workers in this gang. + // This is a number that is dynamically adjusted + // and checked in the run_task() method at each invocation. + // As described above _active_workers determines the number + // of threads started on a task. It must also be used to + // determine completion. + + protected: + uint _active_workers; + public: + // Constructor and destructor. + // Initialize active_workers to a minimum value. Setting it to + // the parameter "workers" will initialize it to a maximum + // value which is not desirable. + FlexibleWorkGang(const char* name, uint workers, + bool are_GC_task_threads, + bool are_ConcurrentGC_threads) : + WorkGang(name, workers, are_GC_task_threads, are_ConcurrentGC_threads), + _active_workers(UseDynamicNumberOfGCThreads ? 1U : ParallelGCThreads) {} + // Accessors for fields + virtual uint active_workers() const { return _active_workers; } + void set_active_workers(uint v) { + assert(v <= _total_workers, + "Trying to set more workers active than there are"); + _active_workers = MIN2(v, _total_workers); + assert(v != 0, "Trying to set active workers to 0"); + _active_workers = MAX2(1U, _active_workers); + assert(UseDynamicNumberOfGCThreads || _active_workers == _total_workers, + "Unless dynamic should use total workers"); + } + virtual void run_task(AbstractGangTask* task); + virtual bool needs_more_workers() const { + return _started_workers < _active_workers; + } +}; + +// A class that acts as a synchronisation barrier. Workers enter +// the barrier and must wait until all other workers have entered +// before any of them may leave. + +class WorkGangBarrierSync : public StackObj { +protected: + Monitor _monitor; + uint _n_workers; + uint _n_completed; + bool _should_reset; + bool _aborted; + + Monitor* monitor() { return &_monitor; } + uint n_workers() { return _n_workers; } + uint n_completed() { return _n_completed; } + bool should_reset() { return _should_reset; } + bool aborted() { return _aborted; } + + void zero_completed() { _n_completed = 0; } + void inc_completed() { _n_completed++; } + void set_aborted() { _aborted = true; } + void set_should_reset(bool v) { _should_reset = v; } + +public: + WorkGangBarrierSync(); + WorkGangBarrierSync(uint n_workers, const char* name); + + // Set the number of workers that will use the barrier. + // Must be called before any of the workers start running. + void set_n_workers(uint n_workers); + + // Enter the barrier. A worker that enters the barrier will + // not be allowed to leave until all other threads have + // also entered the barrier or the barrier is aborted. + // Returns false if the barrier was aborted. + bool enter(); + + // Aborts the barrier and wakes up any threads waiting for + // the barrier to complete. The barrier will remain in the + // aborted state until the next call to set_n_workers(). + void abort(); +}; + +// A class to manage claiming of subtasks within a group of tasks. The +// subtasks will be identified by integer indices, usually elements of an +// enumeration type. + +class SubTasksDone: public CHeapObj { + uint* _tasks; + uint _n_tasks; + // _n_threads is used to determine when a sub task is done. + // It does not control how many threads will execute the subtask + // but must be initialized to the number that do execute the task + // in order to correctly decide when the subtask is done (all the + // threads working on the task have finished). + uint _n_threads; + uint _threads_completed; +#ifdef ASSERT + volatile uint _claimed; +#endif + + // Set all tasks to unclaimed. + void clear(); + +public: + // Initializes "this" to a state in which there are "n" tasks to be + // processed, none of the which are originally claimed. The number of + // threads doing the tasks is initialized 1. + SubTasksDone(uint n); + + // True iff the object is in a valid state. + bool valid(); + + // Get/set the number of parallel threads doing the tasks to "t". Can only + // be called before tasks start or after they are complete. + uint n_threads() { return _n_threads; } + void set_n_threads(uint t); + + // Returns "false" if the task "t" is unclaimed, and ensures that task is + // claimed. The task "t" is required to be within the range of "this". + bool is_task_claimed(uint t); + + // The calling thread asserts that it has attempted to claim all the + // tasks that it will try to claim. Every thread in the parallel task + // must execute this. (When the last thread does so, the task array is + // cleared.) + void all_tasks_completed(); + + // Destructor. + ~SubTasksDone(); +}; + +// As above, but for sequential tasks, i.e. instead of claiming +// sub-tasks from a set (possibly an enumeration), claim sub-tasks +// in sequential order. This is ideal for claiming dynamically +// partitioned tasks (like striding in the parallel remembered +// set scanning). Note that unlike the above class this is +// a stack object - is there any reason for it not to be? + +class SequentialSubTasksDone : public StackObj { +protected: + uint _n_tasks; // Total number of tasks available. + uint _n_claimed; // Number of tasks claimed. + // _n_threads is used to determine when a sub task is done. + // See comments on SubTasksDone::_n_threads + uint _n_threads; // Total number of parallel threads. + uint _n_completed; // Number of completed threads. + + void clear(); + +public: + SequentialSubTasksDone() { + clear(); + } + ~SequentialSubTasksDone() {} + + // True iff the object is in a valid state. + bool valid(); + + // number of tasks + uint n_tasks() const { return _n_tasks; } + + // Get/set the number of parallel threads doing the tasks to t. + // Should be called before the task starts but it is safe + // to call this once a task is running provided that all + // threads agree on the number of threads. + uint n_threads() { return _n_threads; } + void set_n_threads(uint t) { _n_threads = t; } + + // Set the number of tasks to be claimed to t. As above, + // should be called before the tasks start but it is safe + // to call this once a task is running provided all threads + // agree on the number of tasks. + void set_n_tasks(uint t) { _n_tasks = t; } + + // Returns false if the next task in the sequence is unclaimed, + // and ensures that it is claimed. Will set t to be the index + // of the claimed task in the sequence. Will return true if + // the task cannot be claimed and there are none left to claim. + bool is_task_claimed(uint& t); + + // The calling thread asserts that it has attempted to claim + // all the tasks it possibly can in the sequence. Every thread + // claiming tasks must promise call this. Returns true if this + // is the last thread to complete so that the thread can perform + // cleanup if necessary. + bool all_tasks_completed(); +}; + +// Represents a set of free small integer ids. +class FreeIdSet : public CHeapObj { + enum { + end_of_list = -1, + claimed = -2 + }; + + int _sz; + Monitor* _mon; + + int* _ids; + int _hd; + int _waiters; + int _claimed; + + static bool _safepoint; + typedef FreeIdSet* FreeIdSetPtr; + static const int NSets = 10; + static FreeIdSetPtr _sets[NSets]; + static bool _stat_init; + int _index; + +public: + FreeIdSet(int sz, Monitor* mon); + ~FreeIdSet(); + + static void set_safepoint(bool b); + + // Attempt to claim the given id permanently. Returns "true" iff + // successful. + bool claim_perm_id(int i); + + // Returns an unclaimed parallel id (waiting for one to be released if + // necessary). Returns "-1" if a GC wakes up a wait for an id. + int claim_par_id(); + + void release_par_id(int id); +}; + +#endif // SHARE_VM_GC_SHARED_WORKGROUP_HPP