Jack2 1.9.6

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 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