1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxThread (Posix) Implementation
4 // Author: Original from Wolfram Gloger/Guilhem Lavaux
8 // Copyright: (c) Wolfram Gloger (1996, 1997); Guilhem Lavaux (1998)
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 #pragma implementation "thread.h"
19 #include "wx/thread.h"
20 #include "wx/module.h"
32 /////////////////////////////////////////////////////////////////////////////
34 /////////////////////////////////////////////////////////////////////////////
36 static pthread_t p_mainid
;
37 static wxMutex p_list_mutex
;
38 static wxList p_threads_list
;
40 wxMutex
*wxMainMutex
; // controls access to all GUI functions
42 /////////////////////////////////////////////////////////////////////////////
44 /////////////////////////////////////////////////////////////////////////////
45 #include "threadgui.inc"
47 /////////////////////////////////////////////////////////////////////////////
48 // wxThread: Posix Thread implementation (Mutex)
49 /////////////////////////////////////////////////////////////////////////////
51 class wxMutexInternal
{
53 pthread_mutex_t p_mutex
;
58 p_internal
= new wxMutexInternal
;
59 pthread_mutex_init(&(p_internal
->p_mutex
), NULL
);
66 wxDebugMsg("wxMutex warning: freeing a locked mutex (%d locks)\n",
69 pthread_mutex_destroy(&(p_internal
->p_mutex
));
73 wxMutexError
wxMutex::Lock()
77 err
= pthread_mutex_lock(&(p_internal
->p_mutex
));
79 return MUTEX_DEAD_LOCK
;
81 return MUTEX_NO_ERROR
;
84 wxMutexError
wxMutex::TryLock()
90 err
= pthread_mutex_trylock(&(p_internal
->p_mutex
));
92 case EBUSY
: return MUTEX_BUSY
;
95 return MUTEX_NO_ERROR
;
98 wxMutexError
wxMutex::Unlock()
103 return MUTEX_UNLOCKED
;
104 pthread_mutex_unlock(&(p_internal
->p_mutex
));
105 return MUTEX_NO_ERROR
;
108 /////////////////////////////////////////////////////////////////////////////
109 // wxThread: Posix Thread implementation (Condition)
110 /////////////////////////////////////////////////////////////////////////////
112 class wxConditionInternal
{
114 pthread_cond_t p_condition
;
117 wxCondition::wxCondition()
119 p_internal
= new wxConditionInternal
;
120 pthread_cond_init(&(p_internal
->p_condition
), NULL
);
123 wxCondition::~wxCondition()
125 pthread_cond_destroy(&(p_internal
->p_condition
));
129 void wxCondition::Wait(wxMutex
& mutex
)
131 pthread_cond_wait(&(p_internal
->p_condition
), &(mutex
.p_internal
->p_mutex
));
134 bool wxCondition::Wait(wxMutex
& mutex
, unsigned long sec
, unsigned long nsec
)
136 struct timespec tspec
;
138 tspec
.tv_sec
= time(NULL
)+sec
;
139 tspec
.tv_nsec
= nsec
;
140 return (pthread_cond_timedwait(&(p_internal
->p_condition
), &(mutex
.p_internal
->p_mutex
), &tspec
) != ETIMEDOUT
);
143 void wxCondition::Signal()
145 pthread_cond_signal(&(p_internal
->p_condition
));
148 void wxCondition::Broadcast()
150 pthread_cond_broadcast(&(p_internal
->p_condition
));
153 /////////////////////////////////////////////////////////////////////////////
154 // wxThread: Posix Thread implementation (Thread)
155 /////////////////////////////////////////////////////////////////////////////
157 class wxThreadInternal
{
159 wxThreadInternal() { state
= STATE_IDLE
; }
160 ~wxThreadInternal() {}
161 static void *PthreadStart(void *ptr
);
169 void *wxThreadInternal::PthreadStart(void *ptr
)
171 wxThread
*thread
= (wxThread
*)ptr
;
173 // Add the current thread to the list
175 thread
->p_internal
->id
= p_threads_list
.Number();
176 p_threads_list
.Append((wxObject
*)thread
);
177 p_list_mutex
.Unlock();
179 // Call the main entry
180 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS
, NULL
);
181 void* status
= thread
->Entry();
183 thread
->Exit(status
);
188 wxThreadError
wxThread::Create()
191 int min_prio
, max_prio
, p
;
192 struct sched_param sp
;
194 if (p_internal
->state
!= STATE_IDLE
)
195 return THREAD_RUNNING
;
197 // Change thread priority
198 pthread_attr_init(&a
);
199 pthread_attr_getschedpolicy(&a
, &p
);
201 min_prio
= sched_get_priority_min(p
);
202 max_prio
= sched_get_priority_max(p
);
204 pthread_attr_getschedparam(&a
, &sp
);
205 sp
.sched_priority
= min_prio
+
206 (p_internal
->prio
*(max_prio
-min_prio
))/100;
207 pthread_attr_setschedparam(&a
, &sp
);
209 // this is the point of no return
210 p_internal
->state
= STATE_RUNNING
;
211 if (pthread_create(&p_internal
->thread_id
, &a
,
212 wxThreadInternal::PthreadStart
, (void *)this) != 0) {
213 p_internal
->state
= STATE_IDLE
;
214 pthread_attr_destroy(&a
);
215 return THREAD_NO_RESOURCE
;
217 pthread_attr_destroy(&a
);
219 return THREAD_NO_ERROR
;
222 void wxThread::SetPriority(int prio
)
224 if (p_internal
->state
== STATE_RUNNING
)
231 p_internal
->prio
= prio
;
234 int wxThread::GetPriority() const
236 return p_internal
->prio
;
239 void wxThread::DeferDestroy(bool on
)
242 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED
, NULL
);
244 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS
, NULL
);
247 wxThreadError
wxThread::Destroy()
251 if (p_internal
->state
== STATE_RUNNING
) {
252 res
= pthread_cancel(p_internal
->thread_id
);
254 p_internal
->state
= STATE_CANCELED
;
257 return THREAD_NO_ERROR
;
260 wxThreadError
wxThread::Pause()
262 if (p_internal
->state
!= STATE_RUNNING
)
263 return THREAD_NOT_RUNNING
;
265 if (!p_internal
->defer_destroy
)
266 return THREAD_MISC_ERROR
;
268 p_internal
->state
= STATE_PAUSING
;
269 return THREAD_NO_ERROR
;
272 wxThreadError
wxThread::Resume()
274 if (p_internal
->state
== STATE_PAUSING
|| p_internal
->state
== STATE_PAUSED
)
275 p_internal
->state
= STATE_RUNNING
;
277 return THREAD_NO_ERROR
;
280 void *wxThread::Join()
284 if (p_internal
->state
!= STATE_IDLE
) {
285 bool do_unlock
= wxThread::IsMain();
287 while (p_internal
->state
== STATE_RUNNING
)
291 wxMainMutex
->Unlock();
292 pthread_join(p_internal
->thread_id
, &status
);
297 delete p_threads_list
.Nth(p_internal
->id
);
298 p_list_mutex
.Unlock();
300 p_internal
->state
= STATE_IDLE
;
305 unsigned long wxThread::GetID() const
307 return p_internal
->id
;
310 wxThread
*wxThread::GetThreadFromID(unsigned long id
)
312 wxNode
*node
= p_threads_list
.Nth(id
);
316 return (wxThread
*)node
->Data();
319 void wxThread::Exit(void *status
)
321 wxThread
* ptr
= this;
323 THREAD_SEND_EXIT_MSG(ptr
);
324 p_internal
->state
= STATE_EXITED
;
325 pthread_exit(status
);
328 void wxThread::TestDestroy()
330 if (p_internal
->state
== STATE_PAUSING
) {
331 p_internal
->state
= STATE_PAUSED
;
332 while (p_internal
->state
== STATE_PAUSED
) {
333 pthread_testcancel();
337 pthread_testcancel();
340 bool wxThread::IsMain()
342 return (bool)pthread_equal(pthread_self(), p_mainid
);
345 bool wxThread::IsRunning() const
347 return (p_internal
->state
== STATE_RUNNING
);
350 bool wxThread::IsAlive() const
352 return (p_internal
->state
== STATE_RUNNING
) ||
353 (p_internal
->state
== STATE_PAUSING
) ||
354 (p_internal
->state
== STATE_PAUSED
);
359 p_internal
= new wxThreadInternal();
362 wxThread::~wxThread()
369 // The default callback just joins the thread and throws away the result.
370 void wxThread::OnExit()
375 // Automatic initialization
376 class wxThreadModule
: public wxModule
{
377 DECLARE_DYNAMIC_CLASS(wxThreadModule
)
379 virtual bool OnInit() {
380 wxMainMutex
= new wxMutex();
382 p_mainid
= pthread_self();
383 p_threads_list
= wxList(wxKEY_INTEGER
);
389 virtual void OnExit() {
390 wxMainMutex
->Unlock();
396 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule
, wxModule
)