Skip to content
Permalink
Browse files

8244307: Improve assertions against taskqueue underflow

Added assert_not_underflow.

Reviewed-by: tschatzl, sjohanss
  • Loading branch information
Kim Barrett
Kim Barrett committed May 6, 2020
1 parent 7ae3bea commit 98d41015ca58f52e8e0603465cb546d3ec2468f2
Showing with 21 additions and 8 deletions.
  1. +16 −3 src/hotspot/share/gc/shared/taskqueue.hpp
  2. +5 −5 src/hotspot/share/gc/shared/taskqueue.inline.hpp
@@ -202,12 +202,24 @@ class TaskQueueSuper: public CHeapObj<F> {
// 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.
// join the competitors. The "sz == -1" / "sz == N-1" state will not be
// modified by concurrent threads, so the owner thread can reset the state
// to _bottom == top so subsequent pushes will be performed normally.
return (sz == N - 1) ? 0 : sz;
}

// Assert that we're not in the underflow state where bottom has
// been decremented past top, so that _bottom+1 mod N == top. See
// the discussion in clean_size.

void assert_not_underflow(uint bot, uint top) const {
assert_not_underflow(dirty_size(bot, top));
}

void assert_not_underflow(uint dirty_size) const {
assert(dirty_size != N - 1, "invariant");
}

private:
DEFINE_PAD_MINUS_SIZE(0, DEFAULT_CACHE_LINE_SIZE, 0);

@@ -313,6 +325,7 @@ class GenericTaskQueue: public TaskQueueSuper<N, F> {
using TaskQueueSuper<N, F>::decrement_index;
using TaskQueueSuper<N, F>::dirty_size;
using TaskQueueSuper<N, F>::clean_size;
using TaskQueueSuper<N, F>::assert_not_underflow;

public:
using TaskQueueSuper<N, F>::max_elems;
@@ -123,7 +123,7 @@ bool GenericTaskQueue<E, F, N>::pop_local_slow(uint localBot, Age oldAge) {
Age tempAge = cmpxchg_age(oldAge, newAge);
if (tempAge == oldAge) {
// We win.
assert(dirty_size(localBot, age_top_relaxed()) != N - 1, "sanity");
assert_not_underflow(localBot, age_top_relaxed());
TASKQUEUE_STATS_ONLY(stats.record_pop_slow());
return true;
}
@@ -132,7 +132,7 @@ bool GenericTaskQueue<E, F, N>::pop_local_slow(uint localBot, Age oldAge) {
// and top is greater than bottom. Fix this representation of the empty queue
// to become the canonical one.
set_age_relaxed(newAge);
assert(dirty_size(localBot, age_top_relaxed()) != N - 1, "sanity");
assert_not_underflow(localBot, age_top_relaxed());
return false;
}

@@ -144,7 +144,7 @@ GenericTaskQueue<E, F, N>::pop_local(E& t, uint threshold) {
// resets the size to 0 before the next call (which is sequential,
// since this is pop_local.)
uint dirty_n_elems = dirty_size(localBot, age_top_relaxed());
assert(dirty_n_elems != N - 1, "Shouldn't be possible...");
assert_not_underflow(dirty_n_elems);
if (dirty_n_elems <= threshold) return false;
localBot = decrement_index(localBot);
set_bottom_relaxed(localBot);
@@ -158,7 +158,7 @@ GenericTaskQueue<E, F, N>::pop_local(E& t, uint threshold) {
// a "pop_global" operation, and we're done.
idx_t tp = age_top_relaxed();
if (clean_size(localBot, tp) > 0) {
assert(dirty_size(localBot, tp) != N - 1, "sanity");
assert_not_underflow(localBot, tp);
TASKQUEUE_STATS_ONLY(stats.record_pop());
return true;
} else {
@@ -241,7 +241,7 @@ bool GenericTaskQueue<E, F, N>::pop_global(E& t) {

// Note that using "bottom" here might fail, since a pop_local might
// have decremented it.
assert(dirty_size(localBot, newAge.top()) != N - 1, "sanity");
assert_not_underflow(localBot, newAge.top());
return resAge == oldAge;
}

0 comments on commit 98d4101

Please sign in to comment.