Added sync_monitor option
authorkhizmax <libcds.dev@gmail.com>
Mon, 2 Feb 2015 20:13:11 +0000 (23:13 +0300)
committerkhizmax <libcds.dev@gmail.com>
Mon, 2 Feb 2015 20:13:11 +0000 (23:13 +0300)
cds/compiler/clang/defs.h
cds/compiler/gcc/defs.h
cds/compiler/icl/defs.h
cds/compiler/vc/defs.h
cds/container/details/bronson_avltree_base.h
cds/container/impl/bronson_avltree_map_rcu.h
cds/opt/options.h
cds/sync/injecting_monitor.h
cds/sync/monitor.h
doxygen/cds.doxy

index 1c24b09cebb3f30634eb8b8994e9c1d84e520999..8b649d10e8e2be0d44b75fdf960cbfd803038e09 100644 (file)
@@ -44,6 +44,9 @@
 // Full SFINAE support
 #define CDS_CXX11_SFINAE
 
+// Inheriting constructors
+#define CDS_CXX11_INHERITING_CTOR
+
 // *************************************************
 // Alignment macro
 
index 6cf29563b5650ac45513116cadde143029a08206..2dadc6e1edb93544ce4a79bb442d7c21d7b64c47 100644 (file)
@@ -20,7 +20,6 @@
 
 #include <cds/compiler/gcc/compiler_macro.h>
 
-
 #define alignof __alignof__
 
 // ***************************************
@@ -42,6 +41,9 @@
 // Full SFINAE support
 #define CDS_CXX11_SFINAE
 
+// Inheriting constructors
+#define CDS_CXX11_INHERITING_CTOR
+
 // *************************************************
 // Alignment macro
 
index 7552be380502510cab25e1d4d186a758a89a233c..79ffefedbc0e847422fa8196d8597be368152b47 100644 (file)
@@ -86,6 +86,9 @@
 // C++11 inline namespace
 #define CDS_CXX11_INLINE_NAMESPACE_SUPPORT
 
+// Inheriting constructors
+#define CDS_CXX11_INHERITING_CTOR
+
 // *************************************************
 // Alignment macro
 
index 30e2ec597eebf09ea6a3b124e945233dfb757d2b..908aa008b0c4dd467b698b85ac5d782a6df7853b 100644 (file)
@@ -14,7 +14,7 @@
 #define CDS_COMPILER_MSVC14 1900    // 2015 vc14
 
 #if CDS_COMPILER_VERSION < CDS_COMPILER_MSVC12
-#   error "Only MS Visual C++ 12 (2013) and above is supported"
+#   error "Only MS Visual C++ 12 (2013) Update 4 and above is supported"
 #endif
 
 #if _MSC_VER == 1800
 #   define CDS_CXX11_SFINAE
 #endif
 
+// Inheriting constructors
+#if CDS_COMPILER_VERSION > CDS_COMPILER_MSVC12
+#   define CDS_CXX11_INHERITING_CTOR
+#endif
+
 // *************************************************
 // Alignment macro
 
index 77f77ef795639d4d4089ed79ffcce993cfbd4be5..8da14d65f262da05d8b294476a1017e9608016b6 100644 (file)
@@ -17,12 +17,11 @@ namespace cds { namespace container {
         struct node;
 
         //@cond
-        template <typename Key, typename T, typename Lock>
+        template <typename Key, typename T>
         struct link
         {
             typedef node<Key, T> node_type;
             typedef uint32_t version_type;
-            typedef Lock lock_type;
 
             enum
             {
@@ -37,7 +36,6 @@ namespace cds { namespace container {
             atomics::atomic<node_type *>    m_pParent;  ///< Parent node
             atomics::atomic<node_type *>    m_pLeft;    ///< Left child
             atomics::atomic<node_type *>    m_pRight;   ///< Right child
-            lock_type                       m_Lock;     ///< Node-level lock
 
             node_type *                     m_pNextRemoved; ///< thread-local list o removed node
 
@@ -112,12 +110,12 @@ namespace cds { namespace container {
             }
         };
 
-        template <typename Key, typename T, typename Lock>
-        struct node : public link< Key, T, Lock >
+        template <typename Key, typename T>
+        struct node : public link< Key, T >
         {
             typedef Key key_type;
             typedef T   mapped_type;
-            typedef link< key_type, mapped_type, Lock > base_class;
+            typedef link< key_type, mapped_type > base_class;
 
             key_type const  m_key;
             atomics::atomic<mapped_type *>  m_pValue;
@@ -264,8 +262,8 @@ namespace cds { namespace container {
             */
             typedef opt::v::delete_disposer<>       disposer;
 
-            /// Node lock
-            typedef std::mutex                      lock_type;
+            /// @ref cds_sync_monitor "Synchronization monitor" type for node-level locking
+            typedef cds::sync::injecting_monitor<cds::sync::spin>  sync_monitor;
 
             /// Enable relaxed insertion.
             /**
@@ -323,7 +321,8 @@ namespace cds { namespace container {
                 the disposer will be called to signal that the memory for the value can be safely freed.
                 Default is \ref cds::intrusive::opt::delete_disposer "cds::container::opt::v::delete_disposer<>" which calls \p delete operator.
                 Due the nature of GC schema the disposer may be called asynchronously.
-            - \p opt::lock_type - node lock type, default is \p std::mutex
+            - \p opt::sync_monitor -  @ref cds_sync_monitor "synchronization monitor" type for node-level locking,
+                default is cds::sync::injecting_monitor<cds::sync::spin>
             - \p bronson_avltree::relaxed_insert - enable (\p true) or disable (\p false, the default) 
                 @ref bronson_avltree::relaxed_insert "relaxed insertion"
             - \p opt::item_counter - the type of item counting feature, by default it is disabled (\p atomicity::empty_item_counter)
index 533ac3db819c51a64e4844913c7faa327d0f6ec0..4ea56e893d1bd079ee82c948f18f4f4c22c7330e 100644 (file)
@@ -60,14 +60,14 @@ namespace cds { namespace container {
         typedef typename traits::rcu_check_deadlock     rcu_check_deadlock; ///< Deadlock checking policy
         typedef typename traits::back_off               back_off;           ///< Back-off strategy
         typedef typename traits::disposer               disposer;           ///< Value disposer
-        typedef typename traits::lock_type              lock_type;          ///< Node lock type
+        typedef typename traits::sync_monitor           sync_monitor;       ///< @ref cds_sync_monitor "Synchronization monitor" type for node-level locking
 
         /// Enabled or disabled @ref bronson_avltree::relaxed_insert "relaxed insertion"
         static bool const c_bRelaxedInsert = traits::relaxed_insert;
 
     protected:
         //@cond
-        typedef bronson_avltree::node< key_type, mapped_type, lock_type > node_type;
+        typedef typename sync_monitor::template node_injection< bronson_avltree::node< key_type, mapped_type >> node_type;
         typedef typename node_type::version_type version_type;
 
         typedef cds::details::Allocator< node_type, node_allocator_type > cxx_allocator;
@@ -98,22 +98,7 @@ namespace cds { namespace container {
             unlink_required = -1
         };
 
-        class node_scoped_lock
-        {
-            node_type *     m_pNode;
-        public:
-            node_scoped_lock( node_type * pNode )
-                : m_pNode( pNode )
-            {
-                pNode->m_Lock.lock();
-            }
-
-            ~node_scoped_lock()
-            {
-                m_pNode->m_Lock.unlock();
-            }
-        };
-
+        typedef typename sync_monitor::template scoped_lock<node_type> node_scoped_lock;
         //@endcond
 
     protected:
@@ -186,6 +171,7 @@ namespace cds { namespace container {
         typename node_type::base_class      m_Root;
         node_type *                         m_pRoot;
         item_counter                        m_ItemCounter;
+        mutable sync_monitor                m_Monitor;
         mutable stat                        m_stat;
         //@endcond
 
@@ -405,8 +391,9 @@ namespace cds { namespace container {
         template <typename K, typename Func>
         bool find( K const& key, Func f )
         {
-            return do_find( key, key_comparator(), [&f]( node_type * pNode ) -> bool {
-                node_scoped_lock l( pNode );
+            return do_find( key, key_comparator(), [&f]( sync_monitor& monitor, node_type * pNode ) -> bool {
+                assert( pNode != nullptr );
+                node_scoped_lock l( monitor, *pNode );
                 mapped_type * pVal = pNode->m_pValue.load( memory_model::memory_order_relaxed );
                 if ( pVal ) {
                     f( *pVal );
@@ -427,15 +414,18 @@ namespace cds { namespace container {
         bool find_with( K const& key, Less pred, Func f )
         {
             CDS_UNUSED( pred );
-            return do_find( key, opt::details::make_comparator_from_less<Less>(), [&f]( node_type * pNode ) -> bool {
-                node_scoped_lock l( pNode );
-                mapped_type * pVal = pNode->m_pValue.load( memory_model::memory_order_relaxed );
-                if ( pVal ) {
-                    f( *pVal );
-                    return true;
-                }
-                return false;
-            } );
+            return do_find( key, opt::details::make_comparator_from_less<Less>(), 
+                [&f]( sync_monitor& monitor, node_type * pNode ) -> bool {
+                    assert( pNode != nullptr );
+                    node_scoped_lock l( monitor, *pNode );
+                    mapped_type * pVal = pNode->m_pValue.load( memory_model::memory_order_relaxed );
+                    if ( pVal ) {
+                        f( *pVal );
+                        return true;
+                    }
+                    return false;
+                } 
+            );
         }
 
         /// Find the key \p key
@@ -614,7 +604,7 @@ namespace cds { namespace container {
                 if ( nCmp == 0 ) {
                     if ( pChild->is_valued( memory_model::memory_order_relaxed ) ) {
                         // key found
-                        if ( f( pChild ) ) {
+                        if ( f( m_Monitor, pChild ) ) {
                             m_stat.onFindSuccess();
                             return find_result::found;
                         }
@@ -672,7 +662,7 @@ namespace cds { namespace container {
                     if ( nFlags & update_flags::allow_insert ) {
                         // insert into tree as right child of the root
                         {
-                            node_scoped_lock l( m_pRoot );
+                            node_scoped_lock l( m_Monitor, *m_pRoot );
 
                             node_type * pNew = alloc_node( key, 1, 0, m_pRoot, nullptr, nullptr );
                             mapped_type * pVal = funcUpdate( pNew );
@@ -775,7 +765,8 @@ namespace cds { namespace container {
 
             node_type * pDamaged;
             {
-                node_scoped_lock l( pNode );
+                assert( pNode != nullptr );
+                node_scoped_lock l( m_Monitor, *pNode );
 
                 if ( pNode->version( memory_model::memory_order_relaxed ) != nVersion
                      || pNode->child( nDir ).load( memory_model::memory_order_relaxed ) != nullptr ) 
@@ -807,7 +798,8 @@ namespace cds { namespace container {
         {
             mapped_type * pOld;
             {
-                node_scoped_lock l( pNode );
+                assert( pNode != nullptr );
+                node_scoped_lock l( m_Monitor, *pNode );
 
                 if ( pNode->version( memory_model::memory_order_relaxed ) == node_type::unlinked ) {
                     if ( c_RelaxedInsert )
@@ -895,7 +887,8 @@ namespace cds { namespace container {
 
         node_type * fix_height( node_type * pNode )
         {
-            node_scoped_lock l( pNode );
+            assert( pNode != nullptr );
+            node_scoped_lock l( m_Monitor, *pNode );
             return fix_height_locked( pNode );
         }
 
@@ -928,11 +921,11 @@ namespace cds { namespace container {
                     node_type * pParent = pNode->m_pParent.load( memory_model::memry_order_relaxed );
                     assert( pParent != nullptr );
                     {
-                        node_scoped_lock lp( pParent );
+                        node_scoped_lock lp( m_Monitor, *pParent );
                         if ( !pParent->is_unlinked( memory_model::memory_order_relaxed )
                              && pNode->m_pParent.load( memory_model::memory_order_relaxed ) == pParent ) 
                         {
-                            node_scoped_lock ln( pNode );
+                            node_scoped_lock ln( m_Monitor, *pNode );
                             pNode = rebalance_locked( pParent, pNode, disp );
                         }
                     }
@@ -991,7 +984,8 @@ namespace cds { namespace container {
             // If pLeft->pRight is taller than pLeft->pLeft, then we will first rotate-left pLeft.
 
             {
-                node_scoped_lock l( pLeft );
+                assert( pLeft != nullptr );
+                node_scoped_lock l( m_Monitor, *pLeft );
                 if ( pNode->m_pLeft.load( memory_model::memory_order_relaxed ) != pLeft )
                     return pNode; // retry for pNode
 
@@ -1011,7 +1005,7 @@ namespace cds { namespace container {
                 else {
                     assert( pLRight != nullptr );
                     {
-                        node_scoped_lock lr( pLRight );
+                        node_scoped_lock lr( m_Monitor, *pLRight );
                         if ( pLeft->m_pRight.load( memory_model::memory_order_relaxed ) != pLRight )
                             return pNode; // retry
 
@@ -1042,7 +1036,8 @@ namespace cds { namespace container {
 
             // pParent and pNode is locked yet
             {
-                node_scoped_lock l( pRight );
+                assert( pRight != nullptr );
+                node_scoped_lock l( m_Monitor, *pRight );
                 if ( pNode->m_pRight.load( memory_model::memory_order_relaxed ) != pRight )
                     return pNode; // retry for pNode
 
@@ -1059,7 +1054,7 @@ namespace cds { namespace container {
 
                 {
                     assert( pRLeft != nullptr );
-                    node_scoped_lock lrl( pRLeft );
+                    node_scoped_lock lrl( m_Monitor, *pRLeft );
                     if ( pRight->m_pLeft.load( memory_model::memory_order_relaxed ) != pRLeft )
                         return pNode; // retry
 
index 34c289eb3b75c9f10696ba6803b0e86e77f7214a..9c8d208dd071731d96592eba2c3ffff07842919d 100644 (file)
@@ -177,6 +177,21 @@ namespace opt {
         //@endcond
     };
 
+    /// [type-option] @ref cds_sync_monitor "Monitor" type setter
+    /**
+        This option setter specifyes @ref cds_sync_monitor "synchronization monitor"
+        for blocking container.
+    */
+    template <typename Type>
+    struct sync_monitor {
+        //@cond
+        template <class Base> struct pack : public Base
+        {
+            typedef Type sync_monitor;
+        };
+        //@endcond
+    };
+
     /// [type-option] Back-off strategy option setter
     /**
         Back-off strategy used in some algorithm.
index 7991fe2a152669e3324dc668fb643d60e71b0ed2..d7bf7c2f816ff5e6b273fd42457bfa4b61a0e90a 100644 (file)
@@ -4,6 +4,9 @@
 #define CDSLIB_SYNC_INJECTING_MONITOR_H
 
 #include <cds/sync/monitor.h>
+#ifndef CDS_CXX11_INHERITING_CTOR
+#   include <utility> // std::forward
+#endif
 
 namespace cds { namespace sync {
 
@@ -22,19 +25,26 @@ namespace cds { namespace sync {
         typedef Lock lock_type; ///< Lock type
 
         /// Monitor injection into \p Node
-        template <typename Node>
-        struct node_wrapper : public Node
+        struct node_injection
         {
+#       ifdef CDS_CXX11_INHERITING_CTOR
             using Node::Node;
+#       else
+            // Inheriting ctor emulation
+            template <typename... Args>
+            node_injection( Args&&... args )
+                : Node( std::forward<Args>( args )... )
+            {}
+#       endif
             mutable lock_type m_Lock; ///< Node-level lock
 
-            /// Makes exclusive access to the object
+            /// Makes exclusive access to the node
             void lock() const
             {
                 m_Lock.lock;
             }
 
-            /// Unlocks the object
+            /// Unlocks the node
             void unlock() const
             {
                 m_Lock.unlock();
index 008356772d1af0b0482a3a757319ad10e640e8f3..82577420f5fc4bd3c45c241ad36ab934693d098c 100644 (file)
@@ -22,9 +22,9 @@ namespace cds { namespace sync {
         When the node should be locked, the monitor is called to allocate appropriate
         lock object for the node if it's needed, and to lock the node.
         The monitor strategy can significantly reduce the number of system objects
-        required for the data structure.
+        required for data structure.
 
-        <b>Implemetatios</b>
+        <b>Implemetations</b>
 
         \p libcds contains several monitor implementations:
         - \p sync::injecting_monitor injects the lock object into each node.
@@ -45,7 +45,11 @@ namespace cds { namespace sync {
         public:
             // Monitor's injection into the Node class
             template <typename Node>
-            struct node_wrapper;
+            struct node_injection: public Node
+            {
+                // Monitor data to inject into container's node
+                // ... 
+            };
 
             // Locks the node 
             template <typename Node>
index 6e2578af5eb49fdafc63539ff1c5ddf2e7cedf63..bebbae6e628ec765007cdfff49e656bee07b4412 100644 (file)
@@ -1398,7 +1398,8 @@ PREDEFINED             = CDS_BUILD_BITS=64 \
                          CDS_CXX11_INLINE_NAMESPACE_SUPPORT \
                          CDS_CXX11_INLINE_NAMESPACE=inline \
                          CDS_NOEXCEPT=noexcept() \
-                         CDS_CONSTEXPR=constexpr
+                         CDS_CONSTEXPR=constexpr \
+                         CDS_CXX11_INHERITING_CTOR
 
 # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 
 # this tag can be used to specify a list of macro names that should be expanded.