]> git.saurik.com Git - wxWidgets.git/blame - src/unix/threadpsx.cpp
Fixed a bug in threadpsx.cpp (wxBaseArray bug).
[wxWidgets.git] / src / unix / threadpsx.cpp
CommitLineData
518b5d2f
VZ
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$
8// Copyright: (c) Wolfram Gloger (1996, 1997)
9// Guilhem Lavaux (1998)
10// Vadim Zeitlin (1999)
11// Robert Roebling (1999)
12// Licence: wxWindows licence
13/////////////////////////////////////////////////////////////////////////////
14
15// ============================================================================
16// declaration
17// ============================================================================
18
19// ----------------------------------------------------------------------------
20// headers
21// ----------------------------------------------------------------------------
22
23#ifdef __GNUG__
24 #pragma implementation "thread.h"
25#endif
26
7bcb11d3
JS
27// With simple makefiles, we must ignore the file body if not using
28// threads.
29#include "wx/setup.h"
518b5d2f 30
7bcb11d3 31#if wxUSE_THREADS
518b5d2f 32
7bcb11d3 33#include "wx/thread.h"
518b5d2f
VZ
34#include "wx/module.h"
35#include "wx/utils.h"
36#include "wx/log.h"
37#include "wx/intl.h"
38#include "wx/dynarray.h"
39
40#include <stdio.h>
41#include <unistd.h>
42#include <pthread.h>
43#include <errno.h>
44#include <time.h>
45
7bcb11d3 46#if HAVE_SCHED_H
518b5d2f
VZ
47 #include <sched.h>
48#endif
49
50// ----------------------------------------------------------------------------
51// constants
52// ----------------------------------------------------------------------------
53
882eefb1
VZ
54// the possible states of the thread and transitions from them
55enum wxThreadState
518b5d2f
VZ
56{
57 STATE_NEW, // didn't start execution yet (=> RUNNING)
882eefb1
VZ
58 STATE_RUNNING, // running (=> PAUSED or EXITED)
59 STATE_PAUSED, // suspended (=> RUNNING or EXITED)
60 STATE_EXITED // thread doesn't exist any more
518b5d2f
VZ
61};
62
882eefb1
VZ
63// ----------------------------------------------------------------------------
64// types
65// ----------------------------------------------------------------------------
66
518b5d2f
VZ
67WX_DEFINE_ARRAY(wxThread *, wxArrayThread);
68
69// -----------------------------------------------------------------------------
70// global data
71// -----------------------------------------------------------------------------
72
73// we keep the list of all threads created by the application to be able to
74// terminate them on exit if there are some left - otherwise the process would
75// be left in memory
76static wxArrayThread gs_allThreads;
77
78// the id of the main thread
79static pthread_t gs_tidMain;
80
81// the key for the pointer to the associated wxThread object
82static pthread_key_t gs_keySelf;
83
84// this mutex must be acquired before any call to a GUI function
85static wxMutex *gs_mutexGui;
86
87// ============================================================================
88// implementation
89// ============================================================================
90
91//--------------------------------------------------------------------
92// wxMutex (Posix implementation)
93//--------------------------------------------------------------------
94
95class wxMutexInternal
96{
97public:
98 pthread_mutex_t p_mutex;
99};
100
101wxMutex::wxMutex()
102{
e4628635
RR
103 p_internal = new wxMutexInternal;
104
e4628635 105 pthread_mutex_init( &(p_internal->p_mutex), (const pthread_mutexattr_t*) NULL );
518b5d2f
VZ
106 m_locked = 0;
107}
108
109wxMutex::~wxMutex()
110{
111 if (m_locked > 0)
d207efe1 112 wxLogDebug(_T("Freeing a locked mutex (%d locks)"), m_locked);
518b5d2f
VZ
113
114 pthread_mutex_destroy( &(p_internal->p_mutex) );
115 delete p_internal;
116}
117
118wxMutexError wxMutex::Lock()
119{
120 int err = pthread_mutex_lock( &(p_internal->p_mutex) );
121 if (err == EDEADLK)
122 {
d207efe1 123 wxLogDebug(_T("Locking this mutex would lead to deadlock!"));
518b5d2f
VZ
124
125 return wxMUTEX_DEAD_LOCK;
126 }
127
128 m_locked++;
129
130 return wxMUTEX_NO_ERROR;
131}
132
133wxMutexError wxMutex::TryLock()
134{
135 if (m_locked)
136 {
137 return wxMUTEX_BUSY;
138 }
139
140 int err = pthread_mutex_trylock( &(p_internal->p_mutex) );
141 switch (err)
142 {
143 case EBUSY: return wxMUTEX_BUSY;
144 }
145
146 m_locked++;
147
148 return wxMUTEX_NO_ERROR;
149}
150
151wxMutexError wxMutex::Unlock()
152{
153 if (m_locked > 0)
154 {
155 m_locked--;
156 }
157 else
158 {
d207efe1 159 wxLogDebug(_T("Unlocking not locked mutex."));
518b5d2f
VZ
160
161 return wxMUTEX_UNLOCKED;
162 }
163
164 pthread_mutex_unlock( &(p_internal->p_mutex) );
165
166 return wxMUTEX_NO_ERROR;
167}
168
169//--------------------------------------------------------------------
170// wxCondition (Posix implementation)
171//--------------------------------------------------------------------
172
173class wxConditionInternal
174{
175public:
176 pthread_cond_t p_condition;
177};
178
179wxCondition::wxCondition()
180{
181 p_internal = new wxConditionInternal;
182 pthread_cond_init( &(p_internal->p_condition), (const pthread_condattr_t *) NULL );
183}
184
185wxCondition::~wxCondition()
186{
187 pthread_cond_destroy( &(p_internal->p_condition) );
188
189 delete p_internal;
190}
191
192void wxCondition::Wait(wxMutex& mutex)
193{
194 pthread_cond_wait( &(p_internal->p_condition), &(mutex.p_internal->p_mutex) );
195}
196
197bool wxCondition::Wait(wxMutex& mutex, unsigned long sec, unsigned long nsec)
198{
199 struct timespec tspec;
200
201 tspec.tv_sec = time(0L)+sec;
202 tspec.tv_nsec = nsec;
203 return (pthread_cond_timedwait(&(p_internal->p_condition), &(mutex.p_internal->p_mutex), &tspec) != ETIMEDOUT);
204}
205
206void wxCondition::Signal()
207{
208 pthread_cond_signal( &(p_internal->p_condition) );
209}
210
211void wxCondition::Broadcast()
212{
213 pthread_cond_broadcast( &(p_internal->p_condition) );
214}
215
216//--------------------------------------------------------------------
217// wxThread (Posix implementation)
218//--------------------------------------------------------------------
219
220class wxThreadInternal
221{
222public:
223 wxThreadInternal();
224 ~wxThreadInternal();
225
226 // thread entry function
227 static void *PthreadStart(void *ptr);
228
5092b3ad
GL
229#if HAVE_THREAD_CLEANUP_FUNCTIONS
230 // thread exit function
231 static void PthreadCleanup(void *ptr);
232#endif
233
518b5d2f
VZ
234 // thread actions
235 // start the thread
236 wxThreadError Run();
237 // ask the thread to terminate
882eefb1 238 void Wait();
518b5d2f
VZ
239 // wake up threads waiting for our termination
240 void SignalExit();
241 // go to sleep until Resume() is called
242 void Pause();
243 // resume the thread
244 void Resume();
245
246 // accessors
247 // priority
248 int GetPriority() const { return m_prio; }
249 void SetPriority(int prio) { m_prio = prio; }
250 // state
882eefb1
VZ
251 wxThreadState GetState() const { return m_state; }
252 void SetState(wxThreadState state) { m_state = state; }
518b5d2f 253 // id
882eefb1
VZ
254 pthread_t GetId() const { return m_threadId; }
255 pthread_t *GetIdPtr() { return &m_threadId; }
518b5d2f 256 // "cancelled" flag
882eefb1 257 void SetCancelFlag() { m_cancelled = TRUE; }
518b5d2f
VZ
258 bool WasCancelled() const { return m_cancelled; }
259
518b5d2f 260private:
882eefb1
VZ
261 pthread_t m_threadId; // id of the thread
262 wxThreadState m_state; // see wxThreadState enum
263 int m_prio; // in wxWindows units: from 0 to 100
518b5d2f
VZ
264
265 // set when the thread should terminate
266 bool m_cancelled;
267
268 // this (mutex, cond) pair is used to synchronize the main thread and this
269 // thread in several situations:
270 // 1. The thread function blocks until condition is signaled by Run() when
862cc6f9 271 // it's initially created - this allows thread creation in "suspended"
518b5d2f
VZ
272 // state
273 // 2. The Delete() function blocks until the condition is signaled when the
274 // thread exits.
062c4861
GL
275 // GL: On Linux, this may fail because we can have a deadlock in either
276 // SignalExit() or Wait(): so we add m_end_mutex for the finalization.
0dac2f38 277 wxMutex m_mutex, m_end_mutex;
518b5d2f
VZ
278 wxCondition m_cond;
279
280 // another (mutex, cond) pair for Pause()/Resume() usage
281 //
282 // VZ: it's possible that we might reuse the mutex and condition from above
283 // for this too, but as I'm not at all sure that it won't create subtle
284 // problems with race conditions between, say, Pause() and Delete() I
285 // prefer this may be a bit less efficient but much safer solution
286 wxMutex m_mutexSuspend;
287 wxCondition m_condSuspend;
288};
289
290void *wxThreadInternal::PthreadStart(void *ptr)
291{
292 wxThread *thread = (wxThread *)ptr;
293 wxThreadInternal *pthread = thread->p_internal;
5092b3ad 294 void *status;
518b5d2f 295
862cc6f9
VZ
296 int rc = pthread_setspecific(gs_keySelf, thread);
297 if ( rc != 0 )
518b5d2f 298 {
58230fb1 299 wxLogSysError(rc, _("Cannot start thread: error writing TLS"));
518b5d2f
VZ
300
301 return (void *)-1;
302 }
5092b3ad
GL
303#if HAVE_THREAD_CLEANUP_FUNCTIONS
304 // Install the cleanup handler.
062c4861 305 pthread_cleanup_push(wxThreadInternal::PthreadCleanup, ptr);
5092b3ad 306#endif
518b5d2f
VZ
307
308 // wait for the condition to be signaled from Run()
309 // mutex state: currently locked by the thread which created us
310 pthread->m_cond.Wait(pthread->m_mutex);
518b5d2f
VZ
311 // mutex state: locked again on exit of Wait()
312
313 // call the main entry
5092b3ad
GL
314 status = thread->Entry();
315
316#if HAVE_THREAD_CLEANUP_FUNCTIONS
062c4861 317 pthread_cleanup_pop(FALSE);
5092b3ad 318#endif
518b5d2f
VZ
319
320 // terminate the thread
321 thread->Exit(status);
322
d207efe1 323 wxFAIL_MSG(_T("wxThread::Exit() can't return."));
518b5d2f
VZ
324
325 return NULL;
326}
327
5092b3ad
GL
328#if HAVE_THREAD_CLEANUP_FUNCTIONS
329// Only called when the thread is explicitely killed.
330
331void wxThreadInternal::PthreadCleanup(void *ptr)
332{
333 wxThread *thread = (wxThread *) ptr;
334
335 // The thread is already considered as finished.
336 if (thread->p_internal->GetState() == STATE_EXITED)
337 return;
338
339 // first call user-level clean up code
340 thread->OnExit();
341
342 // next wake up the threads waiting for us (OTOH, this function won't retur
343 // until someone waited for us!)
344 thread->p_internal->SetState(STATE_EXITED);
345
346 thread->p_internal->SignalExit();
347}
348#endif
349
518b5d2f
VZ
350wxThreadInternal::wxThreadInternal()
351{
352 m_state = STATE_NEW;
353 m_cancelled = FALSE;
354
355 // this mutex is locked during almost all thread lifetime - it will only be
356 // unlocked in the very end
357 m_mutex.Lock();
0dac2f38 358
9111db68
GL
359 // this mutex is used by wxThreadInternal::Wait() and by
360 // wxThreadInternal::SignalExit(). We don't use m_mutex because of a
361 // possible deadlock in either Wait() or SignalExit().
0dac2f38 362 m_end_mutex.Lock();
518b5d2f
VZ
363
364 // this mutex is used in Pause()/Resume() and is also locked all the time
365 // unless the thread is paused
366 m_mutexSuspend.Lock();
367}
368
369wxThreadInternal::~wxThreadInternal()
370{
a737331d
GL
371 // GL: moved to SignalExit
372 // m_mutexSuspend.Unlock();
518b5d2f
VZ
373
374 // note that m_mutex will be unlocked by the thread which waits for our
375 // termination
9111db68 376
062c4861
GL
377 // In the case, we didn't start the thread, all these mutex are locked:
378 // we must unlock them.
379 if (m_mutex.IsLocked())
380 m_mutex.Unlock();
381
382 if (m_end_mutex.IsLocked())
383 m_end_mutex.Unlock();
384
385 if (m_mutexSuspend.IsLocked())
386 m_mutexSuspend.Unlock();
518b5d2f
VZ
387}
388
389wxThreadError wxThreadInternal::Run()
390{
391 wxCHECK_MSG( GetState() == STATE_NEW, wxTHREAD_RUNNING,
d207efe1 392 _T("thread may only be started once after successful Create()") );
518b5d2f
VZ
393
394 // the mutex was locked on Create(), so we will be able to lock it again
395 // only when the thread really starts executing and enters the wait -
396 // otherwise we might signal the condition before anybody is waiting for it
397 wxMutexLocker lock(m_mutex);
398 m_cond.Signal();
399
400 m_state = STATE_RUNNING;
401
402 return wxTHREAD_NO_ERROR;
403
404 // now the mutex is unlocked back - but just to allow Wait() function to
405 // terminate by relocking it, so the net result is that the worker thread
406 // starts executing and the mutex is still locked
407}
408
882eefb1 409void wxThreadInternal::Wait()
518b5d2f 410{
d207efe1 411 wxCHECK_RET( WasCancelled(), _T("thread should have been cancelled first") );
882eefb1 412
518b5d2f
VZ
413 // if the thread we're waiting for is waiting for the GUI mutex, we will
414 // deadlock so make sure we release it temporarily
415 if ( wxThread::IsMain() )
416 wxMutexGuiLeave();
417
518b5d2f
VZ
418 // entering Wait() releases the mutex thus allowing SignalExit() to acquire
419 // it and to signal us its termination
0dac2f38 420 m_cond.Wait(m_end_mutex);
518b5d2f
VZ
421
422 // mutex is still in the locked state - relocked on exit from Wait(), so
423 // unlock it - we don't need it any more, the thread has already terminated
0dac2f38 424 m_end_mutex.Unlock();
518b5d2f 425
9111db68
GL
426 // After that, we wait for the real end of the other thread.
427 pthread_join(GetId(), NULL);
428
518b5d2f
VZ
429 // reacquire GUI mutex
430 if ( wxThread::IsMain() )
431 wxMutexGuiEnter();
432}
433
434void wxThreadInternal::SignalExit()
435{
a737331d
GL
436 // GL: Unlock mutexSuspend here.
437 m_mutexSuspend.Unlock();
438
518b5d2f
VZ
439 // as mutex is currently locked, this will block until some other thread
440 // (normally the same which created this one) unlocks it by entering Wait()
0dac2f38 441 m_end_mutex.Lock();
518b5d2f
VZ
442
443 // wake up all the threads waiting for our termination
444 m_cond.Broadcast();
445
446 // after this call mutex will be finally unlocked
0dac2f38 447 m_end_mutex.Unlock();
518b5d2f
VZ
448}
449
450void wxThreadInternal::Pause()
451{
882eefb1
VZ
452 // the state is set from the thread which pauses us first, this function
453 // is called later so the state should have been already set
518b5d2f 454 wxCHECK_RET( m_state == STATE_PAUSED,
d207efe1 455 _T("thread must first be paused with wxThread::Pause().") );
518b5d2f 456
862cc6f9
VZ
457 // don't pause the thread which is being terminated - this would lead to
458 // deadlock if the thread is paused after Delete() had called Resume() but
882eefb1
VZ
459 // before it had time to call Wait()
460 if ( WasCancelled() )
862cc6f9
VZ
461 return;
462
518b5d2f
VZ
463 // wait until the condition is signaled from Resume()
464 m_condSuspend.Wait(m_mutexSuspend);
465}
466
467void wxThreadInternal::Resume()
468{
469 wxCHECK_RET( m_state == STATE_PAUSED,
d207efe1 470 _T("can't resume thread which is not suspended.") );
518b5d2f
VZ
471
472 // we will be able to lock this mutex only when Pause() starts waiting
473 wxMutexLocker lock(m_mutexSuspend);
474 m_condSuspend.Signal();
475
476 SetState(STATE_RUNNING);
477}
478
479// -----------------------------------------------------------------------------
480// static functions
481// -----------------------------------------------------------------------------
482
483wxThread *wxThread::This()
484{
485 return (wxThread *)pthread_getspecific(gs_keySelf);
486}
487
488bool wxThread::IsMain()
489{
490 return (bool)pthread_equal(pthread_self(), gs_tidMain);
491}
492
493void wxThread::Yield()
494{
495 sched_yield();
496}
497
498void wxThread::Sleep(unsigned long milliseconds)
499{
500 wxUsleep(milliseconds);
501}
502
503// -----------------------------------------------------------------------------
504// creating thread
505// -----------------------------------------------------------------------------
506
507wxThread::wxThread()
508{
509 // add this thread to the global list of all threads
510 gs_allThreads.Add(this);
511
512 p_internal = new wxThreadInternal();
513}
514
515wxThreadError wxThread::Create()
516{
a737331d 517 if (p_internal->GetState() != STATE_NEW)
518b5d2f
VZ
518 return wxTHREAD_RUNNING;
519
520 // set up the thread attribute: right now, we only set thread priority
521 pthread_attr_t attr;
522 pthread_attr_init(&attr);
523
fc9ef629 524#ifdef HAVE_THREAD_PRIORITY_FUNCTIONS
518b5d2f
VZ
525 int prio;
526 if ( pthread_attr_getschedpolicy(&attr, &prio) != 0 )
527 {
58230fb1 528 wxLogError(_("Cannot retrieve thread scheduling policy."));
518b5d2f
VZ
529 }
530
531 int min_prio = sched_get_priority_min(prio),
532 max_prio = sched_get_priority_max(prio);
533
534 if ( min_prio == -1 || max_prio == -1 )
535 {
58230fb1 536 wxLogError(_("Cannot get priority range for scheduling policy %d."),
518b5d2f
VZ
537 prio);
538 }
539 else
540 {
541 struct sched_param sp;
542 pthread_attr_getschedparam(&attr, &sp);
543 sp.sched_priority = min_prio +
544 (p_internal->GetPriority()*(max_prio-min_prio))/100;
545 pthread_attr_setschedparam(&attr, &sp);
546 }
34f8c26e 547#endif // HAVE_THREAD_PRIORITY_FUNCTIONS
518b5d2f 548
58230fb1
VZ
549#ifdef HAVE_PTHREAD_ATTR_SETSCOPE
550 // this will make the threads created by this process really concurrent
551 pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
552#endif // HAVE_PTHREAD_ATTR_SETSCOPE
553
518b5d2f 554 // create the new OS thread object
882eefb1 555 int rc = pthread_create(p_internal->GetIdPtr(), &attr,
518b5d2f
VZ
556 wxThreadInternal::PthreadStart, (void *)this);
557 pthread_attr_destroy(&attr);
558
559 if ( rc != 0 )
560 {
561 p_internal->SetState(STATE_EXITED);
562 return wxTHREAD_NO_RESOURCE;
563 }
564
565 return wxTHREAD_NO_ERROR;
566}
567
568wxThreadError wxThread::Run()
569{
570 return p_internal->Run();
571}
572
573// -----------------------------------------------------------------------------
574// misc accessors
575// -----------------------------------------------------------------------------
576
577void wxThread::SetPriority(unsigned int prio)
578{
34f8c26e
VZ
579 wxCHECK_RET( ((int)WXTHREAD_MIN_PRIORITY <= (int)prio) &&
580 ((int)prio <= (int)WXTHREAD_MAX_PRIORITY),
d207efe1 581 _T("invalid thread priority") );
518b5d2f
VZ
582
583 wxCriticalSectionLocker lock(m_critsect);
584
585 switch ( p_internal->GetState() )
586 {
587 case STATE_NEW:
588 // thread not yet started, priority will be set when it is
589 p_internal->SetPriority(prio);
590 break;
591
592 case STATE_RUNNING:
593 case STATE_PAUSED:
34f8c26e 594#ifdef HAVE_THREAD_PRIORITY_FUNCTIONS
518b5d2f
VZ
595 {
596 struct sched_param sparam;
597 sparam.sched_priority = prio;
598
599 if ( pthread_setschedparam(p_internal->GetId(),
600 SCHED_OTHER, &sparam) != 0 )
601 {
602 wxLogError(_("Failed to set thread priority %d."), prio);
603 }
604 }
34f8c26e 605#endif // HAVE_THREAD_PRIORITY_FUNCTIONS
518b5d2f
VZ
606 break;
607
608 case STATE_EXITED:
609 default:
d207efe1 610 wxFAIL_MSG(_T("impossible to set thread priority in this state"));
518b5d2f
VZ
611 }
612}
613
614unsigned int wxThread::GetPriority() const
615{
616 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
617
618 return p_internal->GetPriority();
619}
620
621unsigned long wxThread::GetID() const
622{
882eefb1 623 return (unsigned long)p_internal->GetId();
518b5d2f
VZ
624}
625
626// -----------------------------------------------------------------------------
627// pause/resume
628// -----------------------------------------------------------------------------
629
630wxThreadError wxThread::Pause()
631{
632 wxCriticalSectionLocker lock(m_critsect);
633
634 if ( p_internal->GetState() != STATE_RUNNING )
635 {
d207efe1 636 wxLogDebug(_T("Can't pause thread which is not running."));
518b5d2f
VZ
637
638 return wxTHREAD_NOT_RUNNING;
639 }
640
641 p_internal->SetState(STATE_PAUSED);
642
643 return wxTHREAD_NO_ERROR;
644}
645
646wxThreadError wxThread::Resume()
647{
648 wxCriticalSectionLocker lock(m_critsect);
649
650 if ( p_internal->GetState() == STATE_PAUSED )
651 {
a737331d 652 m_critsect.Leave();
518b5d2f 653 p_internal->Resume();
a737331d 654 m_critsect.Enter();
518b5d2f
VZ
655
656 return wxTHREAD_NO_ERROR;
657 }
658 else
659 {
d207efe1 660 wxLogDebug(_T("Attempt to resume a thread which is not paused."));
518b5d2f
VZ
661
662 return wxTHREAD_MISC_ERROR;
663 }
664}
665
666// -----------------------------------------------------------------------------
667// exiting thread
668// -----------------------------------------------------------------------------
669
670wxThread::ExitCode wxThread::Delete()
671{
fae05df5
GL
672 if (IsPaused())
673 Resume();
674
518b5d2f 675 m_critsect.Enter();
882eefb1 676 wxThreadState state = p_internal->GetState();
518b5d2f 677
882eefb1
VZ
678 // ask the thread to stop
679 p_internal->SetCancelFlag();
680
9111db68
GL
681 m_critsect.Leave();
682
518b5d2f
VZ
683 switch ( state )
684 {
685 case STATE_NEW:
686 case STATE_EXITED:
687 // nothing to do
688 break;
689
690 case STATE_PAUSED:
691 // resume the thread first
692 Resume();
693
694 // fall through
695
696 default:
882eefb1
VZ
697 // wait until the thread stops
698 p_internal->Wait();
518b5d2f 699 }
f439844b
GL
700 //GL: As we must auto-destroy, the destruction must happen here.
701 delete this;
518b5d2f
VZ
702
703 return NULL;
704}
705
706wxThreadError wxThread::Kill()
707{
708 switch ( p_internal->GetState() )
709 {
710 case STATE_NEW:
711 case STATE_EXITED:
712 return wxTHREAD_NOT_RUNNING;
713
714 default:
34f8c26e 715#ifdef HAVE_PTHREAD_CANCEL
518b5d2f 716 if ( pthread_cancel(p_internal->GetId()) != 0 )
34f8c26e 717#endif
518b5d2f
VZ
718 {
719 wxLogError(_("Failed to terminate a thread."));
720
721 return wxTHREAD_MISC_ERROR;
722 }
f439844b
GL
723 //GL: As we must auto-destroy, the destruction must happen here (2).
724 delete this;
518b5d2f
VZ
725
726 return wxTHREAD_NO_ERROR;
727 }
728}
729
730void wxThread::Exit(void *status)
731{
732 // first call user-level clean up code
733 OnExit();
734
735 // next wake up the threads waiting for us (OTOH, this function won't return
736 // until someone waited for us!)
2a4f27f2 737 p_internal->SignalExit();
5092b3ad
GL
738
739 p_internal->SetState(STATE_EXITED);
2a4f27f2 740
518b5d2f 741 // delete both C++ thread object and terminate the OS thread object
c84fb40a
GL
742 // GL: This is very ugly and buggy ...
743// delete this;
518b5d2f
VZ
744 pthread_exit(status);
745}
746
747// also test whether we were paused
748bool wxThread::TestDestroy()
749{
882eefb1 750 wxCriticalSectionLocker lock(m_critsect);
518b5d2f
VZ
751
752 if ( p_internal->GetState() == STATE_PAUSED )
753 {
754 // leave the crit section or the other threads will stop too if they try
755 // to call any of (seemingly harmless) IsXXX() functions while we sleep
756 m_critsect.Leave();
757
758 p_internal->Pause();
759
760 // enter it back before it's finally left in lock object dtor
761 m_critsect.Enter();
762 }
763
764 return p_internal->WasCancelled();
765}
766
767wxThread::~wxThread()
768{
062c4861
GL
769 m_critsect.Enter();
770 if (p_internal->GetState() != STATE_EXITED &&
771 p_internal->GetState() != STATE_NEW)
772 wxLogDebug(_T("The thread is being destroyed althought it is still running ! The application may crash."));
773
774 m_critsect.Leave();
775
776 delete p_internal;
518b5d2f
VZ
777 // remove this thread from the global array
778 gs_allThreads.Remove(this);
779}
780
781// -----------------------------------------------------------------------------
782// state tests
783// -----------------------------------------------------------------------------
784
785bool wxThread::IsRunning() const
786{
787 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
788
789 return p_internal->GetState() == STATE_RUNNING;
790}
791
792bool wxThread::IsAlive() const
793{
794 wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
795
796 switch ( p_internal->GetState() )
797 {
798 case STATE_RUNNING:
799 case STATE_PAUSED:
800 return TRUE;
801
802 default:
803 return FALSE;
804 }
805}
806
a737331d
GL
807bool wxThread::IsPaused() const
808{
809 wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
810
811 return (p_internal->GetState() == STATE_PAUSED);
812}
813
518b5d2f
VZ
814//--------------------------------------------------------------------
815// wxThreadModule
816//--------------------------------------------------------------------
817
818class wxThreadModule : public wxModule
819{
820public:
821 virtual bool OnInit();
822 virtual void OnExit();
823
824private:
825 DECLARE_DYNAMIC_CLASS(wxThreadModule)
826};
827
828IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
829
830bool wxThreadModule::OnInit()
831{
58230fb1
VZ
832 int rc = pthread_key_create(&gs_keySelf, NULL /* dtor function */);
833 if ( rc != 0 )
518b5d2f 834 {
58230fb1
VZ
835 wxLogSysError(rc, _("Thread module initialization failed: "
836 "failed to create thread key"));
518b5d2f
VZ
837
838 return FALSE;
839 }
840
841 gs_mutexGui = new wxMutex();
518b5d2f
VZ
842
843 gs_tidMain = pthread_self();
19da4326 844
518b5d2f
VZ
845 gs_mutexGui->Lock();
846
847 return TRUE;
848}
849
850void wxThreadModule::OnExit()
851{
d207efe1 852 wxASSERT_MSG( wxThread::IsMain(), _T("only main thread can be here") );
518b5d2f
VZ
853
854 // terminate any threads left
855 size_t count = gs_allThreads.GetCount();
856 if ( count != 0u )
d207efe1 857 wxLogDebug(_T("Some threads were not terminated by the application."));
518b5d2f
VZ
858
859 for ( size_t n = 0u; n < count; n++ )
860 {
0ac77ef5
GL
861 // Delete calls the destructor which removes the current entry. We
862 // should only delete the first one each time.
863 gs_allThreads[0]->Delete();
518b5d2f
VZ
864 }
865
866 // destroy GUI mutex
867 gs_mutexGui->Unlock();
868
518b5d2f
VZ
869 delete gs_mutexGui;
870
871 // and free TLD slot
872 (void)pthread_key_delete(gs_keySelf);
873}
874
875// ----------------------------------------------------------------------------
876// global functions
877// ----------------------------------------------------------------------------
878
879void wxMutexGuiEnter()
880{
881 gs_mutexGui->Lock();
882}
883
884void wxMutexGuiLeave()
885{
886 gs_mutexGui->Unlock();
887}
80cb83be 888
7bcb11d3
JS
889#endif
890 // wxUSE_THREADS