1 /////////////////////////////////////////////////////////////////////////////
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 // ----------------------------------------------------------------------------
15 // ----------------------------------------------------------------------------
17 // For compilers that support precompilation, includes "wx.h".
18 #include "wx/wxprec.h"
20 #if defined(__BORLANDC__)
30 #include "wx/module.h"
31 #include "wx/thread.h"
34 #if TARGET_API_MAC_OSX
35 #include <CoreServices/CoreServices.h>
37 #include <DriverServices.h>
38 #include <Multiprocessing.h>
41 #include "wx/mac/uma.h"
44 // ----------------------------------------------------------------------------
46 // ----------------------------------------------------------------------------
48 // the possible states of the thread ("=>" shows all possible transitions from
52 STATE_NEW
, // didn't start execution yet (=> RUNNING)
53 STATE_RUNNING
, // thread is running (=> PAUSED, CANCELED)
54 STATE_PAUSED
, // thread is temporarily suspended (=> RUNNING)
55 STATE_CANCELED
, // thread should terminate a.s.a.p. (=> EXITED)
56 STATE_EXITED
// thread is terminating
59 // ----------------------------------------------------------------------------
60 // this module globals
61 // ----------------------------------------------------------------------------
64 // the task ID of the main thread
65 static wxThreadIdType gs_idMainThread
= kInvalidID
;
67 // this is the Per-Task Storage for the pointer to the appropriate wxThread
68 TaskStorageIndex gs_tlsForWXThread
= 0 ;
70 // if it's false, some secondary thread is holding the GUI lock
71 static bool gs_bGuiOwnedByMainThread
= true;
73 // critical section which controls access to all GUI functions: any secondary
74 // thread (i.e. except the main one) must enter this crit section before doing
76 static wxCriticalSection
*gs_critsectGui
= NULL
;
78 // critical section which protects gs_nWaitingForGui variable
79 static wxCriticalSection
*gs_critsectWaitingForGui
= NULL
;
81 // number of threads waiting for GUI in wxMutexGuiEnter()
82 static size_t gs_nWaitingForGui
= 0;
84 // overall number of threads, needed for determining the sleep value of the main
86 size_t g_numberOfThreads
= 0;
92 MPCriticalRegionID gs_guiCritical
= kInvalidID
;
96 // ============================================================================
97 // MacOS implementation of thread classes
98 // ============================================================================
103 The implementation is very close to the phtreads implementation, the reason for
104 using MPServices is the fact that these are also available under OS 9. Thus allowing
105 for one common API for all current builds.
107 As soon as wxThreads are on a 64 bit address space, the TLS must be extended
108 to use two indices one for each 32 bit part as the MP implementation is limited
111 I have two implementations for mutexes :
112 version A based on a binary semaphore, problem - not reentrant, version B based
113 on a critical region, allows for reentrancy, performance implications not
116 The same for condition internal, one implementation by Aj Lavin and the other one
117 copied from the thrimpl.cpp which I assume has been more broadly tested, I've just
118 replaced the interlock increment with the appropriate PPC calls
121 // ----------------------------------------------------------------------------
122 // wxMutex implementation
123 // ----------------------------------------------------------------------------
125 static bool wxMacMPThreadsInitVerify()
127 static bool hasThreadManager
= false ;
128 if ( !hasThreadManager
)
129 hasThreadManager
= MPLibraryIsLoaded();
131 if ( !hasThreadManager
)
133 wxMessageBox( wxT("Error") , wxT("MP Thread Support is not available on this System" ), wxOK
) ;
141 class wxMutexInternal
144 wxMutexInternal(wxMutexType mutexType
) ;
146 bool IsOk() const { return m_isOk
; }
148 wxMutexError
Lock() ;
149 wxMutexError
TryLock() ;
150 wxMutexError
Unlock();
152 MPSemaphoreID m_semaphore
;
156 wxMutexInternal::wxMutexInternal(wxMutexType mutexType
)
158 wxMacMPThreadsInitVerify() ;
161 m_semaphore
= kInvalidID
;
163 OSStatus err
= noErr
;
166 case wxMUTEX_DEFAULT
:
168 verify_noerr( MPCreateBinarySemaphore( & m_semaphore
) );
169 m_isOk
= ( m_semaphore
!= kInvalidID
) ;
172 case wxMUTEX_RECURSIVE
:
173 wxFAIL_MSG(wxT("Recursive Mutex not supported yet") ) ;
176 wxFAIL_MSG(wxT("Unknown mutex type") ) ;
181 wxMutexInternal::~wxMutexInternal()
183 if ( m_semaphore
!= kInvalidID
)
184 MPDeleteSemaphore( m_semaphore
);
187 wxMutexError
wxMutexInternal::Lock()
189 wxCHECK_MSG( m_isOk
, wxMUTEX_MISC_ERROR
, wxT("Invalid Mutex") ) ;
190 OSStatus err
= MPWaitOnSemaphore( m_semaphore
, kDurationForever
);
193 wxLogSysError(wxT("Could not lock mutex"));
194 return wxMUTEX_MISC_ERROR
;
197 return wxMUTEX_NO_ERROR
;
200 wxMutexError
wxMutexInternal::TryLock()
202 wxCHECK_MSG( m_isOk
, wxMUTEX_MISC_ERROR
, wxT("Invalid Mutex") ) ;
203 OSStatus err
= MPWaitOnSemaphore( m_semaphore
, kDurationImmediate
);
206 if ( err
== kMPTimeoutErr
)
210 wxLogSysError(wxT("Could not try lock mutex"));
211 return wxMUTEX_MISC_ERROR
;
214 return wxMUTEX_NO_ERROR
;
217 wxMutexError
wxMutexInternal::Unlock()
219 wxCHECK_MSG( m_isOk
, wxMUTEX_MISC_ERROR
, wxT("Invalid Mutex") ) ;
220 OSStatus err
= MPSignalSemaphore( m_semaphore
);
223 wxLogSysError(_("Could not unlock mutex"));
224 return wxMUTEX_MISC_ERROR
;
227 return wxMUTEX_NO_ERROR
;
232 class wxMutexInternal
235 wxMutexInternal(wxMutexType mutexType
) ;
237 bool IsOk() const { return m_isOk
; }
239 wxMutexError
Lock() ;
240 wxMutexError
TryLock() ;
241 wxMutexError
Unlock();
243 MPCriticalRegionID m_critRegion
;
247 wxMutexInternal::wxMutexInternal(wxMutexType mutexType
)
249 wxMacMPThreadsInitVerify() ;
251 m_critRegion
= kInvalidID
;
253 verify_noerr( MPCreateCriticalRegion( & m_critRegion
) );
254 m_isOk
= ( m_critRegion
!= kInvalidID
) ;
257 wxFAIL_MSG(wxT("Error when creating mutex") ) ;
260 wxMutexInternal::~wxMutexInternal()
262 if ( m_critRegion
!= kInvalidID
)
263 MPDeleteCriticalRegion( m_critRegion
);
266 wxMutexError
wxMutexInternal::Lock()
268 wxCHECK_MSG( m_isOk
, wxMUTEX_MISC_ERROR
, wxT("Invalid Mutex") ) ;
269 OSStatus err
= MPEnterCriticalRegion( m_critRegion
, kDurationForever
);
272 wxLogSysError(wxT("Could not lock mutex"));
273 return wxMUTEX_MISC_ERROR
;
276 return wxMUTEX_NO_ERROR
;
279 wxMutexError
wxMutexInternal::TryLock()
281 wxCHECK_MSG( m_isOk
, wxMUTEX_MISC_ERROR
, wxT("Invalid Mutex") ) ;
282 OSStatus err
= MPEnterCriticalRegion( m_critRegion
, kDurationImmediate
);
285 if ( err
== kMPTimeoutErr
)
289 wxLogSysError(wxT("Could not try lock mutex"));
290 return wxMUTEX_MISC_ERROR
;
293 return wxMUTEX_NO_ERROR
;
296 wxMutexError
wxMutexInternal::Unlock()
298 wxCHECK_MSG( m_isOk
, wxMUTEX_MISC_ERROR
, wxT("Invalid Mutex") ) ;
299 OSStatus err
= MPExitCriticalRegion( m_critRegion
);
302 wxLogSysError(_("Could not unlock mutex"));
303 return wxMUTEX_MISC_ERROR
;
306 return wxMUTEX_NO_ERROR
;
311 // --------------------------------------------------------------------------
313 // --------------------------------------------------------------------------
315 class wxSemaphoreInternal
318 wxSemaphoreInternal(int initialcount
, int maxcount
);
319 ~wxSemaphoreInternal();
321 bool IsOk() const { return m_isOk
; }
323 wxSemaError
WaitTimeout(unsigned long milliseconds
);
325 wxSemaError
Wait() { return WaitTimeout( kDurationForever
); }
327 wxSemaError
TryWait()
329 wxSemaError err
= WaitTimeout(kDurationImmediate
);
330 if ( err
== wxSEMA_TIMEOUT
)
337 MPSemaphoreID m_semaphore
;
341 wxSemaphoreInternal::wxSemaphoreInternal(int initialcount
, int maxcount
)
343 wxMacMPThreadsInitVerify() ;
345 m_semaphore
= kInvalidID
;
348 // make it practically infinite
351 verify_noerr( MPCreateSemaphore( maxcount
, initialcount
, & m_semaphore
) );
352 m_isOk
= ( m_semaphore
!= kInvalidID
) ;
355 wxFAIL_MSG(wxT("Error when creating semaphore") ) ;
358 wxSemaphoreInternal::~wxSemaphoreInternal()
360 if( m_semaphore
!= kInvalidID
)
361 MPDeleteSemaphore( m_semaphore
);
364 wxSemaError
wxSemaphoreInternal::WaitTimeout(unsigned long milliseconds
)
366 OSStatus err
= MPWaitOnSemaphore( m_semaphore
, milliseconds
);
369 if ( err
== kMPTimeoutErr
)
371 return wxSEMA_TIMEOUT
;
373 return wxSEMA_MISC_ERROR
;
375 return wxSEMA_NO_ERROR
;
378 wxSemaError
wxSemaphoreInternal::Post()
380 OSStatus err
= MPSignalSemaphore( m_semaphore
);
383 return wxSEMA_MISC_ERROR
;
385 return wxSEMA_NO_ERROR
;
388 // ----------------------------------------------------------------------------
389 // wxCondition implementation
390 // ----------------------------------------------------------------------------
394 class wxConditionInternal
398 wxConditionInternal(wxMutex
& mutex
)
408 ~wxConditionInternal()
412 bool IsOk() const { return m_mutex
.IsOk() ; }
416 return WaitTimeout( kDurationForever
);
419 wxCondError
WaitTimeout(unsigned long msectimeout
);
423 return DoSignal( false);
426 wxCondError
Broadcast()
428 return DoSignal( true);
433 wxCondError
DoSignal( bool signalAll
);
436 wxSemaphoreInternal m_semaphore
; // Signals the waiting threads.
437 wxSemaphoreInternal m_gate
;
438 wxCriticalSection m_varSection
;
439 size_t m_waiters
; // Number of threads waiting for a signal.
440 size_t m_signals
; // Number of signals to send.
441 size_t m_canceled
; // Number of canceled waiters in m_waiters.
445 wxCondError
wxConditionInternal::WaitTimeout(unsigned long msectimeout
)
448 if ( ++ m_waiters
== INT_MAX
)
450 m_varSection
.Enter();
451 m_waiters
-= m_canceled
;
452 m_signals
-= m_canceled
;
454 m_varSection
.Leave();
460 wxSemaError err
= m_semaphore
.WaitTimeout( msectimeout
);
461 wxASSERT( err
== wxSEMA_NO_ERROR
|| err
== wxSEMA_TIMEOUT
);
463 m_varSection
.Enter();
464 if ( err
!= wxSEMA_NO_ERROR
)
466 if ( m_signals
> m_canceled
)
468 // A signal is being sent after we timed out.
470 if ( m_waiters
== m_signals
)
472 // There are no excess waiters to catch the signal, so
473 // we must throw it away.
475 wxSemaError err2
= m_semaphore
.Wait();
476 if ( err2
!= wxSEMA_NO_ERROR
)
478 wxLogSysError(_("Error while waiting on semaphore"));
480 wxASSERT( err2
== wxSEMA_NO_ERROR
);
482 if ( -- m_signals
== m_canceled
)
484 // This was the last signal. open the gate.
485 wxASSERT( m_waiters
== m_canceled
);
491 // There are excess waiters to catch the signal, leave
498 // No signals is being sent.
499 // The gate may be open or closed, so we can't touch m_waiters.
506 // We caught a signal.
507 wxASSERT( m_signals
> m_canceled
);
509 if ( -- m_signals
== m_canceled
)
511 // This was the last signal. open the gate.
512 wxASSERT( m_waiters
== m_canceled
);
516 m_varSection
.Leave();
522 return err
== wxSEMA_TIMEOUT
? wxCOND_TIMEOUT
: wxCOND_MISC_ERROR
;
525 return wxCOND_NO_ERROR
;
529 wxCondError
wxConditionInternal::DoSignal( bool signalAll
)
532 m_varSection
.Enter();
534 wxASSERT( m_signals
== m_canceled
);
536 if ( m_waiters
== m_canceled
)
538 m_varSection
.Leave();
540 return wxCOND_NO_ERROR
;
545 m_waiters
-= m_canceled
;
550 m_signals
= signalAll
? m_waiters
: 1;
551 size_t n
= m_signals
;
553 m_varSection
.Leave();
555 // Let the waiters inherit the gate lock.
559 wxSemaError err
= m_semaphore
.Post();
560 wxASSERT( err
== wxSEMA_NO_ERROR
);
563 return wxCOND_NO_ERROR
;
567 class wxConditionInternal
570 wxConditionInternal(wxMutex
& mutex
);
572 bool IsOk() const { return m_mutex
.IsOk() && m_semaphore
.IsOk(); }
575 wxCondError
WaitTimeout(unsigned long milliseconds
);
577 wxCondError
Signal();
578 wxCondError
Broadcast();
581 // the number of threads currently waiting for this condition
584 // the critical section protecting m_numWaiters
585 wxCriticalSection m_csWaiters
;
588 wxSemaphore m_semaphore
;
590 DECLARE_NO_COPY_CLASS(wxConditionInternal
)
593 wxConditionInternal::wxConditionInternal(wxMutex
& mutex
)
596 // another thread can't access it until we return from ctor, so no need to
597 // protect access to m_numWaiters here
601 wxCondError
wxConditionInternal::Wait()
603 // increment the number of waiters
604 IncrementAtomic(&m_numWaiters
);
608 // a potential race condition can occur here
610 // after a thread increments nwaiters, and unlocks the mutex and before the
611 // semaphore.Wait() is called, if another thread can cause a signal to be
614 // this race condition is handled by using a semaphore and incrementing the
615 // semaphore only if 'nwaiters' is greater that zero since the semaphore,
616 // can 'remember' signals the race condition will not occur
618 // wait ( if necessary ) and decrement semaphore
619 wxSemaError err
= m_semaphore
.Wait();
622 return err
== wxSEMA_NO_ERROR
? wxCOND_NO_ERROR
: wxCOND_MISC_ERROR
;
625 wxCondError
wxConditionInternal::WaitTimeout(unsigned long milliseconds
)
627 IncrementAtomic(&m_numWaiters
);
631 // a race condition can occur at this point in the code
633 // please see the comments in Wait(), for details
635 wxSemaError err
= m_semaphore
.WaitTimeout(milliseconds
);
637 if ( err
== wxSEMA_BUSY
)
639 // another potential race condition exists here it is caused when a
640 // 'waiting' thread timesout, and returns from WaitForSingleObject, but
641 // has not yet decremented 'nwaiters'.
643 // at this point if another thread calls signal() then the semaphore
644 // will be incremented, but the waiting thread will miss it.
646 // to handle this particular case, the waiting thread calls
647 // WaitForSingleObject again with a timeout of 0, after locking
648 // 'nwaiters_mutex'. this call does not block because of the zero
649 // timeout, but will allow the waiting thread to catch the missed
651 wxCriticalSectionLocker
lock(m_csWaiters
);
653 err
= m_semaphore
.WaitTimeout(0);
655 if ( err
!= wxSEMA_NO_ERROR
)
663 return err
== wxSEMA_NO_ERROR
? wxCOND_NO_ERROR
: wxCOND_MISC_ERROR
;
666 wxCondError
wxConditionInternal::Signal()
668 wxCriticalSectionLocker
lock(m_csWaiters
);
670 if ( m_numWaiters
> 0 )
672 // increment the semaphore by 1
673 if ( m_semaphore
.Post() != wxSEMA_NO_ERROR
)
674 return wxCOND_MISC_ERROR
;
679 return wxCOND_NO_ERROR
;
682 wxCondError
wxConditionInternal::Broadcast()
684 wxCriticalSectionLocker
lock(m_csWaiters
);
686 while ( m_numWaiters
> 0 )
688 if ( m_semaphore
.Post() != wxSEMA_NO_ERROR
)
689 return wxCOND_MISC_ERROR
;
694 return wxCOND_NO_ERROR
;
698 // ----------------------------------------------------------------------------
699 // wxCriticalSection implementation
700 // ----------------------------------------------------------------------------
702 // XXX currently implemented as mutex in headers. Change to critical section.
704 // ----------------------------------------------------------------------------
705 // wxThread implementation
706 // ----------------------------------------------------------------------------
708 // wxThreadInternal class
709 // ----------------------
711 class wxThreadInternal
718 m_prio
= WXTHREAD_DEFAULT_PRIORITY
;
719 m_notifyQueueId
= kInvalidID
;
721 m_cancelled
= FALSE
;
723 // set to TRUE only when the thread starts waiting on m_semSuspend
726 // defaults for joinable threads
727 m_shouldBeJoined
= TRUE
;
728 m_isDetached
= FALSE
;
732 if ( m_notifyQueueId
)
734 MPDeleteQueue( m_notifyQueueId
);
735 m_notifyQueueId
= kInvalidID
;
740 static OSStatus
MacThreadStart(void* arg
);
742 // create a new (suspended) thread (for the given thread object)
743 bool Create(wxThread
*thread
, unsigned int stackSize
);
748 // unblock the thread allowing it to run
749 void SignalRun() { m_semRun
.Post(); }
750 // ask the thread to terminate
752 // go to sleep until Resume() is called
759 int GetPriority() const { return m_prio
; }
760 void SetPriority(int prio
) ;
762 wxThreadState
GetState() const { return m_state
; }
763 void SetState(wxThreadState state
) { m_state
= state
; }
765 // Get the ID of this thread's underlying MP Services task.
766 MPTaskID
GetId() const { return m_tid
; }
768 void SetCancelFlag() { m_cancelled
= TRUE
; }
769 bool WasCancelled() const { return m_cancelled
; }
771 void SetExitCode(wxThread::ExitCode exitcode
) { m_exitcode
= exitcode
; }
772 wxThread::ExitCode
GetExitCode() const { return m_exitcode
; }
775 void SetReallyPaused(bool paused
) { m_isPaused
= paused
; }
776 bool IsReallyPaused() const { return m_isPaused
; }
778 // tell the thread that it is a detached one
781 wxCriticalSectionLocker
lock(m_csJoinFlag
);
783 m_shouldBeJoined
= FALSE
;
788 // the thread we're associated with
791 MPTaskID m_tid
; // thread id
792 MPQueueID m_notifyQueueId
; // its notification queue
794 wxThreadState m_state
; // see wxThreadState enum
795 int m_prio
; // in wxWidgets units: from 0 to 100
797 // this flag is set when the thread should terminate
800 // this flag is set when the thread is blocking on m_semSuspend
803 // the thread exit code - only used for joinable (!detached) threads and
804 // is only valid after the thread termination
805 wxThread::ExitCode m_exitcode
;
807 // many threads may call Wait(), but only one of them should call
808 // pthread_join(), so we have to keep track of this
809 wxCriticalSection m_csJoinFlag
;
810 bool m_shouldBeJoined
;
813 // this semaphore is posted by Run() and the threads Entry() is not
814 // called before it is done
815 wxSemaphore m_semRun
;
817 // this one is signaled when the thread should resume after having been
819 wxSemaphore m_semSuspend
;
822 OSStatus
wxThreadInternal::MacThreadStart(void *parameter
)
824 wxThread
* thread
= (wxThread
*) parameter
;
825 wxThreadInternal
*pthread
= thread
->m_internal
;
827 // add to TLS so that This() will work
828 verify_noerr( MPSetTaskStorageValue( gs_tlsForWXThread
, (long) thread
) ) ;
830 // have to declare this before pthread_cleanup_push() which defines a
834 // wait for the semaphore to be posted from Run()
835 pthread
->m_semRun
.Wait();
837 // test whether we should run the run at all - may be it was deleted
838 // before it started to Run()?
840 wxCriticalSectionLocker
lock(thread
->m_critsect
);
842 dontRunAtAll
= pthread
->GetState() == STATE_NEW
&&
843 pthread
->WasCancelled();
848 pthread
->m_exitcode
= thread
->Entry();
851 wxCriticalSectionLocker
lock(thread
->m_critsect
);
852 pthread
->SetState(STATE_EXITED
);
858 if ( pthread
->m_isDetached
)
865 // on mac for the running code the correct thread termination is to
868 // terminate the thread
869 thread
->Exit(pthread
->m_exitcode
);
871 return (OSStatus
) NULL
; // pthread->m_exitcode;
875 bool wxThreadInternal::Create(wxThread
*thread
, unsigned int stackSize
)
877 wxMacMPThreadsInitVerify() ;
878 wxASSERT_MSG( m_state
== STATE_NEW
&& !m_tid
,
879 _T("Create()ing thread twice?") );
881 OSStatus err
= noErr
;
884 if ( m_notifyQueueId
== kInvalidID
)
886 OSStatus err
= MPCreateQueue( & m_notifyQueueId
);
889 wxLogSysError(_("Cant create the thread event queue"));
896 err
= MPCreateTask( MacThreadStart
,
907 wxLogSysError(_("Can't create thread"));
911 if ( m_prio
!= WXTHREAD_DEFAULT_PRIORITY
)
919 void wxThreadInternal::SetPriority( int priority
)
925 // Mac priorities range from 1 to 10,000, with a default of 100.
926 // wxWidgets priorities range from 0 to 100 with a default of 50.
927 // We can map wxWidgets to Mac priorities easily by assuming
928 // the former uses a logarithmic scale.
929 const unsigned int macPriority
= ( int)( exp( priority
/ 25.0 * log( 10.0)) + 0.5);
931 MPSetTaskWeight( m_tid
, macPriority
);
935 wxThreadError
wxThreadInternal::Run()
937 wxCHECK_MSG( GetState() == STATE_NEW
, wxTHREAD_RUNNING
,
938 wxT("thread may only be started once after Create()") );
940 SetState(STATE_RUNNING
);
942 // wake up threads waiting for our start
945 return wxTHREAD_NO_ERROR
;
948 void wxThreadInternal::Wait()
950 wxCHECK_RET( !m_isDetached
, _T("can't wait for a detached thread") );
952 // if the thread we're waiting for is waiting for the GUI mutex, we will
953 // deadlock so make sure we release it temporarily
954 if ( wxThread::IsMain() )
958 wxCriticalSectionLocker
lock(m_csJoinFlag
);
960 if ( m_shouldBeJoined
)
966 OSStatus err
= MPWaitOnQueue ( m_notifyQueueId
,
973 wxLogSysError( _( "Cannot wait for thread termination."));
977 // actually param1 would be the address of m_exitcode
978 // but we don't need this here
981 m_shouldBeJoined
= FALSE
;
985 // reacquire GUI mutex
986 if ( wxThread::IsMain() )
990 void wxThreadInternal::Pause()
992 // the state is set from the thread which pauses us first, this function
993 // is called later so the state should have been already set
994 wxCHECK_RET( m_state
== STATE_PAUSED
,
995 wxT("thread must first be paused with wxThread::Pause().") );
997 // wait until the semaphore is Post()ed from Resume()
1001 void wxThreadInternal::Resume()
1003 wxCHECK_RET( m_state
== STATE_PAUSED
,
1004 wxT("can't resume thread which is not suspended.") );
1006 // the thread might be not actually paused yet - if there were no call to
1007 // TestDestroy() since the last call to Pause() for example
1008 if ( IsReallyPaused() )
1011 m_semSuspend
.Post();
1014 SetReallyPaused(FALSE
);
1017 SetState(STATE_RUNNING
);
1023 wxThread
*wxThread::This()
1025 wxThread
* thr
= (wxThread
*) MPGetTaskStorageValue( gs_tlsForWXThread
) ;
1029 bool wxThread::IsMain()
1031 return GetCurrentId() == gs_idMainThread
;
1038 void wxThread::Yield()
1040 #if TARGET_API_MAC_OSX
1041 CFRunLoopRunInMode( kCFRunLoopDefaultMode
, 0 , true ) ;
1047 void wxThread::Sleep(unsigned long milliseconds
)
1049 AbsoluteTime wakeup
= AddDurationToAbsolute( milliseconds
, UpTime());
1050 MPDelayUntil( & wakeup
);
1054 int wxThread::GetCPUCount()
1056 return MPProcessors();
1059 unsigned long wxThread::GetCurrentId()
1061 return (unsigned long)MPCurrentTaskID();
1065 bool wxThread::SetConcurrency(size_t level
)
1067 // Cannot be set in MacOS.
1072 wxThread::wxThread(wxThreadKind kind
)
1074 g_numberOfThreads
++;
1075 m_internal
= new wxThreadInternal();
1077 m_isDetached
= (kind
== wxTHREAD_DETACHED
);
1080 wxThread::~wxThread()
1082 wxASSERT_MSG( g_numberOfThreads
>0 , wxT("More threads deleted than created.") ) ;
1083 g_numberOfThreads
--;
1088 // check that the thread either exited or couldn't be created
1089 if ( m_internal
->GetState() != STATE_EXITED
&&
1090 m_internal
->GetState() != STATE_NEW
)
1092 wxLogDebug(_T("The thread %ld is being destroyed although it is still running! The application may crash."), GetId());
1096 #endif // __WXDEBUG__
1098 wxDELETE( m_internal
) ;
1102 wxThreadError
wxThread::Create(unsigned int stackSize
)
1104 wxCriticalSectionLocker
lock(m_critsect
);
1108 m_internal
->Detach() ;
1110 if ( m_internal
->Create(this, stackSize
) == false )
1112 m_internal
->SetState(STATE_EXITED
);
1113 return wxTHREAD_NO_RESOURCE
;
1116 return wxTHREAD_NO_ERROR
;
1119 wxThreadError
wxThread::Run()
1121 wxCriticalSectionLocker
lock(m_critsect
);
1123 wxCHECK_MSG( m_internal
->GetId(), wxTHREAD_MISC_ERROR
,
1124 wxT("must call wxThread::Create() first") );
1126 return m_internal
->Run();
1129 // -----------------------------------------------------------------------------
1131 // -----------------------------------------------------------------------------
1133 wxThreadError
wxThread::Pause()
1135 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR
,
1136 _T("a thread can't pause itself") );
1138 wxCriticalSectionLocker
lock(m_critsect
);
1140 if ( m_internal
->GetState() != STATE_RUNNING
)
1142 wxLogDebug(wxT("Can't pause thread which is not running."));
1144 return wxTHREAD_NOT_RUNNING
;
1147 // just set a flag, the thread will be really paused only during the next
1148 // call to TestDestroy()
1149 m_internal
->SetState(STATE_PAUSED
);
1151 return wxTHREAD_NO_ERROR
;
1154 wxThreadError
wxThread::Resume()
1156 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR
,
1157 _T("a thread can't resume itself") );
1159 wxCriticalSectionLocker
lock(m_critsect
);
1161 wxThreadState state
= m_internal
->GetState();
1166 m_internal
->Resume();
1167 return wxTHREAD_NO_ERROR
;
1169 return wxTHREAD_NO_ERROR
;
1172 wxLogDebug(_T("Attempt to resume a thread which is not paused."));
1174 return wxTHREAD_MISC_ERROR
;
1178 // -----------------------------------------------------------------------------
1180 // -----------------------------------------------------------------------------
1182 wxThread::ExitCode
wxThread::Wait()
1184 wxCHECK_MSG( This() != this, (ExitCode
)-1,
1185 _T("a thread can't wait for itself") );
1187 wxCHECK_MSG( !m_isDetached
, (ExitCode
)-1,
1188 _T("can't wait for detached thread") );
1192 return m_internal
->GetExitCode();
1195 wxThreadError
wxThread::Delete(ExitCode
*rc
)
1197 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR
,
1198 _T("a thread can't delete itself") );
1200 bool isDetached
= m_isDetached
;
1203 wxThreadState state
= m_internal
->GetState();
1205 // ask the thread to stop
1206 m_internal
->SetCancelFlag();
1213 // we need to wake up the thread so that PthreadStart() will
1214 // terminate - right now it's blocking on run semaphore in
1216 m_internal
->SignalRun();
1225 // resume the thread first
1226 m_internal
->Resume();
1233 // wait until the thread stops
1238 // return the exit code of the thread
1239 *rc
= m_internal
->GetExitCode();
1242 //else: can't wait for detached threads
1245 return wxTHREAD_NO_ERROR
;
1248 wxThreadError
wxThread::Kill()
1250 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR
,
1251 _T("a thread can't kill itself") );
1253 switch ( m_internal
->GetState() )
1257 return wxTHREAD_NOT_RUNNING
;
1260 // resume the thread first
1266 OSStatus err
= MPTerminateTask( m_internal
->GetId() , -1 ) ;
1269 wxLogError(_("Failed to terminate a thread."));
1271 return wxTHREAD_MISC_ERROR
;
1280 // this should be retrieved by Wait actually
1281 m_internal
->SetExitCode((void*)-1);
1284 return wxTHREAD_NO_ERROR
;
1288 void wxThread::Exit(ExitCode status
)
1290 wxASSERT_MSG( This() == this,
1291 _T("wxThread::Exit() can only be called in the context of the same thread") );
1293 // don't enter m_critsect before calling OnExit() because the user code
1294 // might deadlock if, for example, it signals a condition in OnExit() (a
1295 // common case) while the main thread calls any of functions entering
1296 // m_critsect on us (almost all of them do)
1299 MPTerminateTask( m_internal
->GetId() , (long) status
) ;
1307 // update the status of the joinable thread
1308 wxCriticalSectionLocker
lock(m_critsect
);
1309 m_internal
->SetState(STATE_EXITED
);
1313 // also test whether we were paused
1314 bool wxThread::TestDestroy()
1316 wxASSERT_MSG( This() == this,
1317 _T("wxThread::TestDestroy() can only be called in the context of the same thread") );
1321 if ( m_internal
->GetState() == STATE_PAUSED
)
1323 m_internal
->SetReallyPaused(TRUE
);
1325 // leave the crit section or the other threads will stop too if they
1326 // try to call any of (seemingly harmless) IsXXX() functions while we
1330 m_internal
->Pause();
1334 // thread wasn't requested to pause, nothing to do
1338 return m_internal
->WasCancelled();
1341 // -----------------------------------------------------------------------------
1343 // -----------------------------------------------------------------------------
1345 void wxThread::SetPriority(unsigned int prio
)
1347 wxCHECK_RET( ((int)WXTHREAD_MIN_PRIORITY
<= (int)prio
) &&
1348 ((int)prio
<= (int)WXTHREAD_MAX_PRIORITY
),
1349 wxT("invalid thread priority") );
1351 wxCriticalSectionLocker
lock(m_critsect
);
1353 switch ( m_internal
->GetState() )
1358 // thread not yet started, priority will be set when it is
1359 m_internal
->SetPriority(prio
);
1364 wxFAIL_MSG(wxT("impossible to set thread priority in this state"));
1368 unsigned int wxThread::GetPriority() const
1370 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
); // const_cast
1372 return m_internal
->GetPriority();
1375 unsigned long wxThread::GetId() const
1377 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
); // const_cast
1379 return (unsigned long)m_internal
->GetId();
1382 // -----------------------------------------------------------------------------
1384 // -----------------------------------------------------------------------------
1386 bool wxThread::IsRunning() const
1388 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
1390 return m_internal
->GetState() == STATE_RUNNING
;
1393 bool wxThread::IsAlive() const
1395 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
1397 switch ( m_internal
->GetState() )
1408 bool wxThread::IsPaused() const
1410 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
1412 return (m_internal
->GetState() == STATE_PAUSED
);
1415 // ----------------------------------------------------------------------------
1416 // Automatic initialization for thread module
1417 // ----------------------------------------------------------------------------
1419 class wxThreadModule
: public wxModule
1422 virtual bool OnInit();
1423 virtual void OnExit();
1426 DECLARE_DYNAMIC_CLASS(wxThreadModule
)
1429 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule
, wxModule
)
1431 bool wxThreadModule::OnInit()
1433 if ( !wxMacMPThreadsInitVerify() )
1438 verify_noerr( MPAllocateTaskStorageIndex( &gs_tlsForWXThread
) ) ;
1439 // main thread's This() is NULL
1440 verify_noerr( MPSetTaskStorageValue( gs_tlsForWXThread
, NULL
) ) ;
1442 gs_idMainThread
= wxThread::GetCurrentId() ;
1444 gs_critsectWaitingForGui
= new wxCriticalSection();
1446 gs_critsectGui
= new wxCriticalSection();
1447 gs_critsectGui
->Enter();
1452 void wxThreadModule::OnExit()
1454 if ( gs_critsectGui
)
1456 gs_critsectGui
->Leave();
1457 delete gs_critsectGui
;
1458 gs_critsectGui
= NULL
;
1461 delete gs_critsectWaitingForGui
;
1462 gs_critsectWaitingForGui
= NULL
;
1465 // ----------------------------------------------------------------------------
1466 // GUI Serialization copied from MSW implementation
1467 // ----------------------------------------------------------------------------
1469 void WXDLLIMPEXP_BASE
wxMutexGuiEnter()
1471 // this would dead lock everything...
1472 wxASSERT_MSG( !wxThread::IsMain(),
1473 wxT("main thread doesn't want to block in wxMutexGuiEnter()!") );
1475 // the order in which we enter the critical sections here is crucial!!
1477 // set the flag telling to the main thread that we want to do some GUI
1479 wxCriticalSectionLocker
enter(*gs_critsectWaitingForGui
);
1481 gs_nWaitingForGui
++;
1484 wxWakeUpMainThread();
1486 // now we may block here because the main thread will soon let us in
1487 // (during the next iteration of OnIdle())
1488 gs_critsectGui
->Enter();
1491 void WXDLLIMPEXP_BASE
wxMutexGuiLeave()
1493 wxCriticalSectionLocker
enter(*gs_critsectWaitingForGui
);
1495 if ( wxThread::IsMain() )
1497 gs_bGuiOwnedByMainThread
= false;
1501 // decrement the number of threads waiting for GUI access now
1502 wxASSERT_MSG( gs_nWaitingForGui
> 0,
1503 wxT("calling wxMutexGuiLeave() without entering it first?") );
1505 gs_nWaitingForGui
--;
1507 wxWakeUpMainThread();
1510 gs_critsectGui
->Leave();
1513 void WXDLLIMPEXP_BASE
wxMutexGuiLeaveOrEnter()
1515 wxASSERT_MSG( wxThread::IsMain(),
1516 wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") );
1518 wxCriticalSectionLocker
enter(*gs_critsectWaitingForGui
);
1520 if ( gs_nWaitingForGui
== 0 )
1522 // no threads are waiting for GUI - so we may acquire the lock without
1523 // any danger (but only if we don't already have it)
1524 if ( !wxGuiOwnedByMainThread() )
1526 gs_critsectGui
->Enter();
1528 gs_bGuiOwnedByMainThread
= true;
1530 //else: already have it, nothing to do
1534 // some threads are waiting, release the GUI lock if we have it
1535 if ( wxGuiOwnedByMainThread() )
1539 //else: some other worker thread is doing GUI
1543 bool WXDLLIMPEXP_BASE
wxGuiOwnedByMainThread()
1545 return gs_bGuiOwnedByMainThread
;
1548 // wake up the main thread
1549 void WXDLLEXPORT
wxWakeUpMainThread()
1554 // ----------------------------------------------------------------------------
1555 // include common implementation code
1556 // ----------------------------------------------------------------------------
1558 #include "wx/thrimpl.cpp"
1560 #endif // wxUSE_THREADS