1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     wxThread (Posix) Implementation 
   4 // Author:      Original from Wolfram Gloger/Guilhem Lavaux 
   8 // Copyright:   (c) Wolfram Gloger (1996, 1997) 
   9 //                  Guilhem Lavaux (1998) 
  10 //                  Vadim Zeitlin (1999) 
  11 //                  Robert Roebling (1999) 
  12 // Licence:     wxWindows licence 
  13 ///////////////////////////////////////////////////////////////////////////// 
  15 // ============================================================================ 
  17 // ============================================================================ 
  19 // ---------------------------------------------------------------------------- 
  21 // ---------------------------------------------------------------------------- 
  24     #pragma implementation "thread.h" 
  27 // With simple makefiles, we must ignore the file body if not using 
  33 #include "wx/thread.h" 
  34 #include "wx/module.h" 
  38 #include "wx/dynarray.h" 
  54 // ---------------------------------------------------------------------------- 
  56 // ---------------------------------------------------------------------------- 
  58 // the possible states of the thread and transitions from them 
  61     STATE_NEW
,          // didn't start execution yet (=> RUNNING) 
  62     STATE_RUNNING
,      // running (=> PAUSED or EXITED) 
  63     STATE_PAUSED
,       // suspended (=> RUNNING or EXITED) 
  64     STATE_EXITED        
// thread doesn't exist any more 
  67 // ---------------------------------------------------------------------------- 
  69 // ---------------------------------------------------------------------------- 
  71 WX_DEFINE_ARRAY(wxThread 
*, wxArrayThread
); 
  73 // ----------------------------------------------------------------------------- 
  75 // ----------------------------------------------------------------------------- 
  77 // we keep the list of all threads created by the application to be able to 
  78 // terminate them on exit if there are some left - otherwise the process would 
  80 static wxArrayThread gs_allThreads
; 
  82 // the id of the main thread 
  83 static pthread_t gs_tidMain
; 
  85 // the key for the pointer to the associated wxThread object 
  86 static pthread_key_t gs_keySelf
; 
  89 // this mutex must be acquired before any call to a GUI function 
  90 static wxMutex 
*gs_mutexGui
; 
  93 // ============================================================================ 
  95 // ============================================================================ 
  97 //-------------------------------------------------------------------- 
  98 // wxMutex (Posix implementation) 
  99 //-------------------------------------------------------------------- 
 101 class wxMutexInternal
 
 104     pthread_mutex_t p_mutex
; 
 109     p_internal 
= new wxMutexInternal
; 
 110     pthread_mutex_init( &(p_internal
->p_mutex
), (const pthread_mutexattr_t
*) NULL 
); 
 117         wxLogDebug(_T("Freeing a locked mutex (%d locks)"), m_locked
); 
 119     pthread_mutex_destroy( &(p_internal
->p_mutex
) ); 
 123 wxMutexError 
wxMutex::Lock() 
 125     int err 
= pthread_mutex_lock( &(p_internal
->p_mutex
) ); 
 128         wxLogDebug(_T("Locking this mutex would lead to deadlock!")); 
 130         return wxMUTEX_DEAD_LOCK
; 
 135     return wxMUTEX_NO_ERROR
; 
 138 wxMutexError 
wxMutex::TryLock() 
 145     int err 
= pthread_mutex_trylock( &(p_internal
->p_mutex
) ); 
 148         case EBUSY
: return wxMUTEX_BUSY
; 
 153     return wxMUTEX_NO_ERROR
; 
 156 wxMutexError 
wxMutex::Unlock() 
 164         wxLogDebug(_T("Unlocking not locked mutex.")); 
 166         return wxMUTEX_UNLOCKED
; 
 169     pthread_mutex_unlock( &(p_internal
->p_mutex
) ); 
 171     return wxMUTEX_NO_ERROR
; 
 174 //-------------------------------------------------------------------- 
 175 // wxCondition (Posix implementation) 
 176 //-------------------------------------------------------------------- 
 178 class wxConditionInternal
 
 181   pthread_cond_t p_condition
; 
 184 wxCondition::wxCondition() 
 186     p_internal 
= new wxConditionInternal
; 
 187     pthread_cond_init( &(p_internal
->p_condition
), (const pthread_condattr_t 
*) NULL 
); 
 190 wxCondition::~wxCondition() 
 192     pthread_cond_destroy( &(p_internal
->p_condition
) ); 
 197 void wxCondition::Wait(wxMutex
& mutex
) 
 199     pthread_cond_wait( &(p_internal
->p_condition
), &(mutex
.p_internal
->p_mutex
) ); 
 202 bool wxCondition::Wait(wxMutex
& mutex
, unsigned long sec
, unsigned long nsec
) 
 204     struct timespec tspec
; 
 206     tspec
.tv_sec 
= time(0L)+sec
; 
 207     tspec
.tv_nsec 
= nsec
; 
 208     return (pthread_cond_timedwait(&(p_internal
->p_condition
), &(mutex
.p_internal
->p_mutex
), &tspec
) != ETIMEDOUT
); 
 211 void wxCondition::Signal() 
 213     pthread_cond_signal( &(p_internal
->p_condition
) ); 
 216 void wxCondition::Broadcast() 
 218     pthread_cond_broadcast( &(p_internal
->p_condition
) ); 
 221 //-------------------------------------------------------------------- 
 222 // wxThread (Posix implementation) 
 223 //-------------------------------------------------------------------- 
 225 class wxThreadInternal
 
 231     // thread entry function 
 232     static void *PthreadStart(void *ptr
); 
 234 #if HAVE_THREAD_CLEANUP_FUNCTIONS 
 235     // thread exit function 
 236     static void PthreadCleanup(void *ptr
); 
 242         // ask the thread to terminate 
 244         // wake up threads waiting for our termination 
 246         // go to sleep until Resume() is called 
 253     int GetPriority() const { return m_prio
; } 
 254     void SetPriority(int prio
) { m_prio 
= prio
; } 
 256     wxThreadState 
GetState() const { return m_state
; } 
 257     void SetState(wxThreadState state
) { m_state 
= state
; } 
 259     pthread_t 
GetId() const { return m_threadId
; } 
 260     pthread_t 
*GetIdPtr() { return &m_threadId
; } 
 262     void SetCancelFlag() { m_cancelled 
= TRUE
; } 
 263     bool WasCancelled() const { return m_cancelled
; } 
 266     pthread_t     m_threadId
;   // id of the thread 
 267     wxThreadState m_state
;      // see wxThreadState enum 
 268     int           m_prio
;       // in wxWindows units: from 0 to 100 
 270     // set when the thread should terminate 
 273     // this (mutex, cond) pair is used to synchronize the main thread and this 
 274     // thread in several situations: 
 275     //  1. The thread function blocks until condition is signaled by Run() when 
 276     //     it's initially created - this allows thread creation in "suspended" 
 278     //  2. The Delete() function blocks until the condition is signaled when the 
 280     wxMutex     m_mutex
, m_end_mutex
; 
 283     // another (mutex, cond) pair for Pause()/Resume() usage 
 285     // VZ: it's possible that we might reuse the mutex and condition from above 
 286     //     for this too, but as I'm not at all sure that it won't create subtle 
 287     //     problems with race conditions between, say, Pause() and Delete() I 
 288     //     prefer this may be a bit less efficient but much safer solution 
 289     wxMutex     m_mutexSuspend
; 
 290     wxCondition m_condSuspend
; 
 293 void *wxThreadInternal::PthreadStart(void *ptr
) 
 295     wxThread 
*thread 
= (wxThread 
*)ptr
; 
 296     wxThreadInternal 
*pthread 
= thread
->p_internal
; 
 299     int rc 
= pthread_setspecific(gs_keySelf
, thread
); 
 302         wxLogSysError(rc
, _("Cannot start thread: error writing TLS")); 
 306 #if HAVE_THREAD_CLEANUP_FUNCTIONS 
 307     // Install the cleanup handler. 
 308 //    pthread_cleanup_push(wxThreadInternal::PthreadCleanup, ptr); 
 311     // wait for the condition to be signaled from Run() 
 312     // mutex state: currently locked by the thread which created us 
 313     pthread
->m_cond
.Wait(pthread
->m_mutex
); 
 314     // mutex state: locked again on exit of Wait() 
 316     // call the main entry 
 317     status 
= thread
->Entry(); 
 319 #if HAVE_THREAD_CLEANUP_FUNCTIONS 
 320 //    pthread_cleanup_pop(FALSE); 
 323     // terminate the thread 
 324     thread
->Exit(status
); 
 326     wxFAIL_MSG(_T("wxThread::Exit() can't return.")); 
 331 #if HAVE_THREAD_CLEANUP_FUNCTIONS 
 332 // Only called when the thread is explicitely killed. 
 334 void wxThreadInternal::PthreadCleanup(void *ptr
) 
 336     wxThread 
*thread 
= (wxThread 
*) ptr
; 
 338     // The thread is already considered as finished. 
 339     if (thread
->p_internal
->GetState() == STATE_EXITED
) 
 342     // first call user-level clean up code 
 345     // next wake up the threads waiting for us (OTOH, this function won't retur 
 346     // until someone waited for us!) 
 347     thread
->p_internal
->SetState(STATE_EXITED
); 
 349     thread
->p_internal
->SignalExit(); 
 353 wxThreadInternal::wxThreadInternal() 
 358     // this mutex is locked during almost all thread lifetime - it will only be 
 359     // unlocked in the very end 
 362     // this mutex is used by wxThreadInternal::Wait() and by 
 363     // wxThreadInternal::SignalExit(). We don't use m_mutex because of a 
 364     // possible deadlock in either Wait() or SignalExit(). 
 367     // this mutex is used in Pause()/Resume() and is also locked all the time 
 368     // unless the thread is paused 
 369     m_mutexSuspend
.Lock(); 
 372 wxThreadInternal::~wxThreadInternal() 
 374     // GL: moved to SignalExit 
 375     // m_mutexSuspend.Unlock(); 
 377     // note that m_mutex will be unlocked by the thread which waits for our 
 380     // m_end_mutex can be unlocked here. 
 381     m_end_mutex
.Unlock(); 
 384 wxThreadError 
wxThreadInternal::Run() 
 386     wxCHECK_MSG( GetState() == STATE_NEW
, wxTHREAD_RUNNING
, 
 387                  _T("thread may only be started once after successful Create()") ); 
 389     // the mutex was locked on Create(), so we will be able to lock it again 
 390     // only when the thread really starts executing and enters the wait - 
 391     // otherwise we might signal the condition before anybody is waiting for it 
 392     wxMutexLocker 
lock(m_mutex
); 
 395     m_state 
= STATE_RUNNING
; 
 397     return wxTHREAD_NO_ERROR
; 
 399     // now the mutex is unlocked back - but just to allow Wait() function to 
 400     // terminate by relocking it, so the net result is that the worker thread 
 401     // starts executing and the mutex is still locked 
 404 void wxThreadInternal::Wait() 
 406     wxCHECK_RET( WasCancelled(), _T("thread should have been cancelled first") ); 
 408     // if the thread we're waiting for is waiting for the GUI mutex, we will 
 409     // deadlock so make sure we release it temporarily 
 410     if ( wxThread::IsMain() ) 
 413     // entering Wait() releases the mutex thus allowing SignalExit() to acquire 
 414     // it and to signal us its termination 
 415     m_cond
.Wait(m_end_mutex
); 
 417     // mutex is still in the locked state - relocked on exit from Wait(), so 
 418     // unlock it - we don't need it any more, the thread has already terminated 
 419     m_end_mutex
.Unlock(); 
 421     // After that, we wait for the real end of the other thread. 
 422     pthread_join(GetId(), NULL
); 
 424     // reacquire GUI mutex 
 425     if ( wxThread::IsMain() ) 
 429 void wxThreadInternal::SignalExit() 
 431     // GL: Unlock mutexSuspend here. 
 432     m_mutexSuspend
.Unlock(); 
 434     // as mutex is currently locked, this will block until some other thread 
 435     // (normally the same which created this one) unlocks it by entering Wait() 
 438     // wake up all the threads waiting for our termination 
 441     // after this call mutex will be finally unlocked 
 442     m_end_mutex
.Unlock(); 
 445 void wxThreadInternal::Pause() 
 447     // the state is set from the thread which pauses us first, this function 
 448     // is called later so the state should have been already set 
 449     wxCHECK_RET( m_state 
== STATE_PAUSED
, 
 450                  _T("thread must first be paused with wxThread::Pause().") ); 
 452     // don't pause the thread which is being terminated - this would lead to 
 453     // deadlock if the thread is paused after Delete() had called Resume() but 
 454     // before it had time to call Wait() 
 455     if ( WasCancelled() ) 
 458     // wait until the condition is signaled from Resume() 
 459     m_condSuspend
.Wait(m_mutexSuspend
); 
 462 void wxThreadInternal::Resume() 
 464     wxCHECK_RET( m_state 
== STATE_PAUSED
, 
 465                  _T("can't resume thread which is not suspended.") ); 
 467     // we will be able to lock this mutex only when Pause() starts waiting 
 468     wxMutexLocker 
lock(m_mutexSuspend
); 
 469     m_condSuspend
.Signal(); 
 471     SetState(STATE_RUNNING
); 
 474 // ----------------------------------------------------------------------------- 
 476 // ----------------------------------------------------------------------------- 
 478 wxThread 
*wxThread::This() 
 480     return (wxThread 
*)pthread_getspecific(gs_keySelf
); 
 483 bool wxThread::IsMain() 
 485     return (bool)pthread_equal(pthread_self(), gs_tidMain
); 
 488 void wxThread::Yield() 
 493 void wxThread::Sleep(unsigned long milliseconds
) 
 495     wxUsleep(milliseconds
); 
 498 // ----------------------------------------------------------------------------- 
 500 // ----------------------------------------------------------------------------- 
 504     // add this thread to the global list of all threads 
 505     gs_allThreads
.Add(this); 
 507     p_internal 
= new wxThreadInternal(); 
 510 wxThreadError 
wxThread::Create() 
 512     if (p_internal
->GetState() != STATE_NEW
) 
 513         return wxTHREAD_RUNNING
; 
 515     // set up the thread attribute: right now, we only set thread priority 
 517     pthread_attr_init(&attr
); 
 519 #ifdef HAVE_THREAD_PRIORITY_FUNCTIONS 
 521     if ( pthread_attr_getschedpolicy(&attr
, &prio
) != 0 ) 
 523         wxLogError(_("Cannot retrieve thread scheduling policy.")); 
 526     int min_prio 
= sched_get_priority_min(prio
), 
 527         max_prio 
= sched_get_priority_max(prio
); 
 529     if ( min_prio 
== -1 || max_prio 
== -1 ) 
 531         wxLogError(_("Cannot get priority range for scheduling policy %d."), 
 536         struct sched_param sp
; 
 537         pthread_attr_getschedparam(&attr
, &sp
); 
 538         sp
.sched_priority 
= min_prio 
+ 
 539                            (p_internal
->GetPriority()*(max_prio
-min_prio
))/100; 
 540         pthread_attr_setschedparam(&attr
, &sp
); 
 542 #endif // HAVE_THREAD_PRIORITY_FUNCTIONS 
 544 #ifdef HAVE_PTHREAD_ATTR_SETSCOPE 
 545     // this will make the threads created by this process really concurrent 
 546     pthread_attr_setscope(&attr
, PTHREAD_SCOPE_SYSTEM
); 
 547 #endif // HAVE_PTHREAD_ATTR_SETSCOPE 
 549     // create the new OS thread object 
 550     int rc 
= pthread_create(p_internal
->GetIdPtr(), &attr
, 
 551                             wxThreadInternal::PthreadStart
, (void *)this); 
 552     pthread_attr_destroy(&attr
); 
 556         p_internal
->SetState(STATE_EXITED
); 
 557         return wxTHREAD_NO_RESOURCE
; 
 560     return wxTHREAD_NO_ERROR
; 
 563 wxThreadError 
wxThread::Run() 
 565     return p_internal
->Run(); 
 568 // ----------------------------------------------------------------------------- 
 570 // ----------------------------------------------------------------------------- 
 572 void wxThread::SetPriority(unsigned int prio
) 
 574     wxCHECK_RET( ((int)WXTHREAD_MIN_PRIORITY 
<= (int)prio
) && 
 575                  ((int)prio 
<= (int)WXTHREAD_MAX_PRIORITY
), 
 576                  _T("invalid thread priority") ); 
 578     wxCriticalSectionLocker 
lock(m_critsect
); 
 580     switch ( p_internal
->GetState() ) 
 583             // thread not yet started, priority will be set when it is 
 584             p_internal
->SetPriority(prio
); 
 589 #ifdef HAVE_THREAD_PRIORITY_FUNCTIONS 
 591                 struct sched_param sparam
; 
 592                 sparam
.sched_priority 
= prio
; 
 594                 if ( pthread_setschedparam(p_internal
->GetId(), 
 595                                            SCHED_OTHER
, &sparam
) != 0 ) 
 597                     wxLogError(_("Failed to set thread priority %d."), prio
); 
 600 #endif // HAVE_THREAD_PRIORITY_FUNCTIONS 
 605             wxFAIL_MSG(_T("impossible to set thread priority in this state")); 
 609 unsigned int wxThread::GetPriority() const 
 611     wxCriticalSectionLocker 
lock((wxCriticalSection 
&)m_critsect
); 
 613     return p_internal
->GetPriority(); 
 616 unsigned long wxThread::GetID() const 
 618     return (unsigned long)p_internal
->GetId(); 
 621 // ----------------------------------------------------------------------------- 
 623 // ----------------------------------------------------------------------------- 
 625 wxThreadError 
wxThread::Pause() 
 627     wxCriticalSectionLocker 
lock(m_critsect
); 
 629     if ( p_internal
->GetState() != STATE_RUNNING 
) 
 631         wxLogDebug(_T("Can't pause thread which is not running.")); 
 633         return wxTHREAD_NOT_RUNNING
; 
 636     p_internal
->SetState(STATE_PAUSED
); 
 638     return wxTHREAD_NO_ERROR
; 
 641 wxThreadError 
wxThread::Resume() 
 643     wxCriticalSectionLocker 
lock(m_critsect
); 
 645     if ( p_internal
->GetState() == STATE_PAUSED 
) 
 648         p_internal
->Resume(); 
 651         return wxTHREAD_NO_ERROR
; 
 655         wxLogDebug(_T("Attempt to resume a thread which is not paused.")); 
 657         return wxTHREAD_MISC_ERROR
; 
 661 // ----------------------------------------------------------------------------- 
 663 // ----------------------------------------------------------------------------- 
 665 wxThread::ExitCode 
wxThread::Delete() 
 668     wxThreadState state 
= p_internal
->GetState(); 
 670     // ask the thread to stop 
 671     p_internal
->SetCancelFlag(); 
 683             // resume the thread first 
 689             // wait until the thread stops 
 696 wxThreadError 
wxThread::Kill() 
 698     switch ( p_internal
->GetState() ) 
 702             return wxTHREAD_NOT_RUNNING
; 
 705 #ifdef HAVE_PTHREAD_CANCEL  
 706             if ( pthread_cancel(p_internal
->GetId()) != 0 ) 
 709                 wxLogError(_("Failed to terminate a thread.")); 
 711                 return wxTHREAD_MISC_ERROR
; 
 714             return wxTHREAD_NO_ERROR
; 
 718 void wxThread::Exit(void *status
) 
 720     // first call user-level clean up code 
 723     // next wake up the threads waiting for us (OTOH, this function won't return 
 724     // until someone waited for us!) 
 725     p_internal
->SignalExit(); 
 727     p_internal
->SetState(STATE_EXITED
); 
 729     // delete both C++ thread object and terminate the OS thread object 
 730     // GL: This is very ugly and buggy ... 
 732     pthread_exit(status
); 
 735 // also test whether we were paused 
 736 bool wxThread::TestDestroy() 
 738     wxCriticalSectionLocker 
lock(m_critsect
); 
 740     if ( p_internal
->GetState() == STATE_PAUSED 
) 
 742         // leave the crit section or the other threads will stop too if they try 
 743         // to call any of (seemingly harmless) IsXXX() functions while we sleep 
 748         // enter it back before it's finally left in lock object dtor 
 752     return p_internal
->WasCancelled(); 
 755 wxThread::~wxThread() 
 757     // remove this thread from the global array 
 758     gs_allThreads
.Remove(this); 
 761 // ----------------------------------------------------------------------------- 
 763 // ----------------------------------------------------------------------------- 
 765 bool wxThread::IsRunning() const 
 767     wxCriticalSectionLocker 
lock((wxCriticalSection 
&)m_critsect
); 
 769     return p_internal
->GetState() == STATE_RUNNING
; 
 772 bool wxThread::IsAlive() const 
 774     wxCriticalSectionLocker 
lock((wxCriticalSection
&)m_critsect
); 
 776     switch ( p_internal
->GetState() ) 
 787 bool wxThread::IsPaused() const 
 789     wxCriticalSectionLocker 
lock((wxCriticalSection
&)m_critsect
); 
 791     return (p_internal
->GetState() == STATE_PAUSED
); 
 794 //-------------------------------------------------------------------- 
 796 //-------------------------------------------------------------------- 
 798 class wxThreadModule 
: public wxModule
 
 801     virtual bool OnInit(); 
 802     virtual void OnExit(); 
 805     DECLARE_DYNAMIC_CLASS(wxThreadModule
) 
 808 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule
, wxModule
) 
 810 bool wxThreadModule::OnInit() 
 812     int rc 
= pthread_key_create(&gs_keySelf
, NULL 
/* dtor function */); 
 815         wxLogSysError(rc
, _("Thread module initialization failed: " 
 816                             "failed to create thread key")); 
 822     gs_mutexGui 
= new wxMutex(); 
 825     gs_tidMain 
= pthread_self(); 
 834 void wxThreadModule::OnExit() 
 836     wxASSERT_MSG( wxThread::IsMain(), _T("only main thread can be here") ); 
 838     // terminate any threads left 
 839     size_t count 
= gs_allThreads
.GetCount(); 
 841         wxLogDebug(_T("Some threads were not terminated by the application.")); 
 843     for ( size_t n 
= 0u; n 
< count
; n
++ ) 
 845         gs_allThreads
[n
]->Delete(); 
 850     gs_mutexGui
->Unlock(); 
 856     (void)pthread_key_delete(gs_keySelf
); 
 859 // ---------------------------------------------------------------------------- 
 861 // ---------------------------------------------------------------------------- 
 863 void wxMutexGuiEnter() 
 872 void wxMutexGuiLeave() 
 877   gs_mutexGui
->Unlock();