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"
50 // ----------------------------------------------------------------------------
52 // ----------------------------------------------------------------------------
54 // the possible states of the thread and transitions from them
57 STATE_NEW
, // didn't start execution yet (=> RUNNING)
58 STATE_RUNNING
, // running (=> PAUSED or EXITED)
59 STATE_PAUSED
, // suspended (=> RUNNING or EXITED)
60 STATE_EXITED
// thread doesn't exist any more
63 // ----------------------------------------------------------------------------
65 // ----------------------------------------------------------------------------
67 WX_DEFINE_ARRAY(wxThread
*, wxArrayThread
);
69 // -----------------------------------------------------------------------------
71 // -----------------------------------------------------------------------------
73 // we keep the list of all threads created by the application to be able to
74 // terminate them on exit if there are some left - otherwise the process would
76 static wxArrayThread gs_allThreads
;
78 // the id of the main thread
79 static pthread_t gs_tidMain
;
81 // the key for the pointer to the associated wxThread object
82 static pthread_key_t gs_keySelf
;
84 // this mutex must be acquired before any call to a GUI function
85 static wxMutex
*gs_mutexGui
;
87 // ============================================================================
89 // ============================================================================
91 //--------------------------------------------------------------------
92 // wxMutex (Posix implementation)
93 //--------------------------------------------------------------------
98 pthread_mutex_t p_mutex
;
103 p_internal
= new wxMutexInternal
;
105 pthread_mutex_init(&(p_internal
->p_mutex
),
106 (pthread_mutexattr_t
*) NULL
);
113 wxLogDebug(wxT("Freeing a locked mutex (%d locks)"), m_locked
);
115 pthread_mutex_destroy( &(p_internal
->p_mutex
) );
119 wxMutexError
wxMutex::Lock()
121 int err
= pthread_mutex_lock( &(p_internal
->p_mutex
) );
124 wxLogDebug(wxT("Locking this mutex would lead to deadlock!"));
126 return wxMUTEX_DEAD_LOCK
;
131 return wxMUTEX_NO_ERROR
;
134 wxMutexError
wxMutex::TryLock()
141 int err
= pthread_mutex_trylock( &(p_internal
->p_mutex
) );
144 case EBUSY
: return wxMUTEX_BUSY
;
149 return wxMUTEX_NO_ERROR
;
152 wxMutexError
wxMutex::Unlock()
160 wxLogDebug(wxT("Unlocking not locked mutex."));
162 return wxMUTEX_UNLOCKED
;
165 pthread_mutex_unlock( &(p_internal
->p_mutex
) );
167 return wxMUTEX_NO_ERROR
;
170 //--------------------------------------------------------------------
171 // wxCondition (Posix implementation)
172 //--------------------------------------------------------------------
174 class wxConditionInternal
177 pthread_cond_t p_condition
;
180 wxCondition::wxCondition()
182 p_internal
= new wxConditionInternal
;
183 pthread_cond_init( &(p_internal
->p_condition
),
184 (pthread_condattr_t
*) NULL
);
187 wxCondition::~wxCondition()
189 pthread_cond_destroy( &(p_internal
->p_condition
) );
194 void wxCondition::Wait(wxMutex
& mutex
)
196 pthread_cond_wait( &(p_internal
->p_condition
), &(mutex
.p_internal
->p_mutex
) );
199 bool wxCondition::Wait(wxMutex
& mutex
, unsigned long sec
, unsigned long nsec
)
201 struct timespec tspec
;
203 tspec
.tv_sec
= time(0L)+sec
;
204 tspec
.tv_nsec
= nsec
;
205 return (pthread_cond_timedwait(&(p_internal
->p_condition
), &(mutex
.p_internal
->p_mutex
), &tspec
) != ETIMEDOUT
);
208 void wxCondition::Signal()
210 pthread_cond_signal( &(p_internal
->p_condition
) );
213 void wxCondition::Broadcast()
215 pthread_cond_broadcast( &(p_internal
->p_condition
) );
218 //--------------------------------------------------------------------
219 // wxThread (Posix implementation)
220 //--------------------------------------------------------------------
222 class wxThreadInternal
228 // thread entry function
229 static void *PthreadStart(void *ptr
);
231 #if HAVE_THREAD_CLEANUP_FUNCTIONS
232 // thread exit function
233 static void PthreadCleanup(void *ptr
);
239 // ask the thread to terminate
241 // wake up threads waiting for our termination
243 // go to sleep until Resume() is called
250 int GetPriority() const { return m_prio
; }
251 void SetPriority(int prio
) { m_prio
= prio
; }
253 wxThreadState
GetState() const { return m_state
; }
254 void SetState(wxThreadState state
) { m_state
= state
; }
256 pthread_t
GetId() const { return m_threadId
; }
257 pthread_t
*GetIdPtr() { return &m_threadId
; }
259 void SetCancelFlag() { m_cancelled
= TRUE
; }
260 bool WasCancelled() const { return m_cancelled
; }
263 pthread_t m_threadId
; // id of the thread
264 wxThreadState m_state
; // see wxThreadState enum
265 int m_prio
; // in wxWindows units: from 0 to 100
267 // set when the thread should terminate
270 // this (mutex, cond) pair is used to synchronize the main thread and this
271 // thread in several situations:
272 // 1. The thread function blocks until condition is signaled by Run() when
273 // it's initially created - this allows thread creation in "suspended"
275 // 2. The Delete() function blocks until the condition is signaled when the
277 // GL: On Linux, this may fail because we can have a deadlock in either
278 // SignalExit() or Wait(): so we add m_end_mutex for the finalization.
279 wxMutex m_mutex
, m_end_mutex
;
282 // another (mutex, cond) pair for Pause()/Resume() usage
284 // VZ: it's possible that we might reuse the mutex and condition from above
285 // for this too, but as I'm not at all sure that it won't create subtle
286 // problems with race conditions between, say, Pause() and Delete() I
287 // prefer this may be a bit less efficient but much safer solution
288 wxMutex m_mutexSuspend
;
289 wxCondition m_condSuspend
;
292 void *wxThreadInternal::PthreadStart(void *ptr
)
294 wxThread
*thread
= (wxThread
*)ptr
;
295 wxThreadInternal
*pthread
= thread
->p_internal
;
298 int rc
= pthread_setspecific(gs_keySelf
, thread
);
301 wxLogSysError(rc
, _("Cannot start thread: error writing TLS"));
305 #if HAVE_THREAD_CLEANUP_FUNCTIONS
306 // Install the cleanup handler.
307 pthread_cleanup_push(wxThreadInternal::PthreadCleanup
, ptr
);
310 // wait for the condition to be signaled from Run()
311 // mutex state: currently locked by the thread which created us
312 pthread
->m_cond
.Wait(pthread
->m_mutex
);
313 // mutex state: locked again on exit of Wait()
315 // call the main entry
316 status
= thread
->Entry();
318 #if HAVE_THREAD_CLEANUP_FUNCTIONS
319 pthread_cleanup_pop(FALSE
);
322 // terminate the thread
323 thread
->Exit(status
);
325 wxFAIL_MSG(wxT("wxThread::Exit() can't return."));
330 #if HAVE_THREAD_CLEANUP_FUNCTIONS
331 // Only called when the thread is explicitely killed.
333 void wxThreadInternal::PthreadCleanup(void *ptr
)
335 wxThread
*thread
= (wxThread
*) ptr
;
337 // The thread is already considered as finished.
338 if (thread
->p_internal
->GetState() == STATE_EXITED
)
341 // first call user-level clean up code
344 // next wake up the threads waiting for us (OTOH, this function won't retur
345 // until someone waited for us!)
346 thread
->p_internal
->SetState(STATE_EXITED
);
348 thread
->p_internal
->SignalExit();
352 wxThreadInternal::wxThreadInternal()
356 m_prio
= WXTHREAD_DEFAULT_PRIORITY
;
359 // this mutex is locked during almost all thread lifetime - it will only be
360 // unlocked in the very end
363 // this mutex is used by wxThreadInternal::Wait() and by
364 // wxThreadInternal::SignalExit(). We don't use m_mutex because of a
365 // possible deadlock in either Wait() or SignalExit().
368 // this mutex is used in Pause()/Resume() and is also locked all the time
369 // unless the thread is paused
370 m_mutexSuspend
.Lock();
373 wxThreadInternal::~wxThreadInternal()
375 // GL: moved to SignalExit
376 // m_mutexSuspend.Unlock();
378 // note that m_mutex will be unlocked by the thread which waits for our
381 // In the case, we didn't start the thread, all these mutex are locked:
382 // we must unlock them.
383 if (m_mutex
.IsLocked())
386 if (m_end_mutex
.IsLocked())
387 m_end_mutex
.Unlock();
389 if (m_mutexSuspend
.IsLocked())
390 m_mutexSuspend
.Unlock();
393 wxThreadError
wxThreadInternal::Run()
395 wxCHECK_MSG( GetState() == STATE_NEW
, wxTHREAD_RUNNING
,
396 wxT("thread may only be started once after successful Create()") );
398 // the mutex was locked on Create(), so we will be able to lock it again
399 // only when the thread really starts executing and enters the wait -
400 // otherwise we might signal the condition before anybody is waiting for it
401 wxMutexLocker
lock(m_mutex
);
404 m_state
= STATE_RUNNING
;
406 return wxTHREAD_NO_ERROR
;
408 // now the mutex is unlocked back - but just to allow Wait() function to
409 // terminate by relocking it, so the net result is that the worker thread
410 // starts executing and the mutex is still locked
413 void wxThreadInternal::Wait()
415 wxCHECK_RET( WasCancelled(), wxT("thread should have been cancelled first") );
417 // if the thread we're waiting for is waiting for the GUI mutex, we will
418 // deadlock so make sure we release it temporarily
419 if ( wxThread::IsMain() )
422 // entering Wait() releases the mutex thus allowing SignalExit() to acquire
423 // it and to signal us its termination
424 m_cond
.Wait(m_end_mutex
);
426 // mutex is still in the locked state - relocked on exit from Wait(), so
427 // unlock it - we don't need it any more, the thread has already terminated
428 m_end_mutex
.Unlock();
430 // After that, we wait for the real end of the other thread.
431 pthread_join(GetId(), NULL
);
433 // reacquire GUI mutex
434 if ( wxThread::IsMain() )
438 void wxThreadInternal::SignalExit()
440 // GL: Unlock mutexSuspend here.
441 m_mutexSuspend
.Unlock();
443 // as mutex is currently locked, this will block until some other thread
444 // (normally the same which created this one) unlocks it by entering Wait()
447 // wake up all the threads waiting for our termination
450 // after this call mutex will be finally unlocked
451 m_end_mutex
.Unlock();
454 void wxThreadInternal::Pause()
456 // the state is set from the thread which pauses us first, this function
457 // is called later so the state should have been already set
458 wxCHECK_RET( m_state
== STATE_PAUSED
,
459 wxT("thread must first be paused with wxThread::Pause().") );
461 // don't pause the thread which is being terminated - this would lead to
462 // deadlock if the thread is paused after Delete() had called Resume() but
463 // before it had time to call Wait()
464 if ( WasCancelled() )
467 // wait until the condition is signaled from Resume()
468 m_condSuspend
.Wait(m_mutexSuspend
);
471 void wxThreadInternal::Resume()
473 wxCHECK_RET( m_state
== STATE_PAUSED
,
474 wxT("can't resume thread which is not suspended.") );
476 // we will be able to lock this mutex only when Pause() starts waiting
477 wxMutexLocker
lock(m_mutexSuspend
);
478 m_condSuspend
.Signal();
480 SetState(STATE_RUNNING
);
483 // -----------------------------------------------------------------------------
485 // -----------------------------------------------------------------------------
487 wxThread
*wxThread::This()
489 return (wxThread
*)pthread_getspecific(gs_keySelf
);
492 bool wxThread::IsMain()
494 return (bool)pthread_equal(pthread_self(), gs_tidMain
);
497 void wxThread::Yield()
502 void wxThread::Sleep(unsigned long milliseconds
)
504 wxUsleep(milliseconds
);
507 // -----------------------------------------------------------------------------
509 // -----------------------------------------------------------------------------
513 // add this thread to the global list of all threads
514 gs_allThreads
.Add(this);
516 p_internal
= new wxThreadInternal();
519 wxThreadError
wxThread::Create()
521 if (p_internal
->GetState() != STATE_NEW
)
522 return wxTHREAD_RUNNING
;
524 // set up the thread attribute: right now, we only set thread priority
526 pthread_attr_init(&attr
);
528 #ifdef HAVE_THREAD_PRIORITY_FUNCTIONS
530 if ( pthread_attr_getschedpolicy(&attr
, &prio
) != 0 )
532 wxLogError(_("Cannot retrieve thread scheduling policy."));
535 int min_prio
= sched_get_priority_min(prio
),
536 max_prio
= sched_get_priority_max(prio
);
538 if ( min_prio
== -1 || max_prio
== -1 )
540 wxLogError(_("Cannot get priority range for scheduling policy %d."),
543 else if ( max_prio
== min_prio
)
545 if ( p_internal
->GetPriority() != WXTHREAD_DEFAULT_PRIORITY
)
547 // notify the programmer that this doesn't work here
548 wxLogWarning(_("Thread priority setting is ignored."));
550 //else: we have default priority, so don't complain
552 // anyhow, don't do anything because priority is just ignored
556 struct sched_param sp
;
557 pthread_attr_getschedparam(&attr
, &sp
);
558 sp
.sched_priority
= min_prio
+
559 (p_internal
->GetPriority()*(max_prio
-min_prio
))/100;
560 pthread_attr_setschedparam(&attr
, &sp
);
562 #endif // HAVE_THREAD_PRIORITY_FUNCTIONS
564 #ifdef HAVE_PTHREAD_ATTR_SETSCOPE
565 // this will make the threads created by this process really concurrent
566 pthread_attr_setscope(&attr
, PTHREAD_SCOPE_SYSTEM
);
567 #endif // HAVE_PTHREAD_ATTR_SETSCOPE
569 // create the new OS thread object
570 int rc
= pthread_create(p_internal
->GetIdPtr(), &attr
,
571 wxThreadInternal::PthreadStart
, (void *)this);
572 pthread_attr_destroy(&attr
);
576 p_internal
->SetState(STATE_EXITED
);
577 return wxTHREAD_NO_RESOURCE
;
580 return wxTHREAD_NO_ERROR
;
583 wxThreadError
wxThread::Run()
585 wxCHECK_MSG( p_internal
->GetId(), wxTHREAD_MISC_ERROR
,
586 wxT("must call wxThread::Create() first") );
588 return p_internal
->Run();
591 // -----------------------------------------------------------------------------
593 // -----------------------------------------------------------------------------
595 void wxThread::SetPriority(unsigned int prio
)
597 wxCHECK_RET( ((int)WXTHREAD_MIN_PRIORITY
<= (int)prio
) &&
598 ((int)prio
<= (int)WXTHREAD_MAX_PRIORITY
),
599 wxT("invalid thread priority") );
601 wxCriticalSectionLocker
lock(m_critsect
);
603 switch ( p_internal
->GetState() )
606 // thread not yet started, priority will be set when it is
607 p_internal
->SetPriority(prio
);
612 #ifdef HAVE_THREAD_PRIORITY_FUNCTIONS
614 struct sched_param sparam
;
615 sparam
.sched_priority
= prio
;
617 if ( pthread_setschedparam(p_internal
->GetId(),
618 SCHED_OTHER
, &sparam
) != 0 )
620 wxLogError(_("Failed to set thread priority %d."), prio
);
623 #endif // HAVE_THREAD_PRIORITY_FUNCTIONS
628 wxFAIL_MSG(wxT("impossible to set thread priority in this state"));
632 unsigned int wxThread::GetPriority() const
634 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
636 return p_internal
->GetPriority();
639 unsigned long wxThread::GetID() const
641 return (unsigned long)p_internal
->GetId();
644 // -----------------------------------------------------------------------------
646 // -----------------------------------------------------------------------------
648 wxThreadError
wxThread::Pause()
650 wxCriticalSectionLocker
lock(m_critsect
);
652 if ( p_internal
->GetState() != STATE_RUNNING
)
654 wxLogDebug(wxT("Can't pause thread which is not running."));
656 return wxTHREAD_NOT_RUNNING
;
659 p_internal
->SetState(STATE_PAUSED
);
661 return wxTHREAD_NO_ERROR
;
664 wxThreadError
wxThread::Resume()
666 wxCriticalSectionLocker
lock(m_critsect
);
668 if ( p_internal
->GetState() == STATE_PAUSED
)
671 p_internal
->Resume();
674 return wxTHREAD_NO_ERROR
;
678 wxLogDebug(wxT("Attempt to resume a thread which is not paused."));
680 return wxTHREAD_MISC_ERROR
;
684 // -----------------------------------------------------------------------------
686 // -----------------------------------------------------------------------------
688 wxThread::ExitCode
Wait()
695 wxThreadError
wxThread::Delete(ExitCode
*rc
)
701 wxThreadState state
= p_internal
->GetState();
703 // ask the thread to stop
704 p_internal
->SetCancelFlag();
716 // resume the thread first
722 // wait until the thread stops
725 //GL: As we must auto-destroy, the destruction must happen here.
731 wxThreadError
wxThread::Kill()
733 switch ( p_internal
->GetState() )
737 return wxTHREAD_NOT_RUNNING
;
740 #ifdef HAVE_PTHREAD_CANCEL
741 if ( pthread_cancel(p_internal
->GetId()) != 0 )
744 wxLogError(_("Failed to terminate a thread."));
746 return wxTHREAD_MISC_ERROR
;
748 //GL: As we must auto-destroy, the destruction must happen here (2).
751 return wxTHREAD_NO_ERROR
;
755 void wxThread::Exit(ExitCode status
)
757 // first call user-level clean up code
760 // next wake up the threads waiting for us (OTOH, this function won't return
761 // until someone waited for us!)
762 p_internal
->SignalExit();
764 p_internal
->SetState(STATE_EXITED
);
766 // delete both C++ thread object and terminate the OS thread object
767 // GL: This is very ugly and buggy ...
769 pthread_exit(status
);
772 // also test whether we were paused
773 bool wxThread::TestDestroy()
775 wxCriticalSectionLocker
lock(m_critsect
);
777 if ( p_internal
->GetState() == STATE_PAUSED
)
779 // leave the crit section or the other threads will stop too if they try
780 // to call any of (seemingly harmless) IsXXX() functions while we sleep
785 // enter it back before it's finally left in lock object dtor
789 return p_internal
->WasCancelled();
792 wxThread::~wxThread()
795 if ( p_internal
->GetState() != STATE_EXITED
&&
796 p_internal
->GetState() != STATE_NEW
)
798 wxLogDebug(wxT("The thread is being destroyed although it is still "
799 "running! The application may crash."));
806 // remove this thread from the global array
807 gs_allThreads
.Remove(this);
810 // -----------------------------------------------------------------------------
812 // -----------------------------------------------------------------------------
814 bool wxThread::IsRunning() const
816 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
818 return p_internal
->GetState() == STATE_RUNNING
;
821 bool wxThread::IsAlive() const
823 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
825 switch ( p_internal
->GetState() )
836 bool wxThread::IsPaused() const
838 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
840 return (p_internal
->GetState() == STATE_PAUSED
);
843 //--------------------------------------------------------------------
845 //--------------------------------------------------------------------
847 class wxThreadModule
: public wxModule
850 virtual bool OnInit();
851 virtual void OnExit();
854 DECLARE_DYNAMIC_CLASS(wxThreadModule
)
857 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule
, wxModule
)
859 bool wxThreadModule::OnInit()
861 int rc
= pthread_key_create(&gs_keySelf
, NULL
/* dtor function */);
864 wxLogSysError(rc
, _("Thread module initialization failed: "
865 "failed to create thread key"));
870 gs_mutexGui
= new wxMutex();
872 gs_tidMain
= pthread_self();
879 void wxThreadModule::OnExit()
881 wxASSERT_MSG( wxThread::IsMain(), wxT("only main thread can be here") );
883 // terminate any threads left
884 size_t count
= gs_allThreads
.GetCount();
886 wxLogDebug(wxT("Some threads were not terminated by the application."));
888 for ( size_t n
= 0u; n
< count
; n
++ )
890 // Delete calls the destructor which removes the current entry. We
891 // should only delete the first one each time.
892 gs_allThreads
[0]->Delete();
896 gs_mutexGui
->Unlock();
901 (void)pthread_key_delete(gs_keySelf
);
904 // ----------------------------------------------------------------------------
906 // ----------------------------------------------------------------------------
908 void wxMutexGuiEnter()
913 void wxMutexGuiLeave()
915 gs_mutexGui
->Unlock();