Jack2 1.9.10

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