190 // The algorithm may fail if _age.get() reads an older value than _age.top().
191 OrderAccess::loadload();
192 return pop_local_slow(localBot, _age.get());
193 }
194 }
195
196 template <class E, MEMFLAGS F, unsigned int N>
197 bool OverflowTaskQueue<E, F, N>::pop_overflow(E& t)
198 {
199 if (overflow_empty()) return false;
200 t = overflow_stack()->pop();
201 return true;
202 }
203
204 template<class E, MEMFLAGS F, unsigned int N>
205 bool GenericTaskQueue<E, F, N>::pop_global(volatile E& t) {
206 Age oldAge = _age.get();
207 // Architectures with weak memory model require a barrier here
208 // to guarantee that bottom is not older than age,
209 // which is crucial for the correctness of the algorithm.
210 #if !(defined SPARC || defined IA32 || defined AMD64)
211 OrderAccess::fence();
212 #endif
213 uint localBot = OrderAccess::load_acquire(&_bottom);
214 uint n_elems = size(localBot, oldAge.top());
215 if (n_elems == 0) {
216 return false;
217 }
218
219 // g++ complains if the volatile result of the assignment is
220 // unused, so we cast the volatile away. We cannot cast directly
221 // to void, because gcc treats that as not using the result of the
222 // assignment. However, casting to E& means that we trigger an
223 // unused-value warning. So, we cast the E& to void.
224 (void) const_cast<E&>(t = _elems[oldAge.top()]);
225 Age newAge(oldAge);
226 newAge.increment();
227 Age resAge = _age.cmpxchg(newAge, oldAge);
228
229 // Note that using "_bottom" here might fail, since a pop_local might
230 // have decremented it.
|
190 // The algorithm may fail if _age.get() reads an older value than _age.top().
191 OrderAccess::loadload();
192 return pop_local_slow(localBot, _age.get());
193 }
194 }
195
196 template <class E, MEMFLAGS F, unsigned int N>
197 bool OverflowTaskQueue<E, F, N>::pop_overflow(E& t)
198 {
199 if (overflow_empty()) return false;
200 t = overflow_stack()->pop();
201 return true;
202 }
203
204 template<class E, MEMFLAGS F, unsigned int N>
205 bool GenericTaskQueue<E, F, N>::pop_global(volatile E& t) {
206 Age oldAge = _age.get();
207 // Architectures with weak memory model require a barrier here
208 // to guarantee that bottom is not older than age,
209 // which is crucial for the correctness of the algorithm.
210 #ifndef CPU_MULTI_COPY_ATOMIC
211 OrderAccess::fence();
212 #endif
213 uint localBot = OrderAccess::load_acquire(&_bottom);
214 uint n_elems = size(localBot, oldAge.top());
215 if (n_elems == 0) {
216 return false;
217 }
218
219 // g++ complains if the volatile result of the assignment is
220 // unused, so we cast the volatile away. We cannot cast directly
221 // to void, because gcc treats that as not using the result of the
222 // assignment. However, casting to E& means that we trigger an
223 // unused-value warning. So, we cast the E& to void.
224 (void) const_cast<E&>(t = _elems[oldAge.top()]);
225 Age newAge(oldAge);
226 newAge.increment();
227 Age resAge = _age.cmpxchg(newAge, oldAge);
228
229 // Note that using "_bottom" here might fail, since a pop_local might
230 // have decremented it.
|