taskqueue.hpp 25.9 KB
Newer Older
D
duke 已提交
1
/*
2
 * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
D
duke 已提交
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
 * 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.
 *
19 20 21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
D
duke 已提交
22 23 24
 *
 */

25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
#ifndef SHARE_VM_UTILITIES_TASKQUEUE_HPP
#define SHARE_VM_UTILITIES_TASKQUEUE_HPP

#include "memory/allocation.hpp"
#include "memory/allocation.inline.hpp"
#include "runtime/mutex.hpp"
#include "utilities/stack.hpp"
#ifdef TARGET_OS_ARCH_linux_x86
# include "orderAccess_linux_x86.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_linux_sparc
# include "orderAccess_linux_sparc.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_linux_zero
# include "orderAccess_linux_zero.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_solaris_x86
# include "orderAccess_solaris_x86.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_solaris_sparc
# include "orderAccess_solaris_sparc.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_windows_x86
# include "orderAccess_windows_x86.inline.hpp"
#endif
50 51 52 53 54 55
#ifdef TARGET_OS_ARCH_linux_arm
# include "orderAccess_linux_arm.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_linux_ppc
# include "orderAccess_linux_ppc.inline.hpp"
#endif
N
never 已提交
56 57 58 59 60 61
#ifdef TARGET_OS_ARCH_bsd_x86
# include "orderAccess_bsd_x86.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_bsd_zero
# include "orderAccess_bsd_zero.inline.hpp"
#endif
62

J
jcoomes 已提交
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
// Simple TaskQueue stats that are collected by default in debug builds.

#if !defined(TASKQUEUE_STATS) && defined(ASSERT)
#define TASKQUEUE_STATS 1
#elif !defined(TASKQUEUE_STATS)
#define TASKQUEUE_STATS 0
#endif

#if TASKQUEUE_STATS
#define TASKQUEUE_STATS_ONLY(code) code
#else
#define TASKQUEUE_STATS_ONLY(code)
#endif // TASKQUEUE_STATS

#if TASKQUEUE_STATS
class TaskQueueStats {
public:
  enum StatId {
    push,             // number of taskqueue pushes
    pop,              // number of taskqueue pops
    pop_slow,         // subset of taskqueue pops that were done slow-path
    steal_attempt,    // number of taskqueue steal attempts
    steal,            // number of taskqueue steals
    overflow,         // number of overflow pushes
    overflow_max_len, // max length of overflow stack
    last_stat_id
  };

public:
  inline TaskQueueStats()       { reset(); }

  inline void record_push()     { ++_stats[push]; }
  inline void record_pop()      { ++_stats[pop]; }
  inline void record_pop_slow() { record_pop(); ++_stats[pop_slow]; }
  inline void record_steal(bool success);
  inline void record_overflow(size_t new_length);

100 101
  TaskQueueStats & operator +=(const TaskQueueStats & addend);

J
jcoomes 已提交
102 103 104 105 106
  inline size_t get(StatId id) const { return _stats[id]; }
  inline const size_t* get() const   { return _stats; }

  inline void reset();

107
  // Print the specified line of the header (does not include a line separator).
J
jcoomes 已提交
108 109
  static void print_header(unsigned int line, outputStream* const stream = tty,
                           unsigned int width = 10);
110
  // Print the statistics (does not include a line separator).
J
jcoomes 已提交
111 112
  void print(outputStream* const stream = tty, unsigned int width = 10) const;

113 114
  DEBUG_ONLY(void verify() const;)

J
jcoomes 已提交
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
private:
  size_t                    _stats[last_stat_id];
  static const char * const _names[last_stat_id];
};

void TaskQueueStats::record_steal(bool success) {
  ++_stats[steal_attempt];
  if (success) ++_stats[steal];
}

void TaskQueueStats::record_overflow(size_t new_len) {
  ++_stats[overflow];
  if (new_len > _stats[overflow_max_len]) _stats[overflow_max_len] = new_len;
}

void TaskQueueStats::reset() {
  memset(_stats, 0, sizeof(_stats));
}
#endif // TASKQUEUE_STATS

Z
zgu 已提交
135 136
template <unsigned int N, MEMFLAGS F>
class TaskQueueSuper: public CHeapObj<F> {
D
duke 已提交
137
protected:
138 139 140 141
  // 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).
142
  volatile uint _bottom;
D
duke 已提交
143

144
  enum { MOD_N_MASK = N - 1 };
D
duke 已提交
145

146 147 148 149 150
  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 已提交
151

152 153
    Age   get()        const volatile { return _data; }
    void  set(Age age) volatile       { _data = age._data; }
D
duke 已提交
154

155 156
    idx_t top()        const volatile { return _fields._top; }
    idx_t tag()        const volatile { return _fields._tag; }
D
duke 已提交
157

158 159 160 161 162
    // Increment top; if it wraps, increment tag also.
    void increment() {
      _fields._top = increment_index(_fields._top);
      if (_fields._top == 0) ++_fields._tag;
    }
D
duke 已提交
163

164 165 166 167
    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 已提交
168
    }
169 170 171 172 173 174 175 176 177 178 179 180

    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 已提交
181 182
  };

183
  volatile Age _age;
D
duke 已提交
184

185 186 187
  // These both operate mod N.
  static uint increment_index(uint ind) {
    return (ind + 1) & MOD_N_MASK;
D
duke 已提交
188
  }
189 190
  static uint decrement_index(uint ind) {
    return (ind - 1) & MOD_N_MASK;
D
duke 已提交
191 192
  }

193 194
  // Returns a number in the range [0..N).  If the result is "N-1", it should be
  // interpreted as 0.
195
  uint dirty_size(uint bot, uint top) const {
196
    return (bot - top) & MOD_N_MASK;
D
duke 已提交
197 198 199
  }

  // Returns the size corresponding to the given "bot" and "top".
200
  uint size(uint bot, uint top) const {
201
    uint sz = dirty_size(bot, top);
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
    // 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 已提交
217 218 219 220 221
  }

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

222 223 224
  // Return true if the TaskQueue contains/does not contain any tasks.
  bool peek()     const { return _bottom != _age.top(); }
  bool is_empty() const { return size() == 0; }
D
duke 已提交
225 226 227 228

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

233
  uint dirty_size() const {
234
    return dirty_size(_bottom, _age.top());
D
duke 已提交
235 236
  }

237 238
  void set_empty() {
    _bottom = 0;
239
    _age.set(0);
240 241
  }

D
duke 已提交
242 243
  // Maximum number of elements allowed in the queue.  This is two less
  // than the actual queue size, for somewhat complicated reasons.
244
  uint max_elems() const { return N - 2; }
245 246 247

  // Total size of queue.
  static const uint total_size() { return N; }
J
jcoomes 已提交
248 249

  TASKQUEUE_STATS_ONLY(TaskQueueStats stats;)
D
duke 已提交
250 251
};

Z
zgu 已提交
252 253 254 255


template <class E, MEMFLAGS F, unsigned int N = TASKQUEUE_SIZE>
class GenericTaskQueue: public TaskQueueSuper<N, F> {
256
protected:
Z
zgu 已提交
257 258
  typedef typename TaskQueueSuper<N, F>::Age Age;
  typedef typename TaskQueueSuper<N, F>::idx_t idx_t;
259

Z
zgu 已提交
260 261 262 263 264
  using TaskQueueSuper<N, F>::_bottom;
  using TaskQueueSuper<N, F>::_age;
  using TaskQueueSuper<N, F>::increment_index;
  using TaskQueueSuper<N, F>::decrement_index;
  using TaskQueueSuper<N, F>::dirty_size;
265 266

public:
Z
zgu 已提交
267 268 269 270 271 272
  using TaskQueueSuper<N, F>::max_elems;
  using TaskQueueSuper<N, F>::size;

#if  TASKQUEUE_STATS
  using TaskQueueSuper<N, F>::stats;
#endif
273

D
duke 已提交
274 275
private:
  // Slow paths for push, pop_local.  (pop_global has no fast path.)
276 277
  bool push_slow(E t, uint dirty_n_elems);
  bool pop_local_slow(uint localBot, Age oldAge);
D
duke 已提交
278 279

public:
280 281
  typedef E element_type;

D
duke 已提交
282 283 284 285 286
  // Initializes the queue to empty.
  GenericTaskQueue();

  void initialize();

287
  // Push the task "t" on the queue.  Returns "false" iff the queue is full.
D
duke 已提交
288 289
  inline bool push(E t);

290 291 292
  // Attempts to claim a task from the "local" end of the queue (the most
  // recently pushed).  If successful, returns true and sets t to the task;
  // otherwise, returns false (the queue is empty).
D
duke 已提交
293 294
  inline bool pop_local(E& t);

295 296
  // Like pop_local(), but uses the "global" end of the queue (the least
  // recently pushed).
D
duke 已提交
297 298 299 300 301
  bool pop_global(E& t);

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

302 303 304
  // apply the closure to all elements in the task queue
  void oops_do(OopClosure* f);

D
duke 已提交
305 306 307 308 309
private:
  // Element array.
  volatile E* _elems;
};

Z
zgu 已提交
310 311
template<class E, MEMFLAGS F, unsigned int N>
GenericTaskQueue<E, F, N>::GenericTaskQueue() {
312
  assert(sizeof(Age) == sizeof(size_t), "Depends on this.");
D
duke 已提交
313 314
}

Z
zgu 已提交
315 316 317
template<class E, MEMFLAGS F, unsigned int N>
void GenericTaskQueue<E, F, N>::initialize() {
  _elems = NEW_C_HEAP_ARRAY(E, N, F);
D
duke 已提交
318 319
}

Z
zgu 已提交
320 321
template<class E, MEMFLAGS F, unsigned int N>
void GenericTaskQueue<E, F, N>::oops_do(OopClosure* f) {
322
  // tty->print_cr("START OopTaskQueue::oops_do");
323 324 325
  uint iters = size();
  uint index = _bottom;
  for (uint i = 0; i < iters; ++i) {
326 327 328 329 330 331 332 333 334 335 336
    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");
}

Z
zgu 已提交
337 338
template<class E, MEMFLAGS F, unsigned int N>
bool GenericTaskQueue<E, F, N>::push_slow(E t, uint dirty_n_elems) {
339
  if (dirty_n_elems == N - 1) {
D
duke 已提交
340
    // Actually means 0, so do the push.
341
    uint localBot = _bottom;
342 343
    // g++ complains if the volatile result of the assignment is unused.
    const_cast<E&>(_elems[localBot] = t);
344
    OrderAccess::release_store(&_bottom, increment_index(localBot));
J
jcoomes 已提交
345
    TASKQUEUE_STATS_ONLY(stats.record_push());
D
duke 已提交
346
    return true;
347 348
  }
  return false;
D
duke 已提交
349 350
}

351 352 353 354 355 356
// pop_local_slow() is done by the owning thread and is trying to
// get the last task in the queue.  It will compete with pop_global()
// that will be used by other threads.  The tag age is incremented
// whenever the queue goes empty which it will do here if this thread
// gets the last task or in pop_global() if the queue wraps (top == 0
// and pop_global() succeeds, see pop_global()).
Z
zgu 已提交
357 358
template<class E, MEMFLAGS F, unsigned int N>
bool GenericTaskQueue<E, F, N>::pop_local_slow(uint localBot, Age oldAge) {
D
duke 已提交
359 360 361 362 363 364 365 366 367
  // 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.)
368
  Age newAge((idx_t)localBot, oldAge.tag() + 1);
D
duke 已提交
369 370 371 372 373
  // 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.
374
    Age tempAge = _age.cmpxchg(newAge, oldAge);
D
duke 已提交
375 376
    if (tempAge == oldAge) {
      // We win.
377
      assert(dirty_size(localBot, _age.top()) != N - 1, "sanity");
J
jcoomes 已提交
378
      TASKQUEUE_STATS_ONLY(stats.record_pop_slow());
D
duke 已提交
379 380 381
      return true;
    }
  }
382 383 384 385 386
  // 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 已提交
387 388 389
  return false;
}

Z
zgu 已提交
390 391
template<class E, MEMFLAGS F, unsigned int N>
bool GenericTaskQueue<E, F, N>::pop_global(E& t) {
392
  Age oldAge = _age.get();
393 394
  uint localBot = _bottom;
  uint n_elems = size(localBot, oldAge.top());
D
duke 已提交
395 396 397
  if (n_elems == 0) {
    return false;
  }
398

399
  const_cast<E&>(t = _elems[oldAge.top()]);
400 401 402 403
  Age newAge(oldAge);
  newAge.increment();
  Age resAge = _age.cmpxchg(newAge, oldAge);

D
duke 已提交
404 405
  // Note that using "_bottom" here might fail, since a pop_local might
  // have decremented it.
406 407
  assert(dirty_size(localBot, newAge.top()) != N - 1, "sanity");
  return resAge == oldAge;
D
duke 已提交
408 409
}

Z
zgu 已提交
410 411 412
template<class E, MEMFLAGS F, unsigned int N>
GenericTaskQueue<E, F, N>::~GenericTaskQueue() {
  FREE_C_HEAP_ARRAY(E, _elems, F);
D
duke 已提交
413 414
}

415 416 417
// OverflowTaskQueue is a TaskQueue that also includes an overflow stack for
// elements that do not fit in the TaskQueue.
//
418
// This class hides two methods from super classes:
419 420 421 422
//
// push() - push onto the task queue or, if that fails, onto the overflow stack
// is_empty() - return true if both the TaskQueue and overflow stack are empty
//
423
// Note that size() is not hidden--it returns the number of elements in the
424 425
// TaskQueue, and does not include the size of the overflow stack.  This
// simplifies replacement of GenericTaskQueues with OverflowTaskQueues.
Z
zgu 已提交
426 427
template<class E, MEMFLAGS F, unsigned int N = TASKQUEUE_SIZE>
class OverflowTaskQueue: public GenericTaskQueue<E, F, N>
428 429
{
public:
Z
zgu 已提交
430 431
  typedef Stack<E, F>               overflow_t;
  typedef GenericTaskQueue<E, F, N> taskqueue_t;
432

J
jcoomes 已提交
433 434
  TASKQUEUE_STATS_ONLY(using taskqueue_t::stats;)

435 436 437 438 439 440
  // Push task t onto the queue or onto the overflow stack.  Return true.
  inline bool push(E t);

  // Attempt to pop from the overflow stack; return true if anything was popped.
  inline bool pop_overflow(E& t);

441 442
  inline overflow_t* overflow_stack() { return &_overflow_stack; }

443
  inline bool taskqueue_empty() const { return taskqueue_t::is_empty(); }
444
  inline bool overflow_empty()  const { return _overflow_stack.is_empty(); }
445 446 447 448 449
  inline bool is_empty()        const {
    return taskqueue_empty() && overflow_empty();
  }

private:
450
  overflow_t _overflow_stack;
451 452
};

Z
zgu 已提交
453 454
template <class E, MEMFLAGS F, unsigned int N>
bool OverflowTaskQueue<E, F, N>::push(E t)
455 456 457
{
  if (!taskqueue_t::push(t)) {
    overflow_stack()->push(t);
458
    TASKQUEUE_STATS_ONLY(stats.record_overflow(overflow_stack()->size()));
459 460 461 462
  }
  return true;
}

Z
zgu 已提交
463 464
template <class E, MEMFLAGS F, unsigned int N>
bool OverflowTaskQueue<E, F, N>::pop_overflow(E& t)
465 466 467 468 469 470
{
  if (overflow_empty()) return false;
  t = overflow_stack()->pop();
  return true;
}

Z
zgu 已提交
471
class TaskQueueSetSuper {
D
duke 已提交
472 473 474 475 476 477 478
protected:
  static int randomParkAndMiller(int* seed0);
public:
  // Returns "true" if some TaskQueue in the set contains a task.
  virtual bool peek() = 0;
};

Z
zgu 已提交
479 480 481 482 483
template <MEMFLAGS F> class TaskQueueSetSuperImpl: public CHeapObj<F>, public TaskQueueSetSuper {
};

template<class T, MEMFLAGS F>
class GenericTaskQueueSet: public TaskQueueSetSuperImpl<F> {
D
duke 已提交
484
private:
485
  uint _n;
486
  T** _queues;
D
duke 已提交
487 488

public:
489 490
  typedef typename T::element_type E;

D
duke 已提交
491
  GenericTaskQueueSet(int n) : _n(n) {
492
    typedef T* GenericTaskQueuePtr;
Z
zgu 已提交
493
    _queues = NEW_C_HEAP_ARRAY(GenericTaskQueuePtr, n, F);
D
duke 已提交
494 495 496 497 498
    for (int i = 0; i < n; i++) {
      _queues[i] = NULL;
    }
  }

499 500 501
  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 已提交
502

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

505
  T* queue(uint n);
D
duke 已提交
506

507 508 509 510 511
  // 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" to the stolen task, otherwise returns
  // false.
512
  bool steal(uint queue_num, int* seed, E& t);
D
duke 已提交
513 514 515 516

  bool peek();
};

Z
zgu 已提交
517 518
template<class T, MEMFLAGS F> void
GenericTaskQueueSet<T, F>::register_queue(uint i, T* q) {
519
  assert(i < _n, "index out of range.");
D
duke 已提交
520 521 522
  _queues[i] = q;
}

Z
zgu 已提交
523 524
template<class T, MEMFLAGS F> T*
GenericTaskQueueSet<T, F>::queue(uint i) {
D
duke 已提交
525 526 527
  return _queues[i];
}

Z
zgu 已提交
528 529
template<class T, MEMFLAGS F> bool
GenericTaskQueueSet<T, F>::steal(uint queue_num, int* seed, E& t) {
J
jcoomes 已提交
530 531 532
  for (uint i = 0; i < 2 * _n; i++) {
    if (steal_best_of_2(queue_num, seed, t)) {
      TASKQUEUE_STATS_ONLY(queue(queue_num)->stats.record_steal(true));
D
duke 已提交
533
      return true;
J
jcoomes 已提交
534 535 536
    }
  }
  TASKQUEUE_STATS_ONLY(queue(queue_num)->stats.record_steal(false));
D
duke 已提交
537 538 539
  return false;
}

Z
zgu 已提交
540 541
template<class T, MEMFLAGS F> bool
GenericTaskQueueSet<T, F>::steal_best_of_all(uint queue_num, int* seed, E& t) {
D
duke 已提交
542 543
  if (_n > 2) {
    int best_k;
544 545
    uint best_sz = 0;
    for (uint k = 0; k < _n; k++) {
D
duke 已提交
546
      if (k == queue_num) continue;
547
      uint sz = _queues[k]->size();
D
duke 已提交
548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563
      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;
  }
}

Z
zgu 已提交
564 565
template<class T, MEMFLAGS F> bool
GenericTaskQueueSet<T, F>::steal_1_random(uint queue_num, int* seed, E& t) {
D
duke 已提交
566
  if (_n > 2) {
567
    uint k = queue_num;
Z
zgu 已提交
568
    while (k == queue_num) k = TaskQueueSetSuper::randomParkAndMiller(seed) % _n;
D
duke 已提交
569 570 571 572 573 574 575 576 577 578 579
    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;
  }
}

Z
zgu 已提交
580 581
template<class T, MEMFLAGS F> bool
GenericTaskQueueSet<T, F>::steal_best_of_2(uint queue_num, int* seed, E& t) {
D
duke 已提交
582
  if (_n > 2) {
583
    uint k1 = queue_num;
Z
zgu 已提交
584
    while (k1 == queue_num) k1 = TaskQueueSetSuper::randomParkAndMiller(seed) % _n;
585
    uint k2 = queue_num;
Z
zgu 已提交
586
    while (k2 == queue_num || k2 == k1) k2 = TaskQueueSetSuper::randomParkAndMiller(seed) % _n;
D
duke 已提交
587
    // Sample both and try the larger.
588 589
    uint sz1 = _queues[k1]->size();
    uint sz2 = _queues[k2]->size();
D
duke 已提交
590 591 592 593
    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.
594
    uint k = (queue_num + 1) % 2;
D
duke 已提交
595 596 597 598 599 600 601
    return _queues[k]->pop_global(t);
  } else {
    assert(_n == 1, "can't be zero.");
    return false;
  }
}

Z
zgu 已提交
602 603
template<class T, MEMFLAGS F>
bool GenericTaskQueueSet<T, F>::peek() {
D
duke 已提交
604
  // Try all the queues.
605
  for (uint j = 0; j < _n; j++) {
D
duke 已提交
606 607 608 609 610 611
    if (_queues[j]->peek())
      return true;
  }
  return false;
}

612
// When to terminate from the termination protocol.
Z
zgu 已提交
613
class TerminatorTerminator: public CHeapObj<mtInternal> {
614 615 616 617
public:
  virtual bool should_exit_termination() = 0;
};

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

621 622
#undef TRACESPINNING

D
duke 已提交
623 624 625 626
class ParallelTaskTerminator: public StackObj {
private:
  int _n_threads;
  TaskQueueSetSuper* _queue_set;
627
  int _offered_termination;
D
duke 已提交
628

629 630 631 632 633 634
#ifdef TRACESPINNING
  static uint _total_yields;
  static uint _total_spins;
  static uint _total_peeks;
#endif

D
duke 已提交
635 636 637 638 639 640 641 642 643 644 645 646 647 648 649
  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.
650 651 652 653
  bool offer_termination() {
    return offer_termination(NULL);
  }

654
  // As above, but it also terminates if the should_exit_termination()
655 656 657
  // method of the terminator parameter returns true. If terminator is
  // NULL, then it is ignored.
  bool offer_termination(TerminatorTerminator* terminator);
D
duke 已提交
658 659 660 661 662 663

  // 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();
664 665 666
  // Same as above but the number of parallel threads is set to the
  // given number.
  void reset_for_reuse(int n_threads);
D
duke 已提交
667

668 669 670 671 672 673
#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 已提交
674 675
};

Z
zgu 已提交
676 677
template<class E, MEMFLAGS F, unsigned int N> inline bool
GenericTaskQueue<E, F, N>::push(E t) {
678
  uint localBot = _bottom;
679 680
  assert((localBot >= 0) && (localBot < N), "_bottom out of range.");
  idx_t top = _age.top();
681
  uint dirty_n_elems = dirty_size(localBot, top);
682
  assert(dirty_n_elems < N, "n_elems out of range.");
D
duke 已提交
683
  if (dirty_n_elems < max_elems()) {
684 685
    // g++ complains if the volatile result of the assignment is unused.
    const_cast<E&>(_elems[localBot] = t);
686
    OrderAccess::release_store(&_bottom, increment_index(localBot));
J
jcoomes 已提交
687
    TASKQUEUE_STATS_ONLY(stats.record_push());
D
duke 已提交
688 689 690 691 692 693
    return true;
  } else {
    return push_slow(t, dirty_n_elems);
  }
}

Z
zgu 已提交
694 695
template<class E, MEMFLAGS F, unsigned int N> inline bool
GenericTaskQueue<E, F, N>::pop_local(E& t) {
696
  uint localBot = _bottom;
697
  // This value cannot be N-1.  That can only occur as a result of
D
duke 已提交
698
  // the assignment to bottom in this method.  If it does, this method
699
  // resets the size to 0 before the next call (which is sequential,
D
duke 已提交
700
  // since this is pop_local.)
701 702
  uint dirty_n_elems = dirty_size(localBot, _age.top());
  assert(dirty_n_elems != N - 1, "Shouldn't be possible...");
D
duke 已提交
703 704 705 706 707 708
  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();
709
  const_cast<E&>(t = _elems[localBot]);
D
duke 已提交
710 711 712 713
  // 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.
714
  idx_t tp = _age.top();    // XXX
D
duke 已提交
715
  if (size(localBot, tp) > 0) {
716
    assert(dirty_size(localBot, tp) != N - 1, "sanity");
J
jcoomes 已提交
717
    TASKQUEUE_STATS_ONLY(stats.record_pop());
D
duke 已提交
718 719 720 721
    return true;
  } else {
    // Otherwise, the queue contained exactly one element; we take the slow
    // path.
722
    return pop_local_slow(localBot, _age.get());
D
duke 已提交
723 724 725
  }
}

Z
zgu 已提交
726 727
typedef GenericTaskQueue<oop, mtGC>             OopTaskQueue;
typedef GenericTaskQueueSet<OopTaskQueue, mtGC> OopTaskQueueSet;
D
duke 已提交
728

729 730 731 732 733
#ifdef _MSC_VER
#pragma warning(push)
// warning C4522: multiple assignment operators specified
#pragma warning(disable:4522)
#endif
734 735 736 737 738 739

// 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*
740 741 742

  enum { COMPRESSED_OOP_MASK = 1 };

743
 public:
744 745 746 747 748 749 750 751
  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;
  }
752 753 754 755 756 757
  StarTask()             { _holder = NULL; }
  operator oop*()        { return (oop*)_holder; }
  operator narrowOop*()  {
    return (narrowOop*)((uintptr_t)_holder & ~COMPRESSED_OOP_MASK);
  }

758 759 760 761 762 763 764 765
  StarTask& operator=(const StarTask& t) {
    _holder = t._holder;
    return *this;
  }
  volatile StarTask& operator=(const volatile StarTask& t) volatile {
    _holder = t._holder;
    return *this;
  }
766 767 768 769 770 771

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

772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806
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

Z
zgu 已提交
807 808
typedef OverflowTaskQueue<StarTask, mtClass>           OopStarTaskQueue;
typedef GenericTaskQueueSet<OopStarTaskQueue, mtClass> OopStarTaskQueueSet;
D
duke 已提交
809

Z
zgu 已提交
810 811
typedef OverflowTaskQueue<size_t, mtInternal>             RegionTaskQueue;
typedef GenericTaskQueueSet<RegionTaskQueue, mtClass>     RegionTaskQueueSet;
812

813 814

#endif // SHARE_VM_UTILITIES_TASKQUEUE_HPP