From b1846a578d1bb4e7c92bb380bbbc7740e4a35a75 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Tue, 10 Nov 2020 17:02:26 +0100 Subject: [PATCH] NO-OP: whitespace, doxygen formatting and naming --- libs/pbd/pbd/rcu.h | 279 ++++++++++++++++++++++++--------------------- 1 file changed, 146 insertions(+), 133 deletions(-) diff --git a/libs/pbd/pbd/rcu.h b/libs/pbd/pbd/rcu.h index aae187e6b8..b5e513d4e2 100644 --- a/libs/pbd/pbd/rcu.h +++ b/libs/pbd/pbd/rcu.h @@ -47,125 +47,129 @@ * The RCU manager will manage the various instances of "the managed object" in a way that is transparent to users of the manager * and managed object. */ -template +template class /*LIBPBD_API*/ RCUManager { - public: - - RCUManager (T* new_rcu_value) : active_reads(0) { - x.m_rcu_value = new boost::shared_ptr (new_rcu_value); +public: + RCUManager (T* new_rcu_value) + : active_reads (0) + { + x.rcu_value = new boost::shared_ptr (new_rcu_value); } - virtual ~RCUManager() { delete x.m_rcu_value; } + virtual ~RCUManager () + { + delete x.rcu_value; + } - boost::shared_ptr reader () const { + boost::shared_ptr reader () const + { boost::shared_ptr rv; - // Keep count of any readers in this section of code, so writers can - // wait until m_rcu_value is no longer in use after an atomic exchange - // before dropping it. - g_atomic_int_inc(&active_reads); - rv = *((boost::shared_ptr *) g_atomic_pointer_get (&x.gptr)); - g_atomic_int_dec_and_test(&active_reads); + /* Keep count of any readers in this section of code, so writers can + * wait until rcu_value is no longer in use after an atomic exchange + * before dropping it. + */ + g_atomic_int_inc (&active_reads); + rv = *((boost::shared_ptr*)g_atomic_pointer_get (&x.gptr)); + g_atomic_int_dec_and_test (&active_reads); return rv; } /* this is an abstract base class - how these are implemented depends on the assumptions - that one can make about the users of the RCUManager. See SerializedRCUManager below - for one implementation. - */ + * that one can make about the users of the RCUManager. See SerializedRCUManager below + * for one implementation. + */ - virtual boost::shared_ptr write_copy () = 0; - virtual bool update (boost::shared_ptr new_value) = 0; + virtual boost::shared_ptr write_copy () = 0; + virtual bool update (boost::shared_ptr new_value) = 0; - protected: +protected: /* ordinarily this would simply be a declaration of a ptr to a shared_ptr. however, the atomic - operations that we are using (from glib) have sufficiently strict typing that it proved hard - to get them to accept even a cast value of the ptr-to-shared-ptr() as the argument to get() - and comp_and_exchange(). Consequently, we play a litle trick here that relies on the fact - that sizeof(A*) == sizeof(B*) no matter what the types of A and B are. for most purposes - we will use x.m_rcu_value, but when we need to use an atomic op, we use x.gptr. Both expressions - evaluate to the same address. + * operations that we are using (from glib) have sufficiently strict typing that it proved hard + * to get them to accept even a cast value of the ptr-to-shared-ptr() as the argument to get() + * and comp_and_exchange(). Consequently, we play a litle trick here that relies on the fact + * that sizeof(A*) == sizeof(B*) no matter what the types of A and B are. for most purposes + * we will use x.rcu_value, but when we need to use an atomic op, we use x.gptr. Both expressions + * evaluate to the same address. */ union { - boost::shared_ptr* m_rcu_value; - mutable volatile gpointer gptr; + boost::shared_ptr* rcu_value; + mutable volatile gpointer gptr; } x; mutable volatile gint active_reads; }; - /** Serialized RCUManager implements the RCUManager interface. It is based on the - following key assumption: among its users we have readers that are bound by - RT time constraints, and writers who are not. Therefore, we do not care how - slow the write_copy()/update() operations are, or what synchronization - primitives they use. - - Because of this design assumption, this class will serialize all - writers. That is, objects calling write_copy()/update() will be serialized by - a mutex. Only a single writer may be in the middle of write_copy()/update(); - all other writers will block until the first has finished. The order of - execution of multiple writers if more than one is blocked in this way is - undefined. - - The class maintains a lock-protected "dead wood" list of old value of - *m_rcu_value (i.e. shared_ptr). The list is cleaned up every time we call - write_copy(). If the list is the last instance of a shared_ptr that - references the object (determined by shared_ptr::unique()) then we - erase it from the list, thus deleting the object it points to. This is lazy - destruction - the SerializedRCUManager assumes that there will sufficient - calls to write_copy() to ensure that we do not inadvertently leave objects - around for excessive periods of time. - - For extremely well defined circumstances (i.e. it is known that there are no - other writer objects in existence), SerializedRCUManager also provides a - flush() method that will unconditionally clear out the "dead wood" list. It - must be used with significant caution, although the use of shared_ptr - means that no actual objects will be deleted incorrectly if this is misused. -*/ -template + * following key assumption: among its users we have readers that are bound by + * RT time constraints, and writers who are not. Therefore, we do not care how + * slow the write_copy()/update() operations are, or what synchronization + * primitives they use. + * + * Because of this design assumption, this class will serialize all + * writers. That is, objects calling write_copy()/update() will be serialized by + * a mutex. Only a single writer may be in the middle of write_copy()/update(); + * all other writers will block until the first has finished. The order of + * execution of multiple writers if more than one is blocked in this way is + * undefined. + * + * The class maintains a lock-protected "dead wood" list of old value of + * *rcu_value (i.e. shared_ptr). The list is cleaned up every time we call + * write_copy(). If the list is the last instance of a shared_ptr that + * references the object (determined by shared_ptr::unique()) then we + * erase it from the list, thus deleting the object it points to. This is lazy + * destruction - the SerializedRCUManager assumes that there will sufficient + * calls to write_copy() to ensure that we do not inadvertently leave objects + * around for excessive periods of time. + * + * For extremely well defined circumstances (i.e. it is known that there are no + * other writer objects in existence), SerializedRCUManager also provides a + * flush() method that will unconditionally clear out the "dead wood" list. It + * must be used with significant caution, although the use of shared_ptr + * means that no actual objects will be deleted incorrectly if this is misused. + */ +template class /*LIBPBD_API*/ SerializedRCUManager : public RCUManager { public: - - SerializedRCUManager(T* new_rcu_value) - : RCUManager(new_rcu_value) + SerializedRCUManager (T* new_rcu_value) + : RCUManager (new_rcu_value) { } boost::shared_ptr write_copy () { - m_lock.lock(); + _lock.lock (); // clean out any dead wood typename std::list >::iterator i; - for (i = m_dead_wood.begin(); i != m_dead_wood.end(); ) { - if ((*i).unique()) { - i = m_dead_wood.erase (i); + for (i = _dead_wood.begin (); i != _dead_wood.end ();) { + if ((*i).unique ()) { + i = _dead_wood.erase (i); } else { ++i; } } /* store the current so that we can do compare and exchange - when someone calls update(). Notice that we hold - a lock, so this store of m_rcu_value is atomic. - */ + * when someone calls update(). Notice that we hold + * a lock, so this store of rcu_value is atomic. + */ - current_write_old = RCUManager::x.m_rcu_value; + _current_write_old = RCUManager::x.rcu_value; - boost::shared_ptr new_copy (new T(**current_write_old)); + boost::shared_ptr new_copy (new T (**_current_write_old)); return new_copy; /* notice that the write lock is still held: update() MUST - be called or we will cause another writer to stall. - */ + * be called or we will cause another writer to stall. + */ } bool update (boost::shared_ptr new_value) @@ -175,113 +179,122 @@ public: boost::shared_ptr* new_spp = new boost::shared_ptr (new_value); /* update, by atomic compare&swap. Only succeeds if the old - value has not been changed. - - XXX but how could it? we hold the freakin' lock! + * value has not been changed. + * + * XXX but how could it? we hold the freakin' lock! */ bool ret = g_atomic_pointer_compare_and_exchange (&RCUManager::x.gptr, - (gpointer) current_write_old, - (gpointer) new_spp); + (gpointer)_current_write_old, + (gpointer)new_spp); if (ret) { + /* successful update + * + * wait until there are no active readers. This ensures that any + * references to the old value have been fully copied into a new + * shared_ptr, and thus have had their reference count incremented. + */ - // successful update - - // wait until there are no active readers. This ensures that any - // references to the old value have been fully copied into a new - // shared_ptr, and thus have had their reference count incremented. - - for (unsigned i = 0; g_atomic_int_get(&(RCUManager::active_reads)) != 0; ++i) { + for (unsigned i = 0; g_atomic_int_get (&(RCUManager::active_reads)) != 0; ++i) { // spin being nice to the scheduler/CPU - boost::detail::yield(i); + boost::detail::yield (i); } - // if we are not the only user, put the old value into dead_wood. - // if we are the only user, then it is safe to drop it here. + /* if we are not the only user, put the old value into dead_wood. + * if we are the only user, then it is safe to drop it here. + */ - if (!current_write_old->unique()) { - m_dead_wood.push_back (*current_write_old); + if (!_current_write_old->unique ()) { + _dead_wood.push_back (*_current_write_old); } - // now delete it - if we are the only user, this deletes the - // underlying object. if other users existed, then there will - // be an extra reference in m_dead_wood, ensuring that the - // underlying object lives on even when the other users - // are done with it + /* now delete it - if we are the only user, this deletes the + * underlying object. if other users existed, then there will + * be an extra reference in _dead_wood, ensuring that the + * underlying object lives on even when the other users + * are done with it + */ - delete current_write_old; + delete _current_write_old; } /* unlock, allowing other writers to proceed */ - m_lock.unlock(); + _lock.unlock (); return ret; } - void flush () { - Glib::Threads::Mutex::Lock lm (m_lock); - m_dead_wood.clear (); + void flush () + { + Glib::Threads::Mutex::Lock lm (_lock); + _dead_wood.clear (); } private: - Glib::Threads::Mutex m_lock; - boost::shared_ptr* current_write_old; - std::list > m_dead_wood; + Glib::Threads::Mutex _lock; + boost::shared_ptr* _current_write_old; + std::list > _dead_wood; }; /** RCUWriter is a convenience object that implements write_copy/update via - lifetime management. Creating the object obtains a writable copy, which can - be obtained via the get_copy() method; deleting the object will update - the manager's copy. Code doing a write/update thus looks like: - - { - - RCUWriter writer (object_manager); - boost::shared_ptr copy = writer.get_copy(); - ... modify copy ... - - } <= writer goes out of scope, update invoked - + * lifetime management. Creating the object obtains a writable copy, which can + * be obtained via the get_copy() method; deleting the object will update + * the manager's copy. Code doing a write/update thus looks like: + * + * @code + * { + * RCUWriter writer (object_manager); + * boost::shared_ptr copy = writer.get_copy(); + * ... modify copy ... + * + * } <= writer goes out of scope, update invoked + * @endcode + * */ -template +template class /*LIBPBD_API*/ RCUWriter { public: + RCUWriter (RCUManager& manager) + : _manager (manager) + , _copy (_manager.write_copy ()) + { + } - RCUWriter(RCUManager& manager) - : m_manager(manager) - , m_copy (m_manager.write_copy()) {} - - ~RCUWriter() { - if (m_copy.unique()) { + ~RCUWriter () + { + if (_copy.unique ()) { /* As intended, our copy is the only reference - to the object pointed to by m_copy. Update + to the object pointed to by _copy. Update the manager with the (presumed) modified version. */ - m_manager.update(m_copy); + _manager.update (_copy); } else { /* This means that some other object is using our copy - of the object. This can only happen if the scope in - which this RCUWriter exists passed it to a function - that created a persistent reference to it, since the - copy was private to this particular RCUWriter. Doing - so will not actually break anything but it violates - the design intention here and so we do not bother to - update the manager's copy. - - XXX should we print a warning about this? + * of the object. This can only happen if the scope in + * which this RCUWriter exists passed it to a function + * that created a persistent reference to it, since the + * copy was private to this particular RCUWriter. Doing + * so will not actually break anything but it violates + * the design intention here and so we do not bother to + * update the manager's copy. + * + * XXX should we print a warning about this? */ } } - boost::shared_ptr get_copy() const { return m_copy; } + boost::shared_ptr get_copy () const + { + return _copy; + } private: - RCUManager& m_manager; - boost::shared_ptr m_copy; + RCUManager& _manager; + boost::shared_ptr _copy; }; #endif /* __pbd_rcu_h__ */