src/share/vm/utilities/workgroup.hpp

Tue, 24 Jul 2018 13:22:11 +0800

author
aoqi
date
Tue, 24 Jul 2018 13:22:11 +0800
changeset 9137
dc1769738300
parent 6876
710a3c8b516e
permissions
-rw-r--r--

#7048 added Loongson release info to hs_err crash files

aoqi@0 1 /*
aoqi@0 2 * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
aoqi@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
aoqi@0 4 *
aoqi@0 5 * This code is free software; you can redistribute it and/or modify it
aoqi@0 6 * under the terms of the GNU General Public License version 2 only, as
aoqi@0 7 * published by the Free Software Foundation.
aoqi@0 8 *
aoqi@0 9 * This code is distributed in the hope that it will be useful, but WITHOUT
aoqi@0 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
aoqi@0 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
aoqi@0 12 * version 2 for more details (a copy is included in the LICENSE file that
aoqi@0 13 * accompanied this code).
aoqi@0 14 *
aoqi@0 15 * You should have received a copy of the GNU General Public License version
aoqi@0 16 * 2 along with this work; if not, write to the Free Software Foundation,
aoqi@0 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
aoqi@0 18 *
aoqi@0 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
aoqi@0 20 * or visit www.oracle.com if you need additional information or have any
aoqi@0 21 * questions.
aoqi@0 22 *
aoqi@0 23 */
aoqi@0 24
aoqi@0 25 #ifndef SHARE_VM_UTILITIES_WORKGROUP_HPP
aoqi@0 26 #define SHARE_VM_UTILITIES_WORKGROUP_HPP
aoqi@0 27
aoqi@0 28 #include "runtime/thread.inline.hpp"
aoqi@0 29 #include "utilities/taskqueue.hpp"
aoqi@0 30
aoqi@0 31 // Task class hierarchy:
aoqi@0 32 // AbstractGangTask
aoqi@0 33 // AbstractGangTaskWOopQueues
aoqi@0 34 //
aoqi@0 35 // Gang/Group class hierarchy:
aoqi@0 36 // AbstractWorkGang
aoqi@0 37 // WorkGang
aoqi@0 38 // FlexibleWorkGang
aoqi@0 39 // YieldingFlexibleWorkGang (defined in another file)
aoqi@0 40 //
aoqi@0 41 // Worker class hierarchy:
aoqi@0 42 // GangWorker (subclass of WorkerThread)
aoqi@0 43 // YieldingFlexibleGangWorker (defined in another file)
aoqi@0 44
aoqi@0 45 // Forward declarations of classes defined here
aoqi@0 46
aoqi@0 47 class WorkGang;
aoqi@0 48 class GangWorker;
aoqi@0 49 class YieldingFlexibleGangWorker;
aoqi@0 50 class YieldingFlexibleGangTask;
aoqi@0 51 class WorkData;
aoqi@0 52 class AbstractWorkGang;
aoqi@0 53
aoqi@0 54 // An abstract task to be worked on by a gang.
aoqi@0 55 // You subclass this to supply your own work() method
aoqi@0 56 class AbstractGangTask VALUE_OBJ_CLASS_SPEC {
aoqi@0 57 public:
aoqi@0 58 // The abstract work method.
aoqi@0 59 // The argument tells you which member of the gang you are.
aoqi@0 60 virtual void work(uint worker_id) = 0;
aoqi@0 61
aoqi@0 62 // This method configures the task for proper termination.
aoqi@0 63 // Some tasks do not have any requirements on termination
aoqi@0 64 // and may inherit this method that does nothing. Some
aoqi@0 65 // tasks do some coordination on termination and override
aoqi@0 66 // this method to implement that coordination.
aoqi@0 67 virtual void set_for_termination(int active_workers) {};
aoqi@0 68
aoqi@0 69 // Debugging accessor for the name.
aoqi@0 70 const char* name() const PRODUCT_RETURN_(return NULL;);
aoqi@0 71 int counter() { return _counter; }
aoqi@0 72 void set_counter(int value) { _counter = value; }
aoqi@0 73 int *address_of_counter() { return &_counter; }
aoqi@0 74
aoqi@0 75 // RTTI
aoqi@0 76 NOT_PRODUCT(virtual bool is_YieldingFlexibleGang_task() const {
aoqi@0 77 return false;
aoqi@0 78 })
aoqi@0 79
aoqi@0 80 private:
aoqi@0 81 NOT_PRODUCT(const char* _name;)
aoqi@0 82 // ??? Should a task have a priority associated with it?
aoqi@0 83 // ??? Or can the run method adjust priority as needed?
aoqi@0 84 int _counter;
aoqi@0 85
aoqi@0 86 protected:
aoqi@0 87 // Constructor and desctructor: only construct subclasses.
aoqi@0 88 AbstractGangTask(const char* name)
aoqi@0 89 {
aoqi@0 90 NOT_PRODUCT(_name = name);
aoqi@0 91 _counter = 0;
aoqi@0 92 }
aoqi@0 93 ~AbstractGangTask() { }
aoqi@0 94
aoqi@0 95 public:
aoqi@0 96 };
aoqi@0 97
aoqi@0 98 class AbstractGangTaskWOopQueues : public AbstractGangTask {
aoqi@0 99 OopTaskQueueSet* _queues;
aoqi@0 100 ParallelTaskTerminator _terminator;
aoqi@0 101 public:
aoqi@0 102 AbstractGangTaskWOopQueues(const char* name, OopTaskQueueSet* queues) :
aoqi@0 103 AbstractGangTask(name), _queues(queues), _terminator(0, _queues) {}
aoqi@0 104 ParallelTaskTerminator* terminator() { return &_terminator; }
aoqi@0 105 virtual void set_for_termination(int active_workers) {
aoqi@0 106 terminator()->reset_for_reuse(active_workers);
aoqi@0 107 }
aoqi@0 108 OopTaskQueueSet* queues() { return _queues; }
aoqi@0 109 };
aoqi@0 110
aoqi@0 111
aoqi@0 112 // Class AbstractWorkGang:
aoqi@0 113 // An abstract class representing a gang of workers.
aoqi@0 114 // You subclass this to supply an implementation of run_task().
aoqi@0 115 class AbstractWorkGang: public CHeapObj<mtInternal> {
aoqi@0 116 // Here's the public interface to this class.
aoqi@0 117 public:
aoqi@0 118 // Constructor and destructor.
aoqi@0 119 AbstractWorkGang(const char* name, bool are_GC_task_threads,
aoqi@0 120 bool are_ConcurrentGC_threads);
aoqi@0 121 ~AbstractWorkGang();
aoqi@0 122 // Run a task, returns when the task is done (or terminated).
aoqi@0 123 virtual void run_task(AbstractGangTask* task) = 0;
aoqi@0 124 // Stop and terminate all workers.
aoqi@0 125 virtual void stop();
aoqi@0 126 // Return true if more workers should be applied to the task.
aoqi@0 127 virtual bool needs_more_workers() const { return true; }
aoqi@0 128 public:
aoqi@0 129 // Debugging.
aoqi@0 130 const char* name() const;
aoqi@0 131 protected:
aoqi@0 132 // Initialize only instance data.
aoqi@0 133 const bool _are_GC_task_threads;
aoqi@0 134 const bool _are_ConcurrentGC_threads;
aoqi@0 135 // Printing support.
aoqi@0 136 const char* _name;
aoqi@0 137 // The monitor which protects these data,
aoqi@0 138 // and notifies of changes in it.
aoqi@0 139 Monitor* _monitor;
aoqi@0 140 // The count of the number of workers in the gang.
aoqi@0 141 uint _total_workers;
aoqi@0 142 // Whether the workers should terminate.
aoqi@0 143 bool _terminate;
aoqi@0 144 // The array of worker threads for this gang.
aoqi@0 145 // This is only needed for cleaning up.
aoqi@0 146 GangWorker** _gang_workers;
aoqi@0 147 // The task for this gang.
aoqi@0 148 AbstractGangTask* _task;
aoqi@0 149 // A sequence number for the current task.
aoqi@0 150 int _sequence_number;
aoqi@0 151 // The number of started workers.
aoqi@0 152 uint _started_workers;
aoqi@0 153 // The number of finished workers.
aoqi@0 154 uint _finished_workers;
aoqi@0 155 public:
aoqi@0 156 // Accessors for fields
aoqi@0 157 Monitor* monitor() const {
aoqi@0 158 return _monitor;
aoqi@0 159 }
aoqi@0 160 uint total_workers() const {
aoqi@0 161 return _total_workers;
aoqi@0 162 }
aoqi@0 163 virtual uint active_workers() const {
aoqi@0 164 return _total_workers;
aoqi@0 165 }
aoqi@0 166 bool terminate() const {
aoqi@0 167 return _terminate;
aoqi@0 168 }
aoqi@0 169 GangWorker** gang_workers() const {
aoqi@0 170 return _gang_workers;
aoqi@0 171 }
aoqi@0 172 AbstractGangTask* task() const {
aoqi@0 173 return _task;
aoqi@0 174 }
aoqi@0 175 int sequence_number() const {
aoqi@0 176 return _sequence_number;
aoqi@0 177 }
aoqi@0 178 uint started_workers() const {
aoqi@0 179 return _started_workers;
aoqi@0 180 }
aoqi@0 181 uint finished_workers() const {
aoqi@0 182 return _finished_workers;
aoqi@0 183 }
aoqi@0 184 bool are_GC_task_threads() const {
aoqi@0 185 return _are_GC_task_threads;
aoqi@0 186 }
aoqi@0 187 bool are_ConcurrentGC_threads() const {
aoqi@0 188 return _are_ConcurrentGC_threads;
aoqi@0 189 }
aoqi@0 190 // Predicates.
aoqi@0 191 bool is_idle() const {
aoqi@0 192 return (task() == NULL);
aoqi@0 193 }
aoqi@0 194 // Return the Ith gang worker.
aoqi@0 195 GangWorker* gang_worker(uint i) const;
aoqi@0 196
aoqi@0 197 void threads_do(ThreadClosure* tc) const;
aoqi@0 198
aoqi@0 199 // Printing
aoqi@0 200 void print_worker_threads_on(outputStream *st) const;
aoqi@0 201 void print_worker_threads() const {
aoqi@0 202 print_worker_threads_on(tty);
aoqi@0 203 }
aoqi@0 204
aoqi@0 205 protected:
aoqi@0 206 friend class GangWorker;
aoqi@0 207 friend class YieldingFlexibleGangWorker;
aoqi@0 208 // Note activation and deactivation of workers.
aoqi@0 209 // These methods should only be called with the mutex held.
aoqi@0 210 void internal_worker_poll(WorkData* data) const;
aoqi@0 211 void internal_note_start();
aoqi@0 212 void internal_note_finish();
aoqi@0 213 };
aoqi@0 214
aoqi@0 215 class WorkData: public StackObj {
aoqi@0 216 // This would be a struct, but I want accessor methods.
aoqi@0 217 private:
aoqi@0 218 bool _terminate;
aoqi@0 219 AbstractGangTask* _task;
aoqi@0 220 int _sequence_number;
aoqi@0 221 public:
aoqi@0 222 // Constructor and destructor
aoqi@0 223 WorkData() {
aoqi@0 224 _terminate = false;
aoqi@0 225 _task = NULL;
aoqi@0 226 _sequence_number = 0;
aoqi@0 227 }
aoqi@0 228 ~WorkData() {
aoqi@0 229 }
aoqi@0 230 // Accessors and modifiers
aoqi@0 231 bool terminate() const { return _terminate; }
aoqi@0 232 void set_terminate(bool value) { _terminate = value; }
aoqi@0 233 AbstractGangTask* task() const { return _task; }
aoqi@0 234 void set_task(AbstractGangTask* value) { _task = value; }
aoqi@0 235 int sequence_number() const { return _sequence_number; }
aoqi@0 236 void set_sequence_number(int value) { _sequence_number = value; }
aoqi@0 237
aoqi@0 238 YieldingFlexibleGangTask* yf_task() const {
aoqi@0 239 return (YieldingFlexibleGangTask*)_task;
aoqi@0 240 }
aoqi@0 241 };
aoqi@0 242
aoqi@0 243 // Class WorkGang:
aoqi@0 244 class WorkGang: public AbstractWorkGang {
aoqi@0 245 public:
aoqi@0 246 // Constructor
aoqi@0 247 WorkGang(const char* name, uint workers,
aoqi@0 248 bool are_GC_task_threads, bool are_ConcurrentGC_threads);
aoqi@0 249 // Run a task, returns when the task is done (or terminated).
aoqi@0 250 virtual void run_task(AbstractGangTask* task);
aoqi@0 251 void run_task(AbstractGangTask* task, uint no_of_parallel_workers);
aoqi@0 252 // Allocate a worker and return a pointer to it.
aoqi@0 253 virtual GangWorker* allocate_worker(uint which);
aoqi@0 254 // Initialize workers in the gang. Return true if initialization
aoqi@0 255 // succeeded. The type of the worker can be overridden in a derived
aoqi@0 256 // class with the appropriate implementation of allocate_worker().
aoqi@0 257 bool initialize_workers();
aoqi@0 258 };
aoqi@0 259
aoqi@0 260 // Class GangWorker:
aoqi@0 261 // Several instances of this class run in parallel as workers for a gang.
aoqi@0 262 class GangWorker: public WorkerThread {
aoqi@0 263 public:
aoqi@0 264 // Constructors and destructor.
aoqi@0 265 GangWorker(AbstractWorkGang* gang, uint id);
aoqi@0 266
aoqi@0 267 // The only real method: run a task for the gang.
aoqi@0 268 virtual void run();
aoqi@0 269 // Predicate for Thread
aoqi@0 270 virtual bool is_GC_task_thread() const;
aoqi@0 271 virtual bool is_ConcurrentGC_thread() const;
aoqi@0 272 // Printing
aoqi@0 273 void print_on(outputStream* st) const;
aoqi@0 274 virtual void print() const { print_on(tty); }
aoqi@0 275 protected:
aoqi@0 276 AbstractWorkGang* _gang;
aoqi@0 277
aoqi@0 278 virtual void initialize();
aoqi@0 279 virtual void loop();
aoqi@0 280
aoqi@0 281 public:
aoqi@0 282 AbstractWorkGang* gang() const { return _gang; }
aoqi@0 283 };
aoqi@0 284
aoqi@0 285 // Dynamic number of worker threads
aoqi@0 286 //
aoqi@0 287 // This type of work gang is used to run different numbers of
aoqi@0 288 // worker threads at different times. The
aoqi@0 289 // number of workers run for a task is "_active_workers"
aoqi@0 290 // instead of "_total_workers" in a WorkGang. The method
aoqi@0 291 // "needs_more_workers()" returns true until "_active_workers"
aoqi@0 292 // have been started and returns false afterwards. The
aoqi@0 293 // implementation of "needs_more_workers()" in WorkGang always
aoqi@0 294 // returns true so that all workers are started. The method
aoqi@0 295 // "loop()" in GangWorker was modified to ask "needs_more_workers()"
aoqi@0 296 // in its loop to decide if it should start working on a task.
aoqi@0 297 // A worker in "loop()" waits for notification on the WorkGang
aoqi@0 298 // monitor and execution of each worker as it checks for work
aoqi@0 299 // is serialized via the same monitor. The "needs_more_workers()"
aoqi@0 300 // call is serialized and additionally the calculation for the
aoqi@0 301 // "part" (effectively the worker id for executing the task) is
aoqi@0 302 // serialized to give each worker a unique "part". Workers that
aoqi@0 303 // are not needed for this tasks (i.e., "_active_workers" have
aoqi@0 304 // been started before it, continue to wait for work.
aoqi@0 305
aoqi@0 306 class FlexibleWorkGang: public WorkGang {
aoqi@0 307 // The currently active workers in this gang.
aoqi@0 308 // This is a number that is dynamically adjusted
aoqi@0 309 // and checked in the run_task() method at each invocation.
aoqi@0 310 // As described above _active_workers determines the number
aoqi@0 311 // of threads started on a task. It must also be used to
aoqi@0 312 // determine completion.
aoqi@0 313
aoqi@0 314 protected:
aoqi@0 315 uint _active_workers;
aoqi@0 316 public:
aoqi@0 317 // Constructor and destructor.
aoqi@0 318 // Initialize active_workers to a minimum value. Setting it to
aoqi@0 319 // the parameter "workers" will initialize it to a maximum
aoqi@0 320 // value which is not desirable.
aoqi@0 321 FlexibleWorkGang(const char* name, uint workers,
aoqi@0 322 bool are_GC_task_threads,
aoqi@0 323 bool are_ConcurrentGC_threads) :
aoqi@0 324 WorkGang(name, workers, are_GC_task_threads, are_ConcurrentGC_threads),
aoqi@0 325 _active_workers(UseDynamicNumberOfGCThreads ? 1U : ParallelGCThreads) {}
aoqi@0 326 // Accessors for fields
aoqi@0 327 virtual uint active_workers() const { return _active_workers; }
aoqi@0 328 void set_active_workers(uint v) {
aoqi@0 329 assert(v <= _total_workers,
aoqi@0 330 "Trying to set more workers active than there are");
aoqi@0 331 _active_workers = MIN2(v, _total_workers);
aoqi@0 332 assert(v != 0, "Trying to set active workers to 0");
aoqi@0 333 _active_workers = MAX2(1U, _active_workers);
aoqi@0 334 assert(UseDynamicNumberOfGCThreads || _active_workers == _total_workers,
aoqi@0 335 "Unless dynamic should use total workers");
aoqi@0 336 }
aoqi@0 337 virtual void run_task(AbstractGangTask* task);
aoqi@0 338 virtual bool needs_more_workers() const {
aoqi@0 339 return _started_workers < _active_workers;
aoqi@0 340 }
aoqi@0 341 };
aoqi@0 342
aoqi@0 343 // Work gangs in garbage collectors: 2009-06-10
aoqi@0 344 //
aoqi@0 345 // SharedHeap - work gang for stop-the-world parallel collection.
aoqi@0 346 // Used by
aoqi@0 347 // ParNewGeneration
aoqi@0 348 // CMSParRemarkTask
aoqi@0 349 // CMSRefProcTaskExecutor
aoqi@0 350 // G1CollectedHeap
aoqi@0 351 // G1ParFinalCountTask
aoqi@0 352 // ConcurrentMark
aoqi@0 353 // CMSCollector
aoqi@0 354
aoqi@0 355 // A class that acts as a synchronisation barrier. Workers enter
aoqi@0 356 // the barrier and must wait until all other workers have entered
aoqi@0 357 // before any of them may leave.
aoqi@0 358
aoqi@0 359 class WorkGangBarrierSync : public StackObj {
aoqi@0 360 protected:
aoqi@0 361 Monitor _monitor;
aoqi@0 362 uint _n_workers;
aoqi@0 363 uint _n_completed;
aoqi@0 364 bool _should_reset;
aoqi@0 365 bool _aborted;
aoqi@0 366
aoqi@0 367 Monitor* monitor() { return &_monitor; }
aoqi@0 368 uint n_workers() { return _n_workers; }
aoqi@0 369 uint n_completed() { return _n_completed; }
aoqi@0 370 bool should_reset() { return _should_reset; }
aoqi@0 371 bool aborted() { return _aborted; }
aoqi@0 372
aoqi@0 373 void zero_completed() { _n_completed = 0; }
aoqi@0 374 void inc_completed() { _n_completed++; }
aoqi@0 375 void set_aborted() { _aborted = true; }
aoqi@0 376 void set_should_reset(bool v) { _should_reset = v; }
aoqi@0 377
aoqi@0 378 public:
aoqi@0 379 WorkGangBarrierSync();
aoqi@0 380 WorkGangBarrierSync(uint n_workers, const char* name);
aoqi@0 381
aoqi@0 382 // Set the number of workers that will use the barrier.
aoqi@0 383 // Must be called before any of the workers start running.
aoqi@0 384 void set_n_workers(uint n_workers);
aoqi@0 385
aoqi@0 386 // Enter the barrier. A worker that enters the barrier will
aoqi@0 387 // not be allowed to leave until all other threads have
aoqi@0 388 // also entered the barrier or the barrier is aborted.
aoqi@0 389 // Returns false if the barrier was aborted.
aoqi@0 390 bool enter();
aoqi@0 391
aoqi@0 392 // Aborts the barrier and wakes up any threads waiting for
aoqi@0 393 // the barrier to complete. The barrier will remain in the
aoqi@0 394 // aborted state until the next call to set_n_workers().
aoqi@0 395 void abort();
aoqi@0 396 };
aoqi@0 397
aoqi@0 398 // A class to manage claiming of subtasks within a group of tasks. The
aoqi@0 399 // subtasks will be identified by integer indices, usually elements of an
aoqi@0 400 // enumeration type.
aoqi@0 401
aoqi@0 402 class SubTasksDone: public CHeapObj<mtInternal> {
aoqi@0 403 uint* _tasks;
aoqi@0 404 uint _n_tasks;
aoqi@0 405 // _n_threads is used to determine when a sub task is done.
aoqi@0 406 // It does not control how many threads will execute the subtask
aoqi@0 407 // but must be initialized to the number that do execute the task
aoqi@0 408 // in order to correctly decide when the subtask is done (all the
aoqi@0 409 // threads working on the task have finished).
aoqi@0 410 uint _n_threads;
aoqi@0 411 uint _threads_completed;
aoqi@0 412 #ifdef ASSERT
aoqi@0 413 volatile uint _claimed;
aoqi@0 414 #endif
aoqi@0 415
aoqi@0 416 // Set all tasks to unclaimed.
aoqi@0 417 void clear();
aoqi@0 418
aoqi@0 419 public:
aoqi@0 420 // Initializes "this" to a state in which there are "n" tasks to be
aoqi@0 421 // processed, none of the which are originally claimed. The number of
aoqi@0 422 // threads doing the tasks is initialized 1.
aoqi@0 423 SubTasksDone(uint n);
aoqi@0 424
aoqi@0 425 // True iff the object is in a valid state.
aoqi@0 426 bool valid();
aoqi@0 427
aoqi@0 428 // Get/set the number of parallel threads doing the tasks to "t". Can only
aoqi@0 429 // be called before tasks start or after they are complete.
aoqi@0 430 uint n_threads() { return _n_threads; }
aoqi@0 431 void set_n_threads(uint t);
aoqi@0 432
aoqi@0 433 // Returns "false" if the task "t" is unclaimed, and ensures that task is
aoqi@0 434 // claimed. The task "t" is required to be within the range of "this".
aoqi@0 435 bool is_task_claimed(uint t);
aoqi@0 436
aoqi@0 437 // The calling thread asserts that it has attempted to claim all the
aoqi@0 438 // tasks that it will try to claim. Every thread in the parallel task
aoqi@0 439 // must execute this. (When the last thread does so, the task array is
aoqi@0 440 // cleared.)
aoqi@0 441 void all_tasks_completed();
aoqi@0 442
aoqi@0 443 // Destructor.
aoqi@0 444 ~SubTasksDone();
aoqi@0 445 };
aoqi@0 446
aoqi@0 447 // As above, but for sequential tasks, i.e. instead of claiming
aoqi@0 448 // sub-tasks from a set (possibly an enumeration), claim sub-tasks
aoqi@0 449 // in sequential order. This is ideal for claiming dynamically
aoqi@0 450 // partitioned tasks (like striding in the parallel remembered
aoqi@0 451 // set scanning). Note that unlike the above class this is
aoqi@0 452 // a stack object - is there any reason for it not to be?
aoqi@0 453
aoqi@0 454 class SequentialSubTasksDone : public StackObj {
aoqi@0 455 protected:
aoqi@0 456 uint _n_tasks; // Total number of tasks available.
aoqi@0 457 uint _n_claimed; // Number of tasks claimed.
aoqi@0 458 // _n_threads is used to determine when a sub task is done.
aoqi@0 459 // See comments on SubTasksDone::_n_threads
aoqi@0 460 uint _n_threads; // Total number of parallel threads.
aoqi@0 461 uint _n_completed; // Number of completed threads.
aoqi@0 462
aoqi@0 463 void clear();
aoqi@0 464
aoqi@0 465 public:
aoqi@0 466 SequentialSubTasksDone() {
aoqi@0 467 clear();
aoqi@0 468 }
aoqi@0 469 ~SequentialSubTasksDone() {}
aoqi@0 470
aoqi@0 471 // True iff the object is in a valid state.
aoqi@0 472 bool valid();
aoqi@0 473
aoqi@0 474 // number of tasks
aoqi@0 475 uint n_tasks() const { return _n_tasks; }
aoqi@0 476
aoqi@0 477 // Get/set the number of parallel threads doing the tasks to t.
aoqi@0 478 // Should be called before the task starts but it is safe
aoqi@0 479 // to call this once a task is running provided that all
aoqi@0 480 // threads agree on the number of threads.
aoqi@0 481 uint n_threads() { return _n_threads; }
aoqi@0 482 void set_n_threads(uint t) { _n_threads = t; }
aoqi@0 483
aoqi@0 484 // Set the number of tasks to be claimed to t. As above,
aoqi@0 485 // should be called before the tasks start but it is safe
aoqi@0 486 // to call this once a task is running provided all threads
aoqi@0 487 // agree on the number of tasks.
aoqi@0 488 void set_n_tasks(uint t) { _n_tasks = t; }
aoqi@0 489
aoqi@0 490 // Returns false if the next task in the sequence is unclaimed,
aoqi@0 491 // and ensures that it is claimed. Will set t to be the index
aoqi@0 492 // of the claimed task in the sequence. Will return true if
aoqi@0 493 // the task cannot be claimed and there are none left to claim.
aoqi@0 494 bool is_task_claimed(uint& t);
aoqi@0 495
aoqi@0 496 // The calling thread asserts that it has attempted to claim
aoqi@0 497 // all the tasks it possibly can in the sequence. Every thread
aoqi@0 498 // claiming tasks must promise call this. Returns true if this
aoqi@0 499 // is the last thread to complete so that the thread can perform
aoqi@0 500 // cleanup if necessary.
aoqi@0 501 bool all_tasks_completed();
aoqi@0 502 };
aoqi@0 503
aoqi@0 504 // Represents a set of free small integer ids.
aoqi@0 505 class FreeIdSet : public CHeapObj<mtInternal> {
aoqi@0 506 enum {
aoqi@0 507 end_of_list = -1,
aoqi@0 508 claimed = -2
aoqi@0 509 };
aoqi@0 510
aoqi@0 511 int _sz;
aoqi@0 512 Monitor* _mon;
aoqi@0 513
aoqi@0 514 int* _ids;
aoqi@0 515 int _hd;
aoqi@0 516 int _waiters;
aoqi@0 517 int _claimed;
aoqi@0 518
aoqi@0 519 static bool _safepoint;
aoqi@0 520 typedef FreeIdSet* FreeIdSetPtr;
aoqi@0 521 static const int NSets = 10;
aoqi@0 522 static FreeIdSetPtr _sets[NSets];
aoqi@0 523 static bool _stat_init;
aoqi@0 524 int _index;
aoqi@0 525
aoqi@0 526 public:
aoqi@0 527 FreeIdSet(int sz, Monitor* mon);
aoqi@0 528 ~FreeIdSet();
aoqi@0 529
aoqi@0 530 static void set_safepoint(bool b);
aoqi@0 531
aoqi@0 532 // Attempt to claim the given id permanently. Returns "true" iff
aoqi@0 533 // successful.
aoqi@0 534 bool claim_perm_id(int i);
aoqi@0 535
aoqi@0 536 // Returns an unclaimed parallel id (waiting for one to be released if
aoqi@0 537 // necessary). Returns "-1" if a GC wakes up a wait for an id.
aoqi@0 538 int claim_par_id();
aoqi@0 539
aoqi@0 540 void release_par_id(int id);
aoqi@0 541 };
aoqi@0 542
aoqi@0 543 #endif // SHARE_VM_UTILITIES_WORKGROUP_HPP

mercurial