• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

src/Thread.cpp

00001 /*
00002  *   This file is part of the Standard Portable Library (SPL).
00003  *
00004  *   SPL is free software: you can redistribute it and/or modify
00005  *   it under the terms of the GNU General Public License as published by
00006  *   the Free Software Foundation, either version 3 of the License, or
00007  *   (at your option) any later version.
00008  *
00009  *   SPL 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 General Public License for more details.
00013  *
00014  *   You should have received a copy of the GNU General Public License
00015  *   along with SPL.  If not, see <http://www.gnu.org/licenses/>.
00016  */
00017 
00018 #include <spl/threading/Thread.h>
00019 #ifdef HAVE_UNISTD_H
00020 #include <unistd.h>
00021 #endif
00022 #ifdef HAVE_STRING_H
00023 #include <string.h>
00024 #endif
00025 
00026 #include <spl/Exception.h>
00027 #include <spl/Log.h>
00028 
00029 #ifndef _WINDOWS
00030 void *TheThread(void *param);
00031 #endif
00032 
00033 Thread::Thread()
00034 : m_joinmutex(), m_hasrun(false)
00035 {
00036         DEBUG_ENABLE_HEAP_LOCK();
00037         m_running = false;
00038 }
00039 
00040 #ifdef _WINDOWS
00041 Thread::Thread(HANDLE threadhandle)
00042 : m_joinmutex(), m_hasrun(false)
00043 {
00044         m_running = false;
00045         m_threadhandle = threadhandle;
00046         m_threadid = 0;
00047 }
00048 #endif
00049 
00050 #ifndef _WINDOWS
00051 Thread::Thread(pthread_t thread)
00052 : m_joinmutex(), m_hasrun(false)
00053 {
00054         DEBUG_ENABLE_HEAP_LOCK();
00055         m_running = false;
00056         m_threadid = thread;
00057 }
00058 #endif
00059 
00060 Thread::~Thread()
00061 {
00062         if ( m_running )
00063         {
00064                 Kill();
00065                 m_running = false;
00066         }
00067 #ifdef _WIN32
00068         if ( NULL != m_threadhandle && m_running )
00069         {
00070                 CloseHandle(m_threadhandle);
00071                 m_threadhandle = NULL;
00072                 m_running = false;
00073         }
00074 #else
00075         // do nothing
00076 #endif
00077 }
00078 
00079 void Thread::Start()
00080 {
00081         if (m_running)
00082         {
00083                 throw new Exception("Thread has already started");
00084         }       
00085 
00086 #ifdef _WIN32   
00087         m_threadhandle = CreateThread(NULL,0,TheThread,this,0,&m_threadid);
00088         if (m_threadhandle == NULL)
00089         {
00090                 throw new ThreadStartException();
00091         }
00092 #else
00093         int ret = pthread_create(&m_threadid, NULL, TheThread, this);
00094         if (0 != ret )
00095         {
00096                 throw new ThreadStartException();
00097         }
00098 #endif  
00099         /* Wait until 'running' is set */
00100 
00101         while (!m_running && !m_hasrun)
00102         {
00103                 Thread::YYield();
00104         }
00105 }
00106 
00107 void Thread::Kill()
00108 {
00109         Thread::YYield();
00110         if (!m_running)
00111         {
00112                 return;
00113         }
00114         m_running = false;
00115         m_hasrun = true;
00116 #ifdef _WIN32
00117         TerminateThread( m_threadhandle, 0 );
00118         m_threadhandle = NULL;
00119 #else
00120         pthread_cancel( m_threadid );
00121         memset(&m_threadid, 0, sizeof(pthread_t));
00122 #endif
00123 }
00124 
00125 bool Thread::IsRunning() const
00126 {
00127         return m_running;
00128 }
00129 
00130 void Thread::Join()
00131 {
00132         m_joinmutex.SetTimeout( 0 );
00133         m_joinmutex.Lock();
00134         m_joinmutex.Unlock();
00135 }
00136 
00137 bool Thread::Join( int timeoutMs )
00138 {
00139         m_joinmutex.SetTimeout( timeoutMs );
00140         if ( ! m_joinmutex.Lock() )
00141         {
00142                 return false;
00143         }
00144         m_joinmutex.Unlock();
00145         return true;
00146 }
00147 
00148 void Thread::SetPriority( enum ThreadPriority prilv )
00149 {
00150 #ifdef WIN32
00151         if ( Thread::PRIORITY_NORMAL == prilv )
00152         {
00153                 SetThreadPriority(m_threadhandle, THREAD_PRIORITY_NORMAL);
00154         }
00155         else if ( Thread::PRIORITY_HI == prilv )
00156         {
00157                 SetThreadPriority(m_threadhandle, THREAD_PRIORITY_ABOVE_NORMAL);
00158         }
00159         else
00160         {
00161                 SetThreadPriority(m_threadhandle, THREAD_PRIORITY_BELOW_NORMAL);
00162         }
00163 #else
00164         struct sched_param sc;
00165         if ( Thread::PRIORITY_NORMAL == prilv )
00166         {
00167                 // BUG: This can't be right
00168                 sc.sched_priority = (sched_get_priority_max(SCHED_FIFO) - 
00169                         sched_get_priority_min(SCHED_FIFO))/2;
00170                 pthread_setschedparam(m_threadid, SCHED_FIFO, &sc);
00171         }
00172         else if ( Thread::PRIORITY_HI == prilv )
00173         {
00174                 sc.sched_priority = sched_get_priority_max(SCHED_FIFO);
00175                 pthread_setschedparam(m_threadid, SCHED_FIFO, &sc);
00176         }
00177         else
00178         {
00179                 sc.sched_priority = sched_get_priority_min(SCHED_FIFO)+1;
00180                 pthread_setschedparam(m_threadid, SCHED_FIFO, &sc);
00181         }
00182 #endif
00183 }
00184 
00185 #ifdef _WINDOWS
00186 DWORD WINAPI Thread::TheThread(void *param)
00187 {
00188         Thread *thread = (Thread *)param;
00189         
00190         thread->m_joinmutex.Lock();
00191         thread->m_running = true;
00192         
00193         try
00194         {
00195                 thread->Run();
00196         }
00197         catch (Exception *ex)
00198         {
00199                 Log::SWrite(ex);
00200                 delete ex;
00201         }
00202         catch (OutOfMemoryException mex)
00203         {
00204                 Log::SWrite(mex);
00205         }
00206         
00207         thread->m_hasrun = true;
00208         thread->m_running = false;
00209         thread->m_joinmutex.Unlock();
00210         
00211         return 0;               
00212 }
00213 #else
00214 void *TheThread(void *param)
00215 {
00216         Thread *thread = (Thread *)param;
00217 
00218         thread->m_joinmutex.Lock();
00219         thread->m_running = true;
00220                 
00221         try
00222         {
00223                 thread->Run();
00224         }
00225         catch (Exception *ex)
00226         {
00227                 Log::SWrite(ex);
00228                 delete ex;
00229         }
00230         catch (OutOfMemoryException mex)
00231         {
00232                 Log::SWrite(mex);
00233         }
00234         
00235         thread->m_hasrun = true;
00236         thread->m_running = false;
00237         thread->m_joinmutex.Unlock();
00238 
00239         return NULL;
00240 }
00241 #endif
00242 
00243 void Thread::YYield()
00244 {
00245 #ifdef _WIN32
00246         ::Sleep( 1 );
00247 #else
00248         sched_yield();
00249 #endif
00250 }
00251 
00252 void Thread::Sleep( long ms )
00253 {
00254 #ifdef _WIN32
00255         ::Sleep( ms );
00256 #else
00257         sleep( (unsigned int)(ms/1000.0) );
00258 #endif
00259 }
00260 
00261 /*
00262 Thread Thread::CurrentThread()
00263 {
00264 #if defined(_WIN32) || defined(WIN32)
00265         return Thread(GetCurrentThread());
00266 #else
00267         return Thread(pthread_self());
00268 #endif
00269 }
00270 */
00271 
00272 #if defined(DEBUG)
00273 void Thread::CheckMem() const
00274 {
00275 }
00276 
00277 void Thread::ValidateMem() const
00278 {
00279 }
00280 #endif