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"
38 STATE_NEW
, // didn't start execution yet (=> RUNNING)
45 //--------------------------------------------------------------------
47 //--------------------------------------------------------------------
49 // the id of the main thread
50 static pthread_t gs_pidMain
;
52 // the key for the pointer to the associated wxThread object
53 static pthread_key_t gs_keySelf
;
55 // this mutex must be acquired before any call to a GUI function
56 static wxMutex
*gs_mutexGui
;
58 //--------------------------------------------------------------------
59 // common GUI thread code
60 //--------------------------------------------------------------------
62 #include "threadgui.inc"
64 //--------------------------------------------------------------------
65 // wxMutex (Posix implementation)
66 //--------------------------------------------------------------------
71 pthread_mutex_t p_mutex
;
76 p_internal
= new wxMutexInternal
;
77 pthread_mutex_init( &(p_internal
->p_mutex
), (const pthread_mutexattr_t
*) NULL
);
84 wxLogDebug( "wxMutex warning: freeing a locked mutex (%d locks)", m_locked
);
86 pthread_mutex_destroy( &(p_internal
->p_mutex
) );
90 wxMutexError
wxMutex::Lock()
92 int err
= pthread_mutex_lock( &(p_internal
->p_mutex
) );
95 return wxMUTEX_DEAD_LOCK
;
100 return wxMUTEX_NO_ERROR
;
103 wxMutexError
wxMutex::TryLock()
110 int err
= pthread_mutex_trylock( &(p_internal
->p_mutex
) );
113 case EBUSY
: return wxMUTEX_BUSY
;
118 return wxMUTEX_NO_ERROR
;
121 wxMutexError
wxMutex::Unlock()
129 return wxMUTEX_UNLOCKED
;
132 pthread_mutex_unlock( &(p_internal
->p_mutex
) );
134 return wxMUTEX_NO_ERROR
;
137 //--------------------------------------------------------------------
138 // wxCondition (Posix implementation)
139 //--------------------------------------------------------------------
141 class wxConditionInternal
144 pthread_cond_t p_condition
;
147 wxCondition::wxCondition()
149 p_internal
= new wxConditionInternal
;
150 pthread_cond_init( &(p_internal
->p_condition
), (const pthread_condattr_t
*) NULL
);
153 wxCondition::~wxCondition()
155 pthread_cond_destroy( &(p_internal
->p_condition
) );
160 void wxCondition::Wait(wxMutex
& mutex
)
162 pthread_cond_wait( &(p_internal
->p_condition
), &(mutex
.p_internal
->p_mutex
) );
165 bool wxCondition::Wait(wxMutex
& mutex
, unsigned long sec
, unsigned long nsec
)
167 struct timespec tspec
;
169 tspec
.tv_sec
= time(0L)+sec
;
170 tspec
.tv_nsec
= nsec
;
171 return (pthread_cond_timedwait(&(p_internal
->p_condition
), &(mutex
.p_internal
->p_mutex
), &tspec
) != ETIMEDOUT
);
174 void wxCondition::Signal()
176 pthread_cond_signal( &(p_internal
->p_condition
) );
179 void wxCondition::Broadcast()
181 pthread_cond_broadcast( &(p_internal
->p_condition
) );
184 //--------------------------------------------------------------------
185 // wxThread (Posix implementation)
186 //--------------------------------------------------------------------
188 class wxThreadInternal
191 wxThreadInternal() { m_state
= STATE_NEW
; }
192 ~wxThreadInternal() {}
194 // thread entry function
195 static void *PthreadStart(void *ptr
);
202 int GetPriority() const { return m_prio
; }
203 void SetPriority(int prio
) { m_prio
= prio
; }
205 thread_state
GetState() const { return m_state
; }
206 void SetState(thread_state state
) { m_state
= state
; }
208 pthread_t
GetId() const { return thread_id
; }
211 bool WasCancelled() const { return m_cancelled
; }
213 //private: -- should be!
217 thread_state m_state
; // see thread_state enum
218 int m_prio
; // in wxWindows units: from 0 to 100
220 // set when the thread should terminate
223 // we start running when this condition becomes true
225 wxCondition m_condRun
;
227 // this condition becomes true when we get back to PthreadStart() function
229 wxCondition m_condStop
;
232 void *wxThreadInternal::PthreadStart(void *ptr
)
234 wxThread
*thread
= (wxThread
*)ptr
;
235 wxThreadInternal
*pthread
= thread
->p_internal
;
237 if ( pthread_setspecific(gs_keySelf
, thread
) != 0 )
239 wxLogError(_("Can not start thread: error writing TLS."));
244 // wait for the condition to be signaled from Run()
245 pthread
->m_mutexRun
.Lock();
246 pthread
->m_condRun
.Wait(pthread
->m_mutexRun
);
248 // call the main entry
249 void* status
= thread
->Entry();
251 pthread
->m_mutexRun
.Unlock();
253 // wake up the pthread(s) waiting for our termination
254 pthread
->m_condStop
.Broadcast();
256 // terminate the thread
257 thread
->Exit(status
);
259 wxFAIL_MSG("wxThread::Exit() can't return.");
264 wxThreadError
wxThreadInternal::Run()
266 wxCHECK_MSG( GetState() == STATE_NEW
, wxTHREAD_RUNNING
,
267 "thread may only be started once after successful Create()" );
269 wxMutexLocker
lock(&m_mutexRun
);
272 return wxTHREAD_NO_ERROR
;
275 void wxThreadInternal::Cancel()
277 wxMutexLocker
lock(&m_mutexStop
);
279 m_condStop
.Wait(m_mutexStop
);
282 // -----------------------------------------------------------------------------
284 // -----------------------------------------------------------------------------
286 wxThread
*wxThread::This()
288 return (wxThread
*)pthread_getspecific(gs_keySelf
);
291 bool wxThread::IsMain()
293 return (bool)pthread_equal(pthread_self(), gs_pidMain
);
296 void wxThread::Yield()
301 void wxThread::Sleep(unsigned long milliseconds
)
303 // FIXME how to test for nanosleep() availability?
305 usleep(milliseconds
* 1000); // usleep(3) wants microseconds
308 // -----------------------------------------------------------------------------
310 // -----------------------------------------------------------------------------
314 p_internal
= new wxThreadInternal();
317 wxThreadError
wxThread::Create()
319 if (p_internal
->GetState() != STATE_NEW
)
320 return wxTHREAD_RUNNING
;
322 // set up the thread attribute: right now, we only set thread priority
324 pthread_attr_init(&attr
);
327 if ( pthread_attr_getschedpolicy(&attr
, &prio
) != 0 )
329 wxLogError(_("Can not retrieve thread scheduling policy."));
332 int min_prio
= sched_get_priority_min(prio
),
333 max_prio
= sched_get_priority_max(prio
);
335 if ( min_prio
== -1 || max_prio
== -1 )
337 wxLogError(_("Can not get priority range for scheduling policy %d."),
342 struct sched_param sp
;
343 pthread_attr_getschedparam(&attr
, &sp
);
344 sp
.sched_priority
= min_prio
+
345 (p_internal
->GetPriority()*(max_prio
-min_prio
))/100;
346 pthread_attr_setschedparam(&attr
, &sp
);
349 // this is the point of no return
350 int rc
= pthread_create(&p_internal
->thread_id
, &attr
,
351 wxThreadInternal::PthreadStart
, (void *)this);
352 pthread_attr_destroy(&attr
);
356 p_internal
->SetState(STATE_EXITED
);
357 return wxTHREAD_NO_RESOURCE
;
360 return wxTHREAD_NO_ERROR
;
363 wxThreadError
wxThread::Run()
365 return p_internal
->Run();
368 // -----------------------------------------------------------------------------
370 // -----------------------------------------------------------------------------
372 void wxThread::SetPriority(unsigned int prio
)
374 wxCHECK_RET( (WXTHREAD_MIN_PRIORITY
<= prio
) &&
375 (prio
<= WXTHREAD_MAX_PRIORITY
), "invalid thread priority" );
377 wxCriticalSectionLocker
lock(m_critsect
);
379 switch ( p_internal
->GetState() )
382 // thread not yet started, priority will be set when it is
383 p_internal
->SetPriority(prio
);
389 struct sched_param sparam
;
390 sparam
.sched_priority
= prio
;
392 if ( pthread_setschedparam(p_internal
->GetId(),
393 SCHED_OTHER
, &sparam
) != 0 )
395 wxLogError(_("Failed to set thread priority %d."), prio
);
402 wxFAIL_MSG("impossible to set thread priority in this state");
406 unsigned int wxThread::GetPriority() const
408 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
410 return p_internal
->GetPriority();
413 unsigned long wxThread::GetID() const
415 return (unsigned long)p_internal
->thread_id
;
418 // -----------------------------------------------------------------------------
420 // -----------------------------------------------------------------------------
422 wxThreadError
wxThread::Pause()
424 wxCriticalSectionLocker
lock(m_critsect
);
426 if ( p_internal
->GetState() != STATE_RUNNING
)
428 wxLogDebug("Can't pause thread which is not running.");
430 return wxTHREAD_NOT_RUNNING
;
433 p_internal
->SetState(STATE_PAUSED
);
435 return wxTHREAD_NO_ERROR
;
438 wxThreadError
wxThread::Resume()
440 wxCriticalSectionLocker
lock(m_critsect
);
442 if ( p_internal
->GetState() == STATE_PAUSED
)
444 p_internal
->SetState(STATE_RUNNING
);
446 return wxTHREAD_NO_ERROR
;
450 wxLogDebug("Attempt to resume a thread which is not paused.");
452 return wxTHREAD_MISC_ERROR
;
456 // -----------------------------------------------------------------------------
458 // -----------------------------------------------------------------------------
460 wxThread::ExitCode
wxThread::Delete()
463 thread_state state
= p_internal
->GetState();
474 // resume the thread first
480 // set the flag telling to the thread to stop and wait
481 p_internal
->Cancel();
487 wxThreadError
wxThread::Kill()
489 switch ( p_internal
->GetState() )
493 return wxTHREAD_NOT_RUNNING
;
496 if ( pthread_cancel(p_internal
->GetId()) != 0 )
498 wxLogError(_("Failed to terminate a thread."));
500 return wxTHREAD_MISC_ERROR
;
503 return wxTHREAD_NO_ERROR
;
507 void wxThread::Exit(void *status
)
509 wxThread
*ptr
= this;
510 THREAD_SEND_EXIT_MSG(ptr
);
514 p_internal
->SetState(STATE_EXITED
);
518 pthread_exit(status
);
521 bool wxThread::TestDestroy() const
523 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
525 return p_internal
->WasCancelled();
528 wxThread::~wxThread()
532 // -----------------------------------------------------------------------------
534 // -----------------------------------------------------------------------------
536 bool wxThread::IsRunning() const
538 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
540 return p_internal
->GetState() == STATE_RUNNING
;
543 bool wxThread::IsAlive() const
545 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
547 switch ( p_internal
->GetState() )
558 //--------------------------------------------------------------------
560 //--------------------------------------------------------------------
562 class wxThreadModule
: public wxModule
565 virtual bool OnInit();
566 virtual void OnExit();
569 DECLARE_DYNAMIC_CLASS(wxThreadModule
)
572 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule
, wxModule
)
574 bool wxThreadModule::OnInit()
576 if ( pthread_key_create(&gs_keySelf
, NULL
/* dtor function */) != 0 )
578 wxLogError(_("Thread module initialization failed: "
579 "failed to create pthread key."));
584 gs_mutexGui
= new wxMutex();
586 gs_pidMain
= (int)getpid();
592 void wxThreadModule::OnExit()
594 gs_mutexGui
->Unlock();
598 (void)pthread_key_delete(gs_keySelf
);