• Main Page
  • Classes
  • Files
  • File List
  • File Members

singleton.h

Go to the documentation of this file.
00001 //
00002 // begin license header
00003 //  
00004 // This file is part of Terk and TerkOS.
00005 //
00006 // All Terk and TerkOS source code is provided under the terms of the 
00007 // GNU General Public License v2 (http://www.gnu.org/licenses/gpl-2.0.html).  
00008 // Those wishing to use Terk and TerkOS source code, software and/or
00009 // technologies under different licensing terms should contact us at 
00010 // [email protected]. Such licensing terms are available for
00011 // all portions of the Terk and TerkOS codebase presented here.
00012 //
00013 // end license header
00014 //
00015 
00016 #ifndef _SINGLETON_H
00017 #define _SINGLETON_H
00018 
00019 #include <sys/types.h>
00020 #include <sys/fcntl.h>
00021 #include <sys/types.h>
00022 #include <sys/ipc.h>
00023 #include <sys/sem.h>
00024 #include <unistd.h>
00025 #include <stdio.h>
00026 #include <string.h>
00027 #include <stdlib.h>
00028 #include <stdexcept>
00029 #include "singleton.h"
00030 
00031 #define SINGLETON_TIMEOUT 1000000000
00032 
00033 // put this in your class declaration
00034 #define SINGLETON(T)                            \
00035   friend class TSingleton<T>;                   \
00036   static TSingleton<T> m_singleton;             \
00037   static T *GetPtr(bool suppressError=false)    \
00038   {                                             \
00039     return m_singleton.GetPtr(suppressError);   \
00040   }                                             \
00041   static T &GetRef()                            \
00042   {                                             \
00043     return m_singleton.GetRef();                \
00044   }                                             \
00045   static void Release()                         \
00046   {                                             \
00047     m_singleton.Release();                      \
00048   }                                             \
00049   static bool Requested()                       \
00050   {                                             \
00051     return m_singleton.Requested();             \
00052   }
00053 
00054 #define SINGLETON_REGISTER(T)                   \
00055   TSingleton<T> T::m_singleton( #T )
00056 
00057   
00058 template <class T>
00059 class TSingleton
00060 {
00061 public:
00062   static T *GetPtr(bool suppressError=false);
00063   static T &GetRef();
00064   static bool Requested();
00065   static void Release();
00066 
00067   TSingleton();
00068   TSingleton(const char *identifier);
00069   ~TSingleton();
00070  
00071 private:
00072   static void Cleanup();
00073   static unsigned int Hash(const char *str);
00074 
00075   static int m_refCount;
00076   static T *m_pInstance;  
00077   static const char *m_identifier;
00078   static int m_id;
00079   static unsigned int m_hash;
00080 };
00081 
00082 template <class T> int TSingleton<T>::m_refCount = 0;
00083 template <class T> T *TSingleton<T>::m_pInstance = NULL;
00084 template <class T> const char *TSingleton<T>::m_identifier = NULL;
00085 template <class T> int TSingleton<T>::m_id = -1;
00086 template <class T> unsigned int TSingleton<T>::m_hash = 0;
00087 
00088 template <class T> T *TSingleton<T>::GetPtr(bool suppressError)
00089 {
00090   if (m_pInstance==NULL)
00091     {
00092       if (m_identifier!=NULL)
00093         {
00094           int ret;
00095           struct sembuf ops;
00096           struct timespec ts;
00097           union semun 
00098           {
00099             int              val;    
00100             struct semid_ds *buf;    
00101             unsigned short  *array;  
00102             struct seminfo  *__buf;  
00103           } sn;
00104 
00105           // hash it
00106           m_hash = Hash(m_identifier);
00107           
00108           // does it exist already?
00109           m_id = semget(m_hash, 1, 0666);
00110           if (m_id<0)
00111             { // create it...
00112               m_id = semget(m_hash, 1, IPC_CREAT | 0666);
00113               if (m_id<0)
00114                 {
00115                   if (!suppressError)
00116                     fprintf(stderr, "ERROR: cannot create semaphore.\n");
00117                   return NULL;
00118                 }
00119 
00120               // ...and initialize it...
00121               sn.val = 1;
00122               semctl(m_id, 0, SETVAL, sn);   
00123               // printf("*** semval initialize %d\n", semctl(m_id, 0, GETVAL));
00124             }
00125           // else
00126             // printf("*** semval %d\n", semctl(m_id, 0, GETVAL));
00127 
00128           // grab it, wait if necessary
00129           ops.sem_num = 0;
00130           ops.sem_op = -1;
00131           ops.sem_flg = SEM_UNDO;
00132           
00133           ts.tv_sec = SINGLETON_TIMEOUT/1000000000;
00134           ts.tv_nsec = SINGLETON_TIMEOUT%1000000000; 
00135           ret = semtimedop(m_id, &ops, 1, &ts);
00136           
00137           if (ret<0)
00138             {
00139               fprintf(stderr, "ERROR: %s object already exists in another process.\n", m_identifier);
00140               m_id = -1;
00141               return NULL;
00142             }
00143         }
00144       m_pInstance = new T();
00145     }
00146   m_refCount++;  
00147   
00148   return m_pInstance;
00149 }
00150 
00151 template <class T> T &TSingleton<T>::GetRef()
00152 {
00153   T *p;
00154  
00155   p = GetPtr();
00156 
00157   if (p==NULL)
00158     throw std::runtime_error("cannot create object");
00159   else 
00160     return *p;
00161 }
00162 
00163 template <class T> unsigned int TSingleton<T>::Hash(const char *str)
00164 {
00165   unsigned int hash = 5381;
00166   int c;
00167 
00168   while ((c=*str++))
00169     hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
00170 
00171   return hash;
00172 }
00173 
00174 template <class T> bool TSingleton<T>::Requested()
00175 {
00176   // get number of processes waiting
00177   if (semctl(m_id, 0, GETNCNT)>0)
00178     return true;
00179   else
00180     return false;
00181 }
00182 
00183 template <class T> void TSingleton<T>::Release()
00184 {
00185   if (m_refCount)
00186     m_refCount--;
00187   
00188   if (m_refCount==0)
00189     Cleanup();
00190 }
00191 
00192 template <class T> TSingleton<T>::TSingleton()
00193 {
00194 }
00195 
00196 template <class T> void TSingleton<T>::Cleanup()
00197 {
00198   if (m_id>=0)
00199     {
00200       struct sembuf ops;
00201       // release (increment) semaphore
00202       ops.sem_num = 0;
00203       ops.sem_op = 1;
00204       ops.sem_flg = SEM_UNDO;
00205       
00206       semop(m_id, &ops, 1);
00207       m_id = -1;
00208     }
00209   if (m_pInstance)
00210     {
00211       delete m_pInstance;
00212       m_pInstance = NULL;
00213     }
00214 }
00215 
00216 template <class T> TSingleton<T>::TSingleton(const char *identifier)
00217 {
00218   m_identifier = identifier;
00219 }
00220 
00221 template <class T> TSingleton<T>::~TSingleton()
00222 {
00223   Cleanup();
00224 }
00225 
00226 
00227 #endif
00228 

Generated on Mon Oct 3 2011 15:36:31 for libqwerk by  doxygen 1.7.1