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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1424 - (hide annotations) (download) (as text)
Sun Oct 14 22:00:17 2007 UTC (16 years, 6 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 7620 byte(s)
* code cleanup:
- global.h now only covers global definitions that are needed for the C++
  API header files, all implementation internal global definitions are now
  in global_private.h
- atomic.h is not exposed to the C++ API anymore (replaced the references
  in SynchronizedConfig.h for this with local definitions)
- no need to include config.h anymore for using LS's API header files
- DB instruments classes are not exposed to the C++ API
- POSIX callback functions of Thread.h are hidden
- the (optional) gig Engine benchmark compiles again
- updated Doxyfile.in
- fixed warnings in API doc generation
* preparations for release 0.5.0

1 persson 840 /***************************************************************************
2     * *
3 schoenebeck 1424 * Copyright (C) 2006, 2007 Andreas Persson *
4 persson 840 * *
5     * This program is free software; you can redistribute it and/or modify *
6     * it under the terms of the GNU General Public License as published by *
7     * the Free Software Foundation; either version 2 of the License, or *
8     * (at your option) any later version. *
9     * *
10     * This program is distributed in the hope that it will be useful, *
11     * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13     * GNU General Public License for more details. *
14     * *
15     * You should have received a copy of the GNU General Public License *
16     * along with this program; if not, write to the Free Software *
17     * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, *
18     * MA 02110-1301 USA *
19     ***************************************************************************/
20    
21     #ifndef __SYNCHRONIZEDCONFIG_H__
22     #define __SYNCHRONIZEDCONFIG_H__
23    
24 persson 846 #include <set>
25 persson 840
26     namespace LinuxSampler {
27    
28     /**
29     * Thread safe management of configuration data, where the data is
30 persson 846 * updated by a single non real time thread and read by a number
31     * of real time threads.
32 persson 840 *
33     * The synchronization is achieved by using two instances of the
34     * configuration data. The non real time thread gets access to the
35 persson 846 * instance not currently in use by the real time threads by
36 persson 840 * calling GetConfigForUpdate(). After the data is updated, the
37     * non real time thread must call SwitchConfig() and redo the
38     * update on the other instance. SwitchConfig() blocks until it is
39     * safe to modify the other instance.
40     *
41 persson 846 * The real time threads need one Reader object each to access the
42 persson 1038 * configuration data. This object must be created outside the
43     * real time thread. The Lock() function returns a reference to
44     * the data to be read, and Unlock() must be called when finished
45 persson 846 * reading the data. (Neither Lock nor Unlock will block the real
46     * time thread, or use any system calls.)
47 persson 840 */
48     template<class T>
49     class SynchronizedConfig {
50 schoenebeck 1424 struct atomic_t { volatile int word; };
51    
52 persson 840 public:
53     SynchronizedConfig();
54    
55     // methods for the real time thread
56    
57 persson 846 class Reader {
58     public:
59     /**
60     * Gets the configuration object for use by the
61     * real time thread. The object is safe to use
62     * (read only) until Unlock() is called.
63     *
64     * @returns a reference to the configuration
65     * object to be read by the real time
66     * thread
67     */
68     const T& Lock() {
69 schoenebeck 1424 atomicSet(&lock, 1);
70     return parent.config[atomicRead(&parent.indexAtomic)];
71 persson 846 }
72 persson 840
73 persson 846 /**
74     * Unlock the configuration object. Unlock() must
75     * be called by the real time thread after it has
76     * finished reading the configuration object. If
77     * the non real time thread is waiting in
78     * SwitchConfig() it will be awaken when no real
79     * time threads are locked anymore.
80     */
81     void Unlock() {
82 schoenebeck 1424 atomicSet(&lock, 0);
83 persson 846 }
84 persson 840
85 persson 846 Reader(SynchronizedConfig& config);
86     ~Reader();
87     private:
88     friend class SynchronizedConfig;
89     SynchronizedConfig& parent;
90     atomic_t lock;
91     Reader *next; // only used locally in SwitchConfig
92     };
93 persson 840
94 persson 846
95 persson 840 // methods for the non real time thread
96    
97     /**
98     * Gets the configuration object for use by the non real
99     * time thread. The object returned is not in use by the
100     * real time thread, so it can safely be updated. After
101     * the update is done, the non real time thread must call
102     * SwitchConfig() and the same update must be done again.
103     *
104     * @returns a reference to the configuration object to be
105     * updated by the non real time thread
106     */
107     T& GetConfigForUpdate();
108    
109     /**
110     * Atomically switch the newly updated configuration
111     * object with the one used by the real time thread, then
112     * wait for the real time thread to finish working with
113     * the old object before returning the old object.
114     * SwitchConfig() must be called by the non real time
115     * thread after an update has been done, and the object
116     * returned must be updated in the same way as the first.
117     *
118     * @returns a reference to the configuration object to be
119     * updated by the non real time thread
120     */
121     T& SwitchConfig();
122    
123     private:
124     atomic_t indexAtomic;
125     int updateIndex;
126     T config[2];
127 persson 846 std::set<Reader*> readers;
128 schoenebeck 1424
129     static int atomicRead(atomic_t* pSharedVariable) {
130     return pSharedVariable->word;
131     }
132    
133     static void atomicSet(atomic_t* pSharedVariable, int value) {
134     pSharedVariable->word = value;
135     }
136 persson 840 };
137    
138     template<class T> SynchronizedConfig<T>::SynchronizedConfig() {
139 schoenebeck 1424 atomicSet(&indexAtomic, 0);
140 persson 846 updateIndex = 1;
141 persson 840 }
142    
143     template<class T> T& SynchronizedConfig<T>::GetConfigForUpdate() {
144     return config[updateIndex];
145     }
146    
147     template<class T> T& SynchronizedConfig<T>::SwitchConfig() {
148 schoenebeck 1424 atomicSet(&indexAtomic, updateIndex);
149 persson 846
150     // first put all locking readers in a linked list
151     Reader* lockingReaders = 0;
152     for (typename std::set<Reader*>::iterator iter = readers.begin() ;
153     iter != readers.end() ;
154     iter++) {
155 schoenebeck 1424 if (atomicRead(&(*iter)->lock)) {
156 persson 846 (*iter)->next = lockingReaders;
157     lockingReaders = *iter;
158     }
159     }
160    
161     // wait until there are no locking readers left
162     while (lockingReaders) {
163 persson 840 usleep(50000);
164 persson 846 Reader** prev = &lockingReaders;
165     for (Reader* p = lockingReaders ; p ; p = p->next) {
166 schoenebeck 1424 if (atomicRead(&p->lock)) prev = &p->next;
167 persson 846 else *prev = p->next; // unlink
168     }
169     }
170    
171     updateIndex ^= 1;
172     return config[updateIndex];
173 persson 840 }
174    
175 persson 846
176     // ----- Reader ----
177    
178     template <class T>
179     SynchronizedConfig<T>::Reader::Reader(SynchronizedConfig& config) : parent(config) {
180 schoenebeck 1424 atomicSet(&lock, 0);
181 persson 846 parent.readers.insert(this);
182     }
183    
184     template <class T>
185     SynchronizedConfig<T>::Reader::~Reader() {
186     parent.readers.erase(this);
187     }
188    
189 persson 840 } // namespace LinuxSampler
190    
191     #endif

  ViewVC Help
Powered by ViewVC