struct publication_record {
atomics::atomic<unsigned int> nRequest; ///< Request field (depends on data structure)
atomics::atomic<unsigned int> nState; ///< Record state: inactive, active, removed
- unsigned int nAge; ///< Age of the record
+ atomics::atomic<unsigned int> nAge; ///< Age of the record
atomics::atomic<publication_record *> pNext; ///< Next record in publication list
void * pOwner; ///< [internal data] Pointer to \ref kernel object that manages the publication list
void release_record( publication_record_type * pRec )
{
assert( pRec->is_done() );
- pRec->nRequest.store( req_EmptyRecord, memory_model::memory_order_relaxed );
+ pRec->nRequest.store( req_EmptyRecord, memory_model::memory_order_release );
m_Stat.onReleasePubRecord();
}
{
assert( pRec->nState.load( memory_model::memory_order_relaxed ) == inactive );
- pRec->nAge = m_nCount;
+ pRec->nAge.store( m_nCount, memory_model::memory_order_release );
pRec->nState.store( active, memory_model::memory_order_release );
// Insert record to publication list
switch ( p->nState.load( memory_model::memory_order_acquire )) {
case active:
if ( p->op() >= req_Operation ) {
- p->nAge = nCurAge;
+ p->nAge.store( nCurAge, memory_model::memory_order_release );
owner.fc_apply( static_cast<publication_record_type *>(p) );
operation_done( *p );
bOpDone = true;
// Thinning publication list
publication_record * pPrev = nullptr;
for ( publication_record * p = m_pHead; p; ) {
- if ( p->nState.load( memory_model::memory_order_acquire ) == active && p->nAge + m_nCompactFactor < nCurAge ) {
+ if ( p->nState.load( memory_model::memory_order_acquire ) == active
+ && p->nAge.load( memory_model::memory_order_acquire ) + m_nCompactFactor < nCurAge )
+ {
if ( pPrev ) {
publication_record * pNext = p->pNext.load( memory_model::memory_order_acquire );
if ( pPrev->pNext.compare_exchange_strong( p, pNext,
{
assert( pRec );
+ // this function is called under FC mutex, so switch TSan off
+ CDS_TSAN_ANNOTATE_IGNORE_RW_BEGIN;
+
switch ( pRec->op() ) {
case op_push_front:
assert( pRec->pValPush );
assert(false);
break;
}
+ CDS_TSAN_ANNOTATE_IGNORE_RW_END;
}
/// Batch-processing flat combining
void fc_process( typename fc_kernel::iterator itBegin, typename fc_kernel::iterator itEnd )
{
typedef typename fc_kernel::iterator fc_iterator;
+
+ // this function is called under FC mutex, so switch TSan off
+ CDS_TSAN_ANNOTATE_IGNORE_RW_BEGIN;
+
for ( fc_iterator it = itBegin, itPrev = itEnd; it != itEnd; ++it ) {
switch ( it->op() ) {
case op_push_front:
break;
}
}
+ CDS_TSAN_ANNOTATE_IGNORE_RW_END;
}
//@endcond
{
assert( pRec );
+ // this function is called under FC mutex, so switch TSan off
+ CDS_TSAN_ANNOTATE_IGNORE_RW_BEGIN;
switch ( pRec->op() ) {
case op_push:
assert( pRec->pValPush );
assert(false);
break;
}
+ CDS_TSAN_ANNOTATE_IGNORE_RW_END;
}
/// Batch-processing flat combining
void fc_process( typename fc_kernel::iterator itBegin, typename fc_kernel::iterator itEnd )
{
+ // this function is called under FC mutex, so switch TSan off
+ CDS_TSAN_ANNOTATE_IGNORE_RW_BEGIN;
typedef typename fc_kernel::iterator fc_iterator;
for ( fc_iterator it = itBegin, itPrev = itEnd; it != itEnd; ++it ) {
switch ( it->op() ) {
break;
}
}
+ CDS_TSAN_ANNOTATE_IGNORE_RW_END;
}
//@endcond
{
assert( pRec );
+ // this function is called under FC mutex, so switch TSan off
+ CDS_TSAN_ANNOTATE_IGNORE_RW_BEGIN;
switch ( pRec->op() ) {
case op_push:
assert( pRec->pVal );
assert(false);
break;
}
+ CDS_TSAN_ANNOTATE_IGNORE_RW_END;
}
/// Batch-processing flat combining
void fc_process( typename fc_kernel::iterator itBegin, typename fc_kernel::iterator itEnd )
{
+ // this function is called under FC mutex, so switch TSan off
+ CDS_TSAN_ANNOTATE_IGNORE_RW_BEGIN;
+
typedef typename fc_kernel::iterator fc_iterator;
for ( fc_iterator it = itBegin, itPrev = itEnd; it != itEnd; ++it ) {
switch ( it->op() ) {
break;
}
}
+
+ CDS_TSAN_ANNOTATE_IGNORE_RW_END;
}
//@endcond
details::retired_vector& dest = pThis->m_arrRetired;
assert( !dest.isFull());
details::retired_vector::iterator itRetired = src.begin();
+
+ // TSan can issue a warning here:
+ // read src.m_nSize in src.end()
+ // write src.m_nSize in src.clear()
+ // This is false positive since we own hprec
+ CDS_TSAN_ANNOTATE_IGNORE_READS_BEGIN;
details::retired_vector::iterator itRetiredEnd = src.end();
+ CDS_TSAN_ANNOTATE_IGNORE_READS_END;
+
while ( itRetired != itRetiredEnd ) {
dest.push( *itRetired );
if ( dest.isFull()) {
}
++itRetired;
}
+
+ // TSan: write src.m_nSize, see a comment above
+ CDS_TSAN_ANNOTATE_IGNORE_WRITES_BEGIN;
src.clear();
+ CDS_TSAN_ANNOTATE_IGNORE_WRITES_END;
hprec->m_bFree.store(true, atomics::memory_order_release);
hprec->m_idOwner.store( nullThreadId, atomics::memory_order_release );