Merge remote-tracking branch 'khizmax/master'
[libcds.git] / cds / intrusive / free_list_tagged.h
index ab71e8f9feb2b95ae119964ae9b496120f45c26d..b9ecd4e085fe641a50033cafb021c28cf8534043 100644 (file)
@@ -1,11 +1,11 @@
 /*
     This file is a part of libcds - Concurrent Data Structures library
 
-    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
 
     Source code repo: http://github.com/khizmax/libcds/
     Download: http://sourceforge.net/projects/libcds/files/
-    
+
     Redistribution and use in source and binary forms, with or without
     modification, are permitted provided that the following conditions are met:
 
@@ -36,7 +36,8 @@
 namespace cds { namespace intrusive {
 
     /// Lock-free free list based on tagged pointers (required double-width CAS)
-    /** @ingroup cds_intrusive_helper
+    /** @ingroup cds_intrusive_freelist
+
         This variant of \p FreeList is intended for processor architectures that support double-width CAS.
         It uses <a href="https://en.wikipedia.org/wiki/Tagged_pointer">tagged pointer</a> technique to solve ABA problem.
 
@@ -87,8 +88,9 @@ namespace cds { namespace intrusive {
             atomics::atomic<node *> m_freeListNext;
 
             node()
-                : m_freeListNext( nullptr )
-            {}
+            {
+                m_freeListNext.store( nullptr, atomics::memory_order_release );
+            }
             //@endcond
         };
 
@@ -129,7 +131,7 @@ namespace cds { namespace intrusive {
         */
         ~TaggedFreeList()
         {
-            assert( empty() );
+            assert( empty());
         }
 
         /// Puts \p pNode to the free list
@@ -142,7 +144,8 @@ namespace cds { namespace intrusive {
             do {
                 newHead.tag = currentHead.tag + 1;
                 pNode->m_freeListNext.store( currentHead.ptr, atomics::memory_order_relaxed );
-            } while ( cds_unlikely( !m_Head.compare_exchange_weak( currentHead, newHead, atomics::memory_order_release, atomics::memory_order_relaxed )));
+                CDS_TSAN_ANNOTATE_HAPPENS_BEFORE( &pNode->m_freeListNext );
+            } while ( cds_unlikely( !m_Head.compare_exchange_weak( currentHead, newHead, atomics::memory_order_release, atomics::memory_order_acquire )));
         }
 
         /// Gets a node from the free list. If the list is empty, returns \p nullptr
@@ -151,6 +154,7 @@ namespace cds { namespace intrusive {
             tagged_ptr currentHead = m_Head.load( atomics::memory_order_acquire );
             tagged_ptr newHead;
             while ( currentHead.ptr != nullptr ) {
+                CDS_TSAN_ANNOTATE_HAPPENS_AFTER( &currentHead.ptr->m_freeListNext );
                 newHead.ptr = currentHead.ptr->m_freeListNext.load( atomics::memory_order_relaxed );
                 newHead.tag = currentHead.tag + 1;
                 if ( cds_likely( m_Head.compare_exchange_weak( currentHead, newHead, atomics::memory_order_release, atomics::memory_order_acquire )))
@@ -193,7 +197,7 @@ namespace cds { namespace intrusive {
     private:
         //@cond
         atomics::atomic<tagged_ptr> m_Head;
-        //@endcond    
+        //@endcond
     };
 
 }} // namespace cds::intrusive