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"
39 STATE_NEW
, // didn't start execution yet (=> RUNNING)
46 WX_DEFINE_ARRAY(wxThread
*, wxArrayThread
);
48 // -----------------------------------------------------------------------------
50 // -----------------------------------------------------------------------------
52 // we keep the list of all threads created by the application to be able to
53 // terminate them on exit if there are some left - otherwise the process would
55 static wxArrayThread gs_allThreads
;
57 // the id of the main thread
58 static pthread_t gs_tidMain
;
60 // the key for the pointer to the associated wxThread object
61 static pthread_key_t gs_keySelf
;
63 // this mutex must be acquired before any call to a GUI function
64 static wxMutex
*gs_mutexGui
;
66 //--------------------------------------------------------------------
67 // common GUI thread code
68 //--------------------------------------------------------------------
70 #include "threadgui.inc"
72 //--------------------------------------------------------------------
73 // wxMutex (Posix implementation)
74 //--------------------------------------------------------------------
79 pthread_mutex_t p_mutex
;
84 p_internal
= new wxMutexInternal
;
85 pthread_mutex_init( &(p_internal
->p_mutex
), (const pthread_mutexattr_t
*) NULL
);
92 wxLogDebug("Freeing a locked mutex (%d locks)", m_locked
);
94 pthread_mutex_destroy( &(p_internal
->p_mutex
) );
98 wxMutexError
wxMutex::Lock()
100 int err
= pthread_mutex_lock( &(p_internal
->p_mutex
) );
103 wxLogDebug("Locking this mutex would lead to deadlock!");
105 return wxMUTEX_DEAD_LOCK
;
110 return wxMUTEX_NO_ERROR
;
113 wxMutexError
wxMutex::TryLock()
120 int err
= pthread_mutex_trylock( &(p_internal
->p_mutex
) );
123 case EBUSY
: return wxMUTEX_BUSY
;
128 return wxMUTEX_NO_ERROR
;
131 wxMutexError
wxMutex::Unlock()
139 wxLogDebug("Unlocking not locked mutex.");
141 return wxMUTEX_UNLOCKED
;
144 pthread_mutex_unlock( &(p_internal
->p_mutex
) );
146 return wxMUTEX_NO_ERROR
;
149 //--------------------------------------------------------------------
150 // wxCondition (Posix implementation)
151 //--------------------------------------------------------------------
153 class wxConditionInternal
156 pthread_cond_t p_condition
;
159 wxCondition::wxCondition()
161 p_internal
= new wxConditionInternal
;
162 pthread_cond_init( &(p_internal
->p_condition
), (const pthread_condattr_t
*) NULL
);
165 wxCondition::~wxCondition()
167 pthread_cond_destroy( &(p_internal
->p_condition
) );
172 void wxCondition::Wait(wxMutex
& mutex
)
174 pthread_cond_wait( &(p_internal
->p_condition
), &(mutex
.p_internal
->p_mutex
) );
177 bool wxCondition::Wait(wxMutex
& mutex
, unsigned long sec
, unsigned long nsec
)
179 struct timespec tspec
;
181 tspec
.tv_sec
= time(0L)+sec
;
182 tspec
.tv_nsec
= nsec
;
183 return (pthread_cond_timedwait(&(p_internal
->p_condition
), &(mutex
.p_internal
->p_mutex
), &tspec
) != ETIMEDOUT
);
186 void wxCondition::Signal()
188 pthread_cond_signal( &(p_internal
->p_condition
) );
191 void wxCondition::Broadcast()
193 pthread_cond_broadcast( &(p_internal
->p_condition
) );
196 //--------------------------------------------------------------------
197 // wxThread (Posix implementation)
198 //--------------------------------------------------------------------
200 class wxThreadInternal
206 // thread entry function
207 static void *PthreadStart(void *ptr
);
212 // ask the thread to terminate
214 // wake up threads waiting for our termination
216 // go to sleep until Resume() is called
223 int GetPriority() const { return m_prio
; }
224 void SetPriority(int prio
) { m_prio
= prio
; }
226 thread_state
GetState() const { return m_state
; }
227 void SetState(thread_state state
) { m_state
= state
; }
229 pthread_t
GetId() const { return thread_id
; }
231 bool WasCancelled() const { return m_cancelled
; }
233 //private: -- should be!
237 thread_state m_state
; // see thread_state enum
238 int m_prio
; // in wxWindows units: from 0 to 100
240 // set when the thread should terminate
243 // this (mutex, cond) pair is used to synchronize the main thread and this
244 // thread in several situations:
245 // 1. The thread function blocks until condition is signaled by Run() when
246 // it's initially created - this allows create thread in "suspended"
248 // 2. The Delete() function blocks until the condition is signaled when the
253 // another (mutex, cond) pair for Pause()/Resume() usage
255 // VZ: it's possible that we might reuse the mutex and condition from above
256 // for this too, but as I'm not at all sure that it won't create subtle
257 // problems with race conditions between, say, Pause() and Delete() I
258 // prefer this may be a bit less efficient but much safer solution
259 wxMutex m_mutexSuspend
;
260 wxCondition m_condSuspend
;
263 void *wxThreadInternal::PthreadStart(void *ptr
)
265 wxThread
*thread
= (wxThread
*)ptr
;
266 wxThreadInternal
*pthread
= thread
->p_internal
;
268 if ( pthread_setspecific(gs_keySelf
, thread
) != 0 )
270 wxLogError(_("Can not start thread: error writing TLS."));
275 // wait for the condition to be signaled from Run()
276 // mutex state: currently locked by the thread which created us
277 pthread
->m_cond
.Wait(pthread
->m_mutex
);
279 // mutex state: locked again on exit of Wait()
281 // call the main entry
282 void* status
= thread
->Entry();
284 // terminate the thread
285 thread
->Exit(status
);
287 wxFAIL_MSG("wxThread::Exit() can't return.");
292 wxThreadInternal::wxThreadInternal()
297 // this mutex is locked during almost all thread lifetime - it will only be
298 // unlocked in the very end
301 // this mutex is used in Pause()/Resume() and is also locked all the time
302 // unless the thread is paused
303 m_mutexSuspend
.Lock();
306 wxThreadInternal::~wxThreadInternal()
308 m_mutexSuspend
.Unlock();
310 // note that m_mutex will be unlocked by the thread which waits for our
314 wxThreadError
wxThreadInternal::Run()
316 wxCHECK_MSG( GetState() == STATE_NEW
, wxTHREAD_RUNNING
,
317 "thread may only be started once after successful Create()" );
319 // the mutex was locked on Create(), so we will be able to lock it again
320 // only when the thread really starts executing and enters the wait -
321 // otherwise we might signal the condition before anybody is waiting for it
322 wxMutexLocker
lock(m_mutex
);
325 m_state
= STATE_RUNNING
;
327 return wxTHREAD_NO_ERROR
;
329 // now the mutex is unlocked back - but just to allow Wait() function to
330 // terminate by relocking it, so the net result is that the worker thread
331 // starts executing and the mutex is still locked
334 void wxThreadInternal::Cancel()
336 // if the thread we're waiting for is waiting for the GUI mutex, we will
337 // deadlock so make sure we release it temporarily
338 if ( wxThread::IsMain() )
341 // nobody ever writes this variable so it's safe to not use any
342 // synchronization here
345 // entering Wait() releases the mutex thus allowing SignalExit() to acquire
346 // it and to signal us its termination
347 m_cond
.Wait(m_mutex
);
349 // mutex is still in the locked state - relocked on exit from Wait(), so
350 // unlock it - we don't need it any more, the thread has already terminated
353 // reacquire GUI mutex
354 if ( wxThread::IsMain() )
358 void wxThreadInternal::SignalExit()
360 // as mutex is currently locked, this will block until some other thread
361 // (normally the same which created this one) unlocks it by entering Wait()
364 // wake up all the threads waiting for our termination
367 // after this call mutex will be finally unlocked
371 void wxThreadInternal::Pause()
373 wxCHECK_RET( m_state
== STATE_PAUSED
,
374 "thread must first be paused with wxThread::Pause()." );
376 // wait until the condition is signaled from Resume()
377 m_condSuspend
.Wait(m_mutexSuspend
);
380 void wxThreadInternal::Resume()
382 wxCHECK_RET( m_state
== STATE_PAUSED
,
383 "can't resume thread which is not suspended." );
385 // we will be able to lock this mutex only when Pause() starts waiting
386 wxMutexLocker
lock(m_mutexSuspend
);
387 m_condSuspend
.Signal();
389 SetState(STATE_RUNNING
);
392 // -----------------------------------------------------------------------------
394 // -----------------------------------------------------------------------------
396 wxThread
*wxThread::This()
398 return (wxThread
*)pthread_getspecific(gs_keySelf
);
401 bool wxThread::IsMain()
403 return (bool)pthread_equal(pthread_self(), gs_tidMain
);
406 void wxThread::Yield()
408 #ifdef HAVE_SCHED_YIELD
410 #else // !HAVE_SCHED_YIELD
411 // may be it will have the desired effect?
413 #endif // HAVE_SCHED_YIELD
416 void wxThread::Sleep(unsigned long milliseconds
)
418 wxUsleep(milliseconds
);
421 // -----------------------------------------------------------------------------
423 // -----------------------------------------------------------------------------
427 // add this thread to the global list of all threads
428 gs_allThreads
.Add(this);
430 p_internal
= new wxThreadInternal();
433 wxThreadError
wxThread::Create()
435 if (p_internal
->GetState() != STATE_NEW
)
436 return wxTHREAD_RUNNING
;
438 // set up the thread attribute: right now, we only set thread priority
440 pthread_attr_init(&attr
);
442 #ifdef HAVE_THREAD_PRIORITY_FUNCTIONS
444 if ( pthread_attr_getschedpolicy(&attr
, &prio
) != 0 )
446 wxLogError(_("Can not retrieve thread scheduling policy."));
449 int min_prio
= sched_get_priority_min(prio
),
450 max_prio
= sched_get_priority_max(prio
);
452 if ( min_prio
== -1 || max_prio
== -1 )
454 wxLogError(_("Can not get priority range for scheduling policy %d."),
459 struct sched_param sp
;
460 pthread_attr_getschedparam(&attr
, &sp
);
461 sp
.sched_priority
= min_prio
+
462 (p_internal
->GetPriority()*(max_prio
-min_prio
))/100;
463 pthread_attr_setschedparam(&attr
, &sp
);
465 #endif // HAVE_THREAD_PRIORITY_FUNCTIONS
467 // create the new OS thread object
468 int rc
= pthread_create(&p_internal
->thread_id
, &attr
,
469 wxThreadInternal::PthreadStart
, (void *)this);
470 pthread_attr_destroy(&attr
);
474 p_internal
->SetState(STATE_EXITED
);
475 return wxTHREAD_NO_RESOURCE
;
478 return wxTHREAD_NO_ERROR
;
481 wxThreadError
wxThread::Run()
483 return p_internal
->Run();
486 // -----------------------------------------------------------------------------
488 // -----------------------------------------------------------------------------
490 void wxThread::SetPriority(unsigned int prio
)
492 wxCHECK_RET( ((int)WXTHREAD_MIN_PRIORITY
<= (int)prio
) &&
493 ((int)prio
<= (int)WXTHREAD_MAX_PRIORITY
),
494 "invalid thread priority" );
496 wxCriticalSectionLocker
lock(m_critsect
);
498 switch ( p_internal
->GetState() )
501 // thread not yet started, priority will be set when it is
502 p_internal
->SetPriority(prio
);
507 #ifdef HAVE_THREAD_PRIORITY_FUNCTIONS
509 struct sched_param sparam
;
510 sparam
.sched_priority
= prio
;
512 if ( pthread_setschedparam(p_internal
->GetId(),
513 SCHED_OTHER
, &sparam
) != 0 )
515 wxLogError(_("Failed to set thread priority %d."), prio
);
518 #endif // HAVE_THREAD_PRIORITY_FUNCTIONS
523 wxFAIL_MSG("impossible to set thread priority in this state");
527 unsigned int wxThread::GetPriority() const
529 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
531 return p_internal
->GetPriority();
534 unsigned long wxThread::GetID() const
536 return (unsigned long)p_internal
->thread_id
;
539 // -----------------------------------------------------------------------------
541 // -----------------------------------------------------------------------------
543 wxThreadError
wxThread::Pause()
545 wxCriticalSectionLocker
lock(m_critsect
);
547 if ( p_internal
->GetState() != STATE_RUNNING
)
549 wxLogDebug("Can't pause thread which is not running.");
551 return wxTHREAD_NOT_RUNNING
;
554 p_internal
->SetState(STATE_PAUSED
);
556 return wxTHREAD_NO_ERROR
;
559 wxThreadError
wxThread::Resume()
561 wxCriticalSectionLocker
lock(m_critsect
);
563 if ( p_internal
->GetState() == STATE_PAUSED
)
565 p_internal
->Resume();
567 return wxTHREAD_NO_ERROR
;
571 wxLogDebug("Attempt to resume a thread which is not paused.");
573 return wxTHREAD_MISC_ERROR
;
577 // -----------------------------------------------------------------------------
579 // -----------------------------------------------------------------------------
581 wxThread::ExitCode
wxThread::Delete()
584 thread_state state
= p_internal
->GetState();
595 // resume the thread first
601 // set the flag telling to the thread to stop and wait
602 p_internal
->Cancel();
608 wxThreadError
wxThread::Kill()
610 switch ( p_internal
->GetState() )
614 return wxTHREAD_NOT_RUNNING
;
617 #ifdef HAVE_PTHREAD_CANCEL
618 if ( pthread_cancel(p_internal
->GetId()) != 0 )
621 wxLogError(_("Failed to terminate a thread."));
623 return wxTHREAD_MISC_ERROR
;
626 return wxTHREAD_NO_ERROR
;
630 void wxThread::Exit(void *status
)
632 // first call user-level clean up code
635 // next wake up the threads waiting for us (OTOH, this function won't return
636 // until someone waited for us!)
637 p_internal
->SignalExit();
639 p_internal
->SetState(STATE_EXITED
);
641 // delete both C++ thread object and terminate the OS thread object
643 pthread_exit(status
);
646 // also test whether we were paused
647 bool wxThread::TestDestroy()
649 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
651 if ( p_internal
->GetState() == STATE_PAUSED
)
653 // leave the crit section or the other threads will stop too if they try
654 // to call any of (seemingly harmless) IsXXX() functions while we sleep
659 // enter it back before it's finally left in lock object dtor
663 return p_internal
->WasCancelled();
666 wxThread::~wxThread()
668 // remove this thread from the global array
669 gs_allThreads
.Remove(this);
672 // -----------------------------------------------------------------------------
674 // -----------------------------------------------------------------------------
676 bool wxThread::IsRunning() const
678 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
680 return p_internal
->GetState() == STATE_RUNNING
;
683 bool wxThread::IsAlive() const
685 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
687 switch ( p_internal
->GetState() )
698 //--------------------------------------------------------------------
700 //--------------------------------------------------------------------
702 class wxThreadModule
: public wxModule
705 virtual bool OnInit();
706 virtual void OnExit();
709 DECLARE_DYNAMIC_CLASS(wxThreadModule
)
712 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule
, wxModule
)
714 bool wxThreadModule::OnInit()
716 if ( pthread_key_create(&gs_keySelf
, NULL
/* dtor function */) != 0 )
718 wxLogError(_("Thread module initialization failed: "
719 "failed to create pthread key."));
724 gs_mutexGui
= new wxMutex();
726 gs_tidMain
= pthread_self();
732 void wxThreadModule::OnExit()
734 wxASSERT_MSG( wxThread::IsMain(), "only main thread can be here" );
736 // terminate any threads left
737 size_t count
= gs_allThreads
.GetCount();
739 wxLogDebug("Some threads were not terminated by the application.");
741 for ( size_t n
= 0u; n
< count
; n
++ )
743 gs_allThreads
[n
]->Delete();
747 gs_mutexGui
->Unlock();
752 (void)pthread_key_delete(gs_keySelf
);