Updated copyright
[libcds.git] / cds / intrusive / msqueue.h
index 7a63639167ce4e28f7aa0b8a185b8571e893d2c5..98d8a64e82f6f91574d65bb37d5af06d055956fa 100644 (file)
@@ -1,7 +1,35 @@
-//$$CDS-header$$
+/*
+    This file is a part of libcds - Concurrent Data Structures library
 
-#ifndef __CDS_INTRUSIVE_MSQUEUE_H
-#define __CDS_INTRUSIVE_MSQUEUE_H
+    (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:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSLIB_INTRUSIVE_MSQUEUE_H
+#define CDSLIB_INTRUSIVE_MSQUEUE_H
 
 #include <type_traits>
 #include <cds/intrusive/details/single_link_struct.h>
@@ -171,8 +199,8 @@ namespace cds { namespace intrusive {
             /// Link checking, see \p cds::opt::link_checker
             static CDS_CONSTEXPR const opt::link_check_type link_checker = opt::debug_check_link;
 
-            /// Alignment for internal queue data. Default is \p opt::cache_line_alignment
-            enum { alignment = opt::cache_line_alignment };
+            /// Padding for internal critical atomic data. Default is \p opt::cache_line_padding
+            enum { padding = opt::cache_line_padding };
         };
 
         /// Metafunction converting option list to \p msqueue::traits
@@ -190,7 +218,7 @@ namespace cds { namespace intrusive {
             - \p opt::stat - the type to gather internal statistics.
                 Possible statistics types are: \p msqueue::stat, \p msqueue::empty_stat, user-provided class that supports \p %msqueue::stat interface.
                 Default is \p %msqueue::empty_stat (internal statistics disabled).
-            - \p opt::alignment - the alignment for internal queue data. Default is \p opt::cache_line_alignment
+            - \p opt::padding - padding for internal critical atomic data. Default is \p opt::cache_line_padding
             - \p opt::memory_model - C++ memory ordering model. Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
                 or \p opt::v::sequential_consistent (sequentially consisnent memory model).
 
@@ -287,7 +315,7 @@ namespace cds { namespace intrusive {
         // Example 2:
         //  MSQueue with Hazard Pointer garbage collector,
         //  member hook + item disposer + item counter,
-        //  without alignment of internal queue data
+        //  without padding of internal queue data
         //  Use msqueue::make_traits
         struct Bar
         {
@@ -307,7 +335,7 @@ namespace cds { namespace intrusive {
                 >
                 ,ci::opt::disposer< fooDisposer >
                 ,cds::opt::item_counter< cds::atomicity::item_counter >
-                ,cds::opt::alignment< cds::opt::no_special_alignment >
+                ,cds::opt::padding< cds::opt::no_special_padding >
             >::type
         > barQueue;
         \endcode
@@ -337,7 +365,7 @@ namespace cds { namespace intrusive {
             typedef MSQueue< GC2, T2, Traits2 > other;   ///< Rebinding result
         };
 
-        static CDS_CONSTEXPR const size_t m_nHazardPtrCount = 2; ///< Count of hazard pointer required for the algorithm
+        static CDS_CONSTEXPR const size_t c_nHazardPtrCount = 2; ///< Count of hazard pointer required for the algorithm
 
     protected:
         //@cond
@@ -345,15 +373,16 @@ namespace cds { namespace intrusive {
         // GC and node_type::gc must be the same
         static_assert((std::is_same<gc, typename node_type::gc>::value), "GC and node_type::gc must be the same");
 
-        typedef intrusive::node_to_value<MSQueue> node_to_value;
-        typedef typename opt::details::alignment_setter< typename node_type::atomic_node_ptr, traits::alignment >::type aligned_node_ptr;
-        typedef typename opt::details::alignment_setter< node_type, traits::alignment >::type dummy_node_type;
+        typedef typename node_type::atomic_node_ptr atomic_node_ptr;
 
-        aligned_node_ptr    m_pHead ;           ///< Queue's head pointer
-        aligned_node_ptr    m_pTail ;           ///< Queue's tail pointer
-        dummy_node_type     m_Dummy ;           ///< dummy node
-        item_counter        m_ItemCounter   ;   ///< Item counter
-        stat                m_Stat  ;           ///< Internal statistics
+        atomic_node_ptr    m_pHead;        ///< Queue's head pointer
+        typename opt::details::apply_padding< atomic_node_ptr, traits::padding >::padding_type pad1_;
+        atomic_node_ptr    m_pTail;        ///< Queue's tail pointer
+        typename opt::details::apply_padding< atomic_node_ptr, traits::padding >::padding_type pad2_;
+        node_type          m_Dummy;        ///< dummy node
+        typename opt::details::apply_padding< node_type, traits::padding >::padding_type pad3_;
+        item_counter        m_ItemCounter; ///< Item counter
+        stat                m_Stat;        ///< Internal statistics
         //@endcond
 
         //@cond
@@ -371,9 +400,8 @@ namespace cds { namespace intrusive {
 
             node_type * h;
             while ( true ) {
-                h = res.guards.protect( 0, m_pHead, node_to_value() );
-                pNext = h->m_pNext.load( memory_model::memory_order_relaxed );
-                res.guards.assign( 1, node_to_value()( pNext ));
+                h = res.guards.protect( 0, m_pHead, []( node_type * p ) -> value_type * { return node_traits::to_value_ptr( p );});
+                pNext = res.guards.protect( 1, h->m_pNext, []( node_type * p ) -> value_type * { return node_traits::to_value_ptr( p );});
                 if ( m_pHead.load(memory_model::memory_order_acquire) != h )
                     continue;
 
@@ -390,7 +418,7 @@ namespace cds { namespace intrusive {
                     continue;
                 }
 
-                if ( m_pHead.compare_exchange_strong( h, pNext, memory_model::memory_order_release, atomics::memory_order_relaxed ))
+                if ( m_pHead.compare_exchange_strong( h, pNext, memory_model::memory_order_acquire, atomics::memory_order_relaxed ))
                     break;
 
                 m_Stat.onDequeueRace();
@@ -428,13 +456,13 @@ namespace cds { namespace intrusive {
                 void operator()( value_type * p ) const
                 {
                     assert( p != nullptr );
-                    MSQueue::clear_links( node_traits::to_node_ptr( p ) );
+                    MSQueue::clear_links( node_traits::to_node_ptr( p ));
                     disposer()(p);
                 }
             };
 
             if ( p != &m_Dummy )
-                gc::template retire<disposer_thunk>( node_traits::to_value_ptr( p ) );
+                gc::template retire<disposer_thunk>( node_traits::to_value_ptr( p ));
         }
         //@endcond
 
@@ -457,7 +485,7 @@ namespace cds { namespace intrusive {
             node_type * pHead = m_pHead.load(memory_model::memory_order_relaxed);
 
             assert( pHead != nullptr );
-            assert( pHead == m_pTail.load(memory_model::memory_order_relaxed) );
+            assert( pHead == m_pTail.load(memory_model::memory_order_relaxed));
 
             m_pHead.store( nullptr, memory_model::memory_order_relaxed );
             m_pTail.store( nullptr, memory_model::memory_order_relaxed );
@@ -479,7 +507,7 @@ namespace cds { namespace intrusive {
 
             node_type * t;
             while ( true ) {
-                t = guard.protect( m_pTail, node_to_value() );
+                t = guard.protect( m_pTail, []( node_type * p ) -> value_type * { return node_traits::to_value_ptr( p );});
 
                 node_type * pNext = t->m_pNext.load(memory_model::memory_order_acquire);
                 if ( pNext != nullptr ) {
@@ -499,7 +527,7 @@ namespace cds { namespace intrusive {
             ++m_ItemCounter;
             m_Stat.onEnqueue();
 
-            if ( !m_pTail.compare_exchange_strong( t, pNew, memory_model::memory_order_acq_rel, atomics::memory_order_relaxed ))
+            if ( !m_pTail.compare_exchange_strong( t, pNew, memory_model::memory_order_release, atomics::memory_order_relaxed ))
                 m_Stat.onAdvanceTailFailed();
             return true;
         }
@@ -556,7 +584,8 @@ namespace cds { namespace intrusive {
         bool empty() const
         {
             typename gc::Guard guard;
-            return guard.protect( m_pHead, node_to_value() )->m_pNext.load( memory_model::memory_order_relaxed ) == nullptr;
+            node_type * p = guard.protect( m_pHead, []( node_type * p ) -> value_type * { return node_traits::to_value_ptr( p );});
+            return p->m_pNext.load( memory_model::memory_order_relaxed ) == nullptr;
         }
 
         /// Clear the queue
@@ -567,7 +596,7 @@ namespace cds { namespace intrusive {
         */
         void clear()
         {
-            while ( dequeue() );
+            while ( dequeue());
         }
 
         /// Returns queue's item count
@@ -592,4 +621,4 @@ namespace cds { namespace intrusive {
 
 }} // namespace cds::intrusive
 
-#endif // #ifndef __CDS_INTRUSIVE_MSQUEUE_H
+#endif // #ifndef CDSLIB_INTRUSIVE_MSQUEUE_H