338 template<class E, MEMFLAGS F, unsigned int N> |
338 template<class E, MEMFLAGS F, unsigned int N> |
339 bool GenericTaskQueue<E, F, N>::push_slow(E t, uint dirty_n_elems) { |
339 bool GenericTaskQueue<E, F, N>::push_slow(E t, uint dirty_n_elems) { |
340 if (dirty_n_elems == N - 1) { |
340 if (dirty_n_elems == N - 1) { |
341 // Actually means 0, so do the push. |
341 // Actually means 0, so do the push. |
342 uint localBot = _bottom; |
342 uint localBot = _bottom; |
343 // g++ complains if the volatile result of the assignment is unused. |
343 // g++ complains if the volatile result of the assignment is |
344 const_cast<E&>(_elems[localBot] = t); |
344 // unused, so we cast the volatile away. We cannot cast directly |
|
345 // to void, because gcc treats that as not using the result of the |
|
346 // assignment. However, casting to E& means that we trigger an |
|
347 // unused-value warning. So, we cast the E& to void. |
|
348 (void)const_cast<E&>(_elems[localBot] = t); |
345 OrderAccess::release_store(&_bottom, increment_index(localBot)); |
349 OrderAccess::release_store(&_bottom, increment_index(localBot)); |
346 TASKQUEUE_STATS_ONLY(stats.record_push()); |
350 TASKQUEUE_STATS_ONLY(stats.record_push()); |
347 return true; |
351 return true; |
348 } |
352 } |
349 return false; |
353 return false; |
395 uint n_elems = size(localBot, oldAge.top()); |
399 uint n_elems = size(localBot, oldAge.top()); |
396 if (n_elems == 0) { |
400 if (n_elems == 0) { |
397 return false; |
401 return false; |
398 } |
402 } |
399 |
403 |
400 const_cast<E&>(t = _elems[oldAge.top()]); |
404 // g++ complains if the volatile result of the assignment is |
|
405 // unused, so we cast the volatile away. We cannot cast directly |
|
406 // to void, because gcc treats that as not using the result of the |
|
407 // assignment. However, casting to E& means that we trigger an |
|
408 // unused-value warning. So, we cast the E& to void. |
|
409 (void) const_cast<E&>(t = _elems[oldAge.top()]); |
401 Age newAge(oldAge); |
410 Age newAge(oldAge); |
402 newAge.increment(); |
411 newAge.increment(); |
403 Age resAge = _age.cmpxchg(newAge, oldAge); |
412 Age resAge = _age.cmpxchg(newAge, oldAge); |
404 |
413 |
405 // Note that using "_bottom" here might fail, since a pop_local might |
414 // Note that using "_bottom" here might fail, since a pop_local might |
638 assert((localBot >= 0) && (localBot < N), "_bottom out of range."); |
647 assert((localBot >= 0) && (localBot < N), "_bottom out of range."); |
639 idx_t top = _age.top(); |
648 idx_t top = _age.top(); |
640 uint dirty_n_elems = dirty_size(localBot, top); |
649 uint dirty_n_elems = dirty_size(localBot, top); |
641 assert(dirty_n_elems < N, "n_elems out of range."); |
650 assert(dirty_n_elems < N, "n_elems out of range."); |
642 if (dirty_n_elems < max_elems()) { |
651 if (dirty_n_elems < max_elems()) { |
643 // g++ complains if the volatile result of the assignment is unused. |
652 // g++ complains if the volatile result of the assignment is |
644 const_cast<E&>(_elems[localBot] = t); |
653 // unused, so we cast the volatile away. We cannot cast directly |
|
654 // to void, because gcc treats that as not using the result of the |
|
655 // assignment. However, casting to E& means that we trigger an |
|
656 // unused-value warning. So, we cast the E& to void. |
|
657 (void) const_cast<E&>(_elems[localBot] = t); |
645 OrderAccess::release_store(&_bottom, increment_index(localBot)); |
658 OrderAccess::release_store(&_bottom, increment_index(localBot)); |
646 TASKQUEUE_STATS_ONLY(stats.record_push()); |
659 TASKQUEUE_STATS_ONLY(stats.record_push()); |
647 return true; |
660 return true; |
648 } else { |
661 } else { |
649 return push_slow(t, dirty_n_elems); |
662 return push_slow(t, dirty_n_elems); |
663 localBot = decrement_index(localBot); |
676 localBot = decrement_index(localBot); |
664 _bottom = localBot; |
677 _bottom = localBot; |
665 // This is necessary to prevent any read below from being reordered |
678 // This is necessary to prevent any read below from being reordered |
666 // before the store just above. |
679 // before the store just above. |
667 OrderAccess::fence(); |
680 OrderAccess::fence(); |
668 const_cast<E&>(t = _elems[localBot]); |
681 // g++ complains if the volatile result of the assignment is |
|
682 // unused, so we cast the volatile away. We cannot cast directly |
|
683 // to void, because gcc treats that as not using the result of the |
|
684 // assignment. However, casting to E& means that we trigger an |
|
685 // unused-value warning. So, we cast the E& to void. |
|
686 (void) const_cast<E&>(t = _elems[localBot]); |
669 // This is a second read of "age"; the "size()" above is the first. |
687 // This is a second read of "age"; the "size()" above is the first. |
670 // If there's still at least one element in the queue, based on the |
688 // If there's still at least one element in the queue, based on the |
671 // "_bottom" and "age" we've read, then there can be no interference with |
689 // "_bottom" and "age" we've read, then there can be no interference with |
672 // a "pop_global" operation, and we're done. |
690 // a "pop_global" operation, and we're done. |
673 idx_t tp = _age.top(); // XXX |
691 idx_t tp = _age.top(); // XXX |