Jack2 1.9.8
|
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 __JackAtomicArrayState__ 00021 #define __JackAtomicArrayState__ 00022 00023 #include "JackAtomic.h" 00024 #include "JackCompilerDeps.h" 00025 #include <string.h> // for memcpy 00026 00027 namespace Jack 00028 { 00029 00033 PRE_PACKED_STRUCTURE 00034 struct AtomicArrayCounter 00035 { 00036 union { 00037 struct { 00038 unsigned char fByteVal[4]; 00039 } 00040 scounter; 00041 UInt32 fLongVal; 00042 }info; 00043 00044 AtomicArrayCounter() 00045 { 00046 info.fLongVal = 0; 00047 } 00048 00049 AtomicArrayCounter(volatile const AtomicArrayCounter& obj) 00050 { 00051 info.fLongVal = obj.info.fLongVal; 00052 } 00053 00054 AtomicArrayCounter(volatile AtomicArrayCounter& obj) 00055 { 00056 info.fLongVal = obj.info.fLongVal; 00057 } 00058 00059 AtomicArrayCounter& operator=(volatile AtomicArrayCounter& obj) 00060 { 00061 info.fLongVal = obj.info.fLongVal; 00062 return *this; 00063 } 00064 00065 AtomicArrayCounter& operator=(AtomicArrayCounter& obj) 00066 { 00067 info.fLongVal = obj.info.fLongVal; 00068 return *this; 00069 } 00070 00071 } POST_PACKED_STRUCTURE; 00072 00073 #define Counter1(e) (e).info.fLongVal 00074 #define GetIndex1(e, state) ((e).info.scounter.fByteVal[state]) 00075 #define SetIndex1(e, state, val) ((e).info.scounter.fByteVal[state] = val) 00076 #define IncIndex1(e, state) ((e).info.scounter.fByteVal[state]++) 00077 #define SwapIndex1(e, state) (((e).info.scounter.fByteVal[0] == state) ? 0 : state) 00078 00110 // CHECK livelock 00111 00112 PRE_PACKED_STRUCTURE 00113 template <class T> 00114 class JackAtomicArrayState 00115 { 00116 00117 protected: 00118 00119 // fState[0] ==> current 00120 // fState[1] ==> pending 00121 // fState[2] ==> request 00122 00123 T fState[3]; 00124 volatile AtomicArrayCounter fCounter; 00125 00126 UInt32 WriteNextStateStartAux(int state, bool* result) 00127 { 00128 AtomicArrayCounter old_val; 00129 AtomicArrayCounter new_val; 00130 UInt32 cur_index; 00131 UInt32 next_index; 00132 bool need_copy; 00133 do { 00134 old_val = fCounter; 00135 new_val = old_val; 00136 *result = GetIndex1(new_val, state); 00137 cur_index = GetIndex1(new_val, 0); 00138 next_index = SwapIndex1(fCounter, state); 00139 need_copy = (GetIndex1(new_val, state) == 0); // Written = false, switch just occured 00140 SetIndex1(new_val, state, 0); // Written = false, invalidate state 00141 } while (!CAS(Counter1(old_val), Counter1(new_val), (UInt32*)&fCounter)); 00142 if (need_copy) 00143 memcpy(&fState[next_index], &fState[cur_index], sizeof(T)); 00144 return next_index; 00145 } 00146 00147 void WriteNextStateStopAux(int state) 00148 { 00149 AtomicArrayCounter old_val; 00150 AtomicArrayCounter new_val; 00151 do { 00152 old_val = fCounter; 00153 new_val = old_val; 00154 SetIndex1(new_val, state, 1); // Written = true, state becomes "switchable" 00155 } while (!CAS(Counter1(old_val), Counter1(new_val), (UInt32*)&fCounter)); 00156 } 00157 00158 public: 00159 00160 JackAtomicArrayState() 00161 { 00162 Counter1(fCounter) = 0; 00163 } 00164 00165 ~JackAtomicArrayState() // Not virtual ?? 00166 {} 00167 00172 T* ReadCurrentState() 00173 { 00174 return &fState[GetIndex1(fCounter, 0)]; 00175 } 00176 00181 UInt16 GetCurrentIndex() 00182 { 00183 return GetIndex1(fCounter, 3); 00184 } 00185 00190 T* TrySwitchState(int state) 00191 { 00192 AtomicArrayCounter old_val; 00193 AtomicArrayCounter new_val; 00194 do { 00195 old_val = fCounter; 00196 new_val = old_val; 00197 if (GetIndex1(new_val, state)) { // If state has been written 00198 SetIndex1(new_val, 0, SwapIndex1(new_val, state)); // Prepare switch 00199 SetIndex1(new_val, state, 0); // Invalidate the state "state" 00200 IncIndex1(new_val, 3); // Inc switch 00201 } 00202 } while (!CAS(Counter1(old_val), Counter1(new_val), (UInt32*)&fCounter)); 00203 return &fState[GetIndex1(fCounter, 0)]; // Read the counter again 00204 } 00205 00210 T* TrySwitchState(int state, bool* result) 00211 { 00212 AtomicArrayCounter old_val; 00213 AtomicArrayCounter new_val; 00214 do { 00215 old_val = fCounter; 00216 new_val = old_val; 00217 if ((*result = GetIndex1(new_val, state))) { // If state has been written 00218 SetIndex1(new_val, 0, SwapIndex1(new_val, state)); // Prepare switch 00219 SetIndex1(new_val, state, 0); // Invalidate the state "state" 00220 IncIndex1(new_val, 3); // Inc switch 00221 } 00222 } while (!CAS(Counter1(old_val), Counter1(new_val), (UInt32*)&fCounter)); 00223 return &fState[GetIndex1(fCounter, 0)]; // Read the counter again 00224 } 00225 00230 T* WriteNextStateStart(int state) 00231 { 00232 bool tmp; 00233 UInt32 index = WriteNextStateStartAux(state, &tmp); 00234 return &fState[index]; 00235 } 00236 00237 T* WriteNextStateStart(int state, bool* result) 00238 { 00239 UInt32 index = WriteNextStateStartAux(state, result); 00240 return &fState[index]; 00241 } 00242 00247 void WriteNextStateStop(int state) 00248 { 00249 WriteNextStateStopAux(state); 00250 } 00251 00252 } POST_PACKED_STRUCTURE; 00253 00254 } // end of namespace 00255 00256 00257 #endif 00258