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 //                  Robert Roebling (1999) 
  11 // Licence:     wxWindows licence 
  12 ///////////////////////////////////////////////////////////////////////////// 
  15     #pragma implementation "thread.h" 
  28 extern int usleep(unsigned int useconds
); 
  32 #include "wx/thread.h" 
  33 #include "wx/module.h" 
  37 #include "wx/dynarray.h" 
  44     STATE_NEW
,          // didn't start execution yet (=> RUNNING) 
  51 WX_DEFINE_ARRAY(wxThread 
*, wxArrayThread
); 
  53 // ----------------------------------------------------------------------------- 
  55 // ----------------------------------------------------------------------------- 
  57 // we keep the list of all threads created by the application to be able to 
  58 // terminate them on exit if there are some left - otherwise the process would 
  60 static wxArrayThread gs_allThreads
; 
  62 // the id of the main thread 
  63 static pthread_t gs_tidMain
; 
  65 // the key for the pointer to the associated wxThread object 
  66 static pthread_key_t gs_keySelf
; 
  68 // this mutex must be acquired before any call to a GUI function 
  69 static wxMutex 
*gs_mutexGui
; 
  71 //-------------------------------------------------------------------- 
  72 // common GUI thread code 
  73 //-------------------------------------------------------------------- 
  75 #include "threadgui.inc" 
  77 //-------------------------------------------------------------------- 
  78 // wxMutex (Posix implementation) 
  79 //-------------------------------------------------------------------- 
  84   pthread_mutex_t p_mutex
; 
  89     p_internal 
= new wxMutexInternal
; 
  90     pthread_mutex_init( &(p_internal
->p_mutex
), (const pthread_mutexattr_t
*) NULL 
); 
  97         wxLogDebug("Freeing a locked mutex (%d locks)", m_locked
); 
  99     pthread_mutex_destroy( &(p_internal
->p_mutex
) ); 
 103 wxMutexError 
wxMutex::Lock() 
 105     int err 
= pthread_mutex_lock( &(p_internal
->p_mutex
) ); 
 108         wxLogDebug("Locking this mutex would lead to deadlock!"); 
 110         return wxMUTEX_DEAD_LOCK
; 
 115     return wxMUTEX_NO_ERROR
; 
 118 wxMutexError 
wxMutex::TryLock() 
 125     int err 
= pthread_mutex_trylock( &(p_internal
->p_mutex
) ); 
 128         case EBUSY
: return wxMUTEX_BUSY
; 
 133     return wxMUTEX_NO_ERROR
; 
 136 wxMutexError 
wxMutex::Unlock() 
 144         wxLogDebug("Unlocking not locked mutex."); 
 146         return wxMUTEX_UNLOCKED
; 
 149     pthread_mutex_unlock( &(p_internal
->p_mutex
) ); 
 151     return wxMUTEX_NO_ERROR
; 
 154 //-------------------------------------------------------------------- 
 155 // wxCondition (Posix implementation) 
 156 //-------------------------------------------------------------------- 
 158 class wxConditionInternal
 
 161   pthread_cond_t p_condition
; 
 164 wxCondition::wxCondition() 
 166     p_internal 
= new wxConditionInternal
; 
 167     pthread_cond_init( &(p_internal
->p_condition
), (const pthread_condattr_t 
*) NULL 
); 
 170 wxCondition::~wxCondition() 
 172     pthread_cond_destroy( &(p_internal
->p_condition
) ); 
 177 void wxCondition::Wait(wxMutex
& mutex
) 
 179     pthread_cond_wait( &(p_internal
->p_condition
), &(mutex
.p_internal
->p_mutex
) ); 
 182 bool wxCondition::Wait(wxMutex
& mutex
, unsigned long sec
, unsigned long nsec
) 
 184     struct timespec tspec
; 
 186     tspec
.tv_sec 
= time(0L)+sec
; 
 187     tspec
.tv_nsec 
= nsec
; 
 188     return (pthread_cond_timedwait(&(p_internal
->p_condition
), &(mutex
.p_internal
->p_mutex
), &tspec
) != ETIMEDOUT
); 
 191 void wxCondition::Signal() 
 193     pthread_cond_signal( &(p_internal
->p_condition
) ); 
 196 void wxCondition::Broadcast() 
 198     pthread_cond_broadcast( &(p_internal
->p_condition
) ); 
 201 //-------------------------------------------------------------------- 
 202 // wxThread (Posix implementation) 
 203 //-------------------------------------------------------------------- 
 205 class wxThreadInternal
 
 211     // thread entry function 
 212     static void *PthreadStart(void *ptr
); 
 217         // ask the thread to terminate 
 219         // wake up threads waiting for our termination 
 221         // go to sleep until Resume() is called 
 228     int GetPriority() const { return m_prio
; } 
 229     void SetPriority(int prio
) { m_prio 
= prio
; } 
 231     thread_state 
GetState() const { return m_state
; } 
 232     void SetState(thread_state state
) { m_state 
= state
; } 
 234     pthread_t 
GetId() const { return thread_id
; } 
 236     bool WasCancelled() const { return m_cancelled
; } 
 238 //private: -- should be! 
 242     thread_state m_state
;    // see thread_state enum 
 243     int          m_prio
;     // in wxWindows units: from 0 to 100 
 245     // set when the thread should terminate 
 248     // this (mutex, cond) pair is used to synchronize the main thread and this 
 249     // thread in several situations: 
 250     //  1. The thread function blocks until condition is signaled by Run() when 
 251     //     it's initially created - this allows create thread in "suspended" 
 253     //  2. The Delete() function blocks until the condition is signaled when the 
 258     // another (mutex, cond) pair for Pause()/Resume() usage 
 260     // VZ: it's possible that we might reuse the mutex and condition from above 
 261     //     for this too, but as I'm not at all sure that it won't create subtle 
 262     //     problems with race conditions between, say, Pause() and Delete() I 
 263     //     prefer this may be a bit less efficient but much safer solution 
 264     wxMutex     m_mutexSuspend
; 
 265     wxCondition m_condSuspend
; 
 268 void *wxThreadInternal::PthreadStart(void *ptr
) 
 270     wxThread 
*thread 
= (wxThread 
*)ptr
; 
 271     wxThreadInternal 
*pthread 
= thread
->p_internal
; 
 273     if ( pthread_setspecific(gs_keySelf
, thread
) != 0 ) 
 275         wxLogError(_("Can not start thread: error writing TLS.")); 
 280     // wait for the condition to be signaled from Run() 
 281     // mutex state: currently locked by the thread which created us 
 282     pthread
->m_cond
.Wait(pthread
->m_mutex
); 
 284     // mutex state: locked again on exit of Wait() 
 286     // call the main entry 
 287     void* status 
= thread
->Entry(); 
 289     // terminate the thread 
 290     thread
->Exit(status
); 
 292     wxFAIL_MSG("wxThread::Exit() can't return."); 
 297 wxThreadInternal::wxThreadInternal() 
 302     // this mutex is locked during almost all thread lifetime - it will only be 
 303     // unlocked in the very end 
 306     // this mutex is used in Pause()/Resume() and is also locked all the time 
 307     // unless the thread is paused 
 308     m_mutexSuspend
.Lock(); 
 311 wxThreadInternal::~wxThreadInternal() 
 313     m_mutexSuspend
.Unlock(); 
 315     // note that m_mutex will be unlocked by the thread which waits for our 
 319 wxThreadError 
wxThreadInternal::Run() 
 321     wxCHECK_MSG( GetState() == STATE_NEW
, wxTHREAD_RUNNING
, 
 322                  "thread may only be started once after successful Create()" ); 
 324     // the mutex was locked on Create(), so we will be able to lock it again 
 325     // only when the thread really starts executing and enters the wait - 
 326     // otherwise we might signal the condition before anybody is waiting for it 
 327     wxMutexLocker 
lock(m_mutex
); 
 330     m_state 
= STATE_RUNNING
; 
 332     return wxTHREAD_NO_ERROR
; 
 334     // now the mutex is unlocked back - but just to allow Wait() function to 
 335     // terminate by relocking it, so the net result is that the worker thread 
 336     // starts executing and the mutex is still locked 
 339 void wxThreadInternal::Cancel() 
 341     // if the thread we're waiting for is waiting for the GUI mutex, we will 
 342     // deadlock so make sure we release it temporarily 
 343     if ( wxThread::IsMain() ) 
 346     // nobody ever writes this variable so it's safe to not use any 
 347     // synchronization here 
 350     // entering Wait() releases the mutex thus allowing SignalExit() to acquire 
 351     // it and to signal us its termination 
 352     m_cond
.Wait(m_mutex
); 
 354     // mutex is still in the locked state - relocked on exit from Wait(), so 
 355     // unlock it - we don't need it any more, the thread has already terminated 
 358     // reacquire GUI mutex 
 359     if ( wxThread::IsMain() ) 
 363 void wxThreadInternal::SignalExit() 
 365     // as mutex is currently locked, this will block until some other thread 
 366     // (normally the same which created this one) unlocks it by entering Wait() 
 369     // wake up all the threads waiting for our termination 
 372     // after this call mutex will be finally unlocked 
 376 void wxThreadInternal::Pause() 
 378     wxCHECK_RET( m_state 
== STATE_PAUSED
, 
 379                  "thread must first be paused with wxThread::Pause()." ); 
 381     // wait until the condition is signaled from Resume() 
 382     m_condSuspend
.Wait(m_mutexSuspend
); 
 385 void wxThreadInternal::Resume() 
 387     wxCHECK_RET( m_state 
== STATE_PAUSED
, 
 388                  "can't resume thread which is not suspended." ); 
 390     // we will be able to lock this mutex only when Pause() starts waiting 
 391     wxMutexLocker 
lock(m_mutexSuspend
); 
 392     m_condSuspend
.Signal(); 
 394     SetState(STATE_RUNNING
); 
 397 // ----------------------------------------------------------------------------- 
 399 // ----------------------------------------------------------------------------- 
 401 wxThread 
*wxThread::This() 
 403     return (wxThread 
*)pthread_getspecific(gs_keySelf
); 
 406 bool wxThread::IsMain() 
 408     return (bool)pthread_equal(pthread_self(), gs_tidMain
); 
 411 void wxThread::Yield() 
 413 #ifdef HAVE_SCHED_YIELD 
 415 #else // !HAVE_SCHED_YIELD 
 416     // may be it will have the desired effect? 
 418 #endif // HAVE_SCHED_YIELD 
 421 void wxThread::Sleep(unsigned long milliseconds
) 
 423     wxUsleep(milliseconds
); 
 426 // ----------------------------------------------------------------------------- 
 428 // ----------------------------------------------------------------------------- 
 432     // add this thread to the global list of all threads 
 433     gs_allThreads
.Add(this); 
 435     p_internal 
= new wxThreadInternal(); 
 438 wxThreadError 
wxThread::Create() 
 440     if (p_internal
->GetState() != STATE_NEW
) 
 441         return wxTHREAD_RUNNING
; 
 443     // set up the thread attribute: right now, we only set thread priority 
 445     pthread_attr_init(&attr
); 
 447 #ifdef HAVE_THREAD_PRIORITY_FUNCTIONS 
 449     if ( pthread_attr_getschedpolicy(&attr
, &prio
) != 0 ) 
 451         wxLogError(_("Can not retrieve thread scheduling policy.")); 
 454     int min_prio 
= sched_get_priority_min(prio
), 
 455         max_prio 
= sched_get_priority_max(prio
); 
 457     if ( min_prio 
== -1 || max_prio 
== -1 ) 
 459         wxLogError(_("Can not get priority range for scheduling policy %d."), 
 464         struct sched_param sp
; 
 465         pthread_attr_getschedparam(&attr
, &sp
); 
 466         sp
.sched_priority 
= min_prio 
+ 
 467                            (p_internal
->GetPriority()*(max_prio
-min_prio
))/100; 
 468         pthread_attr_setschedparam(&attr
, &sp
); 
 470 #endif // HAVE_THREAD_PRIORITY_FUNCTIONS 
 472     // create the new OS thread object 
 473     int rc 
= pthread_create(&p_internal
->thread_id
, &attr
, 
 474                             wxThreadInternal::PthreadStart
, (void *)this); 
 475     pthread_attr_destroy(&attr
); 
 479         p_internal
->SetState(STATE_EXITED
); 
 480         return wxTHREAD_NO_RESOURCE
; 
 483     return wxTHREAD_NO_ERROR
; 
 486 wxThreadError 
wxThread::Run() 
 488     return p_internal
->Run(); 
 491 // ----------------------------------------------------------------------------- 
 493 // ----------------------------------------------------------------------------- 
 495 void wxThread::SetPriority(unsigned int prio
) 
 497     wxCHECK_RET( ((int)WXTHREAD_MIN_PRIORITY 
<= (int)prio
) && 
 498                  ((int)prio 
<= (int)WXTHREAD_MAX_PRIORITY
), 
 499                  "invalid thread priority" ); 
 501     wxCriticalSectionLocker 
lock(m_critsect
); 
 503     switch ( p_internal
->GetState() ) 
 506             // thread not yet started, priority will be set when it is 
 507             p_internal
->SetPriority(prio
); 
 512 #ifdef HAVE_THREAD_PRIORITY_FUNCTIONS 
 514                 struct sched_param sparam
; 
 515                 sparam
.sched_priority 
= prio
; 
 517                 if ( pthread_setschedparam(p_internal
->GetId(), 
 518                                            SCHED_OTHER
, &sparam
) != 0 ) 
 520                     wxLogError(_("Failed to set thread priority %d."), prio
); 
 523 #endif // HAVE_THREAD_PRIORITY_FUNCTIONS 
 528             wxFAIL_MSG("impossible to set thread priority in this state"); 
 532 unsigned int wxThread::GetPriority() const 
 534     wxCriticalSectionLocker 
lock((wxCriticalSection 
&)m_critsect
); 
 536     return p_internal
->GetPriority(); 
 539 unsigned long wxThread::GetID() const 
 541     return (unsigned long)p_internal
->thread_id
; 
 544 // ----------------------------------------------------------------------------- 
 546 // ----------------------------------------------------------------------------- 
 548 wxThreadError 
wxThread::Pause() 
 550     wxCriticalSectionLocker 
lock(m_critsect
); 
 552     if ( p_internal
->GetState() != STATE_RUNNING 
) 
 554         wxLogDebug("Can't pause thread which is not running."); 
 556         return wxTHREAD_NOT_RUNNING
; 
 559     p_internal
->SetState(STATE_PAUSED
); 
 561     return wxTHREAD_NO_ERROR
; 
 564 wxThreadError 
wxThread::Resume() 
 566     wxCriticalSectionLocker 
lock(m_critsect
); 
 568     if ( p_internal
->GetState() == STATE_PAUSED 
) 
 570         p_internal
->Resume(); 
 572         return wxTHREAD_NO_ERROR
; 
 576         wxLogDebug("Attempt to resume a thread which is not paused."); 
 578         return wxTHREAD_MISC_ERROR
; 
 582 // ----------------------------------------------------------------------------- 
 584 // ----------------------------------------------------------------------------- 
 586 wxThread::ExitCode 
wxThread::Delete() 
 589     thread_state state 
= p_internal
->GetState(); 
 600             // resume the thread first 
 606             // set the flag telling to the thread to stop and wait 
 607             p_internal
->Cancel(); 
 613 wxThreadError 
wxThread::Kill() 
 615     switch ( p_internal
->GetState() ) 
 619             return wxTHREAD_NOT_RUNNING
; 
 622 #ifdef HAVE_PTHREAD_CANCEL 
 623             if ( pthread_cancel(p_internal
->GetId()) != 0 ) 
 626                 wxLogError(_("Failed to terminate a thread.")); 
 628                 return wxTHREAD_MISC_ERROR
; 
 631             return wxTHREAD_NO_ERROR
; 
 635 void wxThread::Exit(void *status
) 
 637     // first call user-level clean up code 
 640     // next wake up the threads waiting for us (OTOH, this function won't return 
 641     // until someone waited for us!) 
 642     p_internal
->SignalExit(); 
 644     p_internal
->SetState(STATE_EXITED
); 
 646     // delete both C++ thread object and terminate the OS thread object 
 648     pthread_exit(status
); 
 651 // also test whether we were paused 
 652 bool wxThread::TestDestroy() 
 654     wxCriticalSectionLocker 
lock((wxCriticalSection
&)m_critsect
); 
 656     if ( p_internal
->GetState() == STATE_PAUSED 
) 
 658         // leave the crit section or the other threads will stop too if they try 
 659         // to call any of (seemingly harmless) IsXXX() functions while we sleep 
 664         // enter it back before it's finally left in lock object dtor 
 668     return p_internal
->WasCancelled(); 
 671 wxThread::~wxThread() 
 673     // remove this thread from the global array 
 674     gs_allThreads
.Remove(this); 
 677 // ----------------------------------------------------------------------------- 
 679 // ----------------------------------------------------------------------------- 
 681 bool wxThread::IsRunning() const 
 683     wxCriticalSectionLocker 
lock((wxCriticalSection 
&)m_critsect
); 
 685     return p_internal
->GetState() == STATE_RUNNING
; 
 688 bool wxThread::IsAlive() const 
 690     wxCriticalSectionLocker 
lock((wxCriticalSection
&)m_critsect
); 
 692     switch ( p_internal
->GetState() ) 
 703 //-------------------------------------------------------------------- 
 705 //-------------------------------------------------------------------- 
 707 class wxThreadModule 
: public wxModule
 
 710     virtual bool OnInit(); 
 711     virtual void OnExit(); 
 714     DECLARE_DYNAMIC_CLASS(wxThreadModule
) 
 717 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule
, wxModule
) 
 719 bool wxThreadModule::OnInit() 
 721     if ( pthread_key_create(&gs_keySelf
, NULL 
/* dtor function */) != 0 ) 
 723         wxLogError(_("Thread module initialization failed: " 
 724                      "failed to create pthread key.")); 
 729     gs_mutexGui 
= new wxMutex(); 
 731     gs_tidMain 
= pthread_self(); 
 737 void wxThreadModule::OnExit() 
 739     wxASSERT_MSG( wxThread::IsMain(), "only main thread can be here" ); 
 741     // terminate any threads left 
 742     size_t count 
= gs_allThreads
.GetCount(); 
 744         wxLogDebug("Some threads were not terminated by the application."); 
 746     for ( size_t n 
= 0u; n 
< count
; n
++ ) 
 748         gs_allThreads
[n
]->Delete(); 
 752     gs_mutexGui
->Unlock(); 
 757     (void)pthread_key_delete(gs_keySelf
);