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 // ----------------------------------------------------------------------------
53 // the possible states of the thread and transitions from them
56 STATE_NEW
, // didn't start execution yet (=> RUNNING)
57 STATE_RUNNING
, // running (=> PAUSED or EXITED)
58 STATE_PAUSED
, // suspended (=> RUNNING or EXITED)
59 STATE_EXITED
// thread doesn't exist any more
62 // ----------------------------------------------------------------------------
64 // ----------------------------------------------------------------------------
66 WX_DEFINE_ARRAY(wxThread
*, wxArrayThread
);
68 // -----------------------------------------------------------------------------
70 // -----------------------------------------------------------------------------
72 // we keep the list of all threads created by the application to be able to
73 // terminate them on exit if there are some left - otherwise the process would
75 static wxArrayThread gs_allThreads
;
77 // the id of the main thread
78 static pthread_t gs_tidMain
;
80 // the key for the pointer to the associated wxThread object
81 static pthread_key_t gs_keySelf
;
83 // this mutex must be acquired before any call to a GUI function
84 static wxMutex
*gs_mutexGui
;
86 // ============================================================================
88 // ============================================================================
90 //--------------------------------------------------------------------
91 // wxMutex (Posix implementation)
92 //--------------------------------------------------------------------
97 pthread_mutex_t p_mutex
;
102 p_internal
= new wxMutexInternal
;
103 pthread_mutex_init( &(p_internal
->p_mutex
), (const pthread_mutexattr_t
*) NULL
);
110 wxLogDebug("Freeing a locked mutex (%d locks)", m_locked
);
112 pthread_mutex_destroy( &(p_internal
->p_mutex
) );
116 wxMutexError
wxMutex::Lock()
118 int err
= pthread_mutex_lock( &(p_internal
->p_mutex
) );
121 wxLogDebug("Locking this mutex would lead to deadlock!");
123 return wxMUTEX_DEAD_LOCK
;
128 return wxMUTEX_NO_ERROR
;
131 wxMutexError
wxMutex::TryLock()
138 int err
= pthread_mutex_trylock( &(p_internal
->p_mutex
) );
141 case EBUSY
: return wxMUTEX_BUSY
;
146 return wxMUTEX_NO_ERROR
;
149 wxMutexError
wxMutex::Unlock()
157 wxLogDebug("Unlocking not locked mutex.");
159 return wxMUTEX_UNLOCKED
;
162 pthread_mutex_unlock( &(p_internal
->p_mutex
) );
164 return wxMUTEX_NO_ERROR
;
167 //--------------------------------------------------------------------
168 // wxCondition (Posix implementation)
169 //--------------------------------------------------------------------
171 class wxConditionInternal
174 pthread_cond_t p_condition
;
177 wxCondition::wxCondition()
179 p_internal
= new wxConditionInternal
;
180 pthread_cond_init( &(p_internal
->p_condition
), (const pthread_condattr_t
*) NULL
);
183 wxCondition::~wxCondition()
185 pthread_cond_destroy( &(p_internal
->p_condition
) );
190 void wxCondition::Wait(wxMutex
& mutex
)
192 pthread_cond_wait( &(p_internal
->p_condition
), &(mutex
.p_internal
->p_mutex
) );
195 bool wxCondition::Wait(wxMutex
& mutex
, unsigned long sec
, unsigned long nsec
)
197 struct timespec tspec
;
199 tspec
.tv_sec
= time(0L)+sec
;
200 tspec
.tv_nsec
= nsec
;
201 return (pthread_cond_timedwait(&(p_internal
->p_condition
), &(mutex
.p_internal
->p_mutex
), &tspec
) != ETIMEDOUT
);
204 void wxCondition::Signal()
206 pthread_cond_signal( &(p_internal
->p_condition
) );
209 void wxCondition::Broadcast()
211 pthread_cond_broadcast( &(p_internal
->p_condition
) );
214 //--------------------------------------------------------------------
215 // wxThread (Posix implementation)
216 //--------------------------------------------------------------------
218 class wxThreadInternal
224 // thread entry function
225 static void *PthreadStart(void *ptr
);
230 // ask the thread to terminate
232 // wake up threads waiting for our termination
234 // go to sleep until Resume() is called
241 int GetPriority() const { return m_prio
; }
242 void SetPriority(int prio
) { m_prio
= prio
; }
244 wxThreadState
GetState() const { return m_state
; }
245 void SetState(wxThreadState state
) { m_state
= state
; }
247 pthread_t
GetId() const { return m_threadId
; }
248 pthread_t
*GetIdPtr() { return &m_threadId
; }
250 void SetCancelFlag() { m_cancelled
= TRUE
; }
251 bool WasCancelled() const { return m_cancelled
; }
254 pthread_t m_threadId
; // id of the thread
255 wxThreadState m_state
; // see wxThreadState enum
256 int m_prio
; // in wxWindows units: from 0 to 100
258 // set when the thread should terminate
261 // this (mutex, cond) pair is used to synchronize the main thread and this
262 // thread in several situations:
263 // 1. The thread function blocks until condition is signaled by Run() when
264 // it's initially created - this allows thread creation in "suspended"
266 // 2. The Delete() function blocks until the condition is signaled when the
271 // another (mutex, cond) pair for Pause()/Resume() usage
273 // VZ: it's possible that we might reuse the mutex and condition from above
274 // for this too, but as I'm not at all sure that it won't create subtle
275 // problems with race conditions between, say, Pause() and Delete() I
276 // prefer this may be a bit less efficient but much safer solution
277 wxMutex m_mutexSuspend
;
278 wxCondition m_condSuspend
;
281 void *wxThreadInternal::PthreadStart(void *ptr
)
283 wxThread
*thread
= (wxThread
*)ptr
;
284 wxThreadInternal
*pthread
= thread
->p_internal
;
286 int rc
= pthread_setspecific(gs_keySelf
, thread
);
289 wxLogSysError(rc
, _("Can not start thread: error writing TLS."));
294 // wait for the condition to be signaled from Run()
295 // mutex state: currently locked by the thread which created us
296 pthread
->m_cond
.Wait(pthread
->m_mutex
);
298 // mutex state: locked again on exit of Wait()
300 // call the main entry
301 void* status
= thread
->Entry();
303 // terminate the thread
304 thread
->Exit(status
);
306 wxFAIL_MSG("wxThread::Exit() can't return.");
311 wxThreadInternal::wxThreadInternal()
316 // this mutex is locked during almost all thread lifetime - it will only be
317 // unlocked in the very end
320 // this mutex is used in Pause()/Resume() and is also locked all the time
321 // unless the thread is paused
322 m_mutexSuspend
.Lock();
325 wxThreadInternal::~wxThreadInternal()
327 m_mutexSuspend
.Unlock();
329 // note that m_mutex will be unlocked by the thread which waits for our
333 wxThreadError
wxThreadInternal::Run()
335 wxCHECK_MSG( GetState() == STATE_NEW
, wxTHREAD_RUNNING
,
336 "thread may only be started once after successful Create()" );
338 // the mutex was locked on Create(), so we will be able to lock it again
339 // only when the thread really starts executing and enters the wait -
340 // otherwise we might signal the condition before anybody is waiting for it
341 wxMutexLocker
lock(m_mutex
);
344 m_state
= STATE_RUNNING
;
346 return wxTHREAD_NO_ERROR
;
348 // now the mutex is unlocked back - but just to allow Wait() function to
349 // terminate by relocking it, so the net result is that the worker thread
350 // starts executing and the mutex is still locked
353 void wxThreadInternal::Wait()
355 wxCHECK_RET( WasCancelled(), "thread should have been cancelled first" );
357 // if the thread we're waiting for is waiting for the GUI mutex, we will
358 // deadlock so make sure we release it temporarily
359 if ( wxThread::IsMain() )
362 // entering Wait() releases the mutex thus allowing SignalExit() to acquire
363 // it and to signal us its termination
364 m_cond
.Wait(m_mutex
);
366 // mutex is still in the locked state - relocked on exit from Wait(), so
367 // unlock it - we don't need it any more, the thread has already terminated
370 // reacquire GUI mutex
371 if ( wxThread::IsMain() )
375 void wxThreadInternal::SignalExit()
377 // as mutex is currently locked, this will block until some other thread
378 // (normally the same which created this one) unlocks it by entering Wait()
381 // wake up all the threads waiting for our termination
384 // after this call mutex will be finally unlocked
388 void wxThreadInternal::Pause()
390 // the state is set from the thread which pauses us first, this function
391 // is called later so the state should have been already set
392 wxCHECK_RET( m_state
== STATE_PAUSED
,
393 "thread must first be paused with wxThread::Pause()." );
395 // don't pause the thread which is being terminated - this would lead to
396 // deadlock if the thread is paused after Delete() had called Resume() but
397 // before it had time to call Wait()
398 if ( WasCancelled() )
401 // wait until the condition is signaled from Resume()
402 m_condSuspend
.Wait(m_mutexSuspend
);
405 void wxThreadInternal::Resume()
407 wxCHECK_RET( m_state
== STATE_PAUSED
,
408 "can't resume thread which is not suspended." );
410 // we will be able to lock this mutex only when Pause() starts waiting
411 wxMutexLocker
lock(m_mutexSuspend
);
412 m_condSuspend
.Signal();
414 SetState(STATE_RUNNING
);
417 // -----------------------------------------------------------------------------
419 // -----------------------------------------------------------------------------
421 wxThread
*wxThread::This()
423 return (wxThread
*)pthread_getspecific(gs_keySelf
);
426 bool wxThread::IsMain()
428 return (bool)pthread_equal(pthread_self(), gs_tidMain
);
431 void wxThread::Yield()
436 void wxThread::Sleep(unsigned long milliseconds
)
438 wxUsleep(milliseconds
);
441 // -----------------------------------------------------------------------------
443 // -----------------------------------------------------------------------------
447 // add this thread to the global list of all threads
448 gs_allThreads
.Add(this);
450 p_internal
= new wxThreadInternal();
453 wxThreadError
wxThread::Create()
455 if (p_internal
->GetState() != STATE_NEW
)
456 return wxTHREAD_RUNNING
;
458 // set up the thread attribute: right now, we only set thread priority
460 pthread_attr_init(&attr
);
462 #ifdef HAVE_THREAD_PRIORITY_FUNCTIONS
464 if ( pthread_attr_getschedpolicy(&attr
, &prio
) != 0 )
466 wxLogError(_("Can not retrieve thread scheduling policy."));
469 int min_prio
= sched_get_priority_min(prio
),
470 max_prio
= sched_get_priority_max(prio
);
472 if ( min_prio
== -1 || max_prio
== -1 )
474 wxLogError(_("Can not get priority range for scheduling policy %d."),
479 struct sched_param sp
;
480 pthread_attr_getschedparam(&attr
, &sp
);
481 sp
.sched_priority
= min_prio
+
482 (p_internal
->GetPriority()*(max_prio
-min_prio
))/100;
483 pthread_attr_setschedparam(&attr
, &sp
);
485 #endif // HAVE_THREAD_PRIORITY_FUNCTIONS
487 // create the new OS thread object
488 int rc
= pthread_create(p_internal
->GetIdPtr(), &attr
,
489 wxThreadInternal::PthreadStart
, (void *)this);
490 pthread_attr_destroy(&attr
);
494 p_internal
->SetState(STATE_EXITED
);
495 return wxTHREAD_NO_RESOURCE
;
498 return wxTHREAD_NO_ERROR
;
501 wxThreadError
wxThread::Run()
503 return p_internal
->Run();
506 // -----------------------------------------------------------------------------
508 // -----------------------------------------------------------------------------
510 void wxThread::SetPriority(unsigned int prio
)
512 wxCHECK_RET( ((int)WXTHREAD_MIN_PRIORITY
<= (int)prio
) &&
513 ((int)prio
<= (int)WXTHREAD_MAX_PRIORITY
),
514 "invalid thread priority" );
516 wxCriticalSectionLocker
lock(m_critsect
);
518 switch ( p_internal
->GetState() )
521 // thread not yet started, priority will be set when it is
522 p_internal
->SetPriority(prio
);
527 #ifdef HAVE_THREAD_PRIORITY_FUNCTIONS
529 struct sched_param sparam
;
530 sparam
.sched_priority
= prio
;
532 if ( pthread_setschedparam(p_internal
->GetId(),
533 SCHED_OTHER
, &sparam
) != 0 )
535 wxLogError(_("Failed to set thread priority %d."), prio
);
538 #endif // HAVE_THREAD_PRIORITY_FUNCTIONS
543 wxFAIL_MSG("impossible to set thread priority in this state");
547 unsigned int wxThread::GetPriority() const
549 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
551 return p_internal
->GetPriority();
554 unsigned long wxThread::GetID() const
556 return (unsigned long)p_internal
->GetId();
559 // -----------------------------------------------------------------------------
561 // -----------------------------------------------------------------------------
563 wxThreadError
wxThread::Pause()
565 wxCriticalSectionLocker
lock(m_critsect
);
567 if ( p_internal
->GetState() != STATE_RUNNING
)
569 wxLogDebug("Can't pause thread which is not running.");
571 return wxTHREAD_NOT_RUNNING
;
574 p_internal
->SetState(STATE_PAUSED
);
576 return wxTHREAD_NO_ERROR
;
579 wxThreadError
wxThread::Resume()
581 wxCriticalSectionLocker
lock(m_critsect
);
583 if ( p_internal
->GetState() == STATE_PAUSED
)
585 p_internal
->Resume();
587 return wxTHREAD_NO_ERROR
;
591 wxLogDebug("Attempt to resume a thread which is not paused.");
593 return wxTHREAD_MISC_ERROR
;
597 // -----------------------------------------------------------------------------
599 // -----------------------------------------------------------------------------
601 wxThread::ExitCode
wxThread::Delete()
604 wxThreadState state
= p_internal
->GetState();
607 // ask the thread to stop
608 p_internal
->SetCancelFlag();
618 // resume the thread first
624 // wait until the thread stops
631 wxThreadError
wxThread::Kill()
633 switch ( p_internal
->GetState() )
637 return wxTHREAD_NOT_RUNNING
;
640 #ifdef HAVE_PTHREAD_CANCEL
641 if ( pthread_cancel(p_internal
->GetId()) != 0 )
644 wxLogError(_("Failed to terminate a thread."));
646 return wxTHREAD_MISC_ERROR
;
649 return wxTHREAD_NO_ERROR
;
653 void wxThread::Exit(void *status
)
655 // first call user-level clean up code
658 // next wake up the threads waiting for us (OTOH, this function won't return
659 // until someone waited for us!)
660 p_internal
->SignalExit();
662 p_internal
->SetState(STATE_EXITED
);
664 // delete both C++ thread object and terminate the OS thread object
666 pthread_exit(status
);
669 // also test whether we were paused
670 bool wxThread::TestDestroy()
672 wxCriticalSectionLocker
lock(m_critsect
);
674 if ( p_internal
->GetState() == STATE_PAUSED
)
676 // leave the crit section or the other threads will stop too if they try
677 // to call any of (seemingly harmless) IsXXX() functions while we sleep
682 // enter it back before it's finally left in lock object dtor
686 return p_internal
->WasCancelled();
689 wxThread::~wxThread()
691 // remove this thread from the global array
692 gs_allThreads
.Remove(this);
695 // -----------------------------------------------------------------------------
697 // -----------------------------------------------------------------------------
699 bool wxThread::IsRunning() const
701 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
703 return p_internal
->GetState() == STATE_RUNNING
;
706 bool wxThread::IsAlive() const
708 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
710 switch ( p_internal
->GetState() )
721 //--------------------------------------------------------------------
723 //--------------------------------------------------------------------
725 class wxThreadModule
: public wxModule
728 virtual bool OnInit();
729 virtual void OnExit();
732 DECLARE_DYNAMIC_CLASS(wxThreadModule
)
735 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule
, wxModule
)
737 bool wxThreadModule::OnInit()
739 if ( pthread_key_create(&gs_keySelf
, NULL
/* dtor function */) != 0 )
741 wxLogError(_("Thread module initialization failed: "
742 "failed to create pthread key."));
747 gs_mutexGui
= new wxMutex();
751 gs_tidMain
= pthread_self();
757 void wxThreadModule::OnExit()
759 wxASSERT_MSG( wxThread::IsMain(), "only main thread can be here" );
761 // terminate any threads left
762 size_t count
= gs_allThreads
.GetCount();
764 wxLogDebug("Some threads were not terminated by the application.");
766 for ( size_t n
= 0u; n
< count
; n
++ )
768 gs_allThreads
[n
]->Delete();
772 gs_mutexGui
->Unlock();
779 (void)pthread_key_delete(gs_keySelf
);
782 // ----------------------------------------------------------------------------
784 // ----------------------------------------------------------------------------
786 void wxMutexGuiEnter()
791 void wxMutexGuiLeave()
793 gs_mutexGui
->Unlock();