fix compiler complaints about RCU code; fix a couple of compiler warnings
[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                 x.m_rcu_value = new boost::shared_ptr<T> (new_rcu_value);
16         }
17  
18         virtual ~RCUManager() { delete x.m_rcu_value; }
19  
20         boost::shared_ptr<T> reader () const { return *((boost::shared_ptr<T> *) g_atomic_pointer_get (&x.gptr)); }
21  
22         virtual boost::shared_ptr<T> write_copy () = 0;
23         virtual bool update (boost::shared_ptr<T> new_value) = 0;
24
25   protected:
26         union {
27             boost::shared_ptr<T>* m_rcu_value;
28             volatile gpointer gptr;
29         } x;
30 };
31  
32  
33 template<class T>
34 class SerializedRCUManager : public RCUManager<T>
35 {
36 public:
37  
38         SerializedRCUManager(T* new_rcu_value)
39                 : RCUManager<T>(new_rcu_value)
40         {
41  
42         }
43  
44         boost::shared_ptr<T> write_copy ()
45         {
46                 m_lock.lock();
47
48                 // clean out any dead wood
49
50                 typename std::list<boost::shared_ptr<T> >::iterator i;
51
52                 for (i = m_dead_wood.begin(); i != m_dead_wood.end(); ) {
53                         if ((*i).use_count() == 1) {
54                                 i = m_dead_wood.erase (i);
55                         } else {
56                                 ++i;
57                         }
58                 }
59
60                 // store the current 
61
62                 current_write_old = RCUManager<T>::x.m_rcu_value;
63                 
64                 boost::shared_ptr<T> new_copy (new T(**current_write_old));
65
66                 return new_copy;
67         }
68  
69         bool update (boost::shared_ptr<T> new_value)
70         {
71                 // we hold the lock at this point effectively blocking
72                 // other writers.
73
74                 boost::shared_ptr<T>* new_spp = new boost::shared_ptr<T> (new_value);
75
76                 // update, checking that nobody beat us to it
77
78                 bool ret = g_atomic_pointer_compare_and_exchange (&RCUManager<T>::x.gptr,
79                                                                   (gpointer) current_write_old,
80                                                                   (gpointer) new_spp);
81                 
82                 if (ret) {
83
84                         // successful update : put the old value into dead_wood,
85
86                         m_dead_wood.push_back (*current_write_old);
87
88                         // now delete it - this gets rid of the shared_ptr<T> but
89                         // because dead_wood contains another shared_ptr<T> that
90                         // references the same T, the underlying object lives on
91
92                         delete current_write_old;
93                 }
94
95                 m_lock.unlock();
96
97                 return ret;
98         }
99
100         void flush () {
101                 Glib::Mutex::Lock lm (m_lock);
102                 m_dead_wood.clear ();
103         }
104  
105 private:
106         Glib::Mutex                      m_lock;
107         boost::shared_ptr<T>*            current_write_old;
108         std::list<boost::shared_ptr<T> > m_dead_wood;
109 };
110  
111 template<class T>
112 class RCUWriter
113 {
114 public:
115  
116         RCUWriter(RCUManager<T>& manager)
117                 : m_manager(manager)
118         {
119                 m_copy = m_manager.write_copy();        
120         }
121  
122         ~RCUWriter()
123         {
124                 // we can check here that the refcount of m_copy is 1
125  
126                 if(m_copy.use_count() == 1) {
127                         m_manager.update(m_copy);
128                 } else {
129  
130                         // critical error.
131                 }
132  
133         }
134  
135         // or operator boost::shared_ptr<T> ();
136         boost::shared_ptr<T> get_copy() { return m_copy; }
137  
138 private:
139  
140         RCUManager<T>& m_manager;
141  
142         // preferably this holds a pointer to T
143         boost::shared_ptr<T> m_copy;
144 };
145
146 #endif /* __pbd_rcu_h__ */