]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/threadpsx.cpp
Now uses dcps.h
[wxWidgets.git] / src / gtk / threadpsx.cpp
CommitLineData
7c351dad
GL
1/////////////////////////////////////////////////////////////////////////////
2// Name: threadpsx.cpp
3// Purpose: wxThread (Posix) Implementation
4// Author: Original from Wolfram Gloger/Guilhem Lavaux
5// Modified by:
6// Created: 04/22/98
7// RCS-ID: $Id$
f3855ef0
RR
8// Copyright: (c) Wolfram Gloger (1996, 1997)
9// Guilhem Lavaux (1998)
10// Robert Roebling (1999)
7c351dad
GL
11// Licence: wxWindows licence
12/////////////////////////////////////////////////////////////////////////////
f3855ef0 13
7c351dad 14#ifdef __GNUG__
015ee844 15 #pragma implementation "thread.h"
7c351dad
GL
16#endif
17
18#include <stdio.h>
19#include <unistd.h>
7c351dad 20#include <pthread.h>
6163f5d8 21#include <errno.h>
015ee844
VZ
22
23#ifdef __linux__
24 #include <sched.h>
25#endif
26
82052aff
GL
27#include "wx/thread.h"
28#include "wx/module.h"
29#include "wx/utils.h"
3069ac4e 30#include "wx/log.h"
015ee844 31#include "wx/intl.h"
7c351dad 32
83624f79
RR
33#include "gdk/gdk.h"
34#include "gtk/gtk.h"
35
015ee844 36enum thread_state
f3855ef0 37{
015ee844
VZ
38 STATE_NEW, // didn't start execution yet (=> RUNNING)
39 STATE_RUNNING,
40 STATE_PAUSED,
41 STATE_CANCELED,
42 STATE_EXITED
7c351dad
GL
43};
44
f3855ef0
RR
45//--------------------------------------------------------------------
46// global data
47//--------------------------------------------------------------------
7c351dad 48
015ee844
VZ
49// the id of the main thread
50static pthread_t gs_pidMain;
c2dd8380 51
015ee844
VZ
52// the key for the pointer to the associated wxThread object
53static pthread_key_t gs_keySelf;
54
55// this mutex must be acquired before any call to a GUI function
56static wxMutex *gs_mutexGui;
7c351dad 57
f3855ef0
RR
58//--------------------------------------------------------------------
59// common GUI thread code
60//--------------------------------------------------------------------
61
7c351dad
GL
62#include "threadgui.inc"
63
f3855ef0
RR
64//--------------------------------------------------------------------
65// wxMutex (Posix implementation)
66//--------------------------------------------------------------------
7c351dad 67
015ee844 68class wxMutexInternal
f3855ef0 69{
7c351dad
GL
70public:
71 pthread_mutex_t p_mutex;
72};
73
ee4f8c2a 74wxMutex::wxMutex()
7c351dad 75{
f3855ef0 76 p_internal = new wxMutexInternal;
bbe0af5b 77 pthread_mutex_init( &(p_internal->p_mutex), (const pthread_mutexattr_t*) NULL );
f3855ef0 78 m_locked = 0;
7c351dad
GL
79}
80
ee4f8c2a 81wxMutex::~wxMutex()
7c351dad 82{
f3855ef0 83 if (m_locked > 0)
015ee844 84 wxLogDebug( "wxMutex warning: freeing a locked mutex (%d locks)", m_locked );
b89156b5 85
bbe0af5b 86 pthread_mutex_destroy( &(p_internal->p_mutex) );
f3855ef0 87 delete p_internal;
7c351dad
GL
88}
89
ee4f8c2a 90wxMutexError wxMutex::Lock()
7c351dad 91{
bbe0af5b 92 int err = pthread_mutex_lock( &(p_internal->p_mutex) );
f3855ef0 93 if (err == EDEADLK)
bbe0af5b 94 {
b332090a 95 return wxMUTEX_DEAD_LOCK;
bbe0af5b 96 }
015ee844 97
f3855ef0 98 m_locked++;
015ee844 99
b332090a 100 return wxMUTEX_NO_ERROR;
7c351dad
GL
101}
102
ee4f8c2a 103wxMutexError wxMutex::TryLock()
7c351dad 104{
f3855ef0 105 if (m_locked)
bbe0af5b 106 {
b332090a 107 return wxMUTEX_BUSY;
bbe0af5b 108 }
015ee844 109
bbe0af5b 110 int err = pthread_mutex_trylock( &(p_internal->p_mutex) );
015ee844 111 switch (err)
f3855ef0 112 {
b332090a 113 case EBUSY: return wxMUTEX_BUSY;
f3855ef0 114 }
015ee844 115
f3855ef0 116 m_locked++;
015ee844 117
b332090a 118 return wxMUTEX_NO_ERROR;
7c351dad
GL
119}
120
ee4f8c2a 121wxMutexError wxMutex::Unlock()
7c351dad 122{
f3855ef0 123 if (m_locked > 0)
bbe0af5b 124 {
f3855ef0 125 m_locked--;
bbe0af5b 126 }
f3855ef0 127 else
bbe0af5b 128 {
b332090a 129 return wxMUTEX_UNLOCKED;
bbe0af5b 130 }
015ee844 131
bbe0af5b 132 pthread_mutex_unlock( &(p_internal->p_mutex) );
015ee844 133
b332090a 134 return wxMUTEX_NO_ERROR;
7c351dad
GL
135}
136
f3855ef0
RR
137//--------------------------------------------------------------------
138// wxCondition (Posix implementation)
139//--------------------------------------------------------------------
7c351dad 140
015ee844 141class wxConditionInternal
f3855ef0 142{
7c351dad
GL
143public:
144 pthread_cond_t p_condition;
145};
146
ee4f8c2a 147wxCondition::wxCondition()
7c351dad 148{
f3855ef0 149 p_internal = new wxConditionInternal;
bbe0af5b 150 pthread_cond_init( &(p_internal->p_condition), (const pthread_condattr_t *) NULL );
7c351dad
GL
151}
152
ee4f8c2a 153wxCondition::~wxCondition()
7c351dad 154{
bbe0af5b 155 pthread_cond_destroy( &(p_internal->p_condition) );
015ee844 156
f3855ef0 157 delete p_internal;
7c351dad
GL
158}
159
160void wxCondition::Wait(wxMutex& mutex)
161{
bbe0af5b 162 pthread_cond_wait( &(p_internal->p_condition), &(mutex.p_internal->p_mutex) );
7c351dad
GL
163}
164
165bool wxCondition::Wait(wxMutex& mutex, unsigned long sec, unsigned long nsec)
166{
f3855ef0 167 struct timespec tspec;
7c351dad 168
bbe0af5b 169 tspec.tv_sec = time(0L)+sec;
f3855ef0
RR
170 tspec.tv_nsec = nsec;
171 return (pthread_cond_timedwait(&(p_internal->p_condition), &(mutex.p_internal->p_mutex), &tspec) != ETIMEDOUT);
7c351dad
GL
172}
173
ee4f8c2a 174void wxCondition::Signal()
7c351dad 175{
bbe0af5b 176 pthread_cond_signal( &(p_internal->p_condition) );
7c351dad
GL
177}
178
ee4f8c2a 179void wxCondition::Broadcast()
7c351dad 180{
bbe0af5b 181 pthread_cond_broadcast( &(p_internal->p_condition) );
7c351dad
GL
182}
183
f3855ef0
RR
184//--------------------------------------------------------------------
185// wxThread (Posix implementation)
186//--------------------------------------------------------------------
7c351dad 187
015ee844 188class wxThreadInternal
f3855ef0 189{
7c351dad 190public:
015ee844
VZ
191 wxThreadInternal() { m_state = STATE_NEW; }
192 ~wxThreadInternal() {}
193
194 // thread entry function
195 static void *PthreadStart(void *ptr);
196
197 // start the thread
198 wxThreadError Run();
199
200 // accessors
201 // priority
202 int GetPriority() const { return m_prio; }
203 void SetPriority(int prio) { m_prio = prio; }
204 // state
205 thread_state GetState() const { return m_state; }
206 void SetState(thread_state state) { m_state = state; }
207 // id
208 pthread_t GetId() const { return thread_id; }
209 // "cancelled" flag
210 void Cancel();
211 bool WasCancelled() const { return m_cancelled; }
212
213//private: -- should be!
214 pthread_t thread_id;
215
216private:
217 thread_state m_state; // see thread_state enum
218 int m_prio; // in wxWindows units: from 0 to 100
219
220 // set when the thread should terminate
221 bool m_cancelled;
222
223 // we start running when this condition becomes true
224 wxMutex m_mutexRun;
225 wxCondition m_condRun;
226
227 // this condition becomes true when we get back to PthreadStart() function
228 wxMutex m_mutexStop;
229 wxCondition m_condStop;
7c351dad
GL
230};
231
232void *wxThreadInternal::PthreadStart(void *ptr)
233{
f3855ef0 234 wxThread *thread = (wxThread *)ptr;
015ee844 235 wxThreadInternal *pthread = thread->p_internal;
c2dd8380 236
015ee844
VZ
237 if ( pthread_setspecific(gs_keySelf, thread) != 0 )
238 {
239 wxLogError(_("Can not start thread: error writing TLS."));
240
241 return (void *)-1;
242 }
243
244 // wait for the condition to be signaled from Run()
245 pthread->m_mutexRun.Lock();
246 pthread->m_condRun.Wait(pthread->m_mutexRun);
247
248 // call the main entry
f3855ef0 249 void* status = thread->Entry();
c2dd8380 250
015ee844
VZ
251 pthread->m_mutexRun.Unlock();
252
253 // wake up the pthread(s) waiting for our termination
254 pthread->m_condStop.Broadcast();
255
256 // terminate the thread
f3855ef0 257 thread->Exit(status);
7c351dad 258
015ee844
VZ
259 wxFAIL_MSG("wxThread::Exit() can't return.");
260
f3855ef0 261 return NULL;
7c351dad
GL
262}
263
015ee844 264wxThreadError wxThreadInternal::Run()
7c351dad 265{
015ee844
VZ
266 wxCHECK_MSG( GetState() == STATE_NEW, wxTHREAD_RUNNING,
267 "thread may only be started once after successful Create()" );
7c351dad 268
015ee844
VZ
269 wxMutexLocker lock(&m_mutexRun);
270 m_condRun.Signal();
7c351dad 271
015ee844
VZ
272 return wxTHREAD_NO_ERROR;
273}
7c351dad 274
015ee844
VZ
275void wxThreadInternal::Cancel()
276{
277 wxMutexLocker lock(&m_mutexStop);
278 m_cancelled = TRUE;
279 m_condStop.Wait(m_mutexStop);
280}
7c351dad 281
015ee844
VZ
282// -----------------------------------------------------------------------------
283// static functions
284// -----------------------------------------------------------------------------
7c351dad 285
015ee844
VZ
286wxThread *wxThread::This()
287{
288 return (wxThread *)pthread_getspecific(gs_keySelf);
289}
c2dd8380 290
015ee844
VZ
291bool wxThread::IsMain()
292{
293 return (bool)pthread_equal(pthread_self(), gs_pidMain);
294}
295
296void wxThread::Yield()
297{
298 sched_yield();
7c351dad
GL
299}
300
015ee844 301void wxThread::Sleep(unsigned long milliseconds)
7c351dad 302{
015ee844 303 // FIXME how to test for nanosleep() availability?
f3855ef0 304
015ee844 305 usleep(milliseconds * 1000); // usleep(3) wants microseconds
7c351dad
GL
306}
307
015ee844
VZ
308// -----------------------------------------------------------------------------
309// creating thread
310// -----------------------------------------------------------------------------
311
312wxThread::wxThread()
7c351dad 313{
015ee844 314 p_internal = new wxThreadInternal();
7c351dad
GL
315}
316
015ee844 317wxThreadError wxThread::Create()
7c351dad 318{
015ee844
VZ
319 if (p_internal->GetState() != STATE_NEW)
320 return wxTHREAD_RUNNING;
321
322 // set up the thread attribute: right now, we only set thread priority
323 pthread_attr_t attr;
324 pthread_attr_init(&attr);
325
326 int prio;
327 if ( pthread_attr_getschedpolicy(&attr, &prio) != 0 )
328 {
329 wxLogError(_("Can not retrieve thread scheduling policy."));
330 }
331
332 int min_prio = sched_get_priority_min(prio),
333 max_prio = sched_get_priority_max(prio);
334
335 if ( min_prio == -1 || max_prio == -1 )
336 {
337 wxLogError(_("Can not get priority range for scheduling policy %d."),
338 prio);
339 }
f3855ef0 340 else
015ee844
VZ
341 {
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);
347 }
348
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);
353
354 if ( rc != 0 )
355 {
356 p_internal->SetState(STATE_EXITED);
357 return wxTHREAD_NO_RESOURCE;
358 }
359
360 return wxTHREAD_NO_ERROR;
7c351dad
GL
361}
362
015ee844 363wxThreadError wxThread::Run()
7c351dad 364{
015ee844
VZ
365 return p_internal->Run();
366}
367
368// -----------------------------------------------------------------------------
369// misc accessors
370// -----------------------------------------------------------------------------
7c351dad 371
015ee844
VZ
372void wxThread::SetPriority(unsigned int prio)
373{
374 wxCHECK_RET( (WXTHREAD_MIN_PRIORITY <= prio) &&
375 (prio <= WXTHREAD_MAX_PRIORITY), "invalid thread priority" );
376
377 wxCriticalSectionLocker lock(m_critsect);
378
379 switch ( p_internal->GetState() )
f3855ef0 380 {
015ee844
VZ
381 case STATE_NEW:
382 // thread not yet started, priority will be set when it is
383 p_internal->SetPriority(prio);
384 break;
385
386 case STATE_RUNNING:
387 case STATE_PAUSED:
388 {
389 struct sched_param sparam;
390 sparam.sched_priority = prio;
391
392 if ( pthread_setschedparam(p_internal->GetId(),
393 SCHED_OTHER, &sparam) != 0 )
394 {
395 wxLogError(_("Failed to set thread priority %d."), prio);
396 }
397 }
398 break;
399
400 case STATE_EXITED:
401 default:
402 wxFAIL_MSG("impossible to set thread priority in this state");
f3855ef0 403 }
015ee844 404}
c2dd8380 405
015ee844
VZ
406unsigned int wxThread::GetPriority() const
407{
408 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
409
410 return p_internal->GetPriority();
c2dd8380
GL
411}
412
015ee844
VZ
413unsigned long wxThread::GetID() const
414{
415 return (unsigned long)p_internal->thread_id;
416}
417
418// -----------------------------------------------------------------------------
419// pause/resume
420// -----------------------------------------------------------------------------
421
c2dd8380
GL
422wxThreadError wxThread::Pause()
423{
015ee844
VZ
424 wxCriticalSectionLocker lock(m_critsect);
425
426 if ( p_internal->GetState() != STATE_RUNNING )
427 {
428 wxLogDebug("Can't pause thread which is not running.");
429
b332090a 430 return wxTHREAD_NOT_RUNNING;
015ee844 431 }
c2dd8380 432
015ee844 433 p_internal->SetState(STATE_PAUSED);
c2dd8380 434
b332090a 435 return wxTHREAD_NO_ERROR;
c2dd8380
GL
436}
437
438wxThreadError wxThread::Resume()
439{
015ee844 440 wxCriticalSectionLocker lock(m_critsect);
c2dd8380 441
015ee844
VZ
442 if ( p_internal->GetState() == STATE_PAUSED )
443 {
444 p_internal->SetState(STATE_RUNNING);
445
446 return wxTHREAD_NO_ERROR;
447 }
448 else
449 {
450 wxLogDebug("Attempt to resume a thread which is not paused.");
451
452 return wxTHREAD_MISC_ERROR;
453 }
7c351dad
GL
454}
455
015ee844
VZ
456// -----------------------------------------------------------------------------
457// exiting thread
458// -----------------------------------------------------------------------------
459
460wxThread::ExitCode wxThread::Delete()
7c351dad 461{
015ee844
VZ
462 m_critsect.Enter();
463 thread_state state = p_internal->GetState();
464 m_critsect.Leave();
7c351dad 465
015ee844 466 switch ( state )
f3855ef0 467 {
015ee844
VZ
468 case STATE_NEW:
469 case STATE_EXITED:
470 // nothing to do
471 break;
7c351dad 472
015ee844
VZ
473 case STATE_PAUSED:
474 // resume the thread first
475 Resume();
c2dd8380 476
015ee844 477 // fall through
c2dd8380 478
015ee844
VZ
479 default:
480 // set the flag telling to the thread to stop and wait
481 p_internal->Cancel();
f3855ef0 482 }
015ee844
VZ
483
484 return NULL;
7c351dad
GL
485}
486
015ee844 487wxThreadError wxThread::Kill()
7c351dad 488{
015ee844
VZ
489 switch ( p_internal->GetState() )
490 {
491 case STATE_NEW:
492 case STATE_EXITED:
493 return wxTHREAD_NOT_RUNNING;
494
495 default:
496 if ( pthread_cancel(p_internal->GetId()) != 0 )
497 {
498 wxLogError(_("Failed to terminate a thread."));
499
500 return wxTHREAD_MISC_ERROR;
501 }
502
503 return wxTHREAD_NO_ERROR;
504 }
7c351dad
GL
505}
506
507void wxThread::Exit(void *status)
508{
015ee844 509 wxThread *ptr = this;
f3855ef0 510 THREAD_SEND_EXIT_MSG(ptr);
015ee844
VZ
511
512 OnExit();
513
514 p_internal->SetState(STATE_EXITED);
515
516 delete this;
517
f3855ef0 518 pthread_exit(status);
7c351dad
GL
519}
520
015ee844 521bool wxThread::TestDestroy() const
7c351dad 522{
015ee844 523 wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
2501ce51 524
015ee844 525 return p_internal->WasCancelled();
7c351dad
GL
526}
527
015ee844 528wxThread::~wxThread()
7c351dad 529{
7c351dad
GL
530}
531
015ee844
VZ
532// -----------------------------------------------------------------------------
533// state tests
534// -----------------------------------------------------------------------------
535
c2dd8380
GL
536bool wxThread::IsRunning() const
537{
015ee844
VZ
538 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
539
540 return p_internal->GetState() == STATE_RUNNING;
c2dd8380
GL
541}
542
543bool wxThread::IsAlive() const
544{
015ee844 545 wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
c2dd8380 546
015ee844
VZ
547 switch ( p_internal->GetState() )
548 {
549 case STATE_RUNNING:
550 case STATE_PAUSED:
551 return TRUE;
7c351dad 552
015ee844
VZ
553 default:
554 return FALSE;
555 }
7c351dad
GL
556}
557
f3855ef0 558//--------------------------------------------------------------------
015ee844 559// wxThreadModule
f3855ef0
RR
560//--------------------------------------------------------------------
561
06cfab17
RR
562class wxThreadModule : public wxModule
563{
564public:
565 virtual bool OnInit();
566 virtual void OnExit();
567
568private:
569 DECLARE_DYNAMIC_CLASS(wxThreadModule)
570};
571
d524867f 572IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
f3855ef0 573
015ee844 574bool wxThreadModule::OnInit()
d524867f 575{
015ee844
VZ
576 if ( pthread_key_create(&gs_keySelf, NULL /* dtor function */) != 0 )
577 {
578 wxLogError(_("Thread module initialization failed: "
579 "failed to create pthread key."));
580
581 return FALSE;
582 }
583
584 gs_mutexGui = new wxMutex();
d524867f 585 wxThreadGuiInit();
015ee844
VZ
586 gs_pidMain = (int)getpid();
587 gs_mutexGui->Lock();
588
d524867f
RR
589 return TRUE;
590}
7c351dad 591
d524867f
RR
592void wxThreadModule::OnExit()
593{
015ee844 594 gs_mutexGui->Unlock();
d524867f 595 wxThreadGuiExit();
015ee844 596 delete gs_mutexGui;
f3855ef0 597
015ee844
VZ
598 (void)pthread_key_delete(gs_keySelf);
599}