Jack2 1.9.6
|
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 struct AtomicCounter 00035 { 00036 union { 00037 struct { 00038 UInt16 fShortVal1; // Cur 00039 UInt16 fShortVal2; // Next 00040 } 00041 scounter; 00042 UInt32 fLongVal; 00043 }info; 00044 00045 AtomicCounter() 00046 { 00047 info.fLongVal = 0; 00048 } 00049 00050 AtomicCounter(volatile const AtomicCounter& obj) 00051 { 00052 info.fLongVal = obj.info.fLongVal; 00053 } 00054 00055 AtomicCounter(volatile AtomicCounter& obj) 00056 { 00057 info.fLongVal = obj.info.fLongVal; 00058 } 00059 00060 AtomicCounter& operator=(AtomicCounter& obj) 00061 { 00062 info.fLongVal = obj.info.fLongVal; 00063 return *this; 00064 } 00065 00066 AtomicCounter& operator=(volatile AtomicCounter& obj) 00067 { 00068 info.fLongVal = obj.info.fLongVal; 00069 return *this; 00070 } 00071 00072 } POST_PACKED_STRUCTURE; 00073 00074 #define Counter(e) (e).info.fLongVal 00075 #define CurIndex(e) (e).info.scounter.fShortVal1 00076 #define NextIndex(e) (e).info.scounter.fShortVal2 00077 00078 #define CurArrayIndex(e) (CurIndex(e) & 0x0001) 00079 #define NextArrayIndex(e) ((CurIndex(e) + 1) & 0x0001) 00080 00085 // CHECK livelock 00086 00087 template <class T> 00088 class JackAtomicState 00089 { 00090 00091 protected: 00092 00093 T fState[2]; 00094 volatile AtomicCounter fCounter; 00095 SInt32 fCallWriteCounter; 00096 00097 UInt32 WriteNextStateStartAux() 00098 { 00099 AtomicCounter old_val; 00100 AtomicCounter new_val; 00101 UInt32 cur_index; 00102 UInt32 next_index; 00103 bool need_copy; 00104 do { 00105 old_val = fCounter; 00106 new_val = old_val; 00107 cur_index = CurArrayIndex(new_val); 00108 next_index = NextArrayIndex(new_val); 00109 need_copy = (CurIndex(new_val) == NextIndex(new_val)); 00110 NextIndex(new_val) = CurIndex(new_val); // Invalidate next index 00111 } while (!CAS(Counter(old_val), Counter(new_val), (UInt32*)&fCounter)); 00112 if (need_copy) 00113 memcpy(&fState[next_index], &fState[cur_index], sizeof(T)); 00114 return next_index; 00115 } 00116 00117 void WriteNextStateStopAux() 00118 { 00119 AtomicCounter old_val; 00120 AtomicCounter new_val; 00121 do { 00122 old_val = fCounter; 00123 new_val = old_val; 00124 NextIndex(new_val)++; // Set next index 00125 } while (!CAS(Counter(old_val), Counter(new_val), (UInt32*)&fCounter)); 00126 } 00127 00128 public: 00129 00130 JackAtomicState() 00131 { 00132 Counter(fCounter) = 0; 00133 fCallWriteCounter = 0; 00134 } 00135 00136 ~JackAtomicState() // Not virtual ?? 00137 {} 00138 00142 T* ReadCurrentState() 00143 { 00144 return &fState[CurArrayIndex(fCounter)]; 00145 } 00146 00150 UInt16 GetCurrentIndex() 00151 { 00152 return CurIndex(fCounter); 00153 } 00154 00158 T* TrySwitchState() 00159 { 00160 AtomicCounter old_val; 00161 AtomicCounter new_val; 00162 do { 00163 old_val = fCounter; 00164 new_val = old_val; 00165 CurIndex(new_val) = NextIndex(new_val); // Prepare switch 00166 } while (!CAS(Counter(old_val), Counter(new_val), (UInt32*)&fCounter)); 00167 return &fState[CurArrayIndex(fCounter)]; // Read the counter again 00168 } 00169 00173 T* TrySwitchState(bool* result) 00174 { 00175 AtomicCounter old_val; 00176 AtomicCounter new_val; 00177 do { 00178 old_val = fCounter; 00179 new_val = old_val; 00180 *result = (CurIndex(new_val) != NextIndex(new_val)); 00181 CurIndex(new_val) = NextIndex(new_val); // Prepare switch 00182 } while (!CAS(Counter(old_val), Counter(new_val), (UInt32*)&fCounter)); 00183 return &fState[CurArrayIndex(fCounter)]; // Read the counter again 00184 } 00185 00189 T* WriteNextStateStart() 00190 { 00191 UInt32 next_index = (fCallWriteCounter++ == 0) 00192 ? WriteNextStateStartAux() 00193 : NextArrayIndex(fCounter); // We are inside a wrapping WriteNextStateStart call, NextArrayIndex can be read safely 00194 return &fState[next_index]; 00195 } 00196 00200 void WriteNextStateStop() 00201 { 00202 if (--fCallWriteCounter == 0) 00203 WriteNextStateStopAux(); 00204 } 00205 00206 bool IsPendingChange() 00207 { 00208 return CurIndex(fCounter) != NextIndex(fCounter); 00209 } 00210 00211 /* 00212 // Single writer : write methods get the *next* state to be updated 00213 void TestWriteMethod() 00214 { 00215 T* state = WriteNextStateStart(); 00216 ...... 00217 ...... 00218 WriteNextStateStop(); 00219 } 00220 00221 // First RT call possibly switch state 00222 void TestReadRTMethod1() 00223 { 00224 T* state = TrySwitchState(); 00225 ...... 00226 ...... 00227 } 00228 00229 // Other RT methods can safely use the current state during the *same* RT cycle 00230 void TestReadRTMethod2() 00231 { 00232 T* state = ReadCurrentState(); 00233 ...... 00234 ...... 00235 } 00236 00237 // Non RT read methods : must check state coherency 00238 void TestReadMethod() 00239 { 00240 T* state; 00241 UInt16 cur_index; 00242 UInt16 next_index = GetCurrentIndex(); 00243 do { 00244 cur_index = next_index; 00245 state = ReadCurrentState(); 00246 00247 ...... 00248 ...... 00249 00250 next_index = GetCurrentIndex(); 00251 } while (cur_index != next_index); 00252 } 00253 */ 00254 00255 } POST_PACKED_STRUCTURE; 00256 00257 } // end of namespace 00258 00259 #endif 00260