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
;
104 pthread_mutex_init( &(p_internal
->p_mutex
), (const pthread_mutexattr_t
*) NULL
);
111 wxLogDebug("Freeing a locked mutex (%d locks)", m_locked
);
113 pthread_mutex_destroy( &(p_internal
->p_mutex
) );
117 wxMutexError
wxMutex::Lock()
119 int err
= pthread_mutex_lock( &(p_internal
->p_mutex
) );
122 wxLogDebug("Locking this mutex would lead to deadlock!");
124 return wxMUTEX_DEAD_LOCK
;
129 return wxMUTEX_NO_ERROR
;
132 wxMutexError
wxMutex::TryLock()
139 int err
= pthread_mutex_trylock( &(p_internal
->p_mutex
) );
142 case EBUSY
: return wxMUTEX_BUSY
;
147 return wxMUTEX_NO_ERROR
;
150 wxMutexError
wxMutex::Unlock()
158 wxLogDebug("Unlocking not locked mutex.");
160 return wxMUTEX_UNLOCKED
;
163 pthread_mutex_unlock( &(p_internal
->p_mutex
) );
165 return wxMUTEX_NO_ERROR
;
168 //--------------------------------------------------------------------
169 // wxCondition (Posix implementation)
170 //--------------------------------------------------------------------
172 class wxConditionInternal
175 pthread_cond_t p_condition
;
178 wxCondition::wxCondition()
180 p_internal
= new wxConditionInternal
;
181 pthread_cond_init( &(p_internal
->p_condition
), (const pthread_condattr_t
*) NULL
);
184 wxCondition::~wxCondition()
186 pthread_cond_destroy( &(p_internal
->p_condition
) );
191 void wxCondition::Wait(wxMutex
& mutex
)
193 pthread_cond_wait( &(p_internal
->p_condition
), &(mutex
.p_internal
->p_mutex
) );
196 bool wxCondition::Wait(wxMutex
& mutex
, unsigned long sec
, unsigned long nsec
)
198 struct timespec tspec
;
200 tspec
.tv_sec
= time(0L)+sec
;
201 tspec
.tv_nsec
= nsec
;
202 return (pthread_cond_timedwait(&(p_internal
->p_condition
), &(mutex
.p_internal
->p_mutex
), &tspec
) != ETIMEDOUT
);
205 void wxCondition::Signal()
207 pthread_cond_signal( &(p_internal
->p_condition
) );
210 void wxCondition::Broadcast()
212 pthread_cond_broadcast( &(p_internal
->p_condition
) );
215 //--------------------------------------------------------------------
216 // wxThread (Posix implementation)
217 //--------------------------------------------------------------------
219 class wxThreadInternal
225 // thread entry function
226 static void *PthreadStart(void *ptr
);
231 // ask the thread to terminate
233 // wake up threads waiting for our termination
235 // go to sleep until Resume() is called
242 int GetPriority() const { return m_prio
; }
243 void SetPriority(int prio
) { m_prio
= prio
; }
245 wxThreadState
GetState() const { return m_state
; }
246 void SetState(wxThreadState state
) { m_state
= state
; }
248 pthread_t
GetId() const { return m_threadId
; }
249 pthread_t
*GetIdPtr() { return &m_threadId
; }
251 void SetCancelFlag() { m_cancelled
= TRUE
; }
252 bool WasCancelled() const { return m_cancelled
; }
255 pthread_t m_threadId
; // id of the thread
256 wxThreadState m_state
; // see wxThreadState enum
257 int m_prio
; // in wxWindows units: from 0 to 100
259 // set when the thread should terminate
262 // this (mutex, cond) pair is used to synchronize the main thread and this
263 // thread in several situations:
264 // 1. The thread function blocks until condition is signaled by Run() when
265 // it's initially created - this allows thread creation in "suspended"
267 // 2. The Delete() function blocks until the condition is signaled when the
272 // another (mutex, cond) pair for Pause()/Resume() usage
274 // VZ: it's possible that we might reuse the mutex and condition from above
275 // for this too, but as I'm not at all sure that it won't create subtle
276 // problems with race conditions between, say, Pause() and Delete() I
277 // prefer this may be a bit less efficient but much safer solution
278 wxMutex m_mutexSuspend
;
279 wxCondition m_condSuspend
;
282 void *wxThreadInternal::PthreadStart(void *ptr
)
284 wxThread
*thread
= (wxThread
*)ptr
;
285 wxThreadInternal
*pthread
= thread
->p_internal
;
287 int rc
= pthread_setspecific(gs_keySelf
, thread
);
290 wxLogSysError(rc
, _("Cannot start thread: error writing TLS"));
295 // wait for the condition to be signaled from Run()
296 // mutex state: currently locked by the thread which created us
297 pthread
->m_cond
.Wait(pthread
->m_mutex
);
299 // mutex state: locked again on exit of Wait()
301 // call the main entry
302 void* status
= thread
->Entry();
304 // terminate the thread
305 thread
->Exit(status
);
307 wxFAIL_MSG("wxThread::Exit() can't return.");
312 wxThreadInternal::wxThreadInternal()
317 // this mutex is locked during almost all thread lifetime - it will only be
318 // unlocked in the very end
321 // this mutex is used in Pause()/Resume() and is also locked all the time
322 // unless the thread is paused
323 m_mutexSuspend
.Lock();
326 wxThreadInternal::~wxThreadInternal()
328 m_mutexSuspend
.Unlock();
330 // note that m_mutex will be unlocked by the thread which waits for our
334 wxThreadError
wxThreadInternal::Run()
336 wxCHECK_MSG( GetState() == STATE_NEW
, wxTHREAD_RUNNING
,
337 "thread may only be started once after successful Create()" );
339 // the mutex was locked on Create(), so we will be able to lock it again
340 // only when the thread really starts executing and enters the wait -
341 // otherwise we might signal the condition before anybody is waiting for it
342 wxMutexLocker
lock(m_mutex
);
345 m_state
= STATE_RUNNING
;
347 return wxTHREAD_NO_ERROR
;
349 // now the mutex is unlocked back - but just to allow Wait() function to
350 // terminate by relocking it, so the net result is that the worker thread
351 // starts executing and the mutex is still locked
354 void wxThreadInternal::Wait()
356 wxCHECK_RET( WasCancelled(), "thread should have been cancelled first" );
358 // if the thread we're waiting for is waiting for the GUI mutex, we will
359 // deadlock so make sure we release it temporarily
360 if ( wxThread::IsMain() )
363 // entering Wait() releases the mutex thus allowing SignalExit() to acquire
364 // it and to signal us its termination
365 m_cond
.Wait(m_mutex
);
367 // mutex is still in the locked state - relocked on exit from Wait(), so
368 // unlock it - we don't need it any more, the thread has already terminated
371 // reacquire GUI mutex
372 if ( wxThread::IsMain() )
376 void wxThreadInternal::SignalExit()
378 // as mutex is currently locked, this will block until some other thread
379 // (normally the same which created this one) unlocks it by entering Wait()
382 // wake up all the threads waiting for our termination
385 // after this call mutex will be finally unlocked
389 void wxThreadInternal::Pause()
391 // the state is set from the thread which pauses us first, this function
392 // is called later so the state should have been already set
393 wxCHECK_RET( m_state
== STATE_PAUSED
,
394 "thread must first be paused with wxThread::Pause()." );
396 // don't pause the thread which is being terminated - this would lead to
397 // deadlock if the thread is paused after Delete() had called Resume() but
398 // before it had time to call Wait()
399 if ( WasCancelled() )
402 // wait until the condition is signaled from Resume()
403 m_condSuspend
.Wait(m_mutexSuspend
);
406 void wxThreadInternal::Resume()
408 wxCHECK_RET( m_state
== STATE_PAUSED
,
409 "can't resume thread which is not suspended." );
411 // we will be able to lock this mutex only when Pause() starts waiting
412 wxMutexLocker
lock(m_mutexSuspend
);
413 m_condSuspend
.Signal();
415 SetState(STATE_RUNNING
);
418 // -----------------------------------------------------------------------------
420 // -----------------------------------------------------------------------------
422 wxThread
*wxThread::This()
424 return (wxThread
*)pthread_getspecific(gs_keySelf
);
427 bool wxThread::IsMain()
429 return (bool)pthread_equal(pthread_self(), gs_tidMain
);
432 void wxThread::Yield()
437 void wxThread::Sleep(unsigned long milliseconds
)
439 wxUsleep(milliseconds
);
442 // -----------------------------------------------------------------------------
444 // -----------------------------------------------------------------------------
448 // add this thread to the global list of all threads
449 gs_allThreads
.Add(this);
451 p_internal
= new wxThreadInternal();
454 wxThreadError
wxThread::Create()
456 // Maybe we could think about recreate the thread once it has exited.
457 if (p_internal
->GetState() != STATE_NEW
&&
458 p_internal
->GetState() != STATE_EXITED
)
459 return wxTHREAD_RUNNING
;
461 // set up the thread attribute: right now, we only set thread priority
463 pthread_attr_init(&attr
);
465 #ifdef HAVE_THREAD_PRIORITY_FUNCTIONS
467 if ( pthread_attr_getschedpolicy(&attr
, &prio
) != 0 )
469 wxLogError(_("Cannot retrieve thread scheduling policy."));
472 int min_prio
= sched_get_priority_min(prio
),
473 max_prio
= sched_get_priority_max(prio
);
475 if ( min_prio
== -1 || max_prio
== -1 )
477 wxLogError(_("Cannot get priority range for scheduling policy %d."),
482 struct sched_param sp
;
483 pthread_attr_getschedparam(&attr
, &sp
);
484 sp
.sched_priority
= min_prio
+
485 (p_internal
->GetPriority()*(max_prio
-min_prio
))/100;
486 pthread_attr_setschedparam(&attr
, &sp
);
488 #endif // HAVE_THREAD_PRIORITY_FUNCTIONS
490 #ifdef HAVE_PTHREAD_ATTR_SETSCOPE
491 // this will make the threads created by this process really concurrent
492 pthread_attr_setscope(&attr
, PTHREAD_SCOPE_SYSTEM
);
493 #endif // HAVE_PTHREAD_ATTR_SETSCOPE
495 // create the new OS thread object
496 int rc
= pthread_create(p_internal
->GetIdPtr(), &attr
,
497 wxThreadInternal::PthreadStart
, (void *)this);
498 pthread_attr_destroy(&attr
);
502 p_internal
->SetState(STATE_EXITED
);
503 return wxTHREAD_NO_RESOURCE
;
506 return wxTHREAD_NO_ERROR
;
509 wxThreadError
wxThread::Run()
511 return p_internal
->Run();
514 // -----------------------------------------------------------------------------
516 // -----------------------------------------------------------------------------
518 void wxThread::SetPriority(unsigned int prio
)
520 wxCHECK_RET( ((int)WXTHREAD_MIN_PRIORITY
<= (int)prio
) &&
521 ((int)prio
<= (int)WXTHREAD_MAX_PRIORITY
),
522 "invalid thread priority" );
524 wxCriticalSectionLocker
lock(m_critsect
);
526 switch ( p_internal
->GetState() )
529 // thread not yet started, priority will be set when it is
530 p_internal
->SetPriority(prio
);
535 #ifdef HAVE_THREAD_PRIORITY_FUNCTIONS
537 struct sched_param sparam
;
538 sparam
.sched_priority
= prio
;
540 if ( pthread_setschedparam(p_internal
->GetId(),
541 SCHED_OTHER
, &sparam
) != 0 )
543 wxLogError(_("Failed to set thread priority %d."), prio
);
546 #endif // HAVE_THREAD_PRIORITY_FUNCTIONS
551 wxFAIL_MSG("impossible to set thread priority in this state");
555 unsigned int wxThread::GetPriority() const
557 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
559 return p_internal
->GetPriority();
562 unsigned long wxThread::GetID() const
564 return (unsigned long)p_internal
->GetId();
567 // -----------------------------------------------------------------------------
569 // -----------------------------------------------------------------------------
571 wxThreadError
wxThread::Pause()
573 wxCriticalSectionLocker
lock(m_critsect
);
575 if ( p_internal
->GetState() != STATE_RUNNING
)
577 wxLogDebug("Can't pause thread which is not running.");
579 return wxTHREAD_NOT_RUNNING
;
582 p_internal
->SetState(STATE_PAUSED
);
584 return wxTHREAD_NO_ERROR
;
587 wxThreadError
wxThread::Resume()
589 wxCriticalSectionLocker
lock(m_critsect
);
591 if ( p_internal
->GetState() == STATE_PAUSED
)
593 p_internal
->Resume();
595 return wxTHREAD_NO_ERROR
;
599 wxLogDebug("Attempt to resume a thread which is not paused.");
601 return wxTHREAD_MISC_ERROR
;
605 // -----------------------------------------------------------------------------
607 // -----------------------------------------------------------------------------
609 wxThread::ExitCode
wxThread::Delete()
612 wxThreadState state
= p_internal
->GetState();
615 // ask the thread to stop
616 p_internal
->SetCancelFlag();
626 // resume the thread first
632 // wait until the thread stops
639 wxThreadError
wxThread::Kill()
641 switch ( p_internal
->GetState() )
645 return wxTHREAD_NOT_RUNNING
;
648 #ifdef HAVE_PTHREAD_CANCEL
649 if ( pthread_cancel(p_internal
->GetId()) != 0 )
652 wxLogError(_("Failed to terminate a thread."));
654 return wxTHREAD_MISC_ERROR
;
657 return wxTHREAD_NO_ERROR
;
661 void wxThread::Exit(void *status
)
663 // first call user-level clean up code
666 // next wake up the threads waiting for us (OTOH, this function won't return
667 // until someone waited for us!)
668 p_internal
->SignalExit();
670 p_internal
->SetState(STATE_EXITED
);
672 // delete both C++ thread object and terminate the OS thread object
673 // GL: This is very ugly and buggy ...
675 pthread_exit(status
);
678 // also test whether we were paused
679 bool wxThread::TestDestroy()
681 wxCriticalSectionLocker
lock(m_critsect
);
683 if ( p_internal
->GetState() == STATE_PAUSED
)
685 // leave the crit section or the other threads will stop too if they try
686 // to call any of (seemingly harmless) IsXXX() functions while we sleep
691 // enter it back before it's finally left in lock object dtor
695 return p_internal
->WasCancelled();
698 wxThread::~wxThread()
700 // remove this thread from the global array
701 gs_allThreads
.Remove(this);
704 // -----------------------------------------------------------------------------
706 // -----------------------------------------------------------------------------
708 bool wxThread::IsRunning() const
710 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
712 return p_internal
->GetState() == STATE_RUNNING
;
715 bool wxThread::IsAlive() const
717 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
719 switch ( p_internal
->GetState() )
730 //--------------------------------------------------------------------
732 //--------------------------------------------------------------------
734 class wxThreadModule
: public wxModule
737 virtual bool OnInit();
738 virtual void OnExit();
741 DECLARE_DYNAMIC_CLASS(wxThreadModule
)
744 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule
, wxModule
)
746 bool wxThreadModule::OnInit()
748 int rc
= pthread_key_create(&gs_keySelf
, NULL
/* dtor function */);
751 wxLogSysError(rc
, _("Thread module initialization failed: "
752 "failed to create thread key"));
757 gs_mutexGui
= new wxMutex();
761 gs_tidMain
= pthread_self();
767 void wxThreadModule::OnExit()
769 wxASSERT_MSG( wxThread::IsMain(), "only main thread can be here" );
771 // terminate any threads left
772 size_t count
= gs_allThreads
.GetCount();
774 wxLogDebug("Some threads were not terminated by the application.");
776 for ( size_t n
= 0u; n
< count
; n
++ )
778 gs_allThreads
[n
]->Delete();
782 gs_mutexGui
->Unlock();
789 (void)pthread_key_delete(gs_keySelf
);
792 // ----------------------------------------------------------------------------
794 // ----------------------------------------------------------------------------
796 void wxMutexGuiEnter()
801 void wxMutexGuiLeave()
803 gs_mutexGui
->Unlock();