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
);
315 // mutex state: locked again on exit of Wait()
317 // call the main entry
318 status
= thread
->Entry();
320 #if HAVE_THREAD_CLEANUP_FUNCTIONS
321 pthread_cleanup_pop(FALSE
);
324 // terminate the thread
325 thread
->Exit(status
);
327 wxFAIL_MSG(_T("wxThread::Exit() can't return."));
332 #if HAVE_THREAD_CLEANUP_FUNCTIONS
333 // Only called when the thread is explicitely killed.
335 void wxThreadInternal::PthreadCleanup(void *ptr
)
337 wxThread
*thread
= (wxThread
*) ptr
;
339 // The thread is already considered as finished.
340 if (thread
->p_internal
->GetState() == STATE_EXITED
)
343 // first call user-level clean up code
346 // next wake up the threads waiting for us (OTOH, this function won't retur
347 // until someone waited for us!)
348 thread
->p_internal
->SetState(STATE_EXITED
);
350 thread
->p_internal
->SignalExit();
354 wxThreadInternal::wxThreadInternal()
359 // this mutex is locked during almost all thread lifetime - it will only be
360 // unlocked in the very end
365 // this mutex is used in Pause()/Resume() and is also locked all the time
366 // unless the thread is paused
367 m_mutexSuspend
.Lock();
370 wxThreadInternal::~wxThreadInternal()
372 // GL: moved to SignalExit
373 // m_mutexSuspend.Unlock();
375 // note that m_mutex will be unlocked by the thread which waits for our
377 m_end_mutex
.Unlock();
380 wxThreadError
wxThreadInternal::Run()
382 wxCHECK_MSG( GetState() == STATE_NEW
, wxTHREAD_RUNNING
,
383 _T("thread may only be started once after successful Create()") );
385 // the mutex was locked on Create(), so we will be able to lock it again
386 // only when the thread really starts executing and enters the wait -
387 // otherwise we might signal the condition before anybody is waiting for it
388 wxMutexLocker
lock(m_mutex
);
391 m_state
= STATE_RUNNING
;
393 return wxTHREAD_NO_ERROR
;
395 // now the mutex is unlocked back - but just to allow Wait() function to
396 // terminate by relocking it, so the net result is that the worker thread
397 // starts executing and the mutex is still locked
400 void wxThreadInternal::Wait()
402 wxCHECK_RET( WasCancelled(), _T("thread should have been cancelled first") );
404 // if the thread we're waiting for is waiting for the GUI mutex, we will
405 // deadlock so make sure we release it temporarily
406 if ( wxThread::IsMain() )
409 printf("Entering wait ...\n");
410 // entering Wait() releases the mutex thus allowing SignalExit() to acquire
411 // it and to signal us its termination
412 m_cond
.Wait(m_end_mutex
);
413 printf("Exiting wait ...\n");
415 // mutex is still in the locked state - relocked on exit from Wait(), so
416 // unlock it - we don't need it any more, the thread has already terminated
417 m_end_mutex
.Unlock();
419 // reacquire GUI mutex
420 if ( wxThread::IsMain() )
424 void wxThreadInternal::SignalExit()
426 printf("SignalExit\n");
427 // GL: Unlock mutexSuspend here.
428 m_mutexSuspend
.Unlock();
430 // as mutex is currently locked, this will block until some other thread
431 // (normally the same which created this one) unlocks it by entering Wait()
433 printf("Mutex acquired\n");
435 // wake up all the threads waiting for our termination
438 // after this call mutex will be finally unlocked
439 m_end_mutex
.Unlock();
440 printf("Mutex unacquired\n");
443 void wxThreadInternal::Pause()
445 // the state is set from the thread which pauses us first, this function
446 // is called later so the state should have been already set
447 wxCHECK_RET( m_state
== STATE_PAUSED
,
448 _T("thread must first be paused with wxThread::Pause().") );
450 // don't pause the thread which is being terminated - this would lead to
451 // deadlock if the thread is paused after Delete() had called Resume() but
452 // before it had time to call Wait()
453 if ( WasCancelled() )
456 // wait until the condition is signaled from Resume()
457 m_condSuspend
.Wait(m_mutexSuspend
);
460 void wxThreadInternal::Resume()
462 wxCHECK_RET( m_state
== STATE_PAUSED
,
463 _T("can't resume thread which is not suspended.") );
465 // we will be able to lock this mutex only when Pause() starts waiting
466 wxMutexLocker
lock(m_mutexSuspend
);
467 m_condSuspend
.Signal();
469 SetState(STATE_RUNNING
);
472 // -----------------------------------------------------------------------------
474 // -----------------------------------------------------------------------------
476 wxThread
*wxThread::This()
478 return (wxThread
*)pthread_getspecific(gs_keySelf
);
481 bool wxThread::IsMain()
483 return (bool)pthread_equal(pthread_self(), gs_tidMain
);
486 void wxThread::Yield()
491 void wxThread::Sleep(unsigned long milliseconds
)
493 wxUsleep(milliseconds
);
496 // -----------------------------------------------------------------------------
498 // -----------------------------------------------------------------------------
502 // add this thread to the global list of all threads
503 gs_allThreads
.Add(this);
505 p_internal
= new wxThreadInternal();
508 wxThreadError
wxThread::Create()
510 if (p_internal
->GetState() != STATE_NEW
)
511 return wxTHREAD_RUNNING
;
513 // set up the thread attribute: right now, we only set thread priority
515 pthread_attr_init(&attr
);
517 #ifdef HAVE_THREAD_PRIORITY_FUNCTIONS
519 if ( pthread_attr_getschedpolicy(&attr
, &prio
) != 0 )
521 wxLogError(_("Cannot retrieve thread scheduling policy."));
524 int min_prio
= sched_get_priority_min(prio
),
525 max_prio
= sched_get_priority_max(prio
);
527 if ( min_prio
== -1 || max_prio
== -1 )
529 wxLogError(_("Cannot get priority range for scheduling policy %d."),
534 struct sched_param sp
;
535 pthread_attr_getschedparam(&attr
, &sp
);
536 sp
.sched_priority
= min_prio
+
537 (p_internal
->GetPriority()*(max_prio
-min_prio
))/100;
538 pthread_attr_setschedparam(&attr
, &sp
);
540 #endif // HAVE_THREAD_PRIORITY_FUNCTIONS
542 #ifdef HAVE_PTHREAD_ATTR_SETSCOPE
543 // this will make the threads created by this process really concurrent
544 pthread_attr_setscope(&attr
, PTHREAD_SCOPE_SYSTEM
);
545 #endif // HAVE_PTHREAD_ATTR_SETSCOPE
547 // create the new OS thread object
548 int rc
= pthread_create(p_internal
->GetIdPtr(), &attr
,
549 wxThreadInternal::PthreadStart
, (void *)this);
550 pthread_attr_destroy(&attr
);
554 p_internal
->SetState(STATE_EXITED
);
555 return wxTHREAD_NO_RESOURCE
;
558 return wxTHREAD_NO_ERROR
;
561 wxThreadError
wxThread::Run()
563 return p_internal
->Run();
566 // -----------------------------------------------------------------------------
568 // -----------------------------------------------------------------------------
570 void wxThread::SetPriority(unsigned int prio
)
572 wxCHECK_RET( ((int)WXTHREAD_MIN_PRIORITY
<= (int)prio
) &&
573 ((int)prio
<= (int)WXTHREAD_MAX_PRIORITY
),
574 _T("invalid thread priority") );
576 wxCriticalSectionLocker
lock(m_critsect
);
578 switch ( p_internal
->GetState() )
581 // thread not yet started, priority will be set when it is
582 p_internal
->SetPriority(prio
);
587 #ifdef HAVE_THREAD_PRIORITY_FUNCTIONS
589 struct sched_param sparam
;
590 sparam
.sched_priority
= prio
;
592 if ( pthread_setschedparam(p_internal
->GetId(),
593 SCHED_OTHER
, &sparam
) != 0 )
595 wxLogError(_("Failed to set thread priority %d."), prio
);
598 #endif // HAVE_THREAD_PRIORITY_FUNCTIONS
603 wxFAIL_MSG(_T("impossible to set thread priority in this state"));
607 unsigned int wxThread::GetPriority() const
609 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
611 return p_internal
->GetPriority();
614 unsigned long wxThread::GetID() const
616 return (unsigned long)p_internal
->GetId();
619 // -----------------------------------------------------------------------------
621 // -----------------------------------------------------------------------------
623 wxThreadError
wxThread::Pause()
625 wxCriticalSectionLocker
lock(m_critsect
);
627 if ( p_internal
->GetState() != STATE_RUNNING
)
629 wxLogDebug(_T("Can't pause thread which is not running."));
631 return wxTHREAD_NOT_RUNNING
;
634 p_internal
->SetState(STATE_PAUSED
);
636 return wxTHREAD_NO_ERROR
;
639 wxThreadError
wxThread::Resume()
641 wxCriticalSectionLocker
lock(m_critsect
);
643 if ( p_internal
->GetState() == STATE_PAUSED
)
646 p_internal
->Resume();
649 return wxTHREAD_NO_ERROR
;
653 wxLogDebug(_T("Attempt to resume a thread which is not paused."));
655 return wxTHREAD_MISC_ERROR
;
659 // -----------------------------------------------------------------------------
661 // -----------------------------------------------------------------------------
663 wxThread::ExitCode
wxThread::Delete()
666 wxThreadState state
= p_internal
->GetState();
669 // ask the thread to stop
670 p_internal
->SetCancelFlag();
680 // resume the thread first
686 // wait until the thread stops
693 wxThreadError
wxThread::Kill()
695 switch ( p_internal
->GetState() )
699 return wxTHREAD_NOT_RUNNING
;
702 #ifdef HAVE_PTHREAD_CANCEL
703 if ( pthread_cancel(p_internal
->GetId()) != 0 )
706 wxLogError(_("Failed to terminate a thread."));
708 return wxTHREAD_MISC_ERROR
;
711 return wxTHREAD_NO_ERROR
;
715 void wxThread::Exit(void *status
)
717 // first call user-level clean up code
719 printf(" ... OnExit()\n");
721 // next wake up the threads waiting for us (OTOH, this function won't return
722 // until someone waited for us!)
723 p_internal
->SignalExit();
724 printf(" ... SignalExit()\n");
726 p_internal
->SetState(STATE_EXITED
);
727 printf(" ... SetState()\n");
729 // delete both C++ thread object and terminate the OS thread object
730 // GL: This is very ugly and buggy ...
732 printf(" ... Exit\n");
733 pthread_exit(status
);
736 // also test whether we were paused
737 bool wxThread::TestDestroy()
739 wxCriticalSectionLocker
lock(m_critsect
);
741 if ( p_internal
->GetState() == STATE_PAUSED
)
743 // leave the crit section or the other threads will stop too if they try
744 // to call any of (seemingly harmless) IsXXX() functions while we sleep
749 // enter it back before it's finally left in lock object dtor
753 return p_internal
->WasCancelled();
756 wxThread::~wxThread()
758 // remove this thread from the global array
759 gs_allThreads
.Remove(this);
762 // -----------------------------------------------------------------------------
764 // -----------------------------------------------------------------------------
766 bool wxThread::IsRunning() const
768 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
770 return p_internal
->GetState() == STATE_RUNNING
;
773 bool wxThread::IsAlive() const
775 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
777 switch ( p_internal
->GetState() )
788 bool wxThread::IsPaused() const
790 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
792 return (p_internal
->GetState() == STATE_PAUSED
);
795 //--------------------------------------------------------------------
797 //--------------------------------------------------------------------
799 class wxThreadModule
: public wxModule
802 virtual bool OnInit();
803 virtual void OnExit();
806 DECLARE_DYNAMIC_CLASS(wxThreadModule
)
809 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule
, wxModule
)
811 bool wxThreadModule::OnInit()
813 int rc
= pthread_key_create(&gs_keySelf
, NULL
/* dtor function */);
816 wxLogSysError(rc
, _("Thread module initialization failed: "
817 "failed to create thread key"));
823 gs_mutexGui
= new wxMutex();
826 gs_tidMain
= pthread_self();
835 void wxThreadModule::OnExit()
837 wxASSERT_MSG( wxThread::IsMain(), _T("only main thread can be here") );
839 // terminate any threads left
840 size_t count
= gs_allThreads
.GetCount();
842 wxLogDebug(_T("Some threads were not terminated by the application."));
844 for ( size_t n
= 0u; n
< count
; n
++ )
846 gs_allThreads
[n
]->Delete();
851 gs_mutexGui
->Unlock();
857 (void)pthread_key_delete(gs_keySelf
);
860 // ----------------------------------------------------------------------------
862 // ----------------------------------------------------------------------------
864 void wxMutexGuiEnter()
873 void wxMutexGuiLeave()
878 gs_mutexGui
->Unlock();