Jack2: JackAtomicState.h Source File

Jack2 1.9.12

JackAtomicState.h
1 /*
2 Copyright (C) 2004-2008 Grame
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation; either version 2.1 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18 */
19
20 #ifndef __JackAtomicState__
21 #define __JackAtomicState__
22
23 #include "JackAtomic.h"
24 #include "JackCompilerDeps.h"
25 #include <string.h> // for memcpy
26
27 namespace Jack
28 {
29
34 PRE_PACKED_STRUCTURE
35 struct AtomicCounter
36 {
37 union {
38 struct {
39 UInt16 fShortVal1; // Cur
40 UInt16 fShortVal2; // Next
41 }
42 scounter;
43 UInt32 fLongVal;
44 }info;
45
46 AtomicCounter()
47 {
48 info.fLongVal = 0;
49 }
50
51 AtomicCounter(volatile const AtomicCounter& obj)
52 {
53 info.fLongVal = obj.info.fLongVal;
54 }
55
56 AtomicCounter(volatile AtomicCounter& obj)
57 {
58 info.fLongVal = obj.info.fLongVal;
59 }
60
61 AtomicCounter& operator=(AtomicCounter& obj)
62 {
63 info.fLongVal = obj.info.fLongVal;
64 return *this;
65 }
66
67 AtomicCounter& operator=(volatile AtomicCounter& obj)
68 {
69 info.fLongVal = obj.info.fLongVal;
70 return *this;
71 }
72
73 } POST_PACKED_STRUCTURE;
74
75 #define Counter(e) (e).info.fLongVal
76 #define CurIndex(e) (e).info.scounter.fShortVal1
77 #define NextIndex(e) (e).info.scounter.fShortVal2
78
79 #define CurArrayIndex(e) (CurIndex(e) & 0x0001)
80 #define NextArrayIndex(e) ((CurIndex(e) + 1) & 0x0001)
81
86 // CHECK livelock
87
88 PRE_PACKED_STRUCTURE
89 template <class T>
90 class JackAtomicState
91 {
92
93 protected:
94
95 T fState[2];
96 volatile AtomicCounter fCounter;
97 SInt32 fCallWriteCounter;
98
99 UInt32 WriteNextStateStartAux()
100 {
101 AtomicCounter old_val;
102 AtomicCounter new_val;
103 UInt32 cur_index;
104 UInt32 next_index;
105 bool need_copy;
106 do {
107 old_val = fCounter;
108 new_val = old_val;
109 cur_index = CurArrayIndex(new_val);
110 next_index = NextArrayIndex(new_val);
111 need_copy = (CurIndex(new_val) == NextIndex(new_val));
112 NextIndex(new_val) = CurIndex(new_val); // Invalidate next index
113 } while (!CAS(Counter(old_val), Counter(new_val), (UInt32*)&fCounter));
114 if (need_copy)
115 memcpy(&fState[next_index], &fState[cur_index], sizeof(T));
116 return next_index;
117 }
118
119 void WriteNextStateStopAux()
120 {
121 AtomicCounter old_val;
122 AtomicCounter new_val;
123 do {
124 old_val = fCounter;
125 new_val = old_val;
126 NextIndex(new_val)++; // Set next index
127 } while (!CAS(Counter(old_val), Counter(new_val), (UInt32*)&fCounter));
128 }
129
130 public:
131
132 JackAtomicState()
133 {
134 Counter(fCounter) = 0;
135 fCallWriteCounter = 0;
136 }
137
138 ~JackAtomicState() // Not virtual ??
139 {}
140
144 T* ReadCurrentState()
145 {
146 return &fState[CurArrayIndex(fCounter)];
147 }
148
152 UInt16 GetCurrentIndex()
153 {
154 return CurIndex(fCounter);
155 }
156
160 T* TrySwitchState()
161 {
162 AtomicCounter old_val;
163 AtomicCounter new_val;
164 do {
165 old_val = fCounter;
166 new_val = old_val;
167 CurIndex(new_val) = NextIndex(new_val); // Prepare switch
168 } while (!CAS(Counter(old_val), Counter(new_val), (UInt32*)&fCounter));
169 return &fState[CurArrayIndex(fCounter)]; // Read the counter again
170 }
171
175 T* TrySwitchState(bool* result)
176 {
177 AtomicCounter old_val;
178 AtomicCounter new_val;
179 do {
180 old_val = fCounter;
181 new_val = old_val;
182 *result = (CurIndex(new_val) != NextIndex(new_val));
183 CurIndex(new_val) = NextIndex(new_val); // Prepare switch
184 } while (!CAS(Counter(old_val), Counter(new_val), (UInt32*)&fCounter));
185 return &fState[CurArrayIndex(fCounter)]; // Read the counter again
186 }
187
191 T* WriteNextStateStart()
192 {
193 UInt32 next_index = (fCallWriteCounter++ == 0)
194 ? WriteNextStateStartAux()
195 : NextArrayIndex(fCounter); // We are inside a wrapping WriteNextStateStart call, NextArrayIndex can be read safely
196 return &fState[next_index];
197 }
198
202 void WriteNextStateStop()
203 {
204 if (--fCallWriteCounter == 0)
205 WriteNextStateStopAux();
206 }
207
208 bool IsPendingChange()
209 {
210 return CurIndex(fCounter) != NextIndex(fCounter);
211 }
212
213 /*
214 // Single writer : write methods get the *next* state to be updated
215 void TestWriteMethod()
216 {
217 T* state = WriteNextStateStart();
218 ......
219 ......
220 WriteNextStateStop();
221 }
222
223 // First RT call possibly switch state
224 void TestReadRTMethod1()
225 {
226 T* state = TrySwitchState();
227 ......
228 ......
229 }
230
231 // Other RT methods can safely use the current state during the *same* RT cycle
232 void TestReadRTMethod2()
233 {
234 T* state = ReadCurrentState();
235 ......
236 ......
237 }
238
239 // Non RT read methods : must check state coherency
240 void TestReadMethod()
241 {
242 T* state;
243 UInt16 cur_index;
244 UInt16 next_index = GetCurrentIndex();
245 do {
246 cur_index = next_index;
247 state = ReadCurrentState();
248
249 ......
250 ......
251
252 next_index = GetCurrentIndex();
253 } while (cur_index != next_index);
254 }
255 */
256
257 } POST_PACKED_STRUCTURE;
258
259 } // end of namespace
260
261 #endif
262
Jack::JackAtomicState::ReadCurrentState
T * ReadCurrentState()
Returns the current state : only valid in the RT reader thread.
Definition: JackAtomicState.h:144
Jack::JackAtomicState::WriteNextStateStop
void WriteNextStateStop()
Stop write operation : make the next state ready to be used by the RT thread.
Definition: JackAtomicState.h:202
Jack::JackAtomicState::WriteNextStateStart
T * WriteNextStateStart()
Start write operation : setup and returns the next state to update, check for recursive write calls.
Definition: JackAtomicState.h:191
Jack::AtomicCounter
Counter for CAS.
Definition: JackAtomicState.h:35
Jack::JackAtomicState::GetCurrentIndex
UInt16 GetCurrentIndex()
Returns the current state index.
Definition: JackAtomicState.h:152
Jack::JackAtomicState::TrySwitchState
T * TrySwitchState()
Tries to switch to the next state and returns the new current state (either the same as before if cas...
Definition: JackAtomicState.h:160
Jack::JackAtomicState
A class to handle two states (switching from one to the other) in a lock-free manner.
Definition: JackAtomicState.h:90
Jack::JackAtomicState::TrySwitchState
T * TrySwitchState(bool *result)
Tries to switch to the next state and returns the new current state (either the same as before if cas...
Definition: JackAtomicState.h:175