Moved priority_queue unit test to gtest framework
[libcds.git] / cds / intrusive / lazy_list_rcu.h
index ea9ccbe048f931f33081b310e500571c9ac073a7..de34c4f851023b405602237cf723075a6eb3f20c 100644 (file)
@@ -1,4 +1,32 @@
-//$$CDS-header$$
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    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_LAZY_LIST_RCU_H
 #define CDSLIB_INTRUSIVE_LAZY_LIST_RCU_H
@@ -170,7 +198,7 @@ namespace cds { namespace intrusive {
 
         typedef std::unique_lock< position > scoped_position_lock;
 
-        typedef cds::urcu::details::check_deadlock_policy< gc, rcu_check_deadlock>   check_deadlock_policy;
+        typedef cds::urcu::details::check_deadlock_policy< gc, rcu_check_deadlock>   deadlock_policy;
         //@endcond
 
     protected:
@@ -192,9 +220,9 @@ namespace cds { namespace intrusive {
         static void dispose_node( node_type * pNode )
         {
             assert( pNode );
-            assert( !gc::is_locked() );
+            assert( !gc::is_locked());
 
-            gc::template retire_ptr<clear_and_dispose>( node_traits::to_value_ptr( *pNode ) );
+            gc::template retire_ptr<clear_and_dispose>( node_traits::to_value_ptr( *pNode ));
         }
 
         static void link_node( node_type * pNode, node_type * pPred, node_type * pCur )
@@ -249,10 +277,10 @@ namespace cds { namespace intrusive {
                     node_type * pNode = node_traits::to_node_ptr( m_pNode );
 
                     // Dummy tail node could not be marked
-                    while ( pNode->is_marked() )
+                    while ( pNode->is_marked())
                         pNode = pNode->m_pNext.load(memory_model::memory_order_acquire).ptr();
 
-                    if ( pNode != node_traits::to_node_ptr( m_pNode ) )
+                    if ( pNode != node_traits::to_node_ptr( m_pNode ))
                         m_pNode = node_traits::to_value_ptr( pNode );
                 }
             }
@@ -522,7 +550,7 @@ namespace cds { namespace intrusive {
         template <typename Q>
         bool erase( Q const& key )
         {
-            return erase_at( &m_Head, key, key_comparator() );
+            return erase_at( &m_Head, key, key_comparator());
         }
 
         /// Deletes the item from the list using \p pred predicate for searching
@@ -586,7 +614,7 @@ namespace cds { namespace intrusive {
             If the item is not found the function returns empty \p exempt_ptr.
 
             @note The function does NOT call RCU read-side lock or synchronization,
-            and does NOT dispose the item found. It just excludes the item from the list
+            and does NOT dispose the item found. It just unlinks the item from the list
             and returns a pointer to it.
             You should manually lock RCU before calling this function, and you should manually synchronize RCU
             outside the RCU lock region before reusing returned pointer.
@@ -624,7 +652,7 @@ namespace cds { namespace intrusive {
         template <typename Q>
         exempt_ptr extract( Q const& key )
         {
-            return exempt_ptr( extract_at( &m_Head, key, key_comparator() ));
+            return exempt_ptr( extract_at( &m_Head, key, key_comparator()));
         }
 
         /// Extracts an item from the list using \p pred predicate for searching
@@ -639,7 +667,7 @@ namespace cds { namespace intrusive {
         exempt_ptr extract_with( Q const& key, Less pred )
         {
             CDS_UNUSED( pred );
-            return exempt_ptr( extract_at( &m_Head, key, cds::opt::details::make_comparator_from_less<Less>() ));
+            return exempt_ptr( extract_at( &m_Head, key, cds::opt::details::make_comparator_from_less<Less>()));
         }
 
         /// Finds the key \p key
@@ -701,7 +729,7 @@ namespace cds { namespace intrusive {
         template <typename Q>
         bool contains( Q const& key ) const
         {
-            return find_at( const_cast<node_type *>( &m_Head ), key, key_comparator() );
+            return find_at( const_cast<node_type *>( &m_Head ), key, key_comparator());
         }
         //@cond
         template <typename Q>
@@ -722,7 +750,7 @@ namespace cds { namespace intrusive {
         bool contains( Q const& key, Less pred ) const
         {
             CDS_UNUSED( pred );
-            return find_at( const_cast<node_type *>( &m_Head ), key, cds::opt::details::make_comparator_from_less<Less>() );
+            return find_at( const_cast<node_type *>( &m_Head ), key, cds::opt::details::make_comparator_from_less<Less>());
         }
         //@cond
         template <typename Q, typename Less>
@@ -748,7 +776,7 @@ namespace cds { namespace intrusive {
             // ...
             {
                 // Lock RCU
-                ord_list::rcu_lock lock;
+                typename ord_list::rcu_lock lock;
 
                 foo * pVal = theList.get( 5 );
                 if ( pVal ) {
@@ -789,13 +817,13 @@ namespace cds { namespace intrusive {
             RCU \p synchronize method can be called.
             Note that depending on RCU type used the \ref disposer call can be deferred.
 
-            The function can throw cds::urcu::rcu_deadlock exception if deadlock is encountered and
-            deadlock checking policy is opt::v::rcu_throw_deadlock.
+            The function can throw \p cds::urcu::rcu_deadlock exception if deadlock is encountered and
+            deadlock checking policy is \p opt::v::rcu_throw_deadlock.
         */
         void clear()
         {
-            if( !empty() ) {
-                check_deadlock_policy::check();
+            if( !empty()) {
+                deadlock_policy::check();
 
                 node_type * pHead;
                 for (;;) {
@@ -857,7 +885,7 @@ namespace cds { namespace intrusive {
             // Hack: convert node_type to value_type.
             // Actually, an auxiliary node should not be converted to value_type
             // We assume that comparator can correctly distinguish aux and regular node.
-            return insert_at( pHead, *node_traits::to_value_ptr( pNode ) );
+            return insert_at( pHead, *node_traits::to_value_ptr( pNode ));
         }
 
         bool insert_at( node_type * pHead, value_type& val )
@@ -869,7 +897,7 @@ namespace cds { namespace intrusive {
         template <typename Func>
         bool insert_at( node_type * pHead, value_type& val, Func f )
         {
-            link_checker::is_empty( node_traits::to_node_ptr( val ) );
+            link_checker::is_empty( node_traits::to_node_ptr( val ));
             position pos;
             key_comparator  cmp;
 
@@ -884,8 +912,8 @@ namespace cds { namespace intrusive {
                             return false;
                         }
 
-                        link_node( node_traits::to_node_ptr( val ), pos.pPred, pos.pCur );
                         f( val );
+                        link_node( node_traits::to_node_ptr( val ), pos.pPred, pos.pCur );
                         ++m_ItemCounter;
                         return true;
                     }
@@ -921,7 +949,7 @@ namespace cds { namespace intrusive {
         {
             position pos;
             key_comparator  cmp;
-            check_deadlock_policy::check();
+            deadlock_policy::check();
 
             while ( true ) {
                 int nResult = 0;
@@ -930,7 +958,7 @@ namespace cds { namespace intrusive {
                     search( pHead, val, pos );
                     {
                         scoped_position_lock alp( pos );
-                        if ( validate( pos.pPred, pos.pCur ) ) {
+                        if ( validate( pos.pPred, pos.pCur )) {
                             if ( pos.pCur != &m_Tail
                                 && cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0
                                 && node_traits::to_value_ptr( pos.pCur ) == &val )
@@ -959,7 +987,7 @@ namespace cds { namespace intrusive {
         template <typename Q, typename Compare, typename Func>
         bool erase_at( node_type * const pHead, Q const& val, Compare cmp, Func f, position& pos )
         {
-            check_deadlock_policy::check();
+            deadlock_policy::check();
 
             while ( true ) {
                 int nResult = 0;
@@ -972,7 +1000,7 @@ namespace cds { namespace intrusive {
                             if ( pos.pCur != &m_Tail && cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0 ) {
                                 // key found
                                 unlink_node( pos.pPred, pos.pCur, pHead );
-                                f( *node_traits::to_value_ptr( *pos.pCur ) );
+                                f( *node_traits::to_value_ptr( *pos.pCur ));
                                 --m_ItemCounter;
                                 nResult = 1;
                             }
@@ -1010,7 +1038,7 @@ namespace cds { namespace intrusive {
         value_type * extract_at( node_type * const pHead, Q const& val, Compare cmp )
         {
             position pos;
-            assert( gc::is_locked() ) ; // RCU must be locked!!!
+            assert( gc::is_locked()) ; // RCU must be locked
 
             while ( true ) {
                 search( pHead, val, pos, cmp );
@@ -1066,7 +1094,7 @@ namespace cds { namespace intrusive {
         template <typename Q, typename Compare>
         const_iterator find_at_( node_type * pHead, Q& val, Compare cmp ) const
         {
-            assert( gc::is_locked() );
+            assert( gc::is_locked());
 
             position pos;
 
@@ -1093,14 +1121,14 @@ namespace cds { namespace intrusive {
         template <typename Q>
         void search( node_type * const pHead, Q const& key, position& pos ) const
         {
-            search( pHead, key, pos, key_comparator() );
+            search( pHead, key, pos, key_comparator());
         }
 
         template <typename Q, typename Compare>
         void search( node_type * const pHead, Q const& key, position& pos, Compare cmp ) const
         {
-            // RCU should be locked!!!
-            assert( gc::is_locked() );
+            // RCU should be locked
+            assert( gc::is_locked());
 
             node_type const* pTail = &m_Tail;
 
@@ -1110,6 +1138,8 @@ namespace cds { namespace intrusive {
             while ( pCur != pTail && ( pCur == pHead || cmp( *node_traits::to_value_ptr( *pCur.ptr()), key ) < 0 )) {
                 pPrev = pCur;
                 pCur = pCur->m_pNext.load(memory_model::memory_order_acquire);
+                if ( pCur.bits())
+                    pPrev = pCur = pHead;
             }
 
             pos.pCur = pCur.ptr();
@@ -1118,8 +1148,8 @@ namespace cds { namespace intrusive {
 
         static bool validate( node_type * pPred, node_type * pCur ) CDS_NOEXCEPT
         {
-            // RCU lock should be locked!!!
-            assert( gc::is_locked() );
+            // RCU lock should be locked
+            assert( gc::is_locked());
 
             return !pPred->is_marked()
                 && !pCur->is_marked()
@@ -1132,8 +1162,8 @@ namespace cds { namespace intrusive {
         //@cond
         bool insert_at_locked( node_type * pHead, value_type& val )
         {
-            // RCU lock should be locked!!!
-            assert( gc::is_locked() );
+            // RCU lock should be locked
+            assert( gc::is_locked());
 
             link_checker::is_empty( node_traits::to_node_ptr( val ));
             position pos;
@@ -1143,7 +1173,7 @@ namespace cds { namespace intrusive {
                 search( pHead, val, pos );
                 {
                     scoped_position_lock alp( pos );
-                    if ( validate( pos.pPred, pos.pCur ) ) {
+                    if ( validate( pos.pPred, pos.pCur )) {
                         if ( pos.pCur != &m_Tail && cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0 ) {
                             // failed: key already in list
                             return false;
@@ -1160,8 +1190,8 @@ namespace cds { namespace intrusive {
         template <typename Func>
         std::pair<iterator, bool> update_at_locked( node_type * pHead, value_type& val, Func func, bool bAllowInsert )
         {
-            // RCU lock should be locked!!!
-            assert( gc::is_locked() );
+            // RCU lock should be locked
+            assert( gc::is_locked());
 
             position pos;
             key_comparator  cmp;
@@ -1170,7 +1200,7 @@ namespace cds { namespace intrusive {
                 search( pHead, val, pos );
                 {
                     scoped_position_lock alp( pos );
-                    if ( validate( pos.pPred, pos.pCur ) ) {
+                    if ( validate( pos.pPred, pos.pCur )) {
                         if ( pos.pCur != &m_Tail && cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0 ) {
                             // key already in the list
 
@@ -1182,12 +1212,12 @@ namespace cds { namespace intrusive {
                             if ( !bAllowInsert )
                                 return std::make_pair( end(), false );
 
-                            link_checker::is_empty( node_traits::to_node_ptr( val ) );
+                            link_checker::is_empty( node_traits::to_node_ptr( val ));
 
-                            link_node( node_traits::to_node_ptr( val ), pos.pPred, pos.pCur );
                             func( true, val, val );
+                            link_node( node_traits::to_node_ptr( val ), pos.pPred, pos.pCur );
                             ++m_ItemCounter;
-                            return std::make_pair( iterator( node_traits::to_node_ptr( val ) ), true );
+                            return std::make_pair( iterator( node_traits::to_node_ptr( val )), true );
                         }
                     }
                 }