1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/carbon/thread.cpp
3 // Purpose: wxThread Implementation
4 // Author: Original from Wolfram Gloger/Guilhem Lavaux/Vadim Zeitlin
5 // Modified by: Aj Lavin, Stefan Csomor
8 // Copyright: (c) Wolfram Gloger (1996, 1997); Guilhem Lavaux (1998),
9 // Vadim Zeitlin (1999), Stefan Csomor (2000)
10 // Licence: wxWindows licence
11 /////////////////////////////////////////////////////////////////////////////
13 #include "wx/wxprec.h"
15 #if defined(__BORLANDC__)
21 #include "wx/module.h"
26 #include "wx/thread.h"
28 #if wxOSX_USE_COCOA_OR_CARBON
29 #include <CoreServices/CoreServices.h>
31 #include <Foundation/Foundation.h>
34 #include "wx/osx/uma.h"
36 // the possible states of the thread:
37 // ("=>" shows all possible transitions from this state)
40 STATE_NEW
, // didn't start execution yet (=> RUNNING)
41 STATE_RUNNING
, // thread is running (=> PAUSED, CANCELED)
42 STATE_PAUSED
, // thread is temporarily suspended (=> RUNNING)
43 STATE_CANCELED
, // thread should terminate a.s.a.p. (=> EXITED)
44 STATE_EXITED
// thread is terminating
47 // ----------------------------------------------------------------------------
49 // ----------------------------------------------------------------------------
51 // the task ID of the main thread
52 wxThreadIdType
wxThread::ms_idMainThread
= kInvalidID
;
54 // this is the Per-Task Storage for the pointer to the appropriate wxThread
55 TaskStorageIndex gs_tlsForWXThread
= 0;
57 // if it's false, some secondary thread is holding the GUI lock
58 static bool gs_bGuiOwnedByMainThread
= true;
60 // critical section which controls access to all GUI functions: any secondary
61 // thread (i.e. except the main one) must enter this crit section before doing
63 static wxCriticalSection
*gs_critsectGui
= NULL
;
65 // critical section which protects gs_nWaitingForGui variable
66 static wxCriticalSection
*gs_critsectWaitingForGui
= NULL
;
68 // number of threads waiting for GUI in wxMutexGuiEnter()
69 static size_t gs_nWaitingForGui
= 0;
71 // overall number of threads, needed for determining
72 // the sleep value of the main event loop
73 size_t g_numberOfThreads
= 0;
77 MPCriticalRegionID gs_guiCritical
= kInvalidID
;
80 // ============================================================================
81 // MacOS implementation of thread classes
82 // ============================================================================
87 The implementation is very close to the phtreads implementation, the reason for
88 using MPServices is the fact that these are also available under OS 9. Thus allowing
89 for one common API for all current builds.
91 As soon as wxThreads are on a 64 bit address space, the TLS must be extended
92 to use two indices one for each 32 bit part as the MP implementation is limited
95 I have three implementations for mutexes :
96 version A based on a binary semaphore, problem - not reentrant, version B based
97 on a critical region, allows for reentrancy, performance implications not
98 yet tested, and third a plain pthreads implementation
100 The same for condition internal, one implementation by Aj Lavin and the other one
101 copied from the thrimpl.cpp which I assume has been more broadly tested, I've just
102 replaced the interlock increment with the appropriate PPC calls
105 // ----------------------------------------------------------------------------
107 // ----------------------------------------------------------------------------
109 wxCriticalSection::wxCriticalSection( wxCriticalSectionType
WXUNUSED(critSecType
) )
111 MPCreateCriticalRegion( (MPCriticalRegionID
*) &m_critRegion
);
114 wxCriticalSection::~wxCriticalSection()
116 MPDeleteCriticalRegion( (MPCriticalRegionID
) m_critRegion
);
119 void wxCriticalSection::Enter()
121 MPEnterCriticalRegion( (MPCriticalRegionID
) m_critRegion
, kDurationForever
);
124 bool wxCriticalSection::TryEnter()
126 return MPEnterCriticalRegion( (MPCriticalRegionID
) m_critRegion
, kDurationImmediate
) == noErr
;
129 void wxCriticalSection::Leave()
131 MPExitCriticalRegion( (MPCriticalRegionID
) m_critRegion
);
134 // ----------------------------------------------------------------------------
135 // wxMutex implementation
136 // ----------------------------------------------------------------------------
138 #define wxUSE_MAC_SEMAPHORE_MUTEX 0
139 #define wxUSE_MAC_CRITICAL_REGION_MUTEX 1
140 #define wxUSE_MAC_PTHREADS_MUTEX 0
142 #if wxUSE_MAC_CRITICAL_REGION_MUTEX
144 class wxMutexInternal
147 wxMutexInternal( wxMutexType mutexType
);
148 virtual ~wxMutexInternal();
150 bool IsOk() const { return m_isOk
; }
152 wxMutexError
Lock() { return Lock(kDurationForever
); }
153 wxMutexError
Lock(unsigned long ms
);
154 wxMutexError
TryLock();
155 wxMutexError
Unlock();
158 MPCriticalRegionID m_critRegion
;
162 wxMutexInternal::wxMutexInternal( wxMutexType
WXUNUSED(mutexType
) )
165 m_critRegion
= kInvalidID
;
167 verify_noerr( MPCreateCriticalRegion( &m_critRegion
) );
168 m_isOk
= ( m_critRegion
!= kInvalidID
);
171 wxFAIL_MSG( wxT("Error when creating mutex") );
175 wxMutexInternal::~wxMutexInternal()
177 if ( m_critRegion
!= kInvalidID
)
178 MPDeleteCriticalRegion( m_critRegion
);
183 wxMutexError
wxMutexInternal::Lock(unsigned long ms
)
185 wxCHECK_MSG( m_isOk
, wxMUTEX_MISC_ERROR
, wxT("Invalid Mutex") );
187 OSStatus err
= MPEnterCriticalRegion( m_critRegion
, ms
);
194 wxASSERT_MSG( ms
!= kDurationForever
, wxT("unexpected timeout") );
195 return wxMUTEX_TIMEOUT
;
198 wxLogSysError(wxT("Could not lock mutex"));
199 return wxMUTEX_MISC_ERROR
;
202 return wxMUTEX_NO_ERROR
;
205 wxMutexError
wxMutexInternal::TryLock()
207 wxCHECK_MSG( m_isOk
, wxMUTEX_MISC_ERROR
, wxT("Invalid Mutex") ) ;
209 OSStatus err
= MPEnterCriticalRegion( m_critRegion
, kDurationImmediate
);
212 if ( err
== kMPTimeoutErr
)
215 wxLogSysError( wxT("Could not try lock mutex") );
216 return wxMUTEX_MISC_ERROR
;
219 return wxMUTEX_NO_ERROR
;
222 wxMutexError
wxMutexInternal::Unlock()
224 wxCHECK_MSG( m_isOk
, wxMUTEX_MISC_ERROR
, wxT("Invalid Mutex") ) ;
226 OSStatus err
= MPExitCriticalRegion( m_critRegion
);
231 wxLogSysError( wxT("Could not unlock mutex") );
233 return wxMUTEX_MISC_ERROR
;
236 return wxMUTEX_NO_ERROR
;
241 // --------------------------------------------------------------------------
243 // --------------------------------------------------------------------------
245 class wxSemaphoreInternal
248 wxSemaphoreInternal( int initialcount
, int maxcount
);
249 virtual ~wxSemaphoreInternal();
255 wxSemaError
WaitTimeout( unsigned long milliseconds
);
258 { return WaitTimeout( kDurationForever
); }
260 wxSemaError
TryWait()
262 wxSemaError err
= WaitTimeout( kDurationImmediate
);
263 if (err
== wxSEMA_TIMEOUT
)
270 MPSemaphoreID m_semaphore
;
274 wxSemaphoreInternal::wxSemaphoreInternal( int initialcount
, int maxcount
)
277 m_semaphore
= kInvalidID
;
279 // make it practically infinite
282 verify_noerr( MPCreateSemaphore( maxcount
, initialcount
, &m_semaphore
) );
283 m_isOk
= ( m_semaphore
!= kInvalidID
);
287 wxFAIL_MSG( wxT("Error when creating semaphore") );
291 wxSemaphoreInternal::~wxSemaphoreInternal()
293 if (m_semaphore
!= kInvalidID
)
294 MPDeleteSemaphore( m_semaphore
);
299 wxSemaError
wxSemaphoreInternal::WaitTimeout( unsigned long milliseconds
)
301 OSStatus err
= MPWaitOnSemaphore( m_semaphore
, milliseconds
);
304 if (err
== kMPTimeoutErr
)
305 return wxSEMA_TIMEOUT
;
307 return wxSEMA_MISC_ERROR
;
310 return wxSEMA_NO_ERROR
;
313 wxSemaError
wxSemaphoreInternal::Post()
315 OSStatus err
= MPSignalSemaphore( m_semaphore
);
318 return wxSEMA_MISC_ERROR
;
320 return wxSEMA_NO_ERROR
;
323 // ----------------------------------------------------------------------------
324 // wxCondition implementation
325 // ----------------------------------------------------------------------------
327 class wxConditionInternal
330 wxConditionInternal( wxMutex
& mutex
);
333 { return m_mutex
.IsOk() && m_semaphore
.IsOk(); }
336 wxCondError
WaitTimeout( unsigned long milliseconds
);
338 wxCondError
Signal();
339 wxCondError
Broadcast();
342 // the number of threads currently waiting for this condition
345 // the critical section protecting m_numWaiters
346 wxCriticalSection m_csWaiters
;
349 wxSemaphore m_semaphore
;
351 wxDECLARE_NO_COPY_CLASS(wxConditionInternal
);
354 wxConditionInternal::wxConditionInternal( wxMutex
& mutex
)
357 // another thread can't access it until we return from ctor, so no need to
358 // protect access to m_numWaiters here
362 wxCondError
wxConditionInternal::Wait()
364 // increment the number of waiters
365 IncrementAtomic( &m_numWaiters
);
369 // a potential race condition can occur here
371 // after a thread increments nwaiters, and unlocks the mutex and before the
372 // semaphore.Wait() is called, if another thread can cause a signal to be
375 // this race condition is handled by using a semaphore and incrementing the
376 // semaphore only if 'nwaiters' is greater that zero since the semaphore,
377 // can 'remember' signals the race condition will not occur
379 // wait ( if necessary ) and decrement semaphore
380 wxSemaError err
= m_semaphore
.Wait();
383 return err
== wxSEMA_NO_ERROR
? wxCOND_NO_ERROR
: wxCOND_MISC_ERROR
;
386 wxCondError
wxConditionInternal::WaitTimeout( unsigned long milliseconds
)
388 IncrementAtomic( &m_numWaiters
);
392 // a race condition can occur at this point in the code
394 // please see the comments in Wait(), for details
396 wxSemaError err
= m_semaphore
.WaitTimeout(milliseconds
);
398 if ( err
== wxSEMA_TIMEOUT
)
400 // another potential race condition exists here it is caused when a
401 // 'waiting' thread timesout, and returns from WaitForSingleObject, but
402 // has not yet decremented 'nwaiters'.
404 // at this point if another thread calls signal() then the semaphore
405 // will be incremented, but the waiting thread will miss it.
407 // to handle this particular case, the waiting thread calls
408 // WaitForSingleObject again with a timeout of 0, after locking
409 // 'nwaiters_mutex'. this call does not block because of the zero
410 // timeout, but will allow the waiting thread to catch the missed
412 wxCriticalSectionLocker
lock(m_csWaiters
);
414 err
= m_semaphore
.WaitTimeout(0);
416 if ( err
!= wxSEMA_NO_ERROR
)
424 return err
== wxSEMA_NO_ERROR
? wxCOND_NO_ERROR
: wxCOND_MISC_ERROR
;
427 wxCondError
wxConditionInternal::Signal()
429 wxCriticalSectionLocker
lock(m_csWaiters
);
431 if ( m_numWaiters
> 0 )
433 // increment the semaphore by 1
434 if ( m_semaphore
.Post() != wxSEMA_NO_ERROR
)
435 return wxCOND_MISC_ERROR
;
440 return wxCOND_NO_ERROR
;
443 wxCondError
wxConditionInternal::Broadcast()
445 wxCriticalSectionLocker
lock(m_csWaiters
);
447 while ( m_numWaiters
> 0 )
449 if ( m_semaphore
.Post() != wxSEMA_NO_ERROR
)
450 return wxCOND_MISC_ERROR
;
455 return wxCOND_NO_ERROR
;
458 // ----------------------------------------------------------------------------
459 // wxCriticalSection implementation
460 // ----------------------------------------------------------------------------
462 // XXX currently implemented as mutex in headers. Change to critical section.
464 // ----------------------------------------------------------------------------
465 // wxThread implementation
466 // ----------------------------------------------------------------------------
468 // wxThreadInternal class
469 // ----------------------
471 class wxThreadInternal
478 m_prio
= wxPRIORITY_DEFAULT
;
479 m_notifyQueueId
= kInvalidID
;
481 m_cancelled
= false ;
483 // set to true only when the thread starts waiting on m_semSuspend
486 // defaults for joinable threads
487 m_shouldBeJoined
= true;
488 m_isDetached
= false;
491 virtual ~wxThreadInternal()
493 if ( m_notifyQueueId
)
495 MPDeleteQueue( m_notifyQueueId
);
496 m_notifyQueueId
= kInvalidID
;
501 static OSStatus
MacThreadStart(void* arg
);
503 // create a new (suspended) thread (for the given thread object)
504 bool Create(wxThread
*thread
, unsigned int stackSize
);
511 // unblock the thread allowing it to run
512 void SignalRun() { m_semRun
.Post(); }
514 // ask the thread to terminate
517 // go to sleep until Resume() is called
525 int GetPriority() const
527 void SetPriority(int prio
);
530 wxThreadState
GetState() const
532 void SetState(wxThreadState state
)
535 // Get the ID of this thread's underlying MP Services task.
536 MPTaskID
GetId() const
540 { m_cancelled
= true; }
542 bool WasCancelled() const
543 { return m_cancelled
; }
546 void SetExitCode(wxThread::ExitCode exitcode
)
547 { m_exitcode
= exitcode
; }
548 wxThread::ExitCode
GetExitCode() const
549 { return m_exitcode
; }
552 void SetReallyPaused(bool paused
)
553 { m_isPaused
= paused
; }
554 bool IsReallyPaused() const
555 { return m_isPaused
; }
557 // tell the thread that it is a detached one
560 wxCriticalSectionLocker
lock(m_csJoinFlag
);
562 m_shouldBeJoined
= false;
567 // the thread we're associated with
570 MPTaskID m_tid
; // thread id
571 MPQueueID m_notifyQueueId
; // its notification queue
573 wxThreadState m_state
; // see wxThreadState enum
574 int m_prio
; // in wxWidgets units: from 0 to 100
576 // this flag is set when the thread should terminate
579 // this flag is set when the thread is blocking on m_semSuspend
582 // the thread exit code - only used for joinable (!detached) threads and
583 // is only valid after the thread termination
584 wxThread::ExitCode m_exitcode
;
586 // many threads may call Wait(), but only one of them should call
587 // pthread_join(), so we have to keep track of this
588 wxCriticalSection m_csJoinFlag
;
589 bool m_shouldBeJoined
;
592 // this semaphore is posted by Run() and the threads Entry() is not
593 // called before it is done
594 wxSemaphore m_semRun
;
596 // this one is signaled when the thread should resume after having been
598 wxSemaphore m_semSuspend
;
601 OSStatus
wxThreadInternal::MacThreadStart(void *parameter
)
603 wxThread
* thread
= (wxThread
*) parameter
;
604 wxThreadInternal
*pthread
= thread
->m_internal
;
606 // add to TLS so that This() will work
607 verify_noerr( MPSetTaskStorageValue( gs_tlsForWXThread
, (TaskStorageValue
) thread
) ) ;
609 // have to declare this before pthread_cleanup_push() which defines a
613 // wait for the semaphore to be posted from Run()
614 pthread
->m_semRun
.Wait();
616 // test whether we should run the run at all - may be it was deleted
617 // before it started to Run()?
619 wxCriticalSectionLocker
lock(thread
->m_critsect
);
621 dontRunAtAll
= pthread
->GetState() == STATE_NEW
&&
622 pthread
->WasCancelled();
627 pthread
->m_exitcode
= thread
->Entry();
630 wxCriticalSectionLocker
lock(thread
->m_critsect
);
631 pthread
->SetState( STATE_EXITED
);
637 if ( pthread
->m_isDetached
)
644 // on Mac for the running code,
645 // the correct thread termination is to return
647 // terminate the thread
648 thread
->Exit( pthread
->m_exitcode
);
650 return (OSStatus
) NULL
; // pthread->m_exitcode;
654 bool wxThreadInternal::Create( wxThread
*thread
, unsigned int stackSize
)
656 wxASSERT_MSG( m_state
== STATE_NEW
&& !m_tid
,
657 wxT("Create()ing thread twice?") );
659 if ( thread
->IsDetached() )
662 OSStatus err
= noErr
;
665 if ( m_notifyQueueId
== kInvalidID
)
667 OSStatus err
= MPCreateQueue( &m_notifyQueueId
);
670 wxLogSysError( wxT("Can't create the thread event queue") );
679 MacThreadStart
, (void*)m_thread
, stackSize
,
680 m_notifyQueueId
, &m_exitcode
, 0, 0, &m_tid
);
684 wxLogSysError( wxT("Can't create thread") );
689 if ( m_prio
!= wxPRIORITY_DEFAULT
)
690 SetPriority( m_prio
);
695 void wxThreadInternal::SetPriority( int priority
)
701 // Mac priorities range from 1 to 10,000, with a default of 100.
702 // wxWidgets priorities range from 0 to 100 with a default of 50.
703 // We can map wxWidgets to Mac priorities easily by assuming
704 // the former uses a logarithmic scale.
705 const unsigned int macPriority
= (int)( exp( priority
/ 25.0 * log( 10.0)) + 0.5);
707 MPSetTaskWeight( m_tid
, macPriority
);
711 wxThreadError
wxThreadInternal::Run()
713 wxCHECK_MSG( GetState() == STATE_NEW
, wxTHREAD_RUNNING
,
714 wxT("thread may only be started once after Create()") );
716 SetState( STATE_RUNNING
);
718 // wake up threads waiting for our start
721 return wxTHREAD_NO_ERROR
;
724 void wxThreadInternal::Wait()
726 wxCHECK_RET( !m_isDetached
, wxT("can't wait for a detached thread") );
728 // if the thread we're waiting for is waiting for the GUI mutex, we will
729 // deadlock so make sure we release it temporarily
730 if ( wxThread::IsMain() )
732 // give the thread we're waiting for chance to do the GUI call
733 // it might be in, we don't do this conditionally as the to be waited on
734 // thread might have to acquire the mutex later but before terminating
735 if ( wxGuiOwnedByMainThread() )
740 wxCriticalSectionLocker
lock(m_csJoinFlag
);
742 if ( m_shouldBeJoined
)
744 void *param1
, *param2
, *rc
;
746 OSStatus err
= MPWaitOnQueue(
754 wxLogSysError( wxT( "Cannot wait for thread termination."));
758 // actually param1 would be the address of m_exitcode
759 // but we don't need this here
762 m_shouldBeJoined
= false;
767 void wxThreadInternal::Pause()
769 // the state is set from the thread which pauses us first, this function
770 // is called later so the state should have been already set
771 wxCHECK_RET( m_state
== STATE_PAUSED
,
772 wxT("thread must first be paused with wxThread::Pause().") );
774 // wait until the semaphore is Post()ed from Resume()
778 void wxThreadInternal::Resume()
780 wxCHECK_RET( m_state
== STATE_PAUSED
,
781 wxT("can't resume thread which is not suspended.") );
783 // the thread might be not actually paused yet - if there were no call to
784 // TestDestroy() since the last call to Pause() for example
785 if ( IsReallyPaused() )
791 SetReallyPaused( false );
794 SetState( STATE_RUNNING
);
800 wxThread
*wxThread::This()
802 wxThread
* thr
= (wxThread
*) MPGetTaskStorageValue( gs_tlsForWXThread
) ;
811 void wxThread::Yield()
813 CFRunLoopRunInMode( kCFRunLoopDefaultMode
, 0 , true ) ;
818 void wxThread::Sleep( unsigned long milliseconds
)
820 AbsoluteTime wakeup
= AddDurationToAbsolute( milliseconds
, UpTime() );
821 MPDelayUntil( &wakeup
);
824 int wxThread::GetCPUCount()
826 return MPProcessors();
829 unsigned long wxThread::GetCurrentId()
831 return (unsigned long)MPCurrentTaskID();
834 bool wxThread::SetConcurrency( size_t WXUNUSED(level
) )
836 // Cannot be set in MacOS.
840 wxThread::wxThread( wxThreadKind kind
)
843 m_internal
= new wxThreadInternal();
845 m_isDetached
= (kind
== wxTHREAD_DETACHED
);
848 wxThread::~wxThread()
850 wxASSERT_MSG( g_numberOfThreads
>0 , wxT("More threads deleted than created.") ) ;
856 // check that the thread either exited or couldn't be created
857 if ( m_internal
->GetState() != STATE_EXITED
&&
858 m_internal
->GetState() != STATE_NEW
)
861 wxT("The thread %ld is being destroyed although it is still running! The application may crash."),
867 wxDELETE( m_internal
) ;
870 wxThreadError
wxThread::Create( unsigned int stackSize
)
872 wxCriticalSectionLocker
lock(m_critsect
);
874 if ( !m_internal
->Create(this, stackSize
) )
876 m_internal
->SetState( STATE_EXITED
);
877 return wxTHREAD_NO_RESOURCE
;
880 return wxTHREAD_NO_ERROR
;
883 wxThreadError
wxThread::Run()
885 wxCriticalSectionLocker
lock(m_critsect
);
887 // Create the thread if it wasn't created yet with an explicit
889 if ( m_internal
->GetId() == kInvalidID
)
891 if ( !m_internal
->Create(this, stackSize
) )
893 m_internal
->SetState( STATE_EXITED
);
894 return wxTHREAD_NO_RESOURCE
;
898 wxCHECK_MSG( m_internal
->GetId(), wxTHREAD_MISC_ERROR
,
899 wxT("must call wxThread::Create() first") );
901 return m_internal
->Run();
904 // -----------------------------------------------------------------------------
906 // -----------------------------------------------------------------------------
908 wxThreadError
wxThread::Pause()
910 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR
,
911 wxT("a thread can't pause itself") );
913 wxCriticalSectionLocker
lock(m_critsect
);
915 if ( m_internal
->GetState() != STATE_RUNNING
)
917 wxLogDebug( wxT("Can't pause thread which is not running.") );
919 return wxTHREAD_NOT_RUNNING
;
922 // just set a flag, the thread will be really paused only during the next
923 // call to TestDestroy()
924 m_internal
->SetState( STATE_PAUSED
);
926 return wxTHREAD_NO_ERROR
;
929 wxThreadError
wxThread::Resume()
931 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR
,
932 wxT("a thread can't resume itself") );
934 wxCriticalSectionLocker
lock(m_critsect
);
936 wxThreadState state
= m_internal
->GetState();
941 m_internal
->Resume();
942 return wxTHREAD_NO_ERROR
;
945 return wxTHREAD_NO_ERROR
;
948 wxLogDebug( wxT("Attempt to resume a thread which is not paused.") );
950 return wxTHREAD_MISC_ERROR
;
954 // -----------------------------------------------------------------------------
956 // -----------------------------------------------------------------------------
958 wxThread::ExitCode
wxThread::Wait(wxThreadWait
WXUNUSED(waitMode
))
960 wxCHECK_MSG( This() != this, (ExitCode
)-1,
961 wxT("a thread can't wait for itself") );
963 wxCHECK_MSG( !m_isDetached
, (ExitCode
)-1,
964 wxT("can't wait for detached thread") );
968 return m_internal
->GetExitCode();
971 wxThreadError
wxThread::Delete(ExitCode
*rc
, wxThreadWait
WXUNUSED(waitMode
))
973 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR
,
974 wxT("a thread can't delete itself") );
976 bool isDetached
= m_isDetached
;
979 wxThreadState state
= m_internal
->GetState();
981 // ask the thread to stop
982 m_internal
->SetCancelFlag();
989 // we need to wake up the thread so that PthreadStart() will
990 // terminate - right now it's blocking on run semaphore in
992 m_internal
->SignalRun();
1001 // resume the thread first
1002 m_internal
->Resume();
1009 // wait until the thread stops
1014 // return the exit code of the thread
1015 *rc
= m_internal
->GetExitCode();
1020 return wxTHREAD_NO_ERROR
;
1023 wxThreadError
wxThread::Kill()
1025 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR
,
1026 wxT("a thread can't kill itself") );
1028 switch ( m_internal
->GetState() )
1032 return wxTHREAD_NOT_RUNNING
;
1035 // resume the thread first
1041 OSStatus err
= MPTerminateTask( m_internal
->GetId() , -1 ) ;
1044 wxLogError( wxT("Failed to terminate a thread.") );
1046 return wxTHREAD_MISC_ERROR
;
1055 // this should be retrieved by Wait actually
1056 m_internal
->SetExitCode( (void*)-1 );
1059 return wxTHREAD_NO_ERROR
;
1063 void wxThread::Exit( ExitCode status
)
1065 wxASSERT_MSG( This() == this,
1066 wxT("wxThread::Exit() can only be called in the context of the same thread") );
1068 // don't enter m_critsect before calling OnExit() because the user code
1069 // might deadlock if, for example, it signals a condition in OnExit() (a
1070 // common case) while the main thread calls any of functions entering
1071 // m_critsect on us (almost all of them do)
1074 MPTaskID threadid
= m_internal
->GetId();
1082 // update the status of the joinable thread
1083 wxCriticalSectionLocker
lock( m_critsect
);
1084 m_internal
->SetState( STATE_EXITED
);
1087 MPTerminateTask( threadid
, (long)status
);
1090 // also test whether we were paused
1091 bool wxThread::TestDestroy()
1093 wxASSERT_MSG( This() == this,
1094 wxT("wxThread::TestDestroy() can only be called in the context of the same thread") );
1098 if ( m_internal
->GetState() == STATE_PAUSED
)
1100 m_internal
->SetReallyPaused( true );
1102 // leave the crit section or the other threads will stop too if they attempt
1103 // to call any of (seemingly harmless) IsXXX() functions while we sleep
1106 m_internal
->Pause();
1110 // thread wasn't requested to pause, nothing to do
1114 return m_internal
->WasCancelled();
1117 // -----------------------------------------------------------------------------
1119 // -----------------------------------------------------------------------------
1121 void wxThread::SetPriority(unsigned int prio
)
1123 wxCHECK_RET( wxPRIORITY_MIN
<= prio
&& prio
<= wxPRIORITY_MAX
,
1124 wxT("invalid thread priority") );
1126 wxCriticalSectionLocker
lock(m_critsect
);
1128 switch ( m_internal
->GetState() )
1133 // thread not yet started, priority will be set when it is
1134 m_internal
->SetPriority( prio
);
1139 wxFAIL_MSG( wxT("impossible to set thread priority in this state") );
1143 unsigned int wxThread::GetPriority() const
1145 wxCriticalSectionLocker
lock(const_cast<wxCriticalSection
&>(m_critsect
));
1147 return m_internal
->GetPriority();
1150 unsigned long wxThread::GetId() const
1152 wxCriticalSectionLocker
lock(const_cast<wxCriticalSection
&>(m_critsect
));
1154 return (unsigned long)m_internal
->GetId();
1157 // -----------------------------------------------------------------------------
1159 // -----------------------------------------------------------------------------
1161 bool wxThread::IsRunning() const
1163 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
1165 return m_internal
->GetState() == STATE_RUNNING
;
1168 bool wxThread::IsAlive() const
1170 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
1172 switch ( m_internal
->GetState() )
1183 bool wxThread::IsPaused() const
1185 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
1187 return (m_internal
->GetState() == STATE_PAUSED
);
1190 // ----------------------------------------------------------------------------
1191 // Automatic initialization for thread module
1192 // ----------------------------------------------------------------------------
1194 class wxThreadModule
: public wxModule
1197 virtual bool OnInit();
1198 virtual void OnExit();
1201 DECLARE_DYNAMIC_CLASS(wxThreadModule
)
1204 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule
, wxModule
)
1206 bool wxThreadModule::OnInit()
1208 bool hasThreadManager
=
1210 true ; // TODO VERIFY IN NEXT BUILD
1212 MPLibraryIsLoaded();
1215 if ( !hasThreadManager
)
1217 wxLogError( wxT("MP thread support is not available on this system" ) ) ;
1222 // main thread's This() is NULL
1223 verify_noerr( MPAllocateTaskStorageIndex( &gs_tlsForWXThread
) ) ;
1224 verify_noerr( MPSetTaskStorageValue( gs_tlsForWXThread
, 0 ) ) ;
1226 wxThread::ms_idMainThread
= wxThread::GetCurrentId();
1227 gs_critsectWaitingForGui
= new wxCriticalSection();
1229 gs_critsectGui
= new wxCriticalSection();
1230 gs_critsectGui
->Enter();
1235 void wxThreadModule::OnExit()
1237 if ( gs_critsectGui
)
1239 if ( !wxGuiOwnedByMainThread() )
1241 gs_critsectGui
->Enter();
1242 gs_bGuiOwnedByMainThread
= true;
1245 gs_critsectGui
->Leave();
1246 wxDELETE(gs_critsectGui
);
1249 wxDELETE(gs_critsectWaitingForGui
);
1252 // ----------------------------------------------------------------------------
1253 // GUI Serialization copied from MSW implementation
1254 // ----------------------------------------------------------------------------
1256 void wxMutexGuiEnterImpl()
1258 // this would dead lock everything...
1259 wxASSERT_MSG( !wxThread::IsMain(),
1260 wxT("main thread doesn't want to block in wxMutexGuiEnter()!") );
1262 // the order in which we enter the critical sections here is crucial!!
1264 // set the flag telling to the main thread that we want to do some GUI
1266 wxCriticalSectionLocker
enter(*gs_critsectWaitingForGui
);
1268 gs_nWaitingForGui
++;
1271 wxWakeUpMainThread();
1273 // now we may block here because the main thread will soon let us in
1274 // (during the next iteration of OnIdle())
1275 gs_critsectGui
->Enter();
1278 void wxMutexGuiLeaveImpl()
1280 wxCriticalSectionLocker
enter(*gs_critsectWaitingForGui
);
1282 if ( wxThread::IsMain() )
1284 gs_bGuiOwnedByMainThread
= false;
1288 // decrement the number of threads waiting for GUI access now
1289 wxASSERT_MSG( gs_nWaitingForGui
> 0,
1290 wxT("calling wxMutexGuiLeave() without entering it first?") );
1292 gs_nWaitingForGui
--;
1294 wxWakeUpMainThread();
1297 gs_critsectGui
->Leave();
1300 void WXDLLIMPEXP_BASE
wxMutexGuiLeaveOrEnter()
1302 wxASSERT_MSG( wxThread::IsMain(),
1303 wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") );
1305 if ( !gs_critsectWaitingForGui
)
1308 wxCriticalSectionLocker
enter(*gs_critsectWaitingForGui
);
1310 if ( gs_nWaitingForGui
== 0 )
1312 // no threads are waiting for GUI - so we may acquire the lock without
1313 // any danger (but only if we don't already have it)
1314 if ( !wxGuiOwnedByMainThread() )
1316 gs_critsectGui
->Enter();
1318 gs_bGuiOwnedByMainThread
= true;
1320 //else: already have it, nothing to do
1324 // some threads are waiting, release the GUI lock if we have it
1325 if ( wxGuiOwnedByMainThread() )
1327 //else: some other worker thread is doing GUI
1331 bool WXDLLIMPEXP_BASE
wxGuiOwnedByMainThread()
1333 return gs_bGuiOwnedByMainThread
;
1336 // wake up the main thread
1337 void WXDLLEXPORT
wxWakeUpMainThread()
1342 // ----------------------------------------------------------------------------
1343 // include common implementation code
1344 // ----------------------------------------------------------------------------
1346 #include "wx/thrimpl.cpp"
1348 #endif // wxUSE_THREADS