Dmitry Baikov patch for JackGraphManager.cpp.
[jack2.git] / common / JackAtomicState.h
blob9e140d3eb9e2ceb1343186d12fe836188c80dfe3
1 /*
2 Copyright (C) 2004-2006 Grame
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
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 General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #ifndef __JackAtomicState__
21 #define __JackAtomicState__
23 #include "JackAtomic.h"
24 #include <string.h> // for memcpy
26 namespace Jack
29 /*!
30 \brief Counter for CAS
33 struct AtomicCounter
35 union {
36 struct {
37 UInt16 fShortVal1; // Cur
38 UInt16 fShortVal2; // Next
40 scounter;
41 UInt32 fLongVal;
42 }info;
44 AtomicCounter& operator=(volatile AtomicCounter& obj)
46 info.fLongVal = obj.info.fLongVal;
47 return *this;
53 #define Counter(e) (e).info.fLongVal
54 #define CurIndex(e) (e).info.scounter.fShortVal1
55 #define NextIndex(e) (e).info.scounter.fShortVal2
57 #define CurArrayIndex(e) (CurIndex(e) & 0x0001)
58 #define NextArrayIndex(e) ((CurIndex(e) + 1) & 0x0001)
60 /*!
61 \brief A class to handle two states (switching from one to the other) in a lock-free manner
64 // CHECK livelock
66 template <class T>
67 class JackAtomicState
70 protected:
72 T fState[2];
73 volatile AtomicCounter fCounter;
74 SInt32 fCallWriteCounter;
76 UInt32 WriteNextStateStartAux()
78 AtomicCounter old_val;
79 AtomicCounter new_val;
80 UInt32 cur_index;
81 UInt32 next_index;
82 bool need_copy;
83 do {
84 old_val = fCounter;
85 new_val = old_val;
86 cur_index = CurArrayIndex(new_val);
87 next_index = NextArrayIndex(new_val);
88 need_copy = (CurIndex(new_val) == NextIndex(new_val));
89 NextIndex(new_val) = CurIndex(new_val); // Invalidate next index
90 } while (!CAS(Counter(old_val), Counter(new_val), (UInt32*)&fCounter));
91 if (need_copy)
92 memcpy(&fState[next_index], &fState[cur_index], sizeof(T));
93 return next_index;
96 void WriteNextStateStopAux()
98 AtomicCounter old_val;
99 AtomicCounter new_val;
100 do {
101 old_val = fCounter;
102 new_val = old_val;
103 NextIndex(new_val)++; // Set next index
104 } while (!CAS(Counter(old_val), Counter(new_val), (UInt32*)&fCounter));
107 public:
109 JackAtomicState()
111 Counter(fCounter) = 0;
112 fCallWriteCounter = 0;
115 ~JackAtomicState() // Not virtual ??
119 \brief Returns the current state : only valid in the RT reader thread
121 T* ReadCurrentState()
123 return &fState[CurArrayIndex(fCounter)];
127 \brief Returns the current state index
129 UInt16 GetCurrentIndex()
131 return CurIndex(fCounter);
135 \brief Tries to switch to the next state and returns the new current state (either the same as before if case of switch failure or the new one)
137 T* TrySwitchState()
139 AtomicCounter old_val;
140 AtomicCounter new_val;
141 do {
142 old_val = fCounter;
143 new_val = old_val;
144 CurIndex(new_val) = NextIndex(new_val); // Prepare switch
145 } while (!CAS(Counter(old_val), Counter(new_val), (UInt32*)&fCounter));
146 return &fState[CurArrayIndex(fCounter)]; // Read the counter again
150 \brief Tries to switch to the next state and returns the new current state (either the same as before if case of switch failure or the new one)
152 T* TrySwitchState(bool* result)
154 AtomicCounter old_val;
155 AtomicCounter new_val;
156 do {
157 old_val = fCounter;
158 new_val = old_val;
159 *result = (CurIndex(new_val) != NextIndex(new_val));
160 CurIndex(new_val) = NextIndex(new_val); // Prepare switch
161 } while (!CAS(Counter(old_val), Counter(new_val), (UInt32*)&fCounter));
162 return &fState[CurArrayIndex(fCounter)]; // Read the counter again
166 \brief Start write operation : setup and returns the next state to update, check for recursive write calls.
168 T* WriteNextStateStart()
170 UInt32 next_index = (fCallWriteCounter++ == 0)
171 ? WriteNextStateStartAux()
172 : NextArrayIndex(fCounter); // We are inside a wrapping WriteNextStateStart call, NextArrayIndex can be read safely
173 return &fState[next_index];
177 \brief Stop write operation : make the next state ready to be used by the RT thread
179 void WriteNextStateStop()
181 if (--fCallWriteCounter == 0)
182 WriteNextStateStopAux();
185 bool IsPendingChange()
187 return CurIndex(fCounter) != NextIndex(fCounter);
191 // Single writer : write methods get the *next* state to be updated
192 void TestWriteMethod()
194 T* state = WriteNextStateStart();
195 ......
196 ......
197 WriteNextStateStop();
200 // First RT call possibly switch state
201 void TestReadRTMethod1()
203 T* state = TrySwitchState();
204 ......
205 ......
208 // Other RT methods can safely use the current state during the *same* RT cycle
209 void TestReadRTMethod2()
211 T* state = ReadCurrentState();
212 ......
213 ......
216 // Non RT read methods : must check state coherency
217 void TestReadMethod()
219 T* state;
220 UInt16 cur_index;
221 UInt16 next_index = GetCurrentIndex();
222 do {
223 cur_index = next_index;
224 state = ReadCurrentState();
226 ......
227 ......
229 next_index = GetCurrentIndex();
230 } while (cur_index != next_index);
236 } // end of namespace
239 #endif