Jack2 1.9.10
|
00001 /* 00002 Copyright (C) 2004-2008 Grame 00003 00004 This program is free software; you can redistribute it and/or modify 00005 it under the terms of the GNU Lesser General Public License as published by 00006 the Free Software Foundation; either version 2.1 of the License, or 00007 (at your option) any later version. 00008 00009 This program is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 GNU Lesser General Public License for more details. 00013 00014 You should have received a copy of the GNU Lesser General Public License 00015 along with this program; if not, write to the Free Software 00016 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00017 00018 */ 00019 00020 #ifndef __JackAtomicState__ 00021 #define __JackAtomicState__ 00022 00023 #include "JackAtomic.h" 00024 #include "JackCompilerDeps.h" 00025 #include <string.h> // for memcpy 00026 00027 namespace Jack 00028 { 00029 00034 PRE_PACKED_STRUCTURE 00035 struct AtomicCounter 00036 { 00037 union { 00038 struct { 00039 UInt16 fShortVal1; // Cur 00040 UInt16 fShortVal2; // Next 00041 } 00042 scounter; 00043 UInt32 fLongVal; 00044 }info; 00045 00046 AtomicCounter() 00047 { 00048 info.fLongVal = 0; 00049 } 00050 00051 AtomicCounter(volatile const AtomicCounter& obj) 00052 { 00053 info.fLongVal = obj.info.fLongVal; 00054 } 00055 00056 AtomicCounter(volatile AtomicCounter& obj) 00057 { 00058 info.fLongVal = obj.info.fLongVal; 00059 } 00060 00061 AtomicCounter& operator=(AtomicCounter& obj) 00062 { 00063 info.fLongVal = obj.info.fLongVal; 00064 return *this; 00065 } 00066 00067 AtomicCounter& operator=(volatile AtomicCounter& obj) 00068 { 00069 info.fLongVal = obj.info.fLongVal; 00070 return *this; 00071 } 00072 00073 } POST_PACKED_STRUCTURE; 00074 00075 #define Counter(e) (e).info.fLongVal 00076 #define CurIndex(e) (e).info.scounter.fShortVal1 00077 #define NextIndex(e) (e).info.scounter.fShortVal2 00078 00079 #define CurArrayIndex(e) (CurIndex(e) & 0x0001) 00080 #define NextArrayIndex(e) ((CurIndex(e) + 1) & 0x0001) 00081 00086 // CHECK livelock 00087 00088 PRE_PACKED_STRUCTURE 00089 template <class T> 00090 class JackAtomicState 00091 { 00092 00093 protected: 00094 00095 T fState[2]; 00096 volatile AtomicCounter fCounter; 00097 SInt32 fCallWriteCounter; 00098 00099 UInt32 WriteNextStateStartAux() 00100 { 00101 AtomicCounter old_val; 00102 AtomicCounter new_val; 00103 UInt32 cur_index; 00104 UInt32 next_index; 00105 bool need_copy; 00106 do { 00107 old_val = fCounter; 00108 new_val = old_val; 00109 cur_index = CurArrayIndex(new_val); 00110 next_index = NextArrayIndex(new_val); 00111 need_copy = (CurIndex(new_val) == NextIndex(new_val)); 00112 NextIndex(new_val) = CurIndex(new_val); // Invalidate next index 00113 } while (!CAS(Counter(old_val), Counter(new_val), (UInt32*)&fCounter)); 00114 if (need_copy) 00115 memcpy(&fState[next_index], &fState[cur_index], sizeof(T)); 00116 return next_index; 00117 } 00118 00119 void WriteNextStateStopAux() 00120 { 00121 AtomicCounter old_val; 00122 AtomicCounter new_val; 00123 do { 00124 old_val = fCounter; 00125 new_val = old_val; 00126 NextIndex(new_val)++; // Set next index 00127 } while (!CAS(Counter(old_val), Counter(new_val), (UInt32*)&fCounter)); 00128 } 00129 00130 public: 00131 00132 JackAtomicState() 00133 { 00134 Counter(fCounter) = 0; 00135 fCallWriteCounter = 0; 00136 } 00137 00138 ~JackAtomicState() // Not virtual ?? 00139 {} 00140 00144 T* ReadCurrentState() 00145 { 00146 return &fState[CurArrayIndex(fCounter)]; 00147 } 00148 00152 UInt16 GetCurrentIndex() 00153 { 00154 return CurIndex(fCounter); 00155 } 00156 00160 T* TrySwitchState() 00161 { 00162 AtomicCounter old_val; 00163 AtomicCounter new_val; 00164 do { 00165 old_val = fCounter; 00166 new_val = old_val; 00167 CurIndex(new_val) = NextIndex(new_val); // Prepare switch 00168 } while (!CAS(Counter(old_val), Counter(new_val), (UInt32*)&fCounter)); 00169 return &fState[CurArrayIndex(fCounter)]; // Read the counter again 00170 } 00171 00175 T* TrySwitchState(bool* result) 00176 { 00177 AtomicCounter old_val; 00178 AtomicCounter new_val; 00179 do { 00180 old_val = fCounter; 00181 new_val = old_val; 00182 *result = (CurIndex(new_val) != NextIndex(new_val)); 00183 CurIndex(new_val) = NextIndex(new_val); // Prepare switch 00184 } while (!CAS(Counter(old_val), Counter(new_val), (UInt32*)&fCounter)); 00185 return &fState[CurArrayIndex(fCounter)]; // Read the counter again 00186 } 00187 00191 T* WriteNextStateStart() 00192 { 00193 UInt32 next_index = (fCallWriteCounter++ == 0) 00194 ? WriteNextStateStartAux() 00195 : NextArrayIndex(fCounter); // We are inside a wrapping WriteNextStateStart call, NextArrayIndex can be read safely 00196 return &fState[next_index]; 00197 } 00198 00202 void WriteNextStateStop() 00203 { 00204 if (--fCallWriteCounter == 0) 00205 WriteNextStateStopAux(); 00206 } 00207 00208 bool IsPendingChange() 00209 { 00210 return CurIndex(fCounter) != NextIndex(fCounter); 00211 } 00212 00213 /* 00214 // Single writer : write methods get the *next* state to be updated 00215 void TestWriteMethod() 00216 { 00217 T* state = WriteNextStateStart(); 00218 ...... 00219 ...... 00220 WriteNextStateStop(); 00221 } 00222 00223 // First RT call possibly switch state 00224 void TestReadRTMethod1() 00225 { 00226 T* state = TrySwitchState(); 00227 ...... 00228 ...... 00229 } 00230 00231 // Other RT methods can safely use the current state during the *same* RT cycle 00232 void TestReadRTMethod2() 00233 { 00234 T* state = ReadCurrentState(); 00235 ...... 00236 ...... 00237 } 00238 00239 // Non RT read methods : must check state coherency 00240 void TestReadMethod() 00241 { 00242 T* state; 00243 UInt16 cur_index; 00244 UInt16 next_index = GetCurrentIndex(); 00245 do { 00246 cur_index = next_index; 00247 state = ReadCurrentState(); 00248 00249 ...... 00250 ...... 00251 00252 next_index = GetCurrentIndex(); 00253 } while (cur_index != next_index); 00254 } 00255 */ 00256 00257 } POST_PACKED_STRUCTURE; 00258 00259 } // end of namespace 00260 00261 #endif 00262