FlatCombining: fixed a race
[libcds.git] / cds / algo / flat_combining / kernel.h
index cbc39b778b7bb1d9409c8cbef31507962a860e3e..654992d6adc43da066d43428c75b9a89f1121ae6 100644 (file)
@@ -291,11 +291,14 @@ namespace cds { namespace algo {
             /// Destroys the objects and mark all publication records as inactive
             ~kernel()
             {
-                // mark all publication record as detached
+                m_pThreadRec.reset();   // calls tls_cleanup()
+
+                // delete all publication records
                 for ( publication_record* p = m_pHead; p; ) {
                     publication_record * pRec = p;
                     p = p->pNext.load( memory_model::memory_order_relaxed );
                     free_publication_record( static_cast<publication_record_type *>( pRec ));
+                    m_Stat.onDeletePubRecord();
                 }
             }
 
@@ -596,10 +599,10 @@ namespace cds { namespace algo {
                     publication_record * p = m_pHead->pNext.load(memory_model::memory_order_relaxed);
                     if ( p != static_cast<publication_record *>( pRec )) {
                         do {
-                            pRec->pNext = p;
+                            pRec->pNext.store( p, memory_model::memory_order_relaxed );
                             // Failed CAS changes p
                         } while ( !m_pHead->pNext.compare_exchange_weak( p, static_cast<publication_record *>(pRec),
-                            memory_model::memory_order_release, atomics::memory_order_relaxed ));
+                            memory_model::memory_order_release, atomics::memory_order_acquire ));
                         m_Stat.onActivatePubRecord();
                     }
                 }
@@ -712,9 +715,12 @@ namespace cds { namespace algo {
                             assert( p == m_pHead );
                             break;
                         case removed:
-                            // The record should be removed
-                            p = unlink_and_delete_record( pPrev, p );
-                            continue;
+                            // The record should be removed (except m_pHead)
+                            if ( pPrev ) {
+                                p = unlink_and_delete_record( pPrev, p );
+                                continue;
+                            }
+                            break;
                         default:
                             /// ??? That is impossible
                             assert(false);
@@ -805,22 +811,18 @@ namespace cds { namespace algo {
 
             publication_record * unlink_and_delete_record( publication_record * pPrev, publication_record * p )
             {
-                if ( pPrev ) {
-                    publication_record * pNext = p->pNext.load( memory_model::memory_order_acquire );
-                    if ( pPrev->pNext.compare_exchange_strong( p, pNext,
-                        memory_model::memory_order_release, atomics::memory_order_relaxed ))
-                    {
-                        free_publication_record( static_cast<publication_record_type *>( p ));
-                        m_Stat.onDeletePubRecord();
-                    }
-                    return pNext;
-                }
-                else {
-                    m_pHead = static_cast<publication_record_type *>( p->pNext.load( memory_model::memory_order_acquire ));
+                // m_pHead is persistent node and cannot be deleted
+                assert( pPrev != nullptr );
+                assert( p != m_pHead );
+
+                publication_record * pNext = p->pNext.load( memory_model::memory_order_acquire );
+                if ( pPrev->pNext.compare_exchange_strong( p, pNext,
+                    memory_model::memory_order_acquire, atomics::memory_order_relaxed ))
+                {
                     free_publication_record( static_cast<publication_record_type *>( p ));
                     m_Stat.onDeletePubRecord();
-                    return m_pHead;
                 }
+                return pNext;
             }
             //@endcond
         };