src/share/vm/utilities/workgroup.hpp

Fri, 19 Apr 2013 11:08:52 -0700

author
minqi
date
Fri, 19 Apr 2013 11:08:52 -0700
changeset 4962
6f817ce50129
parent 4370
32164d89fe9c
child 4967
5a9fa2ba85f0
permissions
-rw-r--r--

8010992: Remove calls to global ::operator new[] and new
Summary: disable use of global operator new and new[] which could cause unexpected exception and escape from NMT tracking.
Reviewed-by: coleenp, dholmes, zgu
Contributed-by: yumin.qi@oracle.com

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

mercurial