Back to index

nux  3.0.0
ThreadGNU.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright 2010 Inalogic® Inc.
00003  *
00004  * This program is free software: you can redistribute it and/or modify it
00005  * under the terms of the GNU Lesser General Public License, as
00006  * published by the  Free Software Foundation; either version 2.1 or 3.0
00007  * of the License.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranties of
00011  * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
00012  * PURPOSE.  See the applicable version of the GNU Lesser General Public
00013  * License for more details.
00014  *
00015  * You should have received a copy of both the GNU Lesser General Public
00016  * License along with this program. If not, see <http://www.gnu.org/licenses/>
00017  *
00018  * Authored by: Jay Taoko <jaytaoko@inalogic.com>
00019  *
00020  */
00021 
00022 
00023 #include "NuxCore.h"
00024 
00025 
00026 namespace nux
00027 {
00028 
00029   int NThreadSafeCounter::Increment()
00030   {
00031     return __sync_add_and_fetch (&m_Counter, 1);
00032   }
00033 
00034   int NThreadSafeCounter::Decrement()
00035   {
00036     return __sync_add_and_fetch (&m_Counter, -1);
00037   }
00038 
00039   int NThreadSafeCounter::Set (int i)
00040   {
00041     return __sync_lock_test_and_set (&m_Counter, i);
00042   }
00043 
00044   int NThreadSafeCounter::GetValue() const
00045   {
00046     return m_Counter;
00047   }
00048 
00049   int NThreadSafeCounter::operator ++ ()
00050   {
00051     return Increment();
00052   }
00053 
00054   int NThreadSafeCounter::operator -- ()
00055   {
00056     return Decrement();
00057   }
00058 
00059   bool NThreadSafeCounter::operator == (int i)
00060   {
00061     return (m_Counter == i);
00062   }
00063 
00064   __thread void *NThreadLocalStorage::m_TLSIndex[NThreadLocalStorage::NbTLS];
00065   BOOL NThreadLocalStorage::m_TLSUsed[NThreadLocalStorage::NbTLS];
00066   NThreadLocalStorage::TLS_ShutdownCallback  NThreadLocalStorage::m_TLSCallbacks[NThreadLocalStorage::NbTLS];
00067 
00068   BOOL NThreadLocalStorage::RegisterTLS(unsigned int index, NThreadLocalStorage::TLS_ShutdownCallback shutdownCallback)
00069   {
00070     NUX_RETURN_VALUE_IF_FALSE(index < NThreadLocalStorage::NbTLS, FALSE);
00071     NUX_RETURN_VALUE_IF_TRUE(m_TLSUsed[index], TRUE); // already registered
00072 
00073     m_TLSUsed[index]  = TRUE;
00074     m_TLSCallbacks[index] =  shutdownCallback;
00075     return TRUE;
00076   }
00077 
00078   BOOL NThreadLocalStorage::UnRegisterTLS (unsigned int index)
00079   {
00080     NUX_RETURN_VALUE_IF_FALSE(index < NThreadLocalStorage::NbTLS, FALSE);
00081     NUX_RETURN_VALUE_IF_FALSE(m_TLSUsed[index], FALSE);
00082 
00083     m_TLSUsed[index]  = FALSE;
00084     m_TLSCallbacks[index] =  NULL;
00085     m_TLSIndex[index]  = NULL;
00086 
00087     return TRUE;
00088   }
00089 
00090   void NThreadLocalStorage::Initialize()
00091   {
00092     for (unsigned int i = 0; i < NThreadLocalStorage::NbTLS; i++)
00093     {
00094       m_TLSUsed[i] = FALSE;
00095       // Fill the array with invalid values
00096       m_TLSIndex[i] = 0;
00097     }
00098   }
00099 
00100   void NThreadLocalStorage::Shutdown()
00101   {
00102     ThreadShutdown();
00103   }
00104 
00105   void NThreadLocalStorage::ThreadInit()
00106   {
00107   }
00108 
00109   void NThreadLocalStorage::ThreadShutdown()
00110   {
00111     TLS_ShutdownCallback *callback = m_TLSCallbacks;
00112 
00113     for (unsigned int i = 0; i < NThreadLocalStorage::NbTLS; ++i, ++callback)
00114     {
00115       if (*callback)
00116       {
00117         (**callback) ();
00118       }
00119     }
00120   }
00121 
00122   NUX_IMPLEMENT_ROOT_OBJECT_TYPE (NThread);
00123 
00124   NThread::NThread()
00125     :   m_ThreadState (THREADINIT)
00126   {
00127     m_pThreadFunc = NThread::EntryPoint; // Can call Detach() also.
00128   }
00129 
00130   NThread::NThread (ThreadRoutineFunc lpExternalRoutine)
00131   {
00132     Attach (lpExternalRoutine);
00133   }
00134 
00135   NThread::~NThread()
00136   {
00137     if (m_ThreadCtx.m_dwTID)
00138       pthread_detach (m_ThreadCtx.m_dwTID);
00139   }
00140 
00141   ThreadState NThread::Start ( void *arg )
00142   {
00143     m_ThreadCtx.m_pUserData = arg;
00144     int ret = pthread_create (&m_ThreadCtx.m_dwTID,
00145                               NULL,
00146                               m_pThreadFunc,
00147                               this);
00148 
00149     if (ret != 0)
00150     {
00151       nuxDebugMsg (TEXT ("[NThread::Start] Cannot start thread.") );
00152       m_ThreadState = THREAD_START_ERROR;
00153       return m_ThreadState;
00154     }
00155 
00156     return m_ThreadState;
00157   }
00158 
00159   ThreadState NThread::Stop ( bool bForceKill )
00160   {
00161     int ret = pthread_detach (m_ThreadCtx.m_dwTID);
00162 
00163     if (ret != 0)
00164     {
00165       nuxDebugMsg (TEXT ("[NThread::Stop] Cannot detach thread.") );
00166       m_ThreadState = THREAD_STOP_ERROR;
00167       return m_ThreadState;
00168     }
00169 
00170     m_ThreadState = THREADSTOP;
00171     return m_ThreadState;
00172   }
00173 
00174   ThreadState NThread::Suspend()
00175   {
00176     m_ThreadState = THREADSUSPENDED;
00177     return m_ThreadState;
00178   }
00179 
00180   ThreadState NThread::Resume()
00181   {
00182     return m_ThreadState;
00183   }
00184 
00185 // go from suspended to thread start
00186   ThreadState NThread::ResumeStart()
00187   {
00188     m_ThreadState = THREADINIT;
00189     return m_ThreadState;
00190   }
00191 
00192 // go from suspended to thread exit
00193   ThreadState NThread::ResumeExit()
00194   {
00195     m_ThreadState = THREADSTOP;
00196     return m_ThreadState;
00197   }
00198 
00199   void *NThread::EntryPoint (void *pArg)
00200   {
00201     NThread *pParent = reinterpret_cast<NThread *> (pArg);
00202 
00203     if (pParent == 0)
00204     {
00205       nuxDebugMsg (TEXT ("[NThread::EntryPoint] Invalid pointer. The thread will exit.") );
00206       return 0;
00207     }
00208 
00209     if (!pParent->ThreadCtor() )
00210     {
00211       // return another message saying the thread could not execute due to error in ThreadCtor;
00212     }
00213 
00214     pParent->Run ( pParent->m_ThreadCtx.m_pUserData );
00215 
00216     pParent->ThreadDtor();
00217     return 0;
00218   }
00219 
00220   unsigned int NThread::GetExitCode() const
00221   {
00222     return m_ThreadCtx.m_dwExitCode;
00223   }
00224 
00225   pthread_t NThread::GetPThread()
00226   {
00227     return m_ThreadCtx.m_dwTID;
00228   }
00229 
00230   ThreadState NThread::GetThreadState() const
00231   {
00232     return m_ThreadState;
00233   }
00234 
00235   void NThread::SetThreadState (ThreadState state)
00236   {
00237     m_ThreadState = state;
00238   }
00239 
00240   ThreadWaitResult NThread::JoinThread(NThread *thread, unsigned int milliseconds)
00241   {
00242     if (thread == NULL)
00243     {
00244       return THREAD_WAIT_RESULT_FAILED;
00245     }
00246 
00247     void *value_ptr = NULL;
00248     int result = pthread_join(thread->GetPThread(), &value_ptr);
00249 
00250     switch(result)
00251     {
00252     case 0:
00253       return THREAD_WAIT_RESULT_COMPLETED;
00254     default:
00255       return THREAD_WAIT_RESULT_FAILED;
00256     }
00257   }
00258 }