Jack2  1.9.10
JackAtomicState.h
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