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 // Delete the current thread from the list
186 p_list_mutex
.Unlock();
188 thread
->Exit(status
);
193 wxThreadError
wxThread::Create()
196 int min_prio
, max_prio
, p
;
197 struct sched_param sp
;
199 if (p_internal
->state
!= STATE_IDLE
)
200 return THREAD_RUNNING
;
202 // Change thread priority
203 pthread_attr_init(&a
);
204 pthread_attr_getschedpolicy(&a
, &p
);
206 min_prio
= sched_get_priority_min(p
);
207 max_prio
= sched_get_priority_max(p
);
209 pthread_attr_getschedparam(&a
, &sp
);
210 sp
.sched_priority
= min_prio
+
211 (p_internal
->prio
*(max_prio
-min_prio
))/100;
212 pthread_attr_setschedparam(&a
, &sp
);
214 // this is the point of no return
215 p_internal
->state
= STATE_RUNNING
;
216 if (pthread_create(&p_internal
->thread_id
, &a
,
217 wxThreadInternal::PthreadStart
, (void *)this) != 0) {
218 p_internal
->state
= STATE_IDLE
;
219 pthread_attr_destroy(&a
);
220 return THREAD_NO_RESOURCE
;
222 pthread_attr_destroy(&a
);
224 return THREAD_NO_ERROR
;
227 void wxThread::SetPriority(int prio
)
229 if (p_internal
->state
== STATE_RUNNING
)
236 p_internal
->prio
= prio
;
239 int wxThread::GetPriority() const
241 return p_internal
->prio
;
244 void wxThread::DeferDestroy(bool on
)
247 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED
, NULL
);
249 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS
, NULL
);
252 wxThreadError
wxThread::Destroy()
256 if (p_internal
->state
== STATE_RUNNING
) {
257 res
= pthread_cancel(p_internal
->thread_id
);
259 p_internal
->state
= STATE_CANCELED
;
262 return THREAD_NO_ERROR
;
265 wxThreadError
wxThread::Pause()
267 if (p_internal
->state
!= STATE_RUNNING
)
268 return THREAD_NOT_RUNNING
;
270 if (!p_internal
->defer_destroy
)
271 return THREAD_MISC_ERROR
;
273 p_internal
->state
= STATE_PAUSING
;
274 return THREAD_NO_ERROR
;
277 wxThreadError
wxThread::Resume()
279 if (p_internal
->state
== STATE_PAUSING
|| p_internal
->state
== STATE_PAUSED
)
280 p_internal
->state
= STATE_RUNNING
;
282 return THREAD_NO_ERROR
;
285 void *wxThread::Join()
289 if (p_internal
->state
!= STATE_IDLE
) {
290 bool do_unlock
= wxThread::IsMain();
292 while (p_internal
->state
== STATE_RUNNING
)
296 wxMainMutex
.Unlock();
297 pthread_join(p_internal
->thread_id
, &status
);
302 delete p_threads_list
.Nth(p_internal
->id
);
303 p_list_mutex
.Unlock();
305 p_internal
->state
= STATE_IDLE
;
310 unsigned long wxThread::GetID() const
312 return p_internal
->id
;
315 wxThread
*wxThread::GetThreadFromID(unsigned long id
)
317 wxNode
*node
= p_threads_list
.Nth(id
);
321 return (wxThread
*)node
->Data();
324 void wxThread::Exit(void *status
)
326 wxThread
* ptr
= this;
328 THREAD_SEND_EXIT_MSG(ptr
);
329 p_internal
->state
= STATE_EXITED
;
330 pthread_exit(status
);
333 void wxThread::TestDestroy()
335 if (p_internal
->state
== STATE_PAUSING
) {
336 p_internal
->state
= STATE_PAUSED
;
337 while (p_internal
->state
== STATE_PAUSED
) {
338 pthread_testcancel();
342 pthread_testcancel();
345 bool wxThread::IsMain()
347 return (bool)pthread_equal(pthread_self(), p_mainid
);
350 bool wxThread::IsRunning() const
352 return (p_internal
->state
== STATE_RUNNING
);
355 bool wxThread::IsAlive() const
357 return (p_internal
->state
== STATE_RUNNING
) ||
358 (p_internal
->state
== STATE_PAUSING
) ||
359 (p_internal
->state
== STATE_PAUSED
);
364 p_internal
= new wxThreadInternal();
367 wxThread::~wxThread()
374 // The default callback just joins the thread and throws away the result.
375 void wxThread::OnExit()
380 // Automatic initialization
381 class wxThreadModule
: public wxModule
{
382 DECLARE_DYNAMIC_CLASS(wxThreadModule
)
384 virtual bool OnInit() {
386 p_mainid
= pthread_self();
387 p_threads_list
= wxList(wxKEY_INTEGER
);
393 virtual void OnExit() {
394 wxMainMutex
.Unlock();
399 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule
, wxModule
)