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"
27 #include "wx/thread.h"
28 #include "wx/module.h"
32 #include "wx/dynarray.h"
36 STATE_NEW
, // didn't start execution yet (=> RUNNING)
43 WX_DEFINE_ARRAY(wxThread
*, wxArrayThread
);
45 // -----------------------------------------------------------------------------
47 // -----------------------------------------------------------------------------
49 // we keep the list of all threads created by the application to be able to
50 // terminate them on exit if there are some left - otherwise the process would
52 static wxArrayThread gs_allThreads
;
54 // the id of the main thread
55 static pthread_t gs_tidMain
;
57 // the key for the pointer to the associated wxThread object
58 static pthread_key_t gs_keySelf
;
60 // this mutex must be acquired before any call to a GUI function
61 static wxMutex
*gs_mutexGui
;
63 //--------------------------------------------------------------------
64 // common GUI thread code
65 //--------------------------------------------------------------------
67 //--------------------------------------------------------------------
68 // wxMutex (Posix implementation)
69 //--------------------------------------------------------------------
74 pthread_mutex_t p_mutex
;
79 p_internal
= new wxMutexInternal
;
80 pthread_mutex_init( &(p_internal
->p_mutex
), (const pthread_mutexattr_t
*) NULL
);
87 wxLogDebug("Freeing a locked mutex (%d locks)", m_locked
);
89 pthread_mutex_destroy( &(p_internal
->p_mutex
) );
93 wxMutexError
wxMutex::Lock()
95 int err
= pthread_mutex_lock( &(p_internal
->p_mutex
) );
98 wxLogDebug("Locking this mutex would lead to deadlock!");
100 return wxMUTEX_DEAD_LOCK
;
105 return wxMUTEX_NO_ERROR
;
108 wxMutexError
wxMutex::TryLock()
115 int err
= pthread_mutex_trylock( &(p_internal
->p_mutex
) );
118 case EBUSY
: return wxMUTEX_BUSY
;
123 return wxMUTEX_NO_ERROR
;
126 wxMutexError
wxMutex::Unlock()
134 wxLogDebug("Unlocking not locked mutex.");
136 return wxMUTEX_UNLOCKED
;
139 pthread_mutex_unlock( &(p_internal
->p_mutex
) );
141 return wxMUTEX_NO_ERROR
;
144 //--------------------------------------------------------------------
145 // wxCondition (Posix implementation)
146 //--------------------------------------------------------------------
148 class wxConditionInternal
151 pthread_cond_t p_condition
;
154 wxCondition::wxCondition()
156 p_internal
= new wxConditionInternal
;
157 pthread_cond_init( &(p_internal
->p_condition
), (const pthread_condattr_t
*) NULL
);
160 wxCondition::~wxCondition()
162 pthread_cond_destroy( &(p_internal
->p_condition
) );
167 void wxCondition::Wait(wxMutex
& mutex
)
169 pthread_cond_wait( &(p_internal
->p_condition
), &(mutex
.p_internal
->p_mutex
) );
172 bool wxCondition::Wait(wxMutex
& mutex
, unsigned long sec
, unsigned long nsec
)
174 struct timespec tspec
;
176 tspec
.tv_sec
= time(0L)+sec
;
177 tspec
.tv_nsec
= nsec
;
178 return (pthread_cond_timedwait(&(p_internal
->p_condition
), &(mutex
.p_internal
->p_mutex
), &tspec
) != ETIMEDOUT
);
181 void wxCondition::Signal()
183 pthread_cond_signal( &(p_internal
->p_condition
) );
186 void wxCondition::Broadcast()
188 pthread_cond_broadcast( &(p_internal
->p_condition
) );
191 //--------------------------------------------------------------------
192 // wxThread (Posix implementation)
193 //--------------------------------------------------------------------
195 class wxThreadInternal
201 // thread entry function
202 static void *PthreadStart(void *ptr
);
207 // ask the thread to terminate
209 // wake up threads waiting for our termination
211 // go to sleep until Resume() is called
218 int GetPriority() const { return m_prio
; }
219 void SetPriority(int prio
) { m_prio
= prio
; }
221 thread_state
GetState() const { return m_state
; }
222 void SetState(thread_state state
) { m_state
= state
; }
224 pthread_t
GetId() const { return thread_id
; }
226 bool WasCancelled() const { return m_cancelled
; }
228 //private: -- should be!
232 thread_state m_state
; // see thread_state enum
233 int m_prio
; // in wxWindows units: from 0 to 100
235 // set when the thread should terminate
238 // this (mutex, cond) pair is used to synchronize the main thread and this
239 // thread in several situations:
240 // 1. The thread function blocks until condition is signaled by Run() when
241 // it's initially created - this allows create thread in "suspended"
243 // 2. The Delete() function blocks until the condition is signaled when the
248 // another (mutex, cond) pair for Pause()/Resume() usage
250 // VZ: it's possible that we might reuse the mutex and condition from above
251 // for this too, but as I'm not at all sure that it won't create subtle
252 // problems with race conditions between, say, Pause() and Delete() I
253 // prefer this may be a bit less efficient but much safer solution
254 wxMutex m_mutexSuspend
;
255 wxCondition m_condSuspend
;
258 void *wxThreadInternal::PthreadStart(void *ptr
)
260 wxThread
*thread
= (wxThread
*)ptr
;
261 wxThreadInternal
*pthread
= thread
->p_internal
;
263 if ( pthread_setspecific(gs_keySelf
, thread
) != 0 )
265 wxLogError(_("Can not start thread: error writing TLS."));
270 // wait for the condition to be signaled from Run()
271 // mutex state: currently locked by the thread which created us
272 pthread
->m_cond
.Wait(pthread
->m_mutex
);
274 // mutex state: locked again on exit of Wait()
276 // call the main entry
277 void* status
= thread
->Entry();
279 // terminate the thread
280 thread
->Exit(status
);
282 wxFAIL_MSG("wxThread::Exit() can't return.");
287 wxThreadInternal::wxThreadInternal()
292 // this mutex is locked during almost all thread lifetime - it will only be
293 // unlocked in the very end
296 // this mutex is used in Pause()/Resume() and is also locked all the time
297 // unless the thread is paused
298 m_mutexSuspend
.Lock();
301 wxThreadInternal::~wxThreadInternal()
303 m_mutexSuspend
.Unlock();
305 // note that m_mutex will be unlocked by the thread which waits for our
309 wxThreadError
wxThreadInternal::Run()
311 wxCHECK_MSG( GetState() == STATE_NEW
, wxTHREAD_RUNNING
,
312 "thread may only be started once after successful Create()" );
314 // the mutex was locked on Create(), so we will be able to lock it again
315 // only when the thread really starts executing and enters the wait -
316 // otherwise we might signal the condition before anybody is waiting for it
317 wxMutexLocker
lock(m_mutex
);
320 m_state
= STATE_RUNNING
;
322 return wxTHREAD_NO_ERROR
;
324 // now the mutex is unlocked back - but just to allow Wait() function to
325 // terminate by relocking it, so the net result is that the worker thread
326 // starts executing and the mutex is still locked
329 void wxThreadInternal::Cancel()
331 // if the thread we're waiting for is waiting for the GUI mutex, we will
332 // deadlock so make sure we release it temporarily
333 if ( wxThread::IsMain() )
336 // nobody ever writes this variable so it's safe to not use any
337 // synchronization here
340 // entering Wait() releases the mutex thus allowing SignalExit() to acquire
341 // it and to signal us its termination
342 m_cond
.Wait(m_mutex
);
344 // mutex is still in the locked state - relocked on exit from Wait(), so
345 // unlock it - we don't need it any more, the thread has already terminated
348 // reacquire GUI mutex
349 if ( wxThread::IsMain() )
353 void wxThreadInternal::SignalExit()
355 // as mutex is currently locked, this will block until some other thread
356 // (normally the same which created this one) unlocks it by entering Wait()
359 // wake up all the threads waiting for our termination
362 // after this call mutex will be finally unlocked
366 void wxThreadInternal::Pause()
368 wxCHECK_RET( m_state
== STATE_PAUSED
,
369 "thread must first be paused with wxThread::Pause()." );
371 // wait until the condition is signaled from Resume()
372 m_condSuspend
.Wait(m_mutexSuspend
);
375 void wxThreadInternal::Resume()
377 wxCHECK_RET( m_state
== STATE_PAUSED
,
378 "can't resume thread which is not suspended." );
380 // we will be able to lock this mutex only when Pause() starts waiting
381 wxMutexLocker
lock(m_mutexSuspend
);
382 m_condSuspend
.Signal();
384 SetState(STATE_RUNNING
);
387 // -----------------------------------------------------------------------------
389 // -----------------------------------------------------------------------------
391 wxThread
*wxThread::This()
393 return (wxThread
*)pthread_getspecific(gs_keySelf
);
396 bool wxThread::IsMain()
398 return (bool)pthread_equal(pthread_self(), gs_tidMain
);
401 void wxThread::Yield()
406 void wxThread::Sleep(unsigned long milliseconds
)
408 wxUsleep(milliseconds
);
411 // -----------------------------------------------------------------------------
413 // -----------------------------------------------------------------------------
417 // add this thread to the global list of all threads
418 gs_allThreads
.Add(this);
420 p_internal
= new wxThreadInternal();
423 wxThreadError
wxThread::Create()
425 if (p_internal
->GetState() != STATE_NEW
)
426 return wxTHREAD_RUNNING
;
428 // set up the thread attribute: right now, we only set thread priority
430 pthread_attr_init(&attr
);
433 if ( pthread_attr_getschedpolicy(&attr
, &prio
) != 0 )
435 wxLogError(_("Can not retrieve thread scheduling policy."));
438 int min_prio
= sched_get_priority_min(prio
),
439 max_prio
= sched_get_priority_max(prio
);
441 if ( min_prio
== -1 || max_prio
== -1 )
443 wxLogError(_("Can not get priority range for scheduling policy %d."),
448 struct sched_param sp
;
449 pthread_attr_getschedparam(&attr
, &sp
);
450 sp
.sched_priority
= min_prio
+
451 (p_internal
->GetPriority()*(max_prio
-min_prio
))/100;
452 pthread_attr_setschedparam(&attr
, &sp
);
455 // create the new OS thread object
456 int rc
= pthread_create(&p_internal
->thread_id
, &attr
,
457 wxThreadInternal::PthreadStart
,
459 pthread_attr_destroy(&attr
);
463 p_internal
->SetState(STATE_EXITED
);
464 return wxTHREAD_NO_RESOURCE
;
467 return wxTHREAD_NO_ERROR
;
470 wxThreadError
wxThread::Run()
472 return p_internal
->Run();
475 // -----------------------------------------------------------------------------
477 // -----------------------------------------------------------------------------
479 void wxThread::SetPriority(unsigned int prio
)
481 wxCHECK_RET( (WXTHREAD_MIN_PRIORITY
<= prio
) &&
482 (prio
<= WXTHREAD_MAX_PRIORITY
), "invalid thread priority" );
484 wxCriticalSectionLocker
lock(m_critsect
);
486 switch ( p_internal
->GetState() )
489 // thread not yet started, priority will be set when it is
490 p_internal
->SetPriority(prio
);
496 struct sched_param sparam
;
497 sparam
.sched_priority
= prio
;
499 if ( pthread_setschedparam(p_internal
->GetId(),
500 SCHED_OTHER
, &sparam
) != 0 )
502 wxLogError(_("Failed to set thread priority %d."), prio
);
509 wxFAIL_MSG("impossible to set thread priority in this state");
513 unsigned int wxThread::GetPriority() const
515 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
517 return p_internal
->GetPriority();
520 unsigned long wxThread::GetID() const
522 return (unsigned long)p_internal
->thread_id
;
525 // -----------------------------------------------------------------------------
527 // -----------------------------------------------------------------------------
529 wxThreadError
wxThread::Pause()
531 wxCriticalSectionLocker
lock(m_critsect
);
533 if ( p_internal
->GetState() != STATE_RUNNING
)
535 wxLogDebug("Can't pause thread which is not running.");
537 return wxTHREAD_NOT_RUNNING
;
540 p_internal
->SetState(STATE_PAUSED
);
542 return wxTHREAD_NO_ERROR
;
545 wxThreadError
wxThread::Resume()
547 wxCriticalSectionLocker
lock(m_critsect
);
549 if ( p_internal
->GetState() == STATE_PAUSED
)
551 p_internal
->Resume();
553 return wxTHREAD_NO_ERROR
;
557 wxLogDebug("Attempt to resume a thread which is not paused.");
559 return wxTHREAD_MISC_ERROR
;
563 // -----------------------------------------------------------------------------
565 // -----------------------------------------------------------------------------
567 wxThread::ExitCode
wxThread::Delete()
570 thread_state state
= p_internal
->GetState();
581 // resume the thread first
587 // set the flag telling to the thread to stop and wait
588 p_internal
->Cancel();
594 wxThreadError
wxThread::Kill()
596 switch ( p_internal
->GetState() )
600 return wxTHREAD_NOT_RUNNING
;
603 if ( pthread_cancel(p_internal
->GetId()) != 0 )
605 wxLogError(_("Failed to terminate a thread."));
607 return wxTHREAD_MISC_ERROR
;
610 return wxTHREAD_NO_ERROR
;
614 void wxThread::Exit(void *status
)
616 // first call user-level clean up code
619 // next wake up the threads waiting for us (OTOH, this function won't return
620 // until someone waited for us!)
621 p_internal
->SignalExit();
623 p_internal
->SetState(STATE_EXITED
);
625 // delete both C++ thread object and terminate the OS thread object
627 pthread_exit(status
);
630 // also test whether we were paused
631 bool wxThread::TestDestroy()
633 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
635 if ( p_internal
->GetState() == STATE_PAUSED
)
637 // leave the crit section or the other threads will stop too if they try
638 // to call any of (seemingly harmless) IsXXX() functions while we sleep
643 // enter it back before it's finally left in lock object dtor
647 return p_internal
->WasCancelled();
650 wxThread::~wxThread()
652 // remove this thread from the global array
653 gs_allThreads
.Remove(this);
656 // -----------------------------------------------------------------------------
658 // -----------------------------------------------------------------------------
660 bool wxThread::IsRunning() const
662 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
664 return p_internal
->GetState() == STATE_RUNNING
;
667 bool wxThread::IsAlive() const
669 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
671 switch ( p_internal
->GetState() )
682 //--------------------------------------------------------------------
684 //--------------------------------------------------------------------
686 class wxThreadModule
: public wxModule
689 virtual bool OnInit();
690 virtual void OnExit();
693 DECLARE_DYNAMIC_CLASS(wxThreadModule
)
696 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule
, wxModule
)
698 bool wxThreadModule::OnInit()
700 if ( pthread_key_create(&gs_keySelf
, NULL
/* dtor function */) != 0 )
702 wxLogError(_("Thread module initialization failed: "
703 "failed to create pthread key."));
708 gs_mutexGui
= new wxMutex();
710 gs_tidMain
= pthread_self();
716 void wxThreadModule::OnExit()
718 wxASSERT_MSG( wxThread::IsMain(), "only main thread can be here" );
720 // terminate any threads left
721 size_t count
= gs_allThreads
.GetCount();
723 wxLogDebug("Some threads were not terminated by the application.");
725 for ( size_t n
= 0u; n
< count
; n
++ )
727 gs_allThreads
[n
]->Delete();
731 gs_mutexGui
->Unlock();
736 (void)pthread_key_delete(gs_keySelf
);
739 void wxMutexGuiEnter()
744 void wxMutexGuiLeave()
746 gs_mutexGui
->Unlock();