taskqueue.hpp 20.4 KB
Newer Older
D
duke 已提交
1
/*
X
xdono 已提交
2
 * Copyright 2001-2009 Sun Microsystems, Inc.  All Rights Reserved.
D
duke 已提交
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.com if you need additional information or
 * have any questions.
 *
 */

25
template <unsigned int N>
D
duke 已提交
26 27
class TaskQueueSuper: public CHeapObj {
protected:
28 29 30 31
  // Internal type for indexing the queue; also used for the tag.
  typedef NOT_LP64(uint16_t) LP64_ONLY(uint32_t) idx_t;

  // The first free element after the last one pushed (mod N).
32
  volatile uint _bottom;
D
duke 已提交
33

34
  enum { MOD_N_MASK = N - 1 };
D
duke 已提交
35

36 37 38 39 40
  class Age {
  public:
    Age(size_t data = 0)         { _data = data; }
    Age(const Age& age)          { _data = age._data; }
    Age(idx_t top, idx_t tag)    { _fields._top = top; _fields._tag = tag; }
D
duke 已提交
41

42 43
    Age   get()        const volatile { return _data; }
    void  set(Age age) volatile       { _data = age._data; }
D
duke 已提交
44

45 46
    idx_t top()        const volatile { return _fields._top; }
    idx_t tag()        const volatile { return _fields._tag; }
D
duke 已提交
47

48 49 50 51 52
    // Increment top; if it wraps, increment tag also.
    void increment() {
      _fields._top = increment_index(_fields._top);
      if (_fields._top == 0) ++_fields._tag;
    }
D
duke 已提交
53

54 55 56 57
    Age cmpxchg(const Age new_age, const Age old_age) volatile {
      return (size_t) Atomic::cmpxchg_ptr((intptr_t)new_age._data,
                                          (volatile intptr_t *)&_data,
                                          (intptr_t)old_age._data);
D
duke 已提交
58
    }
59 60 61 62 63 64 65 66 67 68 69 70

    bool operator ==(const Age& other) const { return _data == other._data; }

  private:
    struct fields {
      idx_t _top;
      idx_t _tag;
    };
    union {
      size_t _data;
      fields _fields;
    };
D
duke 已提交
71 72
  };

73
  volatile Age _age;
D
duke 已提交
74

75 76 77
  // These both operate mod N.
  static uint increment_index(uint ind) {
    return (ind + 1) & MOD_N_MASK;
D
duke 已提交
78
  }
79 80
  static uint decrement_index(uint ind) {
    return (ind - 1) & MOD_N_MASK;
D
duke 已提交
81 82
  }

83 84
  // Returns a number in the range [0..N).  If the result is "N-1", it should be
  // interpreted as 0.
85
  uint dirty_size(uint bot, uint top) const {
86
    return (bot - top) & MOD_N_MASK;
D
duke 已提交
87 88 89
  }

  // Returns the size corresponding to the given "bot" and "top".
90
  uint size(uint bot, uint top) const {
91
    uint sz = dirty_size(bot, top);
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
    // Has the queue "wrapped", so that bottom is less than top?  There's a
    // complicated special case here.  A pair of threads could perform pop_local
    // and pop_global operations concurrently, starting from a state in which
    // _bottom == _top+1.  The pop_local could succeed in decrementing _bottom,
    // and the pop_global in incrementing _top (in which case the pop_global
    // will be awarded the contested queue element.)  The resulting state must
    // be interpreted as an empty queue.  (We only need to worry about one such
    // event: only the queue owner performs pop_local's, and several concurrent
    // threads attempting to perform the pop_global will all perform the same
    // CAS, and only one can succeed.)  Any stealing thread that reads after
    // either the increment or decrement will see an empty queue, and will not
    // join the competitors.  The "sz == -1 || sz == N-1" state will not be
    // modified by concurrent queues, so the owner thread can reset the state to
    // _bottom == top so subsequent pushes will be performed normally.
    return (sz == N - 1) ? 0 : sz;
D
duke 已提交
107 108 109 110 111
  }

public:
  TaskQueueSuper() : _bottom(0), _age() {}

112 113
  // Return true if the TaskQueue contains any tasks.
  bool peek() { return _bottom != _age.top(); }
D
duke 已提交
114 115 116 117

  // Return an estimate of the number of elements in the queue.
  // The "careful" version admits the possibility of pop_local/pop_global
  // races.
118
  uint size() const {
119
    return size(_bottom, _age.top());
D
duke 已提交
120 121
  }

122
  uint dirty_size() const {
123
    return dirty_size(_bottom, _age.top());
D
duke 已提交
124 125
  }

126 127
  void set_empty() {
    _bottom = 0;
128
    _age.set(0);
129 130
  }

D
duke 已提交
131 132
  // Maximum number of elements allowed in the queue.  This is two less
  // than the actual queue size, for somewhat complicated reasons.
133
  uint max_elems() const { return N - 2; }
134 135 136

  // Total size of queue.
  static const uint total_size() { return N; }
D
duke 已提交
137 138
};

139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
template<class E, unsigned int N = TASKQUEUE_SIZE>
class GenericTaskQueue: public TaskQueueSuper<N> {
protected:
  typedef typename TaskQueueSuper<N>::Age Age;
  typedef typename TaskQueueSuper<N>::idx_t idx_t;

  using TaskQueueSuper<N>::_bottom;
  using TaskQueueSuper<N>::_age;
  using TaskQueueSuper<N>::increment_index;
  using TaskQueueSuper<N>::decrement_index;
  using TaskQueueSuper<N>::dirty_size;

public:
  using TaskQueueSuper<N>::max_elems;
  using TaskQueueSuper<N>::size;

D
duke 已提交
155 156
private:
  // Slow paths for push, pop_local.  (pop_global has no fast path.)
157 158
  bool push_slow(E t, uint dirty_n_elems);
  bool pop_local_slow(uint localBot, Age oldAge);
D
duke 已提交
159 160

public:
161 162
  typedef E element_type;

D
duke 已提交
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
  // Initializes the queue to empty.
  GenericTaskQueue();

  void initialize();

  // Push the task "t" on the queue.  Returns "false" iff the queue is
  // full.
  inline bool push(E t);

  // If succeeds in claiming a task (from the 'local' end, that is, the
  // most recently pushed task), returns "true" and sets "t" to that task.
  // Otherwise, the queue is empty and returns false.
  inline bool pop_local(E& t);

  // If succeeds in claiming a task (from the 'global' end, that is, the
  // least recently pushed task), returns "true" and sets "t" to that task.
  // Otherwise, the queue is empty and returns false.
  bool pop_global(E& t);

  // Delete any resource associated with the queue.
  ~GenericTaskQueue();

185 186 187
  // apply the closure to all elements in the task queue
  void oops_do(OopClosure* f);

D
duke 已提交
188 189 190 191 192
private:
  // Element array.
  volatile E* _elems;
};

193 194
template<class E, unsigned int N>
GenericTaskQueue<E, N>::GenericTaskQueue() {
195
  assert(sizeof(Age) == sizeof(size_t), "Depends on this.");
D
duke 已提交
196 197
}

198 199
template<class E, unsigned int N>
void GenericTaskQueue<E, N>::initialize() {
200
  _elems = NEW_C_HEAP_ARRAY(E, N);
D
duke 已提交
201 202 203
  guarantee(_elems != NULL, "Allocation failed.");
}

204 205
template<class E, unsigned int N>
void GenericTaskQueue<E, N>::oops_do(OopClosure* f) {
206
  // tty->print_cr("START OopTaskQueue::oops_do");
207 208 209
  uint iters = size();
  uint index = _bottom;
  for (uint i = 0; i < iters; ++i) {
210 211 212 213 214 215 216 217 218 219 220
    index = decrement_index(index);
    // tty->print_cr("  doing entry %d," INTPTR_T " -> " INTPTR_T,
    //            index, &_elems[index], _elems[index]);
    E* t = (E*)&_elems[index];      // cast away volatility
    oop* p = (oop*)t;
    assert((*t)->is_oop_or_null(), "Not an oop or null");
    f->do_oop(p);
  }
  // tty->print_cr("END OopTaskQueue::oops_do");
}

221 222
template<class E, unsigned int N>
bool GenericTaskQueue<E, N>::push_slow(E t, uint dirty_n_elems) {
223
  if (dirty_n_elems == N - 1) {
D
duke 已提交
224
    // Actually means 0, so do the push.
225
    uint localBot = _bottom;
226 227
    // g++ complains if the volatile result of the assignment is unused.
    const_cast<E&>(_elems[localBot] = t);
228
    OrderAccess::release_store(&_bottom, increment_index(localBot));
D
duke 已提交
229
    return true;
230 231
  }
  return false;
D
duke 已提交
232 233
}

234 235
template<class E, unsigned int N>
bool GenericTaskQueue<E, N>::
236
pop_local_slow(uint localBot, Age oldAge) {
D
duke 已提交
237 238 239 240 241 242 243 244 245
  // This queue was observed to contain exactly one element; either this
  // thread will claim it, or a competing "pop_global".  In either case,
  // the queue will be logically empty afterwards.  Create a new Age value
  // that represents the empty queue for the given value of "_bottom".  (We
  // must also increment "tag" because of the case where "bottom == 1",
  // "top == 0".  A pop_global could read the queue element in that case,
  // then have the owner thread do a pop followed by another push.  Without
  // the incrementing of "tag", the pop_global's CAS could succeed,
  // allowing it to believe it has claimed the stale element.)
246
  Age newAge((idx_t)localBot, oldAge.tag() + 1);
D
duke 已提交
247 248 249 250 251
  // Perhaps a competing pop_global has already incremented "top", in which
  // case it wins the element.
  if (localBot == oldAge.top()) {
    // No competing pop_global has yet incremented "top"; we'll try to
    // install new_age, thus claiming the element.
252
    Age tempAge = _age.cmpxchg(newAge, oldAge);
D
duke 已提交
253 254
    if (tempAge == oldAge) {
      // We win.
255
      assert(dirty_size(localBot, _age.top()) != N - 1, "sanity");
D
duke 已提交
256 257 258
      return true;
    }
  }
259 260 261 262 263
  // We lose; a completing pop_global gets the element.  But the queue is empty
  // and top is greater than bottom.  Fix this representation of the empty queue
  // to become the canonical one.
  _age.set(newAge);
  assert(dirty_size(localBot, _age.top()) != N - 1, "sanity");
D
duke 已提交
264 265 266
  return false;
}

267 268
template<class E, unsigned int N>
bool GenericTaskQueue<E, N>::pop_global(E& t) {
269
  Age oldAge = _age.get();
270 271
  uint localBot = _bottom;
  uint n_elems = size(localBot, oldAge.top());
D
duke 已提交
272 273 274
  if (n_elems == 0) {
    return false;
  }
275

276
  const_cast<E&>(t = _elems[oldAge.top()]);
277 278 279 280
  Age newAge(oldAge);
  newAge.increment();
  Age resAge = _age.cmpxchg(newAge, oldAge);

D
duke 已提交
281 282
  // Note that using "_bottom" here might fail, since a pop_local might
  // have decremented it.
283 284
  assert(dirty_size(localBot, newAge.top()) != N - 1, "sanity");
  return resAge == oldAge;
D
duke 已提交
285 286
}

287 288
template<class E, unsigned int N>
GenericTaskQueue<E, N>::~GenericTaskQueue() {
D
duke 已提交
289 290 291 292 293 294 295 296 297 298 299 300
  FREE_C_HEAP_ARRAY(E, _elems);
}

// Inherits the typedef of "Task" from above.
class TaskQueueSetSuper: public CHeapObj {
protected:
  static int randomParkAndMiller(int* seed0);
public:
  // Returns "true" if some TaskQueue in the set contains a task.
  virtual bool peek() = 0;
};

301 302
template<class T>
class GenericTaskQueueSet: public TaskQueueSetSuper {
D
duke 已提交
303
private:
304
  uint _n;
305
  T** _queues;
D
duke 已提交
306 307

public:
308 309
  typedef typename T::element_type E;

D
duke 已提交
310
  GenericTaskQueueSet(int n) : _n(n) {
311
    typedef T* GenericTaskQueuePtr;
D
duke 已提交
312 313 314 315 316 317
    _queues = NEW_C_HEAP_ARRAY(GenericTaskQueuePtr, n);
    for (int i = 0; i < n; i++) {
      _queues[i] = NULL;
    }
  }

318 319 320
  bool steal_1_random(uint queue_num, int* seed, E& t);
  bool steal_best_of_2(uint queue_num, int* seed, E& t);
  bool steal_best_of_all(uint queue_num, int* seed, E& t);
D
duke 已提交
321

322
  void register_queue(uint i, T* q);
D
duke 已提交
323

324
  T* queue(uint n);
D
duke 已提交
325 326 327 328 329 330

  // The thread with queue number "queue_num" (and whose random number seed
  // is at "seed") is trying to steal a task from some other queue.  (It
  // may try several queues, according to some configuration parameter.)
  // If some steal succeeds, returns "true" and sets "t" the stolen task,
  // otherwise returns false.
331
  bool steal(uint queue_num, int* seed, E& t);
D
duke 已提交
332 333 334 335

  bool peek();
};

336 337
template<class T> void
GenericTaskQueueSet<T>::register_queue(uint i, T* q) {
338
  assert(i < _n, "index out of range.");
D
duke 已提交
339 340 341
  _queues[i] = q;
}

342 343
template<class T> T*
GenericTaskQueueSet<T>::queue(uint i) {
D
duke 已提交
344 345 346
  return _queues[i];
}

347 348
template<class T> bool
GenericTaskQueueSet<T>::steal(uint queue_num, int* seed, E& t) {
349
  for (uint i = 0; i < 2 * _n; i++)
D
duke 已提交
350 351 352 353 354
    if (steal_best_of_2(queue_num, seed, t))
      return true;
  return false;
}

355 356
template<class T> bool
GenericTaskQueueSet<T>::steal_best_of_all(uint queue_num, int* seed, E& t) {
D
duke 已提交
357 358
  if (_n > 2) {
    int best_k;
359 360
    uint best_sz = 0;
    for (uint k = 0; k < _n; k++) {
D
duke 已提交
361
      if (k == queue_num) continue;
362
      uint sz = _queues[k]->size();
D
duke 已提交
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
      if (sz > best_sz) {
        best_sz = sz;
        best_k = k;
      }
    }
    return best_sz > 0 && _queues[best_k]->pop_global(t);
  } else if (_n == 2) {
    // Just try the other one.
    int k = (queue_num + 1) % 2;
    return _queues[k]->pop_global(t);
  } else {
    assert(_n == 1, "can't be zero.");
    return false;
  }
}

379 380
template<class T> bool
GenericTaskQueueSet<T>::steal_1_random(uint queue_num, int* seed, E& t) {
D
duke 已提交
381
  if (_n > 2) {
382
    uint k = queue_num;
D
duke 已提交
383 384 385 386 387 388 389 390 391 392 393 394
    while (k == queue_num) k = randomParkAndMiller(seed) % _n;
    return _queues[2]->pop_global(t);
  } else if (_n == 2) {
    // Just try the other one.
    int k = (queue_num + 1) % 2;
    return _queues[k]->pop_global(t);
  } else {
    assert(_n == 1, "can't be zero.");
    return false;
  }
}

395 396
template<class T> bool
GenericTaskQueueSet<T>::steal_best_of_2(uint queue_num, int* seed, E& t) {
D
duke 已提交
397
  if (_n > 2) {
398
    uint k1 = queue_num;
D
duke 已提交
399
    while (k1 == queue_num) k1 = randomParkAndMiller(seed) % _n;
400
    uint k2 = queue_num;
D
duke 已提交
401 402
    while (k2 == queue_num || k2 == k1) k2 = randomParkAndMiller(seed) % _n;
    // Sample both and try the larger.
403 404
    uint sz1 = _queues[k1]->size();
    uint sz2 = _queues[k2]->size();
D
duke 已提交
405 406 407 408
    if (sz2 > sz1) return _queues[k2]->pop_global(t);
    else return _queues[k1]->pop_global(t);
  } else if (_n == 2) {
    // Just try the other one.
409
    uint k = (queue_num + 1) % 2;
D
duke 已提交
410 411 412 413 414 415 416
    return _queues[k]->pop_global(t);
  } else {
    assert(_n == 1, "can't be zero.");
    return false;
  }
}

417 418
template<class T>
bool GenericTaskQueueSet<T>::peek() {
D
duke 已提交
419
  // Try all the queues.
420
  for (uint j = 0; j < _n; j++) {
D
duke 已提交
421 422 423 424 425 426
    if (_queues[j]->peek())
      return true;
  }
  return false;
}

427 428 429 430 431 432
// When to terminate from the termination protocol.
class TerminatorTerminator: public CHeapObj {
public:
  virtual bool should_exit_termination() = 0;
};

D
duke 已提交
433 434 435
// A class to aid in the termination of a set of parallel tasks using
// TaskQueueSet's for work stealing.

436 437
#undef TRACESPINNING

D
duke 已提交
438 439 440 441
class ParallelTaskTerminator: public StackObj {
private:
  int _n_threads;
  TaskQueueSetSuper* _queue_set;
442
  int _offered_termination;
D
duke 已提交
443

444 445 446 447 448 449
#ifdef TRACESPINNING
  static uint _total_yields;
  static uint _total_spins;
  static uint _total_peeks;
#endif

D
duke 已提交
450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
  bool peek_in_queue_set();
protected:
  virtual void yield();
  void sleep(uint millis);

public:

  // "n_threads" is the number of threads to be terminated.  "queue_set" is a
  // queue sets of work queues of other threads.
  ParallelTaskTerminator(int n_threads, TaskQueueSetSuper* queue_set);

  // The current thread has no work, and is ready to terminate if everyone
  // else is.  If returns "true", all threads are terminated.  If returns
  // "false", available work has been observed in one of the task queues,
  // so the global task is not complete.
465 466 467 468
  bool offer_termination() {
    return offer_termination(NULL);
  }

469
  // As above, but it also terminates if the should_exit_termination()
470 471 472
  // method of the terminator parameter returns true. If terminator is
  // NULL, then it is ignored.
  bool offer_termination(TerminatorTerminator* terminator);
D
duke 已提交
473 474 475 476 477 478 479

  // Reset the terminator, so that it may be reused again.
  // The caller is responsible for ensuring that this is done
  // in an MT-safe manner, once the previous round of use of
  // the terminator is finished.
  void reset_for_reuse();

480 481 482 483 484 485
#ifdef TRACESPINNING
  static uint total_yields() { return _total_yields; }
  static uint total_spins() { return _total_spins; }
  static uint total_peeks() { return _total_peeks; }
  static void print_termination_counts();
#endif
D
duke 已提交
486 487
};

488 489
template<class E, unsigned int N> inline bool
GenericTaskQueue<E, N>::push(E t) {
490
  uint localBot = _bottom;
491 492
  assert((localBot >= 0) && (localBot < N), "_bottom out of range.");
  idx_t top = _age.top();
493
  uint dirty_n_elems = dirty_size(localBot, top);
494
  assert(dirty_n_elems < N, "n_elems out of range.");
D
duke 已提交
495
  if (dirty_n_elems < max_elems()) {
496 497
    // g++ complains if the volatile result of the assignment is unused.
    const_cast<E&>(_elems[localBot] = t);
498
    OrderAccess::release_store(&_bottom, increment_index(localBot));
D
duke 已提交
499 500 501 502 503 504
    return true;
  } else {
    return push_slow(t, dirty_n_elems);
  }
}

505 506
template<class E, unsigned int N> inline bool
GenericTaskQueue<E, N>::pop_local(E& t) {
507
  uint localBot = _bottom;
508
  // This value cannot be N-1.  That can only occur as a result of
D
duke 已提交
509 510 511
  // the assignment to bottom in this method.  If it does, this method
  // resets the size( to 0 before the next call (which is sequential,
  // since this is pop_local.)
512 513
  uint dirty_n_elems = dirty_size(localBot, _age.top());
  assert(dirty_n_elems != N - 1, "Shouldn't be possible...");
D
duke 已提交
514 515 516 517 518 519
  if (dirty_n_elems == 0) return false;
  localBot = decrement_index(localBot);
  _bottom = localBot;
  // This is necessary to prevent any read below from being reordered
  // before the store just above.
  OrderAccess::fence();
520
  const_cast<E&>(t = _elems[localBot]);
D
duke 已提交
521 522 523 524
  // This is a second read of "age"; the "size()" above is the first.
  // If there's still at least one element in the queue, based on the
  // "_bottom" and "age" we've read, then there can be no interference with
  // a "pop_global" operation, and we're done.
525
  idx_t tp = _age.top();    // XXX
D
duke 已提交
526
  if (size(localBot, tp) > 0) {
527
    assert(dirty_size(localBot, tp) != N - 1, "sanity");
D
duke 已提交
528 529 530 531
    return true;
  } else {
    // Otherwise, the queue contained exactly one element; we take the slow
    // path.
532
    return pop_local_slow(localBot, _age.get());
D
duke 已提交
533 534 535 536
  }
}

typedef oop Task;
537 538
typedef GenericTaskQueue<Task>            OopTaskQueue;
typedef GenericTaskQueueSet<OopTaskQueue> OopTaskQueueSet;
D
duke 已提交
539

540 541 542 543 544
#ifdef _MSC_VER
#pragma warning(push)
// warning C4522: multiple assignment operators specified
#pragma warning(disable:4522)
#endif
545 546 547 548 549 550

// This is a container class for either an oop* or a narrowOop*.
// Both are pushed onto a task queue and the consumer will test is_narrow()
// to determine which should be processed.
class StarTask {
  void*  _holder;        // either union oop* or narrowOop*
551 552 553

  enum { COMPRESSED_OOP_MASK = 1 };

554
 public:
555 556 557 558 559 560 561 562
  StarTask(narrowOop* p) {
    assert(((uintptr_t)p & COMPRESSED_OOP_MASK) == 0, "Information loss!");
    _holder = (void *)((uintptr_t)p | COMPRESSED_OOP_MASK);
  }
  StarTask(oop* p)       {
    assert(((uintptr_t)p & COMPRESSED_OOP_MASK) == 0, "Information loss!");
    _holder = (void*)p;
  }
563 564 565 566 567 568
  StarTask()             { _holder = NULL; }
  operator oop*()        { return (oop*)_holder; }
  operator narrowOop*()  {
    return (narrowOop*)((uintptr_t)_holder & ~COMPRESSED_OOP_MASK);
  }

569 570 571 572 573 574 575 576
  StarTask& operator=(const StarTask& t) {
    _holder = t._holder;
    return *this;
  }
  volatile StarTask& operator=(const volatile StarTask& t) volatile {
    _holder = t._holder;
    return *this;
  }
577 578 579 580 581 582

  bool is_narrow() const {
    return (((uintptr_t)_holder & COMPRESSED_OOP_MASK) != 0);
  }
};

583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619
class ObjArrayTask
{
public:
  ObjArrayTask(oop o = NULL, int idx = 0): _obj(o), _index(idx) { }
  ObjArrayTask(oop o, size_t idx): _obj(o), _index(int(idx)) {
    assert(idx <= size_t(max_jint), "too big");
  }
  ObjArrayTask(const ObjArrayTask& t): _obj(t._obj), _index(t._index) { }

  ObjArrayTask& operator =(const ObjArrayTask& t) {
    _obj = t._obj;
    _index = t._index;
    return *this;
  }
  volatile ObjArrayTask&
  operator =(const volatile ObjArrayTask& t) volatile {
    _obj = t._obj;
    _index = t._index;
    return *this;
  }

  inline oop obj()   const { return _obj; }
  inline int index() const { return _index; }

  DEBUG_ONLY(bool is_valid() const); // Tasks to be pushed/popped must be valid.

private:
  oop _obj;
  int _index;
};

#ifdef _MSC_VER
#pragma warning(pop)
#endif

typedef GenericTaskQueue<StarTask>            OopStarTaskQueue;
typedef GenericTaskQueueSet<OopStarTaskQueue> OopStarTaskQueueSet;
D
duke 已提交
620

621
typedef size_t RegionTask;  // index for region
622 623
typedef GenericTaskQueue<RegionTask>         RegionTaskQueue;
typedef GenericTaskQueueSet<RegionTaskQueue> RegionTaskQueueSet;
D
duke 已提交
624

625
class RegionTaskQueueWithOverflow: public CHeapObj {
D
duke 已提交
626
 protected:
627 628
  RegionTaskQueue              _region_queue;
  GrowableArray<RegionTask>*   _overflow_stack;
D
duke 已提交
629 630

 public:
631
  RegionTaskQueueWithOverflow() : _overflow_stack(NULL) {}
D
duke 已提交
632 633 634
  // Initialize both stealable queue and overflow
  void initialize();
  // Save first to stealable queue and then to overflow
635
  void save(RegionTask t);
D
duke 已提交
636
  // Retrieve first from overflow and then from stealable queue
637
  bool retrieve(RegionTask& region_index);
D
duke 已提交
638
  // Retrieve from stealable queue
639
  bool retrieve_from_stealable_queue(RegionTask& region_index);
D
duke 已提交
640
  // Retrieve from overflow
641
  bool retrieve_from_overflow(RegionTask& region_index);
D
duke 已提交
642 643 644
  bool is_empty();
  bool stealable_is_empty();
  bool overflow_is_empty();
645
  uint stealable_size() { return _region_queue.size(); }
646
  RegionTaskQueue* task_queue() { return &_region_queue; }
D
duke 已提交
647 648
};

649
#define USE_RegionTaskQueueWithOverflow