135 if (localBot == oldAge.top()) {
136 // No competing pop_global has yet incremented "top"; we'll try to
137 // install new_age, thus claiming the element.
138 Age tempAge = _age.cmpxchg(newAge, oldAge);
139 if (tempAge == oldAge) {
140 // We win.
141 assert(dirty_size(localBot, _age.top()) != N - 1, "sanity");
142 TASKQUEUE_STATS_ONLY(stats.record_pop_slow());
143 return true;
144 }
145 }
146 // We lose; a completing pop_global gets the element. But the queue is empty
147 // and top is greater than bottom. Fix this representation of the empty queue
148 // to become the canonical one.
149 _age.set(newAge);
150 assert(dirty_size(localBot, _age.top()) != N - 1, "sanity");
151 return false;
152 }
153
154 template<class E, MEMFLAGS F, unsigned int N> inline bool
155 GenericTaskQueue<E, F, N>::pop_local(volatile E& t) {
156 uint localBot = _bottom;
157 // This value cannot be N-1. That can only occur as a result of
158 // the assignment to bottom in this method. If it does, this method
159 // resets the size to 0 before the next call (which is sequential,
160 // since this is pop_local.)
161 uint dirty_n_elems = dirty_size(localBot, _age.top());
162 assert(dirty_n_elems != N - 1, "Shouldn't be possible...");
163 if (dirty_n_elems == 0) return false;
164 localBot = decrement_index(localBot);
165 _bottom = localBot;
166 // This is necessary to prevent any read below from being reordered
167 // before the store just above.
168 OrderAccess::fence();
169 // g++ complains if the volatile result of the assignment is
170 // unused, so we cast the volatile away. We cannot cast directly
171 // to void, because gcc treats that as not using the result of the
172 // assignment. However, casting to E& means that we trigger an
173 // unused-value warning. So, we cast the E& to void.
174 (void) const_cast<E&>(t = _elems[localBot]);
175 // This is a second read of "age"; the "size()" above is the first.
176 // If there's still at least one element in the queue, based on the
177 // "_bottom" and "age" we've read, then there can be no interference with
178 // a "pop_global" operation, and we're done.
179 idx_t tp = _age.top(); // XXX
180 if (size(localBot, tp) > 0) {
181 assert(dirty_size(localBot, tp) != N - 1, "sanity");
182 TASKQUEUE_STATS_ONLY(stats.record_pop());
183 return true;
|
135 if (localBot == oldAge.top()) {
136 // No competing pop_global has yet incremented "top"; we'll try to
137 // install new_age, thus claiming the element.
138 Age tempAge = _age.cmpxchg(newAge, oldAge);
139 if (tempAge == oldAge) {
140 // We win.
141 assert(dirty_size(localBot, _age.top()) != N - 1, "sanity");
142 TASKQUEUE_STATS_ONLY(stats.record_pop_slow());
143 return true;
144 }
145 }
146 // We lose; a completing pop_global gets the element. But the queue is empty
147 // and top is greater than bottom. Fix this representation of the empty queue
148 // to become the canonical one.
149 _age.set(newAge);
150 assert(dirty_size(localBot, _age.top()) != N - 1, "sanity");
151 return false;
152 }
153
154 template<class E, MEMFLAGS F, unsigned int N> inline bool
155 GenericTaskQueue<E, F, N>::pop_local(volatile E& t, uint threshold) {
156 uint localBot = _bottom;
157 // This value cannot be N-1. That can only occur as a result of
158 // the assignment to bottom in this method. If it does, this method
159 // resets the size to 0 before the next call (which is sequential,
160 // since this is pop_local.)
161 uint dirty_n_elems = dirty_size(localBot, _age.top());
162 assert(dirty_n_elems != N - 1, "Shouldn't be possible...");
163 if (dirty_n_elems <= threshold) return false;
164 localBot = decrement_index(localBot);
165 _bottom = localBot;
166 // This is necessary to prevent any read below from being reordered
167 // before the store just above.
168 OrderAccess::fence();
169 // g++ complains if the volatile result of the assignment is
170 // unused, so we cast the volatile away. We cannot cast directly
171 // to void, because gcc treats that as not using the result of the
172 // assignment. However, casting to E& means that we trigger an
173 // unused-value warning. So, we cast the E& to void.
174 (void) const_cast<E&>(t = _elems[localBot]);
175 // This is a second read of "age"; the "size()" above is the first.
176 // If there's still at least one element in the queue, based on the
177 // "_bottom" and "age" we've read, then there can be no interference with
178 // a "pop_global" operation, and we're done.
179 idx_t tp = _age.top(); // XXX
180 if (size(localBot, tp) > 0) {
181 assert(dirty_size(localBot, tp) != N - 1, "sanity");
182 TASKQUEUE_STATS_ONLY(stats.record_pop());
183 return true;
|