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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1424 - (show annotations) (download) (as text)
Sun Oct 14 22:00:17 2007 UTC (16 years, 7 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 /***************************************************************************
2 * *
3 * Copyright (C) 2006, 2007 Andreas Persson *
4 * *
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 #include <set>
25
26 namespace LinuxSampler {
27
28 /**
29 * Thread safe management of configuration data, where the data is
30 * updated by a single non real time thread and read by a number
31 * of real time threads.
32 *
33 * The synchronization is achieved by using two instances of the
34 * configuration data. The non real time thread gets access to the
35 * instance not currently in use by the real time threads by
36 * 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 * The real time threads need one Reader object each to access the
42 * 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 * reading the data. (Neither Lock nor Unlock will block the real
46 * time thread, or use any system calls.)
47 */
48 template<class T>
49 class SynchronizedConfig {
50 struct atomic_t { volatile int word; };
51
52 public:
53 SynchronizedConfig();
54
55 // methods for the real time thread
56
57 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 atomicSet(&lock, 1);
70 return parent.config[atomicRead(&parent.indexAtomic)];
71 }
72
73 /**
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 atomicSet(&lock, 0);
83 }
84
85 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
94
95 // 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 std::set<Reader*> readers;
128
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 };
137
138 template<class T> SynchronizedConfig<T>::SynchronizedConfig() {
139 atomicSet(&indexAtomic, 0);
140 updateIndex = 1;
141 }
142
143 template<class T> T& SynchronizedConfig<T>::GetConfigForUpdate() {
144 return config[updateIndex];
145 }
146
147 template<class T> T& SynchronizedConfig<T>::SwitchConfig() {
148 atomicSet(&indexAtomic, updateIndex);
149
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 if (atomicRead(&(*iter)->lock)) {
156 (*iter)->next = lockingReaders;
157 lockingReaders = *iter;
158 }
159 }
160
161 // wait until there are no locking readers left
162 while (lockingReaders) {
163 usleep(50000);
164 Reader** prev = &lockingReaders;
165 for (Reader* p = lockingReaders ; p ; p = p->next) {
166 if (atomicRead(&p->lock)) prev = &p->next;
167 else *prev = p->next; // unlink
168 }
169 }
170
171 updateIndex ^= 1;
172 return config[updateIndex];
173 }
174
175
176 // ----- Reader ----
177
178 template <class T>
179 SynchronizedConfig<T>::Reader::Reader(SynchronizedConfig& config) : parent(config) {
180 atomicSet(&lock, 0);
181 parent.readers.insert(this);
182 }
183
184 template <class T>
185 SynchronizedConfig<T>::Reader::~Reader() {
186 parent.readers.erase(this);
187 }
188
189 } // namespace LinuxSampler
190
191 #endif

  ViewVC Help
Powered by ViewVC