Don't use implicit QAtomic* casts in QFreeList

Pair the _next.testAndSetRelease() call in QFreeList<T>::release() with
_next.loadAcquire(), to ensure that the update to the bucket
being released is properly fenced.

QFreeList<T>:next() does not need a release fence, only an acquire fence,
which is placed on the memory bucket address load.

Change-Id: Ib5b9d6ef6107f87aa8e3ea2dd3a7f9116c75da70
Reviewed-by: Thiago Macieira
Reviewed-on: http://codereview.qt-project.org/5802
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: João Abecasis <joao.abecasis@nokia.com>
This commit is contained in:
Bradley T. Hughes 2011-09-29 11:45:01 +02:00 committed by Qt by Nokia
parent 0e339e2ef5
commit a4a94544f2

View File

@ -218,21 +218,21 @@ template <typename T, typename ConstantsType>
inline QFreeList<T, ConstantsType>::~QFreeList() inline QFreeList<T, ConstantsType>::~QFreeList()
{ {
for (int i = 0; i < ConstantsType::BlockCount; ++i) for (int i = 0; i < ConstantsType::BlockCount; ++i)
delete [] static_cast<ElementType *>(_v[i]); delete [] _v[i].load();
} }
template <typename T, typename ConstantsType> template <typename T, typename ConstantsType>
inline typename QFreeList<T, ConstantsType>::ConstReferenceType QFreeList<T, ConstantsType>::at(int x) const inline typename QFreeList<T, ConstantsType>::ConstReferenceType QFreeList<T, ConstantsType>::at(int x) const
{ {
const int block = blockfor(x); const int block = blockfor(x);
return _v[block][x].t(); return (_v[block].load())[x].t();
} }
template <typename T, typename ConstantsType> template <typename T, typename ConstantsType>
inline typename QFreeList<T, ConstantsType>::ReferenceType QFreeList<T, ConstantsType>::operator[](int x) inline typename QFreeList<T, ConstantsType>::ReferenceType QFreeList<T, ConstantsType>::operator[](int x)
{ {
const int block = blockfor(x); const int block = blockfor(x);
return _v[block][x].t(); return (_v[block].load())[x].t();
} }
template <typename T, typename ConstantsType> template <typename T, typename ConstantsType>
@ -241,24 +241,24 @@ inline int QFreeList<T, ConstantsType>::next()
int id, newid, at; int id, newid, at;
ElementType *v; ElementType *v;
do { do {
id = _next; // .loadAqcuire(); id = _next.load();
at = id & ConstantsType::IndexMask; at = id & ConstantsType::IndexMask;
const int block = blockfor(at); const int block = blockfor(at);
v = _v[block]; v = _v[block].loadAcquire();
if (!v) { if (!v) {
v = allocate((id & ConstantsType::IndexMask) - at, ConstantsType::Sizes[block]); v = allocate((id & ConstantsType::IndexMask) - at, ConstantsType::Sizes[block]);
if (!_v[block].testAndSetRelease(0, v)) { if (!_v[block].testAndSetRelease(0, v)) {
// race with another thread lost // race with another thread lost
delete [] v; delete [] v;
v = _v[block]; v = _v[block].loadAcquire();
Q_ASSERT(v != 0); Q_ASSERT(v != 0);
} }
} }
newid = v[at].next | (id & ~ConstantsType::IndexMask); newid = v[at].next | (id & ~ConstantsType::IndexMask);
} while (!_next.testAndSetRelease(id, newid)); } while (!_next.testAndSetRelaxed(id, newid));
// qDebug("QFreeList::next(): returning %d (_next now %d, serial %d)", // qDebug("QFreeList::next(): returning %d (_next now %d, serial %d)",
// id & ConstantsType::IndexMask, // id & ConstantsType::IndexMask,
// newid & ConstantsType::IndexMask, // newid & ConstantsType::IndexMask,
@ -271,11 +271,11 @@ inline void QFreeList<T, ConstantsType>::release(int id)
{ {
int at = id & ConstantsType::IndexMask; int at = id & ConstantsType::IndexMask;
const int block = blockfor(at); const int block = blockfor(at);
ElementType *v = _v[block]; ElementType *v = _v[block].load();
int x, newid; int x, newid;
do { do {
x = _next; // .loadAcquire(); x = _next.loadAcquire();
v[at].next = x & ConstantsType::IndexMask; v[at].next = x & ConstantsType::IndexMask;
newid = incrementserial(x, id); newid = incrementserial(x, id);