211 private:
212 DEFINE_PAD_MINUS_SIZE(0, DEFAULT_CACHE_LINE_SIZE, 0);
213
214 // Index of the first free element after the last one pushed (mod N).
215 volatile uint _bottom;
216 DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, sizeof(uint));
217
218 // top() is the index of the oldest pushed element (mod N), and tag()
219 // is the associated epoch, to distinguish different modifications of
220 // the age. There is no available element if top() == _bottom or
221 // (_bottom - top()) mod N == N-1; the latter indicates underflow
222 // during concurrent pop_local/pop_global.
223 volatile Age _age;
224 DEFINE_PAD_MINUS_SIZE(2, DEFAULT_CACHE_LINE_SIZE, sizeof(Age));
225
226 NONCOPYABLE(TaskQueueSuper);
227
228 public:
229 TaskQueueSuper() : _bottom(0), _age() {}
230
231 // Return true if the TaskQueue contains any tasks.
232 // Unreliable if there are concurrent pushes or pops.
233 bool peek() const {
234 return bottom_relaxed() != age_top_relaxed();
235 }
236
237 bool is_empty() const {
238 return size() == 0;
239 }
240
241 // Return an estimate of the number of elements in the queue.
242 // Treats pop_local/pop_global race that underflows as empty.
243 uint size() const {
244 return clean_size(bottom_relaxed(), age_top_relaxed());
245 }
246
247 // Discard the contents of the queue.
248 void set_empty() {
249 set_bottom_relaxed(0);
250 set_age_relaxed(Age());
251 }
252
253 // Maximum number of elements allowed in the queue. This is two less
254 // than the actual queue size, so that a full queue can be distinguished
409 // Try to push task t onto the queue only. Returns true if successful, false otherwise.
410 inline bool try_push_to_taskqueue(E t);
411
412 // Attempt to pop from the overflow stack; return true if anything was popped.
413 inline bool pop_overflow(E& t);
414
415 inline overflow_t* overflow_stack() { return &_overflow_stack; }
416
417 inline bool taskqueue_empty() const { return taskqueue_t::is_empty(); }
418 inline bool overflow_empty() const { return _overflow_stack.is_empty(); }
419 inline bool is_empty() const {
420 return taskqueue_empty() && overflow_empty();
421 }
422
423 private:
424 overflow_t _overflow_stack;
425 };
426
427 class TaskQueueSetSuper {
428 public:
429 // Returns "true" if some TaskQueue in the set contains a task.
430 virtual bool peek() = 0;
431 // Tasks in queue
432 virtual uint tasks() const = 0;
433 };
434
435 template <MEMFLAGS F> class TaskQueueSetSuperImpl: public CHeapObj<F>, public TaskQueueSetSuper {
436 };
437
438 template<class T, MEMFLAGS F>
439 class GenericTaskQueueSet: public TaskQueueSetSuperImpl<F> {
440 public:
441 typedef typename T::element_type E;
442
443 private:
444 uint _n;
445 T** _queues;
446
447 bool steal_best_of_2(uint queue_num, E& t);
448
449 public:
450 GenericTaskQueueSet(uint n);
451 ~GenericTaskQueueSet();
452
453 void register_queue(uint i, T* q);
454
455 T* queue(uint n);
456
457 // Try to steal a task from some other queue than queue_num. It may perform several attempts at doing so.
458 // Returns if stealing succeeds, and sets "t" to the stolen task.
459 bool steal(uint queue_num, E& t);
460
461 bool peek();
462 uint tasks() const;
463
464 uint size() const { return _n; }
465 };
466
467 template<class T, MEMFLAGS F> void
468 GenericTaskQueueSet<T, F>::register_queue(uint i, T* q) {
469 assert(i < _n, "index out of range.");
470 _queues[i] = q;
471 }
472
473 template<class T, MEMFLAGS F> T*
474 GenericTaskQueueSet<T, F>::queue(uint i) {
475 return _queues[i];
476 }
477
478 template<class T, MEMFLAGS F>
479 bool GenericTaskQueueSet<T, F>::peek() {
480 // Try all the queues.
481 for (uint j = 0; j < _n; j++) {
482 if (_queues[j]->peek())
483 return true;
484 }
485 return false;
486 }
487
488 template<class T, MEMFLAGS F>
489 uint GenericTaskQueueSet<T, F>::tasks() const {
490 uint n = 0;
491 for (uint j = 0; j < _n; j++) {
492 n += _queues[j]->size();
493 }
494 return n;
495 }
496
497 // When to terminate from the termination protocol.
498 class TerminatorTerminator: public CHeapObj<mtInternal> {
499 public:
500 virtual bool should_exit_termination() = 0;
501 };
502
503 // This is a container class for either an oop* or a narrowOop*.
504 // Both are pushed onto a task queue and the consumer will test is_narrow()
505 // to determine which should be processed.
506 class StarTask {
|
211 private:
212 DEFINE_PAD_MINUS_SIZE(0, DEFAULT_CACHE_LINE_SIZE, 0);
213
214 // Index of the first free element after the last one pushed (mod N).
215 volatile uint _bottom;
216 DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, sizeof(uint));
217
218 // top() is the index of the oldest pushed element (mod N), and tag()
219 // is the associated epoch, to distinguish different modifications of
220 // the age. There is no available element if top() == _bottom or
221 // (_bottom - top()) mod N == N-1; the latter indicates underflow
222 // during concurrent pop_local/pop_global.
223 volatile Age _age;
224 DEFINE_PAD_MINUS_SIZE(2, DEFAULT_CACHE_LINE_SIZE, sizeof(Age));
225
226 NONCOPYABLE(TaskQueueSuper);
227
228 public:
229 TaskQueueSuper() : _bottom(0), _age() {}
230
231 // Assert the queue is empty.
232 // Unreliable if there are concurrent pushes or pops.
233 void assert_empty() const {
234 assert(bottom_relaxed() == age_top_relaxed(), "not empty");
235 }
236
237 bool is_empty() const {
238 return size() == 0;
239 }
240
241 // Return an estimate of the number of elements in the queue.
242 // Treats pop_local/pop_global race that underflows as empty.
243 uint size() const {
244 return clean_size(bottom_relaxed(), age_top_relaxed());
245 }
246
247 // Discard the contents of the queue.
248 void set_empty() {
249 set_bottom_relaxed(0);
250 set_age_relaxed(Age());
251 }
252
253 // Maximum number of elements allowed in the queue. This is two less
254 // than the actual queue size, so that a full queue can be distinguished
409 // Try to push task t onto the queue only. Returns true if successful, false otherwise.
410 inline bool try_push_to_taskqueue(E t);
411
412 // Attempt to pop from the overflow stack; return true if anything was popped.
413 inline bool pop_overflow(E& t);
414
415 inline overflow_t* overflow_stack() { return &_overflow_stack; }
416
417 inline bool taskqueue_empty() const { return taskqueue_t::is_empty(); }
418 inline bool overflow_empty() const { return _overflow_stack.is_empty(); }
419 inline bool is_empty() const {
420 return taskqueue_empty() && overflow_empty();
421 }
422
423 private:
424 overflow_t _overflow_stack;
425 };
426
427 class TaskQueueSetSuper {
428 public:
429 // Assert all queues in the set are empty.
430 NOT_DEBUG(void assert_empty() const {})
431 DEBUG_ONLY(virtual void assert_empty() const = 0;)
432
433 // Tasks in queue
434 virtual uint tasks() const = 0;
435 };
436
437 template <MEMFLAGS F> class TaskQueueSetSuperImpl: public CHeapObj<F>, public TaskQueueSetSuper {
438 };
439
440 template<class T, MEMFLAGS F>
441 class GenericTaskQueueSet: public TaskQueueSetSuperImpl<F> {
442 public:
443 typedef typename T::element_type E;
444
445 private:
446 uint _n;
447 T** _queues;
448
449 bool steal_best_of_2(uint queue_num, E& t);
450
451 public:
452 GenericTaskQueueSet(uint n);
453 ~GenericTaskQueueSet();
454
455 void register_queue(uint i, T* q);
456
457 T* queue(uint n);
458
459 // Try to steal a task from some other queue than queue_num. It may perform several attempts at doing so.
460 // Returns if stealing succeeds, and sets "t" to the stolen task.
461 bool steal(uint queue_num, E& t);
462
463 DEBUG_ONLY(virtual void assert_empty() const;)
464
465 virtual uint tasks() const;
466
467 uint size() const { return _n; }
468 };
469
470 template<class T, MEMFLAGS F> void
471 GenericTaskQueueSet<T, F>::register_queue(uint i, T* q) {
472 assert(i < _n, "index out of range.");
473 _queues[i] = q;
474 }
475
476 template<class T, MEMFLAGS F> T*
477 GenericTaskQueueSet<T, F>::queue(uint i) {
478 return _queues[i];
479 }
480
481 #ifdef ASSERT
482 template<class T, MEMFLAGS F>
483 void GenericTaskQueueSet<T, F>::assert_empty() const {
484 for (uint j = 0; j < _n; j++) {
485 _queues[j]->assert_empty();
486 }
487 }
488 #endif // ASSERT
489
490 template<class T, MEMFLAGS F>
491 uint GenericTaskQueueSet<T, F>::tasks() const {
492 uint n = 0;
493 for (uint j = 0; j < _n; j++) {
494 n += _queues[j]->size();
495 }
496 return n;
497 }
498
499 // When to terminate from the termination protocol.
500 class TerminatorTerminator: public CHeapObj<mtInternal> {
501 public:
502 virtual bool should_exit_termination() = 0;
503 };
504
505 // This is a container class for either an oop* or a narrowOop*.
506 // Both are pushed onto a task queue and the consumer will test is_narrow()
507 // to determine which should be processed.
508 class StarTask {
|