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 #include "wx/thread.h"
30 #error This file needs wxUSE_THREADS
33 #include "wx/module.h"
37 #include "wx/dynarray.h"
49 // ----------------------------------------------------------------------------
51 // ----------------------------------------------------------------------------
55 STATE_NEW
, // didn't start execution yet (=> RUNNING)
62 WX_DEFINE_ARRAY(wxThread
*, wxArrayThread
);
64 // -----------------------------------------------------------------------------
66 // -----------------------------------------------------------------------------
68 // we keep the list of all threads created by the application to be able to
69 // terminate them on exit if there are some left - otherwise the process would
71 static wxArrayThread gs_allThreads
;
73 // the id of the main thread
74 static pthread_t gs_tidMain
;
76 // the key for the pointer to the associated wxThread object
77 static pthread_key_t gs_keySelf
;
79 // this mutex must be acquired before any call to a GUI function
80 static wxMutex
*gs_mutexGui
;
82 // ============================================================================
84 // ============================================================================
86 //--------------------------------------------------------------------
87 // wxMutex (Posix implementation)
88 //--------------------------------------------------------------------
93 pthread_mutex_t p_mutex
;
98 p_internal
= new wxMutexInternal
;
99 pthread_mutex_init( &(p_internal
->p_mutex
), (const pthread_mutexattr_t
*) NULL
);
106 wxLogDebug("Freeing a locked mutex (%d locks)", m_locked
);
108 pthread_mutex_destroy( &(p_internal
->p_mutex
) );
112 wxMutexError
wxMutex::Lock()
114 int err
= pthread_mutex_lock( &(p_internal
->p_mutex
) );
117 wxLogDebug("Locking this mutex would lead to deadlock!");
119 return wxMUTEX_DEAD_LOCK
;
124 return wxMUTEX_NO_ERROR
;
127 wxMutexError
wxMutex::TryLock()
134 int err
= pthread_mutex_trylock( &(p_internal
->p_mutex
) );
137 case EBUSY
: return wxMUTEX_BUSY
;
142 return wxMUTEX_NO_ERROR
;
145 wxMutexError
wxMutex::Unlock()
153 wxLogDebug("Unlocking not locked mutex.");
155 return wxMUTEX_UNLOCKED
;
158 pthread_mutex_unlock( &(p_internal
->p_mutex
) );
160 return wxMUTEX_NO_ERROR
;
163 //--------------------------------------------------------------------
164 // wxCondition (Posix implementation)
165 //--------------------------------------------------------------------
167 class wxConditionInternal
170 pthread_cond_t p_condition
;
173 wxCondition::wxCondition()
175 p_internal
= new wxConditionInternal
;
176 pthread_cond_init( &(p_internal
->p_condition
), (const pthread_condattr_t
*) NULL
);
179 wxCondition::~wxCondition()
181 pthread_cond_destroy( &(p_internal
->p_condition
) );
186 void wxCondition::Wait(wxMutex
& mutex
)
188 pthread_cond_wait( &(p_internal
->p_condition
), &(mutex
.p_internal
->p_mutex
) );
191 bool wxCondition::Wait(wxMutex
& mutex
, unsigned long sec
, unsigned long nsec
)
193 struct timespec tspec
;
195 tspec
.tv_sec
= time(0L)+sec
;
196 tspec
.tv_nsec
= nsec
;
197 return (pthread_cond_timedwait(&(p_internal
->p_condition
), &(mutex
.p_internal
->p_mutex
), &tspec
) != ETIMEDOUT
);
200 void wxCondition::Signal()
202 pthread_cond_signal( &(p_internal
->p_condition
) );
205 void wxCondition::Broadcast()
207 pthread_cond_broadcast( &(p_internal
->p_condition
) );
210 //--------------------------------------------------------------------
211 // wxThread (Posix implementation)
212 //--------------------------------------------------------------------
214 class wxThreadInternal
220 // thread entry function
221 static void *PthreadStart(void *ptr
);
226 // ask the thread to terminate
228 // wake up threads waiting for our termination
230 // go to sleep until Resume() is called
237 int GetPriority() const { return m_prio
; }
238 void SetPriority(int prio
) { m_prio
= prio
; }
240 thread_state
GetState() const { return m_state
; }
241 void SetState(thread_state state
) { m_state
= state
; }
243 pthread_t
GetId() const { return thread_id
; }
245 bool WasCancelled() const { return m_cancelled
; }
247 //private: -- should be!
251 thread_state m_state
; // see thread_state enum
252 int m_prio
; // in wxWindows units: from 0 to 100
254 // set when the thread should terminate
257 // this (mutex, cond) pair is used to synchronize the main thread and this
258 // thread in several situations:
259 // 1. The thread function blocks until condition is signaled by Run() when
260 // it's initially created - this allows thread creation in "suspended"
262 // 2. The Delete() function blocks until the condition is signaled when the
267 // another (mutex, cond) pair for Pause()/Resume() usage
269 // VZ: it's possible that we might reuse the mutex and condition from above
270 // for this too, but as I'm not at all sure that it won't create subtle
271 // problems with race conditions between, say, Pause() and Delete() I
272 // prefer this may be a bit less efficient but much safer solution
273 wxMutex m_mutexSuspend
;
274 wxCondition m_condSuspend
;
277 void *wxThreadInternal::PthreadStart(void *ptr
)
279 wxThread
*thread
= (wxThread
*)ptr
;
280 wxThreadInternal
*pthread
= thread
->p_internal
;
282 int rc
= pthread_setspecific(gs_keySelf
, thread
);
285 wxLogSysError(rc
, _("Can not start thread: error writing TLS."));
290 // wait for the condition to be signaled from Run()
291 // mutex state: currently locked by the thread which created us
292 pthread
->m_cond
.Wait(pthread
->m_mutex
);
294 // mutex state: locked again on exit of Wait()
296 // call the main entry
297 void* status
= thread
->Entry();
299 // terminate the thread
300 thread
->Exit(status
);
302 wxFAIL_MSG("wxThread::Exit() can't return.");
307 wxThreadInternal::wxThreadInternal()
312 // this mutex is locked during almost all thread lifetime - it will only be
313 // unlocked in the very end
316 // this mutex is used in Pause()/Resume() and is also locked all the time
317 // unless the thread is paused
318 m_mutexSuspend
.Lock();
321 wxThreadInternal::~wxThreadInternal()
323 m_mutexSuspend
.Unlock();
325 // note that m_mutex will be unlocked by the thread which waits for our
329 wxThreadError
wxThreadInternal::Run()
331 wxCHECK_MSG( GetState() == STATE_NEW
, wxTHREAD_RUNNING
,
332 "thread may only be started once after successful Create()" );
334 // the mutex was locked on Create(), so we will be able to lock it again
335 // only when the thread really starts executing and enters the wait -
336 // otherwise we might signal the condition before anybody is waiting for it
337 wxMutexLocker
lock(m_mutex
);
340 m_state
= STATE_RUNNING
;
342 return wxTHREAD_NO_ERROR
;
344 // now the mutex is unlocked back - but just to allow Wait() function to
345 // terminate by relocking it, so the net result is that the worker thread
346 // starts executing and the mutex is still locked
349 void wxThreadInternal::Cancel()
351 // if the thread we're waiting for is waiting for the GUI mutex, we will
352 // deadlock so make sure we release it temporarily
353 if ( wxThread::IsMain() )
356 // nobody ever writes this variable so it's safe to not use any
357 // synchronization here
360 // entering Wait() releases the mutex thus allowing SignalExit() to acquire
361 // it and to signal us its termination
362 m_cond
.Wait(m_mutex
);
364 // mutex is still in the locked state - relocked on exit from Wait(), so
365 // unlock it - we don't need it any more, the thread has already terminated
368 // reacquire GUI mutex
369 if ( wxThread::IsMain() )
373 void wxThreadInternal::SignalExit()
375 // as mutex is currently locked, this will block until some other thread
376 // (normally the same which created this one) unlocks it by entering Wait()
379 // wake up all the threads waiting for our termination
382 // after this call mutex will be finally unlocked
386 void wxThreadInternal::Pause()
388 wxCHECK_RET( m_state
== STATE_PAUSED
,
389 "thread must first be paused with wxThread::Pause()." );
391 // don't pause the thread which is being terminated - this would lead to
392 // deadlock if the thread is paused after Delete() had called Resume() but
393 // before it had time to call Cancel()
397 // wait until the condition is signaled from Resume()
398 m_condSuspend
.Wait(m_mutexSuspend
);
401 void wxThreadInternal::Resume()
403 wxCHECK_RET( m_state
== STATE_PAUSED
,
404 "can't resume thread which is not suspended." );
406 // we will be able to lock this mutex only when Pause() starts waiting
407 wxMutexLocker
lock(m_mutexSuspend
);
408 m_condSuspend
.Signal();
410 SetState(STATE_RUNNING
);
413 // -----------------------------------------------------------------------------
415 // -----------------------------------------------------------------------------
417 wxThread
*wxThread::This()
419 return (wxThread
*)pthread_getspecific(gs_keySelf
);
422 bool wxThread::IsMain()
424 return (bool)pthread_equal(pthread_self(), gs_tidMain
);
427 void wxThread::Yield()
432 void wxThread::Sleep(unsigned long milliseconds
)
434 wxUsleep(milliseconds
);
437 // -----------------------------------------------------------------------------
439 // -----------------------------------------------------------------------------
443 // add this thread to the global list of all threads
444 gs_allThreads
.Add(this);
446 p_internal
= new wxThreadInternal();
449 wxThreadError
wxThread::Create()
451 if (p_internal
->GetState() != STATE_NEW
)
452 return wxTHREAD_RUNNING
;
454 // set up the thread attribute: right now, we only set thread priority
456 pthread_attr_init(&attr
);
458 #ifdef HAVE_THREAD_PRIORITY_FUNCTIONS
460 if ( pthread_attr_getschedpolicy(&attr
, &prio
) != 0 )
462 wxLogError(_("Can not retrieve thread scheduling policy."));
465 int min_prio
= sched_get_priority_min(prio
),
466 max_prio
= sched_get_priority_max(prio
);
468 if ( min_prio
== -1 || max_prio
== -1 )
470 wxLogError(_("Can not get priority range for scheduling policy %d."),
475 struct sched_param sp
;
476 pthread_attr_getschedparam(&attr
, &sp
);
477 sp
.sched_priority
= min_prio
+
478 (p_internal
->GetPriority()*(max_prio
-min_prio
))/100;
479 pthread_attr_setschedparam(&attr
, &sp
);
481 #endif // HAVE_THREAD_PRIORITY_FUNCTIONS
483 // create the new OS thread object
484 int rc
= pthread_create(&p_internal
->thread_id
, &attr
,
485 wxThreadInternal::PthreadStart
, (void *)this);
486 pthread_attr_destroy(&attr
);
490 p_internal
->SetState(STATE_EXITED
);
491 return wxTHREAD_NO_RESOURCE
;
494 return wxTHREAD_NO_ERROR
;
497 wxThreadError
wxThread::Run()
499 return p_internal
->Run();
502 // -----------------------------------------------------------------------------
504 // -----------------------------------------------------------------------------
506 void wxThread::SetPriority(unsigned int prio
)
508 wxCHECK_RET( ((int)WXTHREAD_MIN_PRIORITY
<= (int)prio
) &&
509 ((int)prio
<= (int)WXTHREAD_MAX_PRIORITY
),
510 "invalid thread priority" );
512 wxCriticalSectionLocker
lock(m_critsect
);
514 switch ( p_internal
->GetState() )
517 // thread not yet started, priority will be set when it is
518 p_internal
->SetPriority(prio
);
523 #ifdef HAVE_THREAD_PRIORITY_FUNCTIONS
525 struct sched_param sparam
;
526 sparam
.sched_priority
= prio
;
528 if ( pthread_setschedparam(p_internal
->GetId(),
529 SCHED_OTHER
, &sparam
) != 0 )
531 wxLogError(_("Failed to set thread priority %d."), prio
);
534 #endif // HAVE_THREAD_PRIORITY_FUNCTIONS
539 wxFAIL_MSG("impossible to set thread priority in this state");
543 unsigned int wxThread::GetPriority() const
545 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
547 return p_internal
->GetPriority();
550 unsigned long wxThread::GetID() const
552 return (unsigned long)p_internal
->thread_id
;
555 // -----------------------------------------------------------------------------
557 // -----------------------------------------------------------------------------
559 wxThreadError
wxThread::Pause()
561 wxCriticalSectionLocker
lock(m_critsect
);
563 if ( p_internal
->GetState() != STATE_RUNNING
)
565 wxLogDebug("Can't pause thread which is not running.");
567 return wxTHREAD_NOT_RUNNING
;
570 p_internal
->SetState(STATE_PAUSED
);
572 return wxTHREAD_NO_ERROR
;
575 wxThreadError
wxThread::Resume()
577 wxCriticalSectionLocker
lock(m_critsect
);
579 if ( p_internal
->GetState() == STATE_PAUSED
)
581 p_internal
->Resume();
583 return wxTHREAD_NO_ERROR
;
587 wxLogDebug("Attempt to resume a thread which is not paused.");
589 return wxTHREAD_MISC_ERROR
;
593 // -----------------------------------------------------------------------------
595 // -----------------------------------------------------------------------------
597 wxThread::ExitCode
wxThread::Delete()
600 thread_state state
= p_internal
->GetState();
611 // resume the thread first
617 // set the flag telling to the thread to stop and wait
618 p_internal
->Cancel();
624 wxThreadError
wxThread::Kill()
626 switch ( p_internal
->GetState() )
630 return wxTHREAD_NOT_RUNNING
;
633 #ifdef HAVE_PTHREAD_CANCEL
634 if ( pthread_cancel(p_internal
->GetId()) != 0 )
637 wxLogError(_("Failed to terminate a thread."));
639 return wxTHREAD_MISC_ERROR
;
642 return wxTHREAD_NO_ERROR
;
646 void wxThread::Exit(void *status
)
648 // first call user-level clean up code
651 // next wake up the threads waiting for us (OTOH, this function won't return
652 // until someone waited for us!)
653 p_internal
->SignalExit();
655 p_internal
->SetState(STATE_EXITED
);
657 // delete both C++ thread object and terminate the OS thread object
659 pthread_exit(status
);
662 // also test whether we were paused
663 bool wxThread::TestDestroy()
665 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
667 if ( p_internal
->GetState() == STATE_PAUSED
)
669 // leave the crit section or the other threads will stop too if they try
670 // to call any of (seemingly harmless) IsXXX() functions while we sleep
675 // enter it back before it's finally left in lock object dtor
679 return p_internal
->WasCancelled();
682 wxThread::~wxThread()
684 // remove this thread from the global array
685 gs_allThreads
.Remove(this);
688 // -----------------------------------------------------------------------------
690 // -----------------------------------------------------------------------------
692 bool wxThread::IsRunning() const
694 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
696 return p_internal
->GetState() == STATE_RUNNING
;
699 bool wxThread::IsAlive() const
701 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
703 switch ( p_internal
->GetState() )
714 //--------------------------------------------------------------------
716 //--------------------------------------------------------------------
718 class wxThreadModule
: public wxModule
721 virtual bool OnInit();
722 virtual void OnExit();
725 DECLARE_DYNAMIC_CLASS(wxThreadModule
)
728 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule
, wxModule
)
730 bool wxThreadModule::OnInit()
732 if ( pthread_key_create(&gs_keySelf
, NULL
/* dtor function */) != 0 )
734 wxLogError(_("Thread module initialization failed: "
735 "failed to create pthread key."));
740 gs_mutexGui
= new wxMutex();
744 gs_tidMain
= pthread_self();
750 void wxThreadModule::OnExit()
752 wxASSERT_MSG( wxThread::IsMain(), "only main thread can be here" );
754 // terminate any threads left
755 size_t count
= gs_allThreads
.GetCount();
757 wxLogDebug("Some threads were not terminated by the application.");
759 for ( size_t n
= 0u; n
< count
; n
++ )
761 gs_allThreads
[n
]->Delete();
765 gs_mutexGui
->Unlock();
772 (void)pthread_key_delete(gs_keySelf
);
775 // ----------------------------------------------------------------------------
777 // ----------------------------------------------------------------------------
779 void wxMutexGuiEnter()
784 void wxMutexGuiLeave()
786 gs_mutexGui
->Unlock();