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
31 \brief Counter for CAS
39 UInt16 fShortVal1
; // Cur
40 UInt16 fShortVal2
; // Next
51 AtomicCounter(volatile const AtomicCounter
& obj
)
53 info
.fLongVal
= obj
.info
.fLongVal
;
56 AtomicCounter(volatile AtomicCounter
& obj
)
58 info
.fLongVal
= obj
.info
.fLongVal
;
61 AtomicCounter
& operator=(AtomicCounter
& obj
)
63 info
.fLongVal
= obj
.info
.fLongVal
;
67 AtomicCounter
& operator=(volatile AtomicCounter
& obj
)
69 info
.fLongVal
= obj
.info
.fLongVal
;
73 } POST_PACKED_STRUCTURE
;
75 #define Counter(e) (e).info.fLongVal
76 #define CurIndex(e) (e).info.scounter.fShortVal1
77 #define NextIndex(e) (e).info.scounter.fShortVal2
79 #define CurArrayIndex(e) (CurIndex(e) & 0x0001)
80 #define NextArrayIndex(e) ((CurIndex(e) + 1) & 0x0001)
83 \brief A class to handle two states (switching from one to the other) in a lock-free manner
96 volatile AtomicCounter fCounter
;
97 SInt32 fCallWriteCounter
;
99 UInt32
WriteNextStateStartAux()
101 AtomicCounter old_val
;
102 AtomicCounter new_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
));
115 memcpy(&fState
[next_index
], &fState
[cur_index
], sizeof(T
));
119 void WriteNextStateStopAux()
121 AtomicCounter old_val
;
122 AtomicCounter new_val
;
126 NextIndex(new_val
)++; // Set next index
127 } while (!CAS(Counter(old_val
), Counter(new_val
), (UInt32
*)&fCounter
));
134 Counter(fCounter
) = 0;
135 fCallWriteCounter
= 0;
138 ~JackAtomicState() // Not virtual ??
142 \brief Returns the current state : only valid in the RT reader thread
144 T
* ReadCurrentState()
146 return &fState
[CurArrayIndex(fCounter
)];
150 \brief Returns the current state index
152 UInt16
GetCurrentIndex()
154 return CurIndex(fCounter
);
158 \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)
162 AtomicCounter old_val
;
163 AtomicCounter new_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
173 \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)
175 T
* TrySwitchState(bool* result
)
177 AtomicCounter old_val
;
178 AtomicCounter new_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
189 \brief Start write operation : setup and returns the next state to update, check for recursive write calls.
191 T
* WriteNextStateStart()
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
];
200 \brief Stop write operation : make the next state ready to be used by the RT thread
202 void WriteNextStateStop()
204 if (--fCallWriteCounter
== 0)
205 WriteNextStateStopAux();
208 bool IsPendingChange()
210 return CurIndex(fCounter
) != NextIndex(fCounter
);
214 // Single writer : write methods get the *next* state to be updated
215 void TestWriteMethod()
217 T* state = WriteNextStateStart();
220 WriteNextStateStop();
223 // First RT call possibly switch state
224 void TestReadRTMethod1()
226 T* state = TrySwitchState();
231 // Other RT methods can safely use the current state during the *same* RT cycle
232 void TestReadRTMethod2()
234 T* state = ReadCurrentState();
239 // Non RT read methods : must check state coherency
240 void TestReadMethod()
244 UInt16 next_index = GetCurrentIndex();
246 cur_index = next_index;
247 state = ReadCurrentState();
252 next_index = GetCurrentIndex();
253 } while (cur_index != next_index);
257 } POST_PACKED_STRUCTURE
;
259 } // end of namespace