Jack2 1.9.6

JackAtomicArrayState.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 __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 
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 template <class T>
00113 class JackAtomicArrayState
00114 {
00115 
00116     protected:
00117 
00118         // fState[0] ==> current
00119         // fState[1] ==> pending
00120         // fState[2] ==> request
00121 
00122         T fState[3];
00123         volatile AtomicArrayCounter fCounter;
00124 
00125         UInt32 WriteNextStateStartAux(int state, bool* result)
00126         {
00127             AtomicArrayCounter old_val;
00128             AtomicArrayCounter new_val;
00129             UInt32 cur_index;
00130             UInt32 next_index;
00131             bool need_copy;
00132             do {
00133                 old_val = fCounter;
00134                 new_val = old_val;
00135                 *result = GetIndex1(new_val, state);
00136                 cur_index = GetIndex1(new_val, 0);
00137                 next_index = SwapIndex1(fCounter, state);
00138                 need_copy = (GetIndex1(new_val, state) == 0);   // Written = false, switch just occured
00139                 SetIndex1(new_val, state, 0);                                   // Written = false, invalidate state
00140             } while (!CAS(Counter1(old_val), Counter1(new_val), (UInt32*)&fCounter));
00141             if (need_copy)
00142                 memcpy(&fState[next_index], &fState[cur_index], sizeof(T));
00143             return next_index;
00144         }
00145 
00146         void WriteNextStateStopAux(int state)
00147         {
00148             AtomicArrayCounter old_val;
00149             AtomicArrayCounter new_val;
00150             do {
00151                 old_val = fCounter;
00152                 new_val = old_val;
00153                 SetIndex1(new_val, state, 1);  // Written = true, state becomes "switchable"
00154             } while (!CAS(Counter1(old_val), Counter1(new_val), (UInt32*)&fCounter));
00155         }
00156 
00157     public:
00158 
00159         JackAtomicArrayState()
00160         {
00161             Counter1(fCounter) = 0;
00162         }
00163 
00164         ~JackAtomicArrayState() // Not virtual ??
00165         {}
00166 
00171         T* ReadCurrentState()
00172         {
00173             return &fState[GetIndex1(fCounter, 0)];
00174         }
00175 
00180         UInt16 GetCurrentIndex()
00181         {
00182             return GetIndex1(fCounter, 3);
00183         }
00184 
00189         T* TrySwitchState(int state)
00190         {
00191             AtomicArrayCounter old_val;
00192             AtomicArrayCounter new_val;
00193             do {
00194                 old_val = fCounter;
00195                 new_val = old_val;
00196                 if (GetIndex1(new_val, state)) {                                                // If state has been written
00197                     SetIndex1(new_val, 0, SwapIndex1(new_val, state));  // Prepare switch
00198                     SetIndex1(new_val, state, 0);                                               // Invalidate the state "state"
00199                     IncIndex1(new_val, 3);                                                              // Inc switch
00200                 }
00201             } while (!CAS(Counter1(old_val), Counter1(new_val), (UInt32*)&fCounter));
00202             return &fState[GetIndex1(fCounter, 0)];     // Read the counter again
00203         }
00204 
00209         T* TrySwitchState(int state, bool* result)
00210         {
00211             AtomicArrayCounter old_val;
00212             AtomicArrayCounter new_val;
00213             do {
00214                 old_val = fCounter;
00215                 new_val = old_val;
00216                 if ((*result = GetIndex1(new_val, state))) {                    // If state has been written
00217                     SetIndex1(new_val, 0, SwapIndex1(new_val, state));  // Prepare switch
00218                     SetIndex1(new_val, state, 0);                                               // Invalidate the state "state"
00219                     IncIndex1(new_val, 3);                                                              // Inc switch
00220                 }
00221             } while (!CAS(Counter1(old_val), Counter1(new_val), (UInt32*)&fCounter));
00222             return &fState[GetIndex1(fCounter, 0)];     // Read the counter again
00223         }
00224 
00229         T* WriteNextStateStart(int state)
00230         {
00231             bool tmp;
00232             UInt32 index = WriteNextStateStartAux(state, &tmp);
00233             return &fState[index];
00234         }
00235 
00236         T* WriteNextStateStart(int state, bool* result)
00237         {
00238             UInt32 index = WriteNextStateStartAux(state, result);
00239             return &fState[index];
00240         }
00241 
00246         void WriteNextStateStop(int state)
00247         {
00248             WriteNextStateStopAux(state);
00249         }
00250 
00251 } POST_PACKED_STRUCTURE;
00252 
00253 } // end of namespace
00254 
00255 
00256 #endif
00257