Skip to content

Commit 45246bc

Browse files
author
Kim Barrett
committed
8371965: Convert TaskQueueSuper to use Atomic<T>
Reviewed-by: iwalulya, tschatzl
1 parent 41d6dc3 commit 45246bc

File tree

1 file changed

+62
-43
lines changed

1 file changed

+62
-43
lines changed

src/hotspot/share/gc/shared/taskqueue.hpp

Lines changed: 62 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,16 @@
2525
#ifndef SHARE_GC_SHARED_TASKQUEUE_HPP
2626
#define SHARE_GC_SHARED_TASKQUEUE_HPP
2727

28+
#include "cppstdlib/type_traits.hpp"
2829
#include "memory/allocation.hpp"
2930
#include "memory/padded.hpp"
31+
#include "metaprogramming/primitiveConversions.hpp"
3032
#include "oops/oopsHierarchy.hpp"
31-
#include "runtime/atomicAccess.hpp"
33+
#include "runtime/atomic.hpp"
3234
#include "utilities/debug.hpp"
3335
#include "utilities/globalDefinitions.hpp"
3436
#include "utilities/ostream.hpp"
37+
#include "utilities/powerOfTwo.hpp"
3538
#include "utilities/stack.hpp"
3639

3740
#if TASKQUEUE_STATS
@@ -100,76 +103,92 @@ void TaskQueueStats::reset() {
100103
}
101104
#endif // TASKQUEUE_STATS
102105

106+
// Helper for TaskQueueSuper, encoding {queue index, tag} pair in a form that
107+
// supports atomic access to the pair.
108+
class TaskQueueAge {
109+
friend struct PrimitiveConversions::Translate<TaskQueueAge>;
110+
111+
public:
112+
// Internal type used for indexing the queue, and for the tag.
113+
using idx_t = NOT_LP64(uint16_t) LP64_ONLY(uint32_t);
114+
115+
explicit TaskQueueAge(size_t data = 0) : _data{data} {}
116+
TaskQueueAge(idx_t top, idx_t tag) : _fields{top, tag} {}
117+
118+
idx_t top() const { return _fields._top; }
119+
idx_t tag() const { return _fields._tag; }
120+
121+
bool operator==(const TaskQueueAge& other) const { return _data == other._data; }
122+
123+
private:
124+
struct Fields {
125+
idx_t _top;
126+
idx_t _tag;
127+
};
128+
union {
129+
size_t _data; // Provides access to _fields as a single integral value.
130+
Fields _fields;
131+
};
132+
// _data must be able to hold combined _fields. Must be equal to ensure
133+
// there isn't any padding that could be uninitialized by 2-arg ctor.
134+
static_assert(sizeof(_data) == sizeof(_fields));
135+
};
136+
137+
// Support for Atomic<TaskQueueAge>.
138+
template<>
139+
struct PrimitiveConversions::Translate<TaskQueueAge> : public std::true_type {
140+
using Value = TaskQueueAge;
141+
using Decayed = decltype(TaskQueueAge::_data);
142+
143+
static Decayed decay(Value x) { return x._data; }
144+
static Value recover(Decayed x) { return Value(x); }
145+
};
146+
103147
// TaskQueueSuper collects functionality common to all GenericTaskQueue instances.
104148

105149
template <unsigned int N, MemTag MT>
106150
class TaskQueueSuper: public CHeapObj<MT> {
107151
protected:
108-
// Internal type for indexing the queue; also used for the tag.
109-
typedef NOT_LP64(uint16_t) LP64_ONLY(uint32_t) idx_t;
110-
STATIC_ASSERT(N == idx_t(N)); // Ensure N fits in an idx_t.
152+
using Age = TaskQueueAge;
153+
using idx_t = Age::idx_t;
154+
static_assert(N == idx_t(N)); // Ensure N fits in an idx_t.
111155

112156
// N must be a power of 2 for computing modulo via masking.
113157
// N must be >= 2 for the algorithm to work at all, though larger is better.
114-
STATIC_ASSERT(N >= 2);
115-
STATIC_ASSERT(is_power_of_2(N));
158+
static_assert(N >= 2);
159+
static_assert(is_power_of_2(N));
116160
static const uint MOD_N_MASK = N - 1;
117161

118-
class Age {
119-
friend class TaskQueueSuper;
120-
121-
public:
122-
explicit Age(size_t data = 0) : _data(data) {}
123-
Age(idx_t top, idx_t tag) { _fields._top = top; _fields._tag = tag; }
124-
125-
idx_t top() const { return _fields._top; }
126-
idx_t tag() const { return _fields._tag; }
127-
128-
bool operator ==(const Age& other) const { return _data == other._data; }
129-
130-
private:
131-
struct fields {
132-
idx_t _top;
133-
idx_t _tag;
134-
};
135-
union {
136-
size_t _data;
137-
fields _fields;
138-
};
139-
STATIC_ASSERT(sizeof(size_t) >= sizeof(fields));
140-
};
141-
142162
uint bottom_relaxed() const {
143-
return AtomicAccess::load(&_bottom);
163+
return _bottom.load_relaxed();
144164
}
145165

146166
uint bottom_acquire() const {
147-
return AtomicAccess::load_acquire(&_bottom);
167+
return _bottom.load_acquire();
148168
}
149169

150170
void set_bottom_relaxed(uint new_bottom) {
151-
AtomicAccess::store(&_bottom, new_bottom);
171+
_bottom.store_relaxed(new_bottom);
152172
}
153173

154174
void release_set_bottom(uint new_bottom) {
155-
AtomicAccess::release_store(&_bottom, new_bottom);
175+
_bottom.release_store(new_bottom);
156176
}
157177

158178
Age age_relaxed() const {
159-
return Age(AtomicAccess::load(&_age._data));
179+
return _age.load_relaxed();
160180
}
161181

162182
void set_age_relaxed(Age new_age) {
163-
AtomicAccess::store(&_age._data, new_age._data);
183+
_age.store_relaxed(new_age);
164184
}
165185

166186
Age cmpxchg_age(Age old_age, Age new_age) {
167-
return Age(AtomicAccess::cmpxchg(&_age._data, old_age._data, new_age._data));
187+
return _age.compare_exchange(old_age, new_age);
168188
}
169189

170190
idx_t age_top_relaxed() const {
171-
// Atomically accessing a subfield of an "atomic" member.
172-
return AtomicAccess::load(&_age._fields._top);
191+
return _age.load_relaxed().top();
173192
}
174193

175194
// These both operate mod N.
@@ -222,16 +241,16 @@ class TaskQueueSuper: public CHeapObj<MT> {
222241
DEFINE_PAD_MINUS_SIZE(0, DEFAULT_PADDING_SIZE, 0);
223242

224243
// Index of the first free element after the last one pushed (mod N).
225-
volatile uint _bottom;
226-
DEFINE_PAD_MINUS_SIZE(1, DEFAULT_PADDING_SIZE, sizeof(uint));
244+
Atomic<uint> _bottom;
245+
DEFINE_PAD_MINUS_SIZE(1, DEFAULT_PADDING_SIZE, sizeof(_bottom));
227246

228247
// top() is the index of the oldest pushed element (mod N), and tag()
229248
// is the associated epoch, to distinguish different modifications of
230249
// the age. There is no available element if top() == _bottom or
231250
// (_bottom - top()) mod N == N-1; the latter indicates underflow
232251
// during concurrent pop_local/pop_global.
233-
volatile Age _age;
234-
DEFINE_PAD_MINUS_SIZE(2, DEFAULT_PADDING_SIZE, sizeof(Age));
252+
Atomic<Age> _age;
253+
DEFINE_PAD_MINUS_SIZE(2, DEFAULT_PADDING_SIZE, sizeof(_age));
235254

236255
NONCOPYABLE(TaskQueueSuper);
237256

0 commit comments

Comments
 (0)