Back to index

lightning-sunbird  0.9+nobinonly
GUSISpecific.h
Go to the documentation of this file.
00001 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
00002 // % Project  :      GUSI                        -      Grand Unified Socket Interface                    
00003 // % File            :      GUSISpecific.nw             -      Thread specific variables                  
00004 // % Author   :      Matthias Neeracher                                           
00005 // % Language :      C++                                                        
00006 // %                                                                       
00007 // % $Log: GUSISpecific.h,v $
00008 // % Revision 1.1  2001/03/11 22:38:39  sgehani%netscape.com
00009 // % First Checked In.
00010 // %                                             
00011 // % Revision 1.9  2000/10/16 04:11:21  neeri                              
00012 // % Plug memory leak                                                      
00013 // %                                                                       
00014 // % Revision 1.8  2000/03/15 07:22:07  neeri                              
00015 // % Enforce alignment choices                                             
00016 // %                                                                       
00017 // % Revision 1.7  1999/08/26 05:45:10  neeri                              
00018 // % Fixes for literate edition of source code                             
00019 // %                                                                       
00020 // % Revision 1.6  1999/05/30 03:09:31  neeri                              
00021 // % Added support for MPW compilers                                       
00022 // %                                                                       
00023 // % Revision 1.5  1999/04/29 04:58:20  neeri                              
00024 // % Fix key destruction bug                                               
00025 // %                                                                       
00026 // % Revision 1.4  1999/03/17 09:05:13  neeri                              
00027 // % Added GUSITimer, expanded docs                                        
00028 // %                                                                       
00029 // % Revision 1.3  1998/10/11 16:45:25  neeri                              
00030 // % Ready to release 2.0a2                                                
00031 // %                                                                       
00032 // % Revision 1.2  1998/08/01 21:32:11  neeri                              
00033 // % About ready for 2.0a1                                                 
00034 // %                                                                       
00035 // % Revision 1.1  1998/01/25 21:02:52  neeri                              
00036 // % Engine implemented, except for signals & scheduling                   
00037 // %                                                                       
00038 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
00039 //                                                                         
00040 // \chapter{Thread Specific Variables}                                     
00041 //                                                                         
00042 // It is often useful to have variables which maintain a different value   
00043 // for each process. The [[GUSISpecific]] class implements such a mechanism
00044 // in a way that is easily mappable to pthreads.                           
00045 //                                                                         
00046 //                                                                         
00047 // <GUSISpecific.h>=                                                       
00048 #ifndef _GUSISpecific_
00049 #define _GUSISpecific_
00050 
00051 #ifndef GUSI_SOURCE
00052 
00053 typedef struct GUSISpecific GUSISpecific;
00054 
00055 #else
00056 
00057 #include <Types.h>
00058 #include <ConditionalMacros.h>
00059 
00060 #if PRAGMA_STRUCT_ALIGN
00061 #pragma options align=native
00062 #endif
00063 
00064 // \section{Definition of Thread Specific Variables}                       
00065 //                                                                         
00066 // A [[GUSISpecific]] instance contains a variable ID and a per-process    
00067 // destructor.                                                             
00068 //                                                                         
00069 // <Definition of class [[GUSISpecific]]>=                                 
00070 extern "C"  {
00071        typedef void (*GUSISpecificDestructor)(void *);
00072 }
00073 
00074 class GUSISpecific {
00075        friend class GUSISpecificTable;
00076 public:
00077        GUSISpecific(GUSISpecificDestructor destructor = nil);
00078        ~GUSISpecific();
00079        
00080        void                               Destruct(void * data);
00081 private:
00082        GUSISpecificDestructor      fDestructor;
00083        unsigned                           fID;
00084        static unsigned                    sNextID;
00085 };
00086 // A [[GUSIContext]] contains a [[GUSISpecificTable]] storing the values of all
00087 // thread specific variables defined for this thread.                      
00088 //                                                                         
00089 // <Definition of class [[GUSISpecificTable]]>=                            
00090 class GUSISpecificTable {
00091        friend class GUSISpecific;
00092 public:
00093        GUSISpecificTable();
00094        ~GUSISpecificTable();
00095        void *        GetSpecific(const GUSISpecific * key) const;
00096        void   SetSpecific(const GUSISpecific * key, void * value);
00097        void   DeleteSpecific(const GUSISpecific * key);
00098 private:
00099        static void Register(GUSISpecific * key);
00100        static void Destruct(GUSISpecific * key);
00101        
00102        // We store a [[GUSISpecificTable]] as a contiguous range of IDs.          
00103  //                                                                         
00104  // <Privatissima of [[GUSISpecificTable]]>=                                
00105  void ***                          fValues;
00106  unsigned                          fAlloc;
00107 
00108  bool                              Valid(const GUSISpecific * key) const;
00109  // All keys are registered in a global table.                              
00110  //                                                                         
00111  // <Privatissima of [[GUSISpecificTable]]>=                                
00112  static GUSISpecific ***    sKeys;
00113  static unsigned                   sKeyAlloc;
00114 };
00115 // To simplify having a particular variable assume a different instance in every
00116 // thread, we define the [[GUSISpecificData]] template.                    
00117 //                                                                         
00118 // <Definition of template [[GUSISpecificData]]>=                          
00119 template <class T, GUSISpecificDestructor D> 
00120 class GUSISpecificData {
00121 public:
00122        GUSISpecificData() : fKey(D)              {                                                                     }
00123        T & operator*()                                         { return *get();                                        }
00124        T * operator->()                                        { return get();                                         }
00125        
00126        const GUSISpecific * Key() const   { return &fKey;                                         }
00127        T * get(GUSISpecificTable * table);
00128        T * get()                                                      { return get(GUSIContext::Current());     }
00129 protected:
00130        GUSISpecific  fKey;
00131 };
00132 
00133 template <class T, GUSISpecificDestructor D> 
00134        T * GUSISpecificData<T,D>::get(GUSISpecificTable * table)
00135 {
00136        void *                      data  = table->GetSpecific(&fKey);
00137        
00138        if (!data)
00139               table->SetSpecific(&fKey, data = new T);
00140        
00141        return static_cast<T *>(data);
00142 }
00143 
00144 #if PRAGMA_STRUCT_ALIGN
00145 #pragma options align=reset
00146 #endif
00147 
00148 // <Inline member functions for class [[GUSISpecific]]>=                   
00149 inline GUSISpecific::GUSISpecific(GUSISpecificDestructor destructor)
00150        : fDestructor(destructor), fID(sNextID++)
00151 {
00152        GUSISpecificTable::Register(this);
00153 }
00154 
00155 inline GUSISpecific::~GUSISpecific()
00156 {
00157        GUSISpecificTable::Destruct(this);
00158 }
00159 
00160 inline void GUSISpecific::Destruct(void * data)
00161 {
00162        if (fDestructor)
00163               fDestructor(data);
00164 }
00165 // <Inline member functions for class [[GUSISpecificTable]]>=              
00166 inline bool GUSISpecificTable::Valid(const GUSISpecific * key) const
00167 {
00168        return key && key->fID < fAlloc;
00169 }
00170 // <Inline member functions for class [[GUSISpecificTable]]>=              
00171 inline GUSISpecificTable::GUSISpecificTable()
00172        : fValues(nil), fAlloc(0)
00173 {      
00174 }
00175 // <Inline member functions for class [[GUSISpecificTable]]>=              
00176 inline void * GUSISpecificTable::GetSpecific(const GUSISpecific * key) const
00177 {
00178        if (Valid(key))
00179               return fValues[0][key->fID];
00180        else
00181               return nil;
00182 }
00183 
00184 #endif /* GUSI_SOURCE */
00185 
00186 #endif /* _GUSISpecific_ */