1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/vm/utilities/workgroup.hpp Sat Dec 01 00:00:00 2007 +0000 1.3 @@ -0,0 +1,345 @@ 1.4 +/* 1.5 + * Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. 1.11 + * 1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.15 + * version 2 for more details (a copy is included in the LICENSE file that 1.16 + * accompanied this code). 1.17 + * 1.18 + * You should have received a copy of the GNU General Public License version 1.19 + * 2 along with this work; if not, write to the Free Software Foundation, 1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.21 + * 1.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 1.23 + * CA 95054 USA or visit www.sun.com if you need additional information or 1.24 + * have any questions. 1.25 + * 1.26 + */ 1.27 + 1.28 +// Forward declarations of classes defined here 1.29 + 1.30 +class WorkGang; 1.31 +class GangWorker; 1.32 +class YieldingFlexibleGangWorker; 1.33 +class YieldingFlexibleGangTask; 1.34 +class WorkData; 1.35 + 1.36 +// An abstract task to be worked on by a gang. 1.37 +// You subclass this to supply your own work() method 1.38 +class AbstractGangTask: public CHeapObj { 1.39 +public: 1.40 + // The abstract work method. 1.41 + // The argument tells you which member of the gang you are. 1.42 + virtual void work(int i) = 0; 1.43 + 1.44 + // Debugging accessor for the name. 1.45 + const char* name() const PRODUCT_RETURN_(return NULL;); 1.46 + int counter() { return _counter; } 1.47 + void set_counter(int value) { _counter = value; } 1.48 + int *address_of_counter() { return &_counter; } 1.49 + 1.50 + // RTTI 1.51 + NOT_PRODUCT(virtual bool is_YieldingFlexibleGang_task() const { 1.52 + return false; 1.53 + }) 1.54 + 1.55 +private: 1.56 + NOT_PRODUCT(const char* _name;) 1.57 + // ??? Should a task have a priority associated with it? 1.58 + // ??? Or can the run method adjust priority as needed? 1.59 + int _counter; 1.60 + 1.61 +protected: 1.62 + // Constructor and desctructor: only construct subclasses. 1.63 + AbstractGangTask(const char* name) { 1.64 + NOT_PRODUCT(_name = name); 1.65 + _counter = 0; 1.66 + } 1.67 + virtual ~AbstractGangTask() { } 1.68 +}; 1.69 + 1.70 + 1.71 +// Class AbstractWorkGang: 1.72 +// An abstract class representing a gang of workers. 1.73 +// You subclass this to supply an implementation of run_task(). 1.74 +class AbstractWorkGang: public CHeapObj { 1.75 + // Here's the public interface to this class. 1.76 +public: 1.77 + // Constructor and destructor. 1.78 + AbstractWorkGang(const char* name, bool are_GC_threads); 1.79 + ~AbstractWorkGang(); 1.80 + // Run a task, returns when the task is done (or terminated). 1.81 + virtual void run_task(AbstractGangTask* task) = 0; 1.82 + // Stop and terminate all workers. 1.83 + virtual void stop(); 1.84 +public: 1.85 + // Debugging. 1.86 + const char* name() const; 1.87 +protected: 1.88 + // Initialize only instance data. 1.89 + const bool _are_GC_threads; 1.90 + // Printing support. 1.91 + const char* _name; 1.92 + // The monitor which protects these data, 1.93 + // and notifies of changes in it. 1.94 + Monitor* _monitor; 1.95 + // The count of the number of workers in the gang. 1.96 + int _total_workers; 1.97 + // Whether the workers should terminate. 1.98 + bool _terminate; 1.99 + // The array of worker threads for this gang. 1.100 + // This is only needed for cleaning up. 1.101 + GangWorker** _gang_workers; 1.102 + // The task for this gang. 1.103 + AbstractGangTask* _task; 1.104 + // A sequence number for the current task. 1.105 + int _sequence_number; 1.106 + // The number of started workers. 1.107 + int _started_workers; 1.108 + // The number of finished workers. 1.109 + int _finished_workers; 1.110 +public: 1.111 + // Accessors for fields 1.112 + Monitor* monitor() const { 1.113 + return _monitor; 1.114 + } 1.115 + int total_workers() const { 1.116 + return _total_workers; 1.117 + } 1.118 + bool terminate() const { 1.119 + return _terminate; 1.120 + } 1.121 + GangWorker** gang_workers() const { 1.122 + return _gang_workers; 1.123 + } 1.124 + AbstractGangTask* task() const { 1.125 + return _task; 1.126 + } 1.127 + int sequence_number() const { 1.128 + return _sequence_number; 1.129 + } 1.130 + int started_workers() const { 1.131 + return _started_workers; 1.132 + } 1.133 + int finished_workers() const { 1.134 + return _finished_workers; 1.135 + } 1.136 + bool are_GC_threads() const { 1.137 + return _are_GC_threads; 1.138 + } 1.139 + // Predicates. 1.140 + bool is_idle() const { 1.141 + return (task() == NULL); 1.142 + } 1.143 + // Return the Ith gang worker. 1.144 + GangWorker* gang_worker(int i) const; 1.145 + 1.146 + void threads_do(ThreadClosure* tc) const; 1.147 + 1.148 + // Printing 1.149 + void print_worker_threads_on(outputStream *st) const; 1.150 + void print_worker_threads() const { 1.151 + print_worker_threads_on(tty); 1.152 + } 1.153 + 1.154 +protected: 1.155 + friend class GangWorker; 1.156 + friend class YieldingFlexibleGangWorker; 1.157 + // Note activation and deactivation of workers. 1.158 + // These methods should only be called with the mutex held. 1.159 + void internal_worker_poll(WorkData* data) const; 1.160 + void internal_note_start(); 1.161 + void internal_note_finish(); 1.162 +}; 1.163 + 1.164 +class WorkData: public StackObj { 1.165 + // This would be a struct, but I want accessor methods. 1.166 +private: 1.167 + bool _terminate; 1.168 + AbstractGangTask* _task; 1.169 + int _sequence_number; 1.170 +public: 1.171 + // Constructor and destructor 1.172 + WorkData() { 1.173 + _terminate = false; 1.174 + _task = NULL; 1.175 + _sequence_number = 0; 1.176 + } 1.177 + ~WorkData() { 1.178 + } 1.179 + // Accessors and modifiers 1.180 + bool terminate() const { return _terminate; } 1.181 + void set_terminate(bool value) { _terminate = value; } 1.182 + AbstractGangTask* task() const { return _task; } 1.183 + void set_task(AbstractGangTask* value) { _task = value; } 1.184 + int sequence_number() const { return _sequence_number; } 1.185 + void set_sequence_number(int value) { _sequence_number = value; } 1.186 + 1.187 + YieldingFlexibleGangTask* yf_task() const { 1.188 + return (YieldingFlexibleGangTask*)_task; 1.189 + } 1.190 +}; 1.191 + 1.192 +// Class WorkGang: 1.193 +class WorkGang: public AbstractWorkGang { 1.194 +public: 1.195 + // Constructor 1.196 + WorkGang(const char* name, int workers, bool are_GC_threads); 1.197 + // Run a task, returns when the task is done (or terminated). 1.198 + virtual void run_task(AbstractGangTask* task); 1.199 +}; 1.200 + 1.201 +// Class GangWorker: 1.202 +// Several instances of this class run in parallel as workers for a gang. 1.203 +class GangWorker: public WorkerThread { 1.204 +public: 1.205 + // Constructors and destructor. 1.206 + GangWorker(AbstractWorkGang* gang, uint id); 1.207 + 1.208 + // The only real method: run a task for the gang. 1.209 + virtual void run(); 1.210 + // Predicate for Thread 1.211 + virtual bool is_GC_task_thread() const; 1.212 + // Printing 1.213 + void print_on(outputStream* st) const; 1.214 + virtual void print() const { print_on(tty); } 1.215 +protected: 1.216 + AbstractWorkGang* _gang; 1.217 + 1.218 + virtual void initialize(); 1.219 + virtual void loop(); 1.220 + 1.221 +public: 1.222 + AbstractWorkGang* gang() const { return _gang; } 1.223 +}; 1.224 + 1.225 +// A class that acts as a synchronisation barrier. Workers enter 1.226 +// the barrier and must wait until all other workers have entered 1.227 +// before any of them may leave. 1.228 + 1.229 +class WorkGangBarrierSync : public StackObj { 1.230 +protected: 1.231 + Monitor _monitor; 1.232 + int _n_workers; 1.233 + int _n_completed; 1.234 + 1.235 + Monitor* monitor() { return &_monitor; } 1.236 + int n_workers() { return _n_workers; } 1.237 + int n_completed() { return _n_completed; } 1.238 + 1.239 + void inc_completed() { _n_completed++; } 1.240 + 1.241 +public: 1.242 + WorkGangBarrierSync(); 1.243 + WorkGangBarrierSync(int n_workers, const char* name); 1.244 + 1.245 + // Set the number of workers that will use the barrier. 1.246 + // Must be called before any of the workers start running. 1.247 + void set_n_workers(int n_workers); 1.248 + 1.249 + // Enter the barrier. A worker that enters the barrier will 1.250 + // not be allowed to leave until all other threads have 1.251 + // also entered the barrier. 1.252 + void enter(); 1.253 +}; 1.254 + 1.255 +// A class to manage claiming of subtasks within a group of tasks. The 1.256 +// subtasks will be identified by integer indices, usually elements of an 1.257 +// enumeration type. 1.258 + 1.259 +class SubTasksDone: public CHeapObj { 1.260 + jint* _tasks; 1.261 + int _n_tasks; 1.262 + int _n_threads; 1.263 + jint _threads_completed; 1.264 +#ifdef ASSERT 1.265 + jint _claimed; 1.266 +#endif 1.267 + 1.268 + // Set all tasks to unclaimed. 1.269 + void clear(); 1.270 + 1.271 +public: 1.272 + // Initializes "this" to a state in which there are "n" tasks to be 1.273 + // processed, none of the which are originally claimed. The number of 1.274 + // threads doing the tasks is initialized 1. 1.275 + SubTasksDone(int n); 1.276 + 1.277 + // True iff the object is in a valid state. 1.278 + bool valid(); 1.279 + 1.280 + // Set the number of parallel threads doing the tasks to "t". Can only 1.281 + // be called before tasks start or after they are complete. 1.282 + void set_par_threads(int t); 1.283 + 1.284 + // Returns "false" if the task "t" is unclaimed, and ensures that task is 1.285 + // claimed. The task "t" is required to be within the range of "this". 1.286 + bool is_task_claimed(int t); 1.287 + 1.288 + // The calling thread asserts that it has attempted to claim all the 1.289 + // tasks that it will try to claim. Every thread in the parallel task 1.290 + // must execute this. (When the last thread does so, the task array is 1.291 + // cleared.) 1.292 + void all_tasks_completed(); 1.293 + 1.294 + // Destructor. 1.295 + ~SubTasksDone(); 1.296 +}; 1.297 + 1.298 +// As above, but for sequential tasks, i.e. instead of claiming 1.299 +// sub-tasks from a set (possibly an enumeration), claim sub-tasks 1.300 +// in sequential order. This is ideal for claiming dynamically 1.301 +// partitioned tasks (like striding in the parallel remembered 1.302 +// set scanning). Note that unlike the above class this is 1.303 +// a stack object - is there any reason for it not to be? 1.304 + 1.305 +class SequentialSubTasksDone : public StackObj { 1.306 +protected: 1.307 + jint _n_tasks; // Total number of tasks available. 1.308 + jint _n_claimed; // Number of tasks claimed. 1.309 + jint _n_threads; // Total number of parallel threads. 1.310 + jint _n_completed; // Number of completed threads. 1.311 + 1.312 + void clear(); 1.313 + 1.314 +public: 1.315 + SequentialSubTasksDone() { clear(); } 1.316 + ~SequentialSubTasksDone() {} 1.317 + 1.318 + // True iff the object is in a valid state. 1.319 + bool valid(); 1.320 + 1.321 + // number of tasks 1.322 + jint n_tasks() const { return _n_tasks; } 1.323 + 1.324 + // Set the number of parallel threads doing the tasks to t. 1.325 + // Should be called before the task starts but it is safe 1.326 + // to call this once a task is running provided that all 1.327 + // threads agree on the number of threads. 1.328 + void set_par_threads(int t) { _n_threads = t; } 1.329 + 1.330 + // Set the number of tasks to be claimed to t. As above, 1.331 + // should be called before the tasks start but it is safe 1.332 + // to call this once a task is running provided all threads 1.333 + // agree on the number of tasks. 1.334 + void set_n_tasks(int t) { _n_tasks = t; } 1.335 + 1.336 + // Returns false if the next task in the sequence is unclaimed, 1.337 + // and ensures that it is claimed. Will set t to be the index 1.338 + // of the claimed task in the sequence. Will return true if 1.339 + // the task cannot be claimed and there are none left to claim. 1.340 + bool is_task_claimed(int& t); 1.341 + 1.342 + // The calling thread asserts that it has attempted to claim 1.343 + // all the tasks it possibly can in the sequence. Every thread 1.344 + // claiming tasks must promise call this. Returns true if this 1.345 + // is the last thread to complete so that the thread can perform 1.346 + // cleanup if necessary. 1.347 + bool all_tasks_completed(); 1.348 +};