/[svn]/linuxsampler/trunk/src/common/SynchronizedConfig.h
ViewVC logotype

Diff of /linuxsampler/trunk/src/common/SynchronizedConfig.h

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 845 by persson, Sun Feb 26 13:00:08 2006 UTC revision 846 by persson, Sun Mar 19 16:38:22 2006 UTC
# Line 22  Line 22 
22  #define __SYNCHRONIZEDCONFIG_H__  #define __SYNCHRONIZEDCONFIG_H__
23    
24  #include "atomic.h"  #include "atomic.h"
25    #include <set>
26    
27  namespace LinuxSampler {  namespace LinuxSampler {
28    
29      /**      /**
30       * Thread safe management of configuration data, where the data is       * Thread safe management of configuration data, where the data is
31       * updated by a single non real time thread and read by a single       * updated by a single non real time thread and read by a number
32       * real time thread.       * of real time threads.
33       *       *
34       * The synchronization is achieved by using two instances of the       * The synchronization is achieved by using two instances of the
35       * configuration data. The non real time thread gets access to the       * configuration data. The non real time thread gets access to the
36       * instance not currently in use by the real time thread by       * instance not currently in use by the real time threads by
37       * calling GetConfigForUpdate(). After the data is updated, the       * calling GetConfigForUpdate(). After the data is updated, the
38       * non real time thread must call SwitchConfig() and redo the       * non real time thread must call SwitchConfig() and redo the
39       * update on the other instance. SwitchConfig() blocks until it is       * update on the other instance. SwitchConfig() blocks until it is
40       * safe to modify the other instance.       * safe to modify the other instance.
41       *       *
42       * The real time thread calls Lock() to get access to the data,       * The real time threads need one Reader object each to access the
43       * and Unlock() when it is finished reading the data. (Neither       * confuration data. This object must be created outside the real
44       * Lock nor Unlock will block the real time thread, or use any       * time thread. The Lock() function returns a reference to the
45       * system calls.)       * data to be read, and Unlock() must be called when finished
46         * reading the data. (Neither Lock nor Unlock will block the real
47         * time thread, or use any system calls.)
48       */       */
49      template<class T>      template<class T>
50      class SynchronizedConfig {      class SynchronizedConfig {
# Line 50  namespace LinuxSampler { Line 53  namespace LinuxSampler {
53    
54              // methods for the real time thread              // methods for the real time thread
55    
56              /**              class Reader {
57               * Gets the configuration object for use by the real time                  public:
58               * thread. The object is safe to use (read only) until                      /**
59               * Unlock() is called.                       * Gets the configuration object for use by the
60               *                       * real time thread. The object is safe to use
61               * @returns a reference to the configuration object to be                       * (read only) until Unlock() is called.
62               *          read by the real time thread                       *
63               */                       * @returns a reference to the configuration
64              const T& Lock() {                       *          object to be read by the real time
65                  atomic_set(&lock, 1);                       *          thread
66                  return config[atomic_read(&indexAtomic)];                       */
67              }                      const T& Lock() {
68                            atomic_set(&lock, 1);
69              /**                          return parent.config[atomic_read(&parent.indexAtomic)];
70               * Unlock the configuration object. Unlock() must be                      }
71               * called by the real time thread after it has finished  
72               * reading the configuration object. If the non real time                      /**
73               * thread is waiting in SwitchConfig() it will be awaken.                       * Unlock the configuration object. Unlock() must
74               */                       * be called by the real time thread after it has
75              void Unlock() {                       * finished reading the configuration object. If
76                  atomic_set(&lock, 0);                       * the non real time thread is waiting in
77              }                       * SwitchConfig() it will be awaken when no real
78                         * time threads are locked anymore.
79                         */
80                        void Unlock() {
81                            atomic_set(&lock, 0);
82                        }
83    
84                        Reader(SynchronizedConfig& config);
85                        ~Reader();
86                    private:
87                        friend class SynchronizedConfig;
88                        SynchronizedConfig& parent;
89                        atomic_t lock;
90                        Reader *next; // only used locally in SwitchConfig
91                };
92    
93    
94              // methods for the non real time thread              // methods for the non real time thread
# Line 103  namespace LinuxSampler { Line 120  namespace LinuxSampler {
120              T& SwitchConfig();              T& SwitchConfig();
121    
122          private:          private:
             atomic_t lock;  
123              atomic_t indexAtomic;              atomic_t indexAtomic;
124              int updateIndex;              int updateIndex;
125              T config[2];              T config[2];
126                std::set<Reader*> readers;
127      };      };
128    
129      template<class T> SynchronizedConfig<T>::SynchronizedConfig() {      template<class T> SynchronizedConfig<T>::SynchronizedConfig() {
         atomic_set(&lock, 0);  
130          atomic_set(&indexAtomic, 0);          atomic_set(&indexAtomic, 0);
131            updateIndex = 1;
132      }      }
133    
134      template<class T> T& SynchronizedConfig<T>::GetConfigForUpdate() {      template<class T> T& SynchronizedConfig<T>::GetConfigForUpdate() {
         updateIndex = atomic_read(&indexAtomic) ^ 1;  
135          return config[updateIndex];          return config[updateIndex];
136      }      }
137    
138      template<class T> T& SynchronizedConfig<T>::SwitchConfig() {      template<class T> T& SynchronizedConfig<T>::SwitchConfig() {
139          atomic_set(&indexAtomic, updateIndex);          atomic_set(&indexAtomic, updateIndex);
140          while (atomic_read(&lock))  
141            // first put all locking readers in a linked list
142            Reader* lockingReaders = 0;
143            for (typename std::set<Reader*>::iterator iter = readers.begin() ;
144                 iter != readers.end() ;
145                 iter++) {
146                if (atomic_read(&(*iter)->lock)) {
147                    (*iter)->next = lockingReaders;
148                    lockingReaders = *iter;
149                }
150            }
151    
152            // wait until there are no locking readers left
153            while (lockingReaders) {
154              usleep(50000);              usleep(50000);
155          return config[updateIndex ^ 1];              Reader** prev = &lockingReaders;
156                for (Reader* p = lockingReaders ; p ; p = p->next) {
157                    if (atomic_read(&p->lock)) prev = &p->next;
158                    else *prev = p->next; // unlink
159                }
160            }
161    
162            updateIndex ^= 1;
163            return config[updateIndex];
164        }
165    
166    
167        // ----- Reader ----
168    
169        template <class T>
170        SynchronizedConfig<T>::Reader::Reader(SynchronizedConfig& config) : parent(config) {
171            atomic_set(&lock, 0);
172            parent.readers.insert(this);
173        }
174    
175        template <class T>
176        SynchronizedConfig<T>::Reader::~Reader() {
177            parent.readers.erase(this);
178      }      }
179    
180  } // namespace LinuxSampler  } // namespace LinuxSampler

Legend:
Removed from v.845  
changed lines
  Added in v.846

  ViewVC Help
Powered by ViewVC