CDS_TSAN_ANNOTATE_IGNORE_WRITES_END;\
CDS_TSAN_ANNOTATE_IGNORE_READS_END
# define CDS_TSAN_ANNOTATE_NEW_MEMORY( addr, sz ) AnnotateNewMemory( __FILE__, __LINE__, reinterpret_cast<void *>(addr), sz )
+
+// Publish/unpublish - DEPRECATED
+#if 0
# define CDS_TSAN_ANNOTATE_PUBLISH_MEMORY_RANGE( addr, sz ) AnnotatePublishMemoryRange( __FILE__, __LINE__, reinterpret_cast<void *>(addr), sz )
+# define CDS_TSAN_ANNOTATE_UNPUBLISH_MEMORY_RANGE( addr, sz ) AnnotateUnpublishMemoryRange( __FILE__, __LINE__, reinterpret_cast<void *>(addr), sz )
+#endif
# define CDS_TSAN_ANNOTATE_MUTEX_CREATE( addr ) AnnotateRWLockCreate( __FILE__, __LINE__, reinterpret_cast<void *>(addr))
# define CDS_TSAN_ANNOTATE_MUTEX_DESTROY( addr ) AnnotateRWLockDestroy( __FILE__, __LINE__, reinterpret_cast<void *>(addr))
void AnnotateIgnoreWritesBegin(const char *f, int l);
void AnnotateIgnoreWritesEnd(const char *f, int l);
+#if 0
void AnnotatePublishMemoryRange( const char *f, int l, void * mem, size_t size );
+ void AnnotateUnpublishMemoryRange( const char *f, int l, void * addr, size_t size );
+#endif
void AnnotateNewMemory( const char *f, int l, void * mem, size_t size );
void AnnotateRWLockCreate( const char *f, int l, void* m );
# define CDS_TSAN_ANNOTATE_IGNORE_RW_BEGIN
# define CDS_TSAN_ANNOTATE_IGNORE_RW_END
+#if 0
# define CDS_TSAN_ANNOTATE_PUBLISH_MEMORY_RANGE( addr, sz )
+# define CDS_TSAN_ANNOTATE_UNPUBLISH_MEMORY_RANGE( addr, sz )
+#endif
# define CDS_TSAN_ANNOTATE_NEW_MEMORY( addr, sz )
# define CDS_TSAN_ANNOTATE_MUTEX_CREATE( addr )
void init_tower( unsigned int nHeight, atomic_marked_ptr * pTower )
{
if ( nHeight > 1 ) {
- // TSan: make_tower() issues atomic_thread_fence( release )
- CDS_TSAN_ANNOTATE_IGNORE_WRITES_BEGIN;
new (pTower) atomic_marked_ptr[ nHeight - 1 ];
base_class::make_tower( nHeight, pTower );
- CDS_TSAN_ANNOTATE_IGNORE_WRITES_END;
}
}
};
void init_tower( unsigned nHeight, atomic_marked_ptr* pTower )
{
if ( nHeight > 1 ) {
- // TSan: make_tower() issues atomic_thread_fence( release )
- CDS_TSAN_ANNOTATE_IGNORE_WRITES_BEGIN;
new ( pTower ) atomic_marked_ptr[nHeight - 1];
base_class::make_tower( nHeight, pTower );
- CDS_TSAN_ANNOTATE_IGNORE_WRITES_END;
}
}
};
{
return c_nNodeSize + (nHeight - 1) * c_nTowerItemSize;
}
+
static unsigned char * alloc_space( unsigned int nHeight )
{
+ unsigned char * pMem;
+ size_t const sz = node_size( nHeight );
+
if ( nHeight > 1 ) {
- unsigned char * pMem = tower_allocator_type().allocate( node_size(nHeight));
+ pMem = tower_allocator_type().allocate( sz );
// check proper alignments
assert( (((uintptr_t) pMem) & (alignof(node_type) - 1)) == 0 );
assert( (((uintptr_t) (pMem + c_nNodeSize)) & (alignof(node_tower_item) - 1)) == 0 );
return pMem;
}
+ else
+ pMem = reinterpret_cast<unsigned char *>( node_allocator_type().allocate( 1 ) );
- return reinterpret_cast<unsigned char *>( node_allocator_type().allocate(1));
+ return pMem;
}
static void free_space( unsigned char * p, unsigned int nHeight )
{
assert( p != nullptr );
+
if ( nHeight == 1 )
node_allocator_type().deallocate( reinterpret_cast<node_type *>(p), 1 );
else
: m_pNext( nullptr )
, m_nHeight( 1 )
, m_arrNext( nullptr )
- , m_nUnlink( 1 )
- {}
+ {
+ m_nUnlink.store( 1, atomics::memory_order_release );
+ }
/// Constructs a node's tower of height \p nHeight
assert( nLevel < height());
assert( nLevel == 0 || (nLevel > 0 && m_arrNext != nullptr));
- return nLevel ? m_arrNext[ nLevel - 1] : m_pNext;
+ if ( nLevel ) {
+ // TSan: data race between m_arrNext[ nLevel - 1 ] and make_tower()
+ // In fact, m_arrNext is a const array that is never changed
+ CDS_TSAN_ANNOTATE_HAPPENS_BEFORE( &m_arrNext[ nLevel - 1 ] );
+ return m_arrNext[nLevel - 1];
+ }
+ return m_pNext;
}
/// Access to element of next pointer array (const version)
assert( nLevel < height());
assert( nLevel == 0 || nLevel > 0 && m_arrNext != nullptr );
- return nLevel ? m_arrNext[ nLevel - 1] : m_pNext;
+ if ( nLevel ) {
+ CDS_TSAN_ANNOTATE_HAPPENS_BEFORE( &m_arrNext[nLevel - 1] );
+ return m_arrNext[nLevel - 1];
+ }
+ return m_pNext;
}
/// Access to element of next pointer array (synonym for \p next() function)
// Insert at level 0
{
marked_node_ptr p( pos.pSucc[0] );
- pNode->next( 0 ).store( p, memory_model::memory_order_relaxed );
+ pNode->next( 0 ).store( p, memory_model::memory_order_release );
if ( !pos.pPrev[0]->next( 0 ).compare_exchange_strong( p, marked_node_ptr( pNode ), memory_model::memory_order_release, atomics::memory_order_relaxed ))
return false;
// Set pNode->next
// pNode->next can have "logical deleted" flag if another thread is removing pNode right now
if ( !pNode->next( nLevel ).compare_exchange_strong( p, pSucc,
- memory_model::memory_order_acq_rel, atomics::memory_order_acquire ))
+ memory_model::memory_order_release, atomics::memory_order_acquire ))
{
// pNode has been marked as removed while we are inserting it
// Stop inserting
, m_pDelChain( nullptr )
, m_nHeight(1)
, m_arrNext( nullptr )
- , m_nUnlink(1)
- {}
+ {
+ m_nUnlink.store( 1, atomics::memory_order_release );
+ }
/// Constructs a node of height \p nHeight
void make_tower( unsigned int nHeight, atomic_marked_ptr * nextTower )
assert( nLevel < height());
assert( nLevel == 0 || (nLevel > 0 && m_arrNext != nullptr));
-# ifdef CDS_THREAD_SANITIZER_ENABLED
- // TSan false positive: m_arrNext is read-only array
- CDS_TSAN_ANNOTATE_IGNORE_READS_BEGIN;
- atomic_marked_ptr& r = nLevel ? m_arrNext[ nLevel - 1] : m_pNext;
- CDS_TSAN_ANNOTATE_IGNORE_READS_END;
- return r;
-# else
return nLevel ? m_arrNext[ nLevel - 1] : m_pNext;
-# endif
}
/// Access to element of next pointer array (const version)
assert( nLevel < height());
assert( nLevel == 0 || nLevel > 0 && m_arrNext != nullptr );
-# ifdef CDS_THREAD_SANITIZER_ENABLED
- // TSan false positive: m_arrNext is read-only array
- CDS_TSAN_ANNOTATE_IGNORE_READS_BEGIN;
- atomic_marked_ptr& r = nLevel ? m_arrNext[ nLevel - 1] : m_pNext;
- CDS_TSAN_ANNOTATE_IGNORE_READS_END;
- return r;
-# else
return nLevel ? m_arrNext[ nLevel - 1] : m_pNext;
-# endif
}
/// Access to element of next pointer array (same as \ref next function)