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 General Public License as published by
00006 the Free Software Foundation; either version 2 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 General Public License for more details.
00013 
00014 You should have received a copy of the GNU General Public License
00015 along with this program; if not, write to the Free Software
00016 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00017 
00018 */
00019 
00020 #ifndef __JackAtomicState__
00021 #define __JackAtomicState__
00022 
00023 #include "JackAtomic.h"
00024 #include <string.h> // for memcpy
00025 
00026 namespace Jack
00027 {
00028 
00033 struct AtomicCounter
00034 {
00035     union {
00036         struct {
00037             UInt16 fShortVal1;  // Cur
00038             UInt16 fShortVal2;  // Next
00039         }
00040         scounter;
00041         UInt32 fLongVal;
00042     }info;
00043 
00044     AtomicCounter& operator=(volatile AtomicCounter& obj)
00045     {
00046         info.fLongVal = obj.info.fLongVal;
00047         return *this;
00048     }
00049 
00050 };
00051 
00052 
00053 #define Counter(e) (e).info.fLongVal
00054 #define CurIndex(e) (e).info.scounter.fShortVal1
00055 #define NextIndex(e) (e).info.scounter.fShortVal2
00056 
00057 #define CurArrayIndex(e) (CurIndex(e) & 0x0001)
00058 #define NextArrayIndex(e) ((CurIndex(e) + 1) & 0x0001)
00059 
00064 // CHECK livelock
00065 
00066 template <class T>
00067 class JackAtomicState
00068 {
00069 
00070     protected:
00071 
00072         T fState[2];
00073         volatile AtomicCounter fCounter;
00074         SInt32 fCallWriteCounter;
00075 
00076         UInt32 WriteNextStateStartAux()
00077         {
00078             AtomicCounter old_val;
00079             AtomicCounter new_val;
00080             UInt32 cur_index;
00081             UInt32 next_index;
00082             bool need_copy;
00083             do {
00084                 old_val = fCounter;
00085                 new_val = old_val;
00086                 cur_index = CurArrayIndex(new_val);
00087                 next_index = NextArrayIndex(new_val);
00088                 need_copy = (CurIndex(new_val) == NextIndex(new_val));
00089                 NextIndex(new_val) = CurIndex(new_val); // Invalidate next index
00090             } while (!CAS(Counter(old_val), Counter(new_val), (UInt32*)&fCounter));
00091             if (need_copy)
00092                 memcpy(&fState[next_index], &fState[cur_index], sizeof(T));
00093             return next_index;
00094         }
00095 
00096         void WriteNextStateStopAux()
00097         {
00098             AtomicCounter old_val;
00099             AtomicCounter new_val;
00100             do {
00101                 old_val = fCounter;
00102                 new_val = old_val;
00103                 NextIndex(new_val)++; // Set next index
00104             } while (!CAS(Counter(old_val), Counter(new_val), (UInt32*)&fCounter));
00105         }
00106 
00107     public:
00108 
00109         JackAtomicState()
00110         {
00111             Counter(fCounter) = 0;
00112             fCallWriteCounter = 0;
00113         }
00114 
00115         ~JackAtomicState() // Not virtual ??
00116         {}
00117 
00121         T* ReadCurrentState()
00122         {
00123             return &fState[CurArrayIndex(fCounter)];
00124         }
00125 
00129         UInt16 GetCurrentIndex()
00130         {
00131             return CurIndex(fCounter);
00132         }
00133 
00137         T* TrySwitchState()
00138         {
00139             AtomicCounter old_val;
00140             AtomicCounter new_val;
00141             do {
00142                 old_val = fCounter;
00143                 new_val = old_val;
00144                 CurIndex(new_val) = NextIndex(new_val); // Prepare switch
00145             } while (!CAS(Counter(old_val), Counter(new_val), (UInt32*)&fCounter));
00146             return &fState[CurArrayIndex(fCounter)];    // Read the counter again
00147         }
00148 
00152         T* TrySwitchState(bool* result)
00153         {
00154             AtomicCounter old_val;
00155             AtomicCounter new_val;
00156             do {
00157                 old_val = fCounter;
00158                 new_val = old_val;
00159                 *result = (CurIndex(new_val) != NextIndex(new_val));
00160                 CurIndex(new_val) = NextIndex(new_val);  // Prepare switch
00161             } while (!CAS(Counter(old_val), Counter(new_val), (UInt32*)&fCounter));
00162             return &fState[CurArrayIndex(fCounter)];    // Read the counter again
00163         }
00164 
00168         T* WriteNextStateStart()
00169         {
00170             UInt32 next_index = (fCallWriteCounter++ == 0)
00171                                 ? WriteNextStateStartAux()
00172                                 : NextArrayIndex(fCounter); // We are inside a wrapping WriteNextStateStart call, NextArrayIndex can be read safely
00173             return &fState[next_index];
00174         }
00175 
00179         void WriteNextStateStop()
00180         {
00181             if (--fCallWriteCounter == 0)
00182                 WriteNextStateStopAux();
00183         }
00184 
00185         bool IsPendingChange()
00186         {
00187             return CurIndex(fCounter) != NextIndex(fCounter);
00188         }
00189 
00190         /*
00191               // Single writer : write methods get the *next* state to be updated
00192         void TestWriteMethod() 
00193         {
00194                 T* state = WriteNextStateStart();
00195                 ......
00196                 ......
00197                 WriteNextStateStop(); 
00198         }
00199 
00200               // First RT call possibly switch state
00201         void TestReadRTMethod1() 
00202         {
00203                 T* state = TrySwitchState();
00204                 ......
00205                 ......
00206         }
00207 
00208               // Other RT methods can safely use the current state during the *same* RT cycle
00209         void TestReadRTMethod2() 
00210         {
00211                 T* state = ReadCurrentState();
00212                 ......
00213                 ......
00214         }
00215               
00216               // Non RT read methods : must check state coherency
00217         void TestReadMethod() 
00218         {
00219                 T* state;
00220                 UInt16 cur_index;
00221                         UInt16 next_index = GetCurrentIndex();
00222                 do {
00223                                 cur_index = next_index; 
00224                         state = ReadCurrentState();
00225                         
00226                         ......
00227                         ......
00228                        
00229                                 next_index = GetCurrentIndex();
00230                 } while (cur_index != next_index);
00231         }
00232         */
00233 };
00234 
00235 
00236 } // end of namespace
00237 
00238 
00239 #endif
00240 

Generated on Thu Feb 14 11:16:01 2008 for Jackdmp by  doxygen 1.5.1