Aggregate device code added to JackCoreAudioAdapter.
[jack2.git] / common / JackAtomicState.h
blobeaf164ee5a4e5257d3767fd218555151fd7a3108
1 /*
2 Copyright (C) 2004-2008 Grame
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.
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.
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.
20 #ifndef __JackAtomicState__
21 #define __JackAtomicState__
23 #include "JackAtomic.h"
24 #include "JackCompilerDeps.h"
25 #include <string.h> // for memcpy
27 namespace Jack
30 /*!
31 \brief Counter for CAS
34 struct AtomicCounter
36 union {
37 struct {
38 UInt16 fShortVal1; // Cur
39 UInt16 fShortVal2; // Next
41 scounter;
42 UInt32 fLongVal;
43 }info;
45 AtomicCounter()
47 info.fLongVal = 0;
50 AtomicCounter(volatile const AtomicCounter& obj)
52 info.fLongVal = obj.info.fLongVal;
55 AtomicCounter(volatile AtomicCounter& obj)
57 info.fLongVal = obj.info.fLongVal;
60 AtomicCounter& operator=(AtomicCounter& obj)
62 info.fLongVal = obj.info.fLongVal;
63 return *this;
66 AtomicCounter& operator=(volatile AtomicCounter& obj)
68 info.fLongVal = obj.info.fLongVal;
69 return *this;
72 } POST_PACKED_STRUCTURE;
74 #define Counter(e) (e).info.fLongVal
75 #define CurIndex(e) (e).info.scounter.fShortVal1
76 #define NextIndex(e) (e).info.scounter.fShortVal2
78 #define CurArrayIndex(e) (CurIndex(e) & 0x0001)
79 #define NextArrayIndex(e) ((CurIndex(e) + 1) & 0x0001)
81 /*!
82 \brief A class to handle two states (switching from one to the other) in a lock-free manner
85 // CHECK livelock
87 template <class T>
88 class JackAtomicState
91 protected:
93 T fState[2];
94 volatile AtomicCounter fCounter;
95 SInt32 fCallWriteCounter;
97 UInt32 WriteNextStateStartAux()
99 AtomicCounter old_val;
100 AtomicCounter new_val;
101 UInt32 cur_index;
102 UInt32 next_index;
103 bool need_copy;
104 do {
105 old_val = fCounter;
106 new_val = old_val;
107 cur_index = CurArrayIndex(new_val);
108 next_index = NextArrayIndex(new_val);
109 need_copy = (CurIndex(new_val) == NextIndex(new_val));
110 NextIndex(new_val) = CurIndex(new_val); // Invalidate next index
111 } while (!CAS(Counter(old_val), Counter(new_val), (UInt32*)&fCounter));
112 if (need_copy)
113 memcpy(&fState[next_index], &fState[cur_index], sizeof(T));
114 return next_index;
117 void WriteNextStateStopAux()
119 AtomicCounter old_val;
120 AtomicCounter new_val;
121 do {
122 old_val = fCounter;
123 new_val = old_val;
124 NextIndex(new_val)++; // Set next index
125 } while (!CAS(Counter(old_val), Counter(new_val), (UInt32*)&fCounter));
128 public:
130 JackAtomicState()
132 Counter(fCounter) = 0;
133 fCallWriteCounter = 0;
136 ~JackAtomicState() // Not virtual ??
140 \brief Returns the current state : only valid in the RT reader thread
142 T* ReadCurrentState()
144 return &fState[CurArrayIndex(fCounter)];
148 \brief Returns the current state index
150 UInt16 GetCurrentIndex()
152 return CurIndex(fCounter);
156 \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)
158 T* TrySwitchState()
160 AtomicCounter old_val;
161 AtomicCounter new_val;
162 do {
163 old_val = fCounter;
164 new_val = old_val;
165 CurIndex(new_val) = NextIndex(new_val); // Prepare switch
166 } while (!CAS(Counter(old_val), Counter(new_val), (UInt32*)&fCounter));
167 return &fState[CurArrayIndex(fCounter)]; // Read the counter again
171 \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)
173 T* TrySwitchState(bool* result)
175 AtomicCounter old_val;
176 AtomicCounter new_val;
177 do {
178 old_val = fCounter;
179 new_val = old_val;
180 *result = (CurIndex(new_val) != NextIndex(new_val));
181 CurIndex(new_val) = NextIndex(new_val); // Prepare switch
182 } while (!CAS(Counter(old_val), Counter(new_val), (UInt32*)&fCounter));
183 return &fState[CurArrayIndex(fCounter)]; // Read the counter again
187 \brief Start write operation : setup and returns the next state to update, check for recursive write calls.
189 T* WriteNextStateStart()
191 UInt32 next_index = (fCallWriteCounter++ == 0)
192 ? WriteNextStateStartAux()
193 : NextArrayIndex(fCounter); // We are inside a wrapping WriteNextStateStart call, NextArrayIndex can be read safely
194 return &fState[next_index];
198 \brief Stop write operation : make the next state ready to be used by the RT thread
200 void WriteNextStateStop()
202 if (--fCallWriteCounter == 0)
203 WriteNextStateStopAux();
206 bool IsPendingChange()
208 return CurIndex(fCounter) != NextIndex(fCounter);
212 // Single writer : write methods get the *next* state to be updated
213 void TestWriteMethod()
215 T* state = WriteNextStateStart();
216 ......
217 ......
218 WriteNextStateStop();
221 // First RT call possibly switch state
222 void TestReadRTMethod1()
224 T* state = TrySwitchState();
225 ......
226 ......
229 // Other RT methods can safely use the current state during the *same* RT cycle
230 void TestReadRTMethod2()
232 T* state = ReadCurrentState();
233 ......
234 ......
237 // Non RT read methods : must check state coherency
238 void TestReadMethod()
240 T* state;
241 UInt16 cur_index;
242 UInt16 next_index = GetCurrentIndex();
243 do {
244 cur_index = next_index;
245 state = ReadCurrentState();
247 ......
248 ......
250 next_index = GetCurrentIndex();
251 } while (cur_index != next_index);
255 } POST_PACKED_STRUCTURE;
257 } // end of namespace
259 #endif