6d9586cb3c6bfc68b7be43b762d8da92f2f3c834
[ardour.git] / libs / pbd / pbd / rcu.h
1 #ifndef __pbd_rcu_h__
2 #define __pbd_rcu_h__
3
4 #include "boost/shared_ptr.hpp"
5 #include "glibmm/thread.h"
6  
7 #include <list> 
8  
9 template<class T>
10 class RCUManager
11 {
12 public:
13  
14         RCUManager (T* new_rcu_value)
15                 : m_rcu_value(new_rcu_value)
16         {
17  
18         }
19  
20         virtual ~RCUManager() { }
21  
22         boost::shared_ptr<T> reader () const { return m_rcu_value; }
23  
24         // should be private
25         virtual boost::shared_ptr<T> write_copy () = 0;
26  
27         // should be private
28         virtual void update (boost::shared_ptr<T> new_value) = 0;
29  
30 protected:
31  
32         boost::shared_ptr<T> m_rcu_value;
33  
34  
35 };
36  
37  
38 template<class T>
39 class SerializedRCUManager : public RCUManager<T>
40 {
41 public:
42  
43         SerializedRCUManager(T* new_rcu_value)
44                 : RCUManager<T>(new_rcu_value)
45         {
46  
47         }
48  
49         virtual boost::shared_ptr<T> write_copy ()
50         {
51                 m_lock.lock();
52  
53                 // I hope this is doing what I think it is doing :)
54                 boost::shared_ptr<T> new_copy(new T(*RCUManager<T>::m_rcu_value));
55  
56                 // XXX todo remove old copies with only 1 reference from the list.
57  
58                 return new_copy;
59         }
60  
61         virtual void update (boost::shared_ptr<T> new_value)
62         {
63                 // So a current reader doesn't hold the only reference to
64                 // the existing value when we assign it a new value which 
65                 // should ensure that deletion of old values doesn't
66                 // occur in a reader thread.
67                 boost::shared_ptr<T> old_copy = RCUManager<T>::m_rcu_value;
68  
69                 // we hold the lock at this point effectively blocking
70                 // other writers.
71                 RCUManager<T>::m_rcu_value = new_value;
72  
73  
74                 // XXX add the old value to the list of old copies.
75  
76                 m_lock.unlock();
77         }
78  
79 private:
80         Glib::Mutex                     m_lock;
81  
82         std::list<boost::shared_ptr<T> > m_old_values;
83 };
84  
85 template<class T>
86 class RCUWriter
87 {
88 public:
89  
90         RCUWriter(RCUManager<T>& manager)
91                 : m_manager(manager)
92         {
93                 m_copy = m_manager.write_copy();        
94         }
95  
96         ~RCUWriter()
97         {
98                 // we can check here that the refcount of m_copy is 1
99  
100                 if(m_copy.use_count() == 1) {
101                         m_manager.update(m_copy);
102                 } else {
103  
104                         // critical error.
105                 }
106  
107         }
108  
109         // or operator boost::shared_ptr<T> ();
110         boost::shared_ptr<T> get_copy() { return m_copy; }
111  
112 private:
113  
114         RCUManager<T>& m_manager;
115  
116         // preferably this holds a pointer to T
117         boost::shared_ptr<T> m_copy;
118 };
119
120 #endif /* __pbd_rcu_h__ */