1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/mac/carbon/mpthread.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 // ----------------------------------------------------------------------------
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>
40 #include "wx/mac/uma.h"
43 // ----------------------------------------------------------------------------
45 // ----------------------------------------------------------------------------
47 // the possible states of the thread ("=>" shows all possible transitions from
51 STATE_NEW
, // didn't start execution yet (=> RUNNING)
52 STATE_RUNNING
, // thread is running (=> PAUSED, CANCELED)
53 STATE_PAUSED
, // thread is temporarily suspended (=> RUNNING)
54 STATE_CANCELED
, // thread should terminate a.s.a.p. (=> EXITED)
55 STATE_EXITED
// thread is terminating
58 // ----------------------------------------------------------------------------
59 // this module globals
60 // ----------------------------------------------------------------------------
63 // the task ID of the main thread
64 static wxThreadIdType gs_idMainThread
= kInvalidID
;
66 // this is the Per-Task Storage for the pointer to the appropriate wxThread
67 TaskStorageIndex gs_tlsForWXThread
= 0 ;
69 // if it's false, some secondary thread is holding the GUI lock
70 static bool gs_bGuiOwnedByMainThread
= true;
72 // critical section which controls access to all GUI functions: any secondary
73 // thread (i.e. except the main one) must enter this crit section before doing
75 static wxCriticalSection
*gs_critsectGui
= NULL
;
77 // critical section which protects gs_nWaitingForGui variable
78 static wxCriticalSection
*gs_critsectWaitingForGui
= NULL
;
80 // number of threads waiting for GUI in wxMutexGuiEnter()
81 static size_t gs_nWaitingForGui
= 0;
83 // overall number of threads, needed for determining the sleep value of the main
85 size_t g_numberOfThreads
= 0;
91 MPCriticalRegionID gs_guiCritical
= kInvalidID
;
95 // ============================================================================
96 // MacOS implementation of thread classes
97 // ============================================================================
102 The implementation is very close to the phtreads implementation, the reason for
103 using MPServices is the fact that these are also available under OS 9. Thus allowing
104 for one common API for all current builds.
106 As soon as wxThreads are on a 64 bit address space, the TLS must be extended
107 to use two indices one for each 32 bit part as the MP implementation is limited
110 I have two implementations for mutexes :
111 version A based on a binary semaphore, problem - not reentrant, version B based
112 on a critical region, allows for reentrancy, performance implications not
115 The same for condition internal, one implementation by Aj Lavin and the other one
116 copied from the thrimpl.cpp which I assume has been more broadly tested, I've just
117 replaced the interlock increment with the appropriate PPC calls
120 // ----------------------------------------------------------------------------
121 // wxMutex implementation
122 // ----------------------------------------------------------------------------
124 static bool wxMacMPThreadsInitVerify()
126 static bool hasThreadManager
= false ;
127 if ( !hasThreadManager
)
128 hasThreadManager
= MPLibraryIsLoaded();
130 if ( !hasThreadManager
)
132 wxMessageBox( wxT("Error") , wxT("MP Thread Support is not available on this System" ), wxOK
) ;
140 class wxMutexInternal
143 wxMutexInternal(wxMutexType mutexType
) ;
145 bool IsOk() const { return m_isOk
; }
147 wxMutexError
Lock() ;
148 wxMutexError
TryLock() ;
149 wxMutexError
Unlock();
151 MPSemaphoreID m_semaphore
;
155 wxMutexInternal::wxMutexInternal(wxMutexType mutexType
)
157 wxMacMPThreadsInitVerify() ;
160 m_semaphore
= kInvalidID
;
162 OSStatus err
= noErr
;
165 case wxMUTEX_DEFAULT
:
167 verify_noerr( MPCreateBinarySemaphore( & m_semaphore
) );
168 m_isOk
= ( m_semaphore
!= kInvalidID
) ;
171 case wxMUTEX_RECURSIVE
:
172 wxFAIL_MSG(wxT("Recursive Mutex not supported yet") ) ;
175 wxFAIL_MSG(wxT("Unknown mutex type") ) ;
180 wxMutexInternal::~wxMutexInternal()
182 if ( m_semaphore
!= kInvalidID
)
183 MPDeleteSemaphore( m_semaphore
);
186 wxMutexError
wxMutexInternal::Lock()
188 wxCHECK_MSG( m_isOk
, wxMUTEX_MISC_ERROR
, wxT("Invalid Mutex") ) ;
189 OSStatus err
= MPWaitOnSemaphore( m_semaphore
, kDurationForever
);
192 wxLogSysError(wxT("Could not lock mutex"));
193 return wxMUTEX_MISC_ERROR
;
196 return wxMUTEX_NO_ERROR
;
199 wxMutexError
wxMutexInternal::TryLock()
201 wxCHECK_MSG( m_isOk
, wxMUTEX_MISC_ERROR
, wxT("Invalid Mutex") ) ;
202 OSStatus err
= MPWaitOnSemaphore( m_semaphore
, kDurationImmediate
);
205 if ( err
== kMPTimeoutErr
)
209 wxLogSysError(wxT("Could not try lock mutex"));
210 return wxMUTEX_MISC_ERROR
;
213 return wxMUTEX_NO_ERROR
;
216 wxMutexError
wxMutexInternal::Unlock()
218 wxCHECK_MSG( m_isOk
, wxMUTEX_MISC_ERROR
, wxT("Invalid Mutex") ) ;
219 OSStatus err
= MPSignalSemaphore( m_semaphore
);
222 wxLogSysError(_("Could not unlock mutex"));
223 return wxMUTEX_MISC_ERROR
;
226 return wxMUTEX_NO_ERROR
;
231 class wxMutexInternal
234 wxMutexInternal(wxMutexType mutexType
) ;
236 bool IsOk() const { return m_isOk
; }
238 wxMutexError
Lock() ;
239 wxMutexError
TryLock() ;
240 wxMutexError
Unlock();
242 MPCriticalRegionID m_critRegion
;
246 wxMutexInternal::wxMutexInternal(wxMutexType mutexType
)
248 wxMacMPThreadsInitVerify() ;
250 m_critRegion
= kInvalidID
;
252 verify_noerr( MPCreateCriticalRegion( & m_critRegion
) );
253 m_isOk
= ( m_critRegion
!= kInvalidID
) ;
256 wxFAIL_MSG(wxT("Error when creating mutex") ) ;
259 wxMutexInternal::~wxMutexInternal()
261 if ( m_critRegion
!= kInvalidID
)
262 MPDeleteCriticalRegion( m_critRegion
);
265 wxMutexError
wxMutexInternal::Lock()
267 wxCHECK_MSG( m_isOk
, wxMUTEX_MISC_ERROR
, wxT("Invalid Mutex") ) ;
268 OSStatus err
= MPEnterCriticalRegion( m_critRegion
, kDurationForever
);
271 wxLogSysError(wxT("Could not lock mutex"));
272 return wxMUTEX_MISC_ERROR
;
275 return wxMUTEX_NO_ERROR
;
278 wxMutexError
wxMutexInternal::TryLock()
280 wxCHECK_MSG( m_isOk
, wxMUTEX_MISC_ERROR
, wxT("Invalid Mutex") ) ;
281 OSStatus err
= MPEnterCriticalRegion( m_critRegion
, kDurationImmediate
);
284 if ( err
== kMPTimeoutErr
)
288 wxLogSysError(wxT("Could not try lock mutex"));
289 return wxMUTEX_MISC_ERROR
;
292 return wxMUTEX_NO_ERROR
;
295 wxMutexError
wxMutexInternal::Unlock()
297 wxCHECK_MSG( m_isOk
, wxMUTEX_MISC_ERROR
, wxT("Invalid Mutex") ) ;
298 OSStatus err
= MPExitCriticalRegion( m_critRegion
);
301 wxLogSysError(_("Could not unlock mutex"));
302 return wxMUTEX_MISC_ERROR
;
305 return wxMUTEX_NO_ERROR
;
310 // --------------------------------------------------------------------------
312 // --------------------------------------------------------------------------
314 class wxSemaphoreInternal
317 wxSemaphoreInternal(int initialcount
, int maxcount
);
318 ~wxSemaphoreInternal();
320 bool IsOk() const { return m_isOk
; }
322 wxSemaError
WaitTimeout(unsigned long milliseconds
);
324 wxSemaError
Wait() { return WaitTimeout( kDurationForever
); }
326 wxSemaError
TryWait()
328 wxSemaError err
= WaitTimeout(kDurationImmediate
);
329 if ( err
== wxSEMA_TIMEOUT
)
336 MPSemaphoreID m_semaphore
;
340 wxSemaphoreInternal::wxSemaphoreInternal(int initialcount
, int maxcount
)
342 wxMacMPThreadsInitVerify() ;
344 m_semaphore
= kInvalidID
;
347 // make it practically infinite
350 verify_noerr( MPCreateSemaphore( maxcount
, initialcount
, & m_semaphore
) );
351 m_isOk
= ( m_semaphore
!= kInvalidID
) ;
354 wxFAIL_MSG(wxT("Error when creating semaphore") ) ;
357 wxSemaphoreInternal::~wxSemaphoreInternal()
359 if( m_semaphore
!= kInvalidID
)
360 MPDeleteSemaphore( m_semaphore
);
363 wxSemaError
wxSemaphoreInternal::WaitTimeout(unsigned long milliseconds
)
365 OSStatus err
= MPWaitOnSemaphore( m_semaphore
, milliseconds
);
368 if ( err
== kMPTimeoutErr
)
370 return wxSEMA_TIMEOUT
;
372 return wxSEMA_MISC_ERROR
;
374 return wxSEMA_NO_ERROR
;
377 wxSemaError
wxSemaphoreInternal::Post()
379 OSStatus err
= MPSignalSemaphore( m_semaphore
);
382 return wxSEMA_MISC_ERROR
;
384 return wxSEMA_NO_ERROR
;
387 // ----------------------------------------------------------------------------
388 // wxCondition implementation
389 // ----------------------------------------------------------------------------
393 class wxConditionInternal
397 wxConditionInternal(wxMutex
& mutex
)
407 ~wxConditionInternal()
411 bool IsOk() const { return m_mutex
.IsOk() ; }
415 return WaitTimeout( kDurationForever
);
418 wxCondError
WaitTimeout(unsigned long msectimeout
);
422 return DoSignal( false);
425 wxCondError
Broadcast()
427 return DoSignal( true);
432 wxCondError
DoSignal( bool signalAll
);
435 wxSemaphoreInternal m_semaphore
; // Signals the waiting threads.
436 wxSemaphoreInternal m_gate
;
437 wxCriticalSection m_varSection
;
438 size_t m_waiters
; // Number of threads waiting for a signal.
439 size_t m_signals
; // Number of signals to send.
440 size_t m_canceled
; // Number of canceled waiters in m_waiters.
444 wxCondError
wxConditionInternal::WaitTimeout(unsigned long msectimeout
)
447 if ( ++ m_waiters
== INT_MAX
)
449 m_varSection
.Enter();
450 m_waiters
-= m_canceled
;
451 m_signals
-= m_canceled
;
453 m_varSection
.Leave();
459 wxSemaError err
= m_semaphore
.WaitTimeout( msectimeout
);
460 wxASSERT( err
== wxSEMA_NO_ERROR
|| err
== wxSEMA_TIMEOUT
);
462 m_varSection
.Enter();
463 if ( err
!= wxSEMA_NO_ERROR
)
465 if ( m_signals
> m_canceled
)
467 // A signal is being sent after we timed out.
469 if ( m_waiters
== m_signals
)
471 // There are no excess waiters to catch the signal, so
472 // we must throw it away.
474 wxSemaError err2
= m_semaphore
.Wait();
475 if ( err2
!= wxSEMA_NO_ERROR
)
477 wxLogSysError(_("Error while waiting on semaphore"));
479 wxASSERT( err2
== wxSEMA_NO_ERROR
);
481 if ( -- m_signals
== m_canceled
)
483 // This was the last signal. open the gate.
484 wxASSERT( m_waiters
== m_canceled
);
490 // There are excess waiters to catch the signal, leave
497 // No signals is being sent.
498 // The gate may be open or closed, so we can't touch m_waiters.
505 // We caught a signal.
506 wxASSERT( m_signals
> m_canceled
);
508 if ( -- m_signals
== m_canceled
)
510 // This was the last signal. open the gate.
511 wxASSERT( m_waiters
== m_canceled
);
515 m_varSection
.Leave();
521 return err
== wxSEMA_TIMEOUT
? wxCOND_TIMEOUT
: wxCOND_MISC_ERROR
;
524 return wxCOND_NO_ERROR
;
528 wxCondError
wxConditionInternal::DoSignal( bool signalAll
)
531 m_varSection
.Enter();
533 wxASSERT( m_signals
== m_canceled
);
535 if ( m_waiters
== m_canceled
)
537 m_varSection
.Leave();
539 return wxCOND_NO_ERROR
;
544 m_waiters
-= m_canceled
;
549 m_signals
= signalAll
? m_waiters
: 1;
550 size_t n
= m_signals
;
552 m_varSection
.Leave();
554 // Let the waiters inherit the gate lock.
558 wxSemaError err
= m_semaphore
.Post();
559 wxASSERT( err
== wxSEMA_NO_ERROR
);
562 return wxCOND_NO_ERROR
;
566 class wxConditionInternal
569 wxConditionInternal(wxMutex
& mutex
);
571 bool IsOk() const { return m_mutex
.IsOk() && m_semaphore
.IsOk(); }
574 wxCondError
WaitTimeout(unsigned long milliseconds
);
576 wxCondError
Signal();
577 wxCondError
Broadcast();
580 // the number of threads currently waiting for this condition
583 // the critical section protecting m_numWaiters
584 wxCriticalSection m_csWaiters
;
587 wxSemaphore m_semaphore
;
589 DECLARE_NO_COPY_CLASS(wxConditionInternal
)
592 wxConditionInternal::wxConditionInternal(wxMutex
& mutex
)
595 // another thread can't access it until we return from ctor, so no need to
596 // protect access to m_numWaiters here
600 wxCondError
wxConditionInternal::Wait()
602 // increment the number of waiters
603 IncrementAtomic(&m_numWaiters
);
607 // a potential race condition can occur here
609 // after a thread increments nwaiters, and unlocks the mutex and before the
610 // semaphore.Wait() is called, if another thread can cause a signal to be
613 // this race condition is handled by using a semaphore and incrementing the
614 // semaphore only if 'nwaiters' is greater that zero since the semaphore,
615 // can 'remember' signals the race condition will not occur
617 // wait ( if necessary ) and decrement semaphore
618 wxSemaError err
= m_semaphore
.Wait();
621 return err
== wxSEMA_NO_ERROR
? wxCOND_NO_ERROR
: wxCOND_MISC_ERROR
;
624 wxCondError
wxConditionInternal::WaitTimeout(unsigned long milliseconds
)
626 IncrementAtomic(&m_numWaiters
);
630 // a race condition can occur at this point in the code
632 // please see the comments in Wait(), for details
634 wxSemaError err
= m_semaphore
.WaitTimeout(milliseconds
);
636 if ( err
== wxSEMA_BUSY
)
638 // another potential race condition exists here it is caused when a
639 // 'waiting' thread timesout, and returns from WaitForSingleObject, but
640 // has not yet decremented 'nwaiters'.
642 // at this point if another thread calls signal() then the semaphore
643 // will be incremented, but the waiting thread will miss it.
645 // to handle this particular case, the waiting thread calls
646 // WaitForSingleObject again with a timeout of 0, after locking
647 // 'nwaiters_mutex'. this call does not block because of the zero
648 // timeout, but will allow the waiting thread to catch the missed
650 wxCriticalSectionLocker
lock(m_csWaiters
);
652 err
= m_semaphore
.WaitTimeout(0);
654 if ( err
!= wxSEMA_NO_ERROR
)
662 return err
== wxSEMA_NO_ERROR
? wxCOND_NO_ERROR
: wxCOND_MISC_ERROR
;
665 wxCondError
wxConditionInternal::Signal()
667 wxCriticalSectionLocker
lock(m_csWaiters
);
669 if ( m_numWaiters
> 0 )
671 // increment the semaphore by 1
672 if ( m_semaphore
.Post() != wxSEMA_NO_ERROR
)
673 return wxCOND_MISC_ERROR
;
678 return wxCOND_NO_ERROR
;
681 wxCondError
wxConditionInternal::Broadcast()
683 wxCriticalSectionLocker
lock(m_csWaiters
);
685 while ( m_numWaiters
> 0 )
687 if ( m_semaphore
.Post() != wxSEMA_NO_ERROR
)
688 return wxCOND_MISC_ERROR
;
693 return wxCOND_NO_ERROR
;
697 // ----------------------------------------------------------------------------
698 // wxCriticalSection implementation
699 // ----------------------------------------------------------------------------
701 // XXX currently implemented as mutex in headers. Change to critical section.
703 // ----------------------------------------------------------------------------
704 // wxThread implementation
705 // ----------------------------------------------------------------------------
707 // wxThreadInternal class
708 // ----------------------
710 class wxThreadInternal
717 m_prio
= WXTHREAD_DEFAULT_PRIORITY
;
718 m_notifyQueueId
= kInvalidID
;
720 m_cancelled
= false ;
722 // set to true only when the thread starts waiting on m_semSuspend
725 // defaults for joinable threads
726 m_shouldBeJoined
= true;
727 m_isDetached
= false;
731 if ( m_notifyQueueId
)
733 MPDeleteQueue( m_notifyQueueId
);
734 m_notifyQueueId
= kInvalidID
;
739 static OSStatus
MacThreadStart(void* arg
);
741 // create a new (suspended) thread (for the given thread object)
742 bool Create(wxThread
*thread
, unsigned int stackSize
);
747 // unblock the thread allowing it to run
748 void SignalRun() { m_semRun
.Post(); }
749 // ask the thread to terminate
751 // go to sleep until Resume() is called
758 int GetPriority() const { return m_prio
; }
759 void SetPriority(int prio
) ;
761 wxThreadState
GetState() const { return m_state
; }
762 void SetState(wxThreadState state
) { m_state
= state
; }
764 // Get the ID of this thread's underlying MP Services task.
765 MPTaskID
GetId() const { return m_tid
; }
767 void SetCancelFlag() { m_cancelled
= true; }
768 bool WasCancelled() const { return m_cancelled
; }
770 void SetExitCode(wxThread::ExitCode exitcode
) { m_exitcode
= exitcode
; }
771 wxThread::ExitCode
GetExitCode() const { return m_exitcode
; }
774 void SetReallyPaused(bool paused
) { m_isPaused
= paused
; }
775 bool IsReallyPaused() const { return m_isPaused
; }
777 // tell the thread that it is a detached one
780 wxCriticalSectionLocker
lock(m_csJoinFlag
);
782 m_shouldBeJoined
= false;
787 // the thread we're associated with
790 MPTaskID m_tid
; // thread id
791 MPQueueID m_notifyQueueId
; // its notification queue
793 wxThreadState m_state
; // see wxThreadState enum
794 int m_prio
; // in wxWidgets units: from 0 to 100
796 // this flag is set when the thread should terminate
799 // this flag is set when the thread is blocking on m_semSuspend
802 // the thread exit code - only used for joinable (!detached) threads and
803 // is only valid after the thread termination
804 wxThread::ExitCode m_exitcode
;
806 // many threads may call Wait(), but only one of them should call
807 // pthread_join(), so we have to keep track of this
808 wxCriticalSection m_csJoinFlag
;
809 bool m_shouldBeJoined
;
812 // this semaphore is posted by Run() and the threads Entry() is not
813 // called before it is done
814 wxSemaphore m_semRun
;
816 // this one is signaled when the thread should resume after having been
818 wxSemaphore m_semSuspend
;
821 OSStatus
wxThreadInternal::MacThreadStart(void *parameter
)
823 wxThread
* thread
= (wxThread
*) parameter
;
824 wxThreadInternal
*pthread
= thread
->m_internal
;
826 // add to TLS so that This() will work
827 verify_noerr( MPSetTaskStorageValue( gs_tlsForWXThread
, (long) thread
) ) ;
829 // have to declare this before pthread_cleanup_push() which defines a
833 // wait for the semaphore to be posted from Run()
834 pthread
->m_semRun
.Wait();
836 // test whether we should run the run at all - may be it was deleted
837 // before it started to Run()?
839 wxCriticalSectionLocker
lock(thread
->m_critsect
);
841 dontRunAtAll
= pthread
->GetState() == STATE_NEW
&&
842 pthread
->WasCancelled();
847 pthread
->m_exitcode
= thread
->Entry();
850 wxCriticalSectionLocker
lock(thread
->m_critsect
);
851 pthread
->SetState(STATE_EXITED
);
857 if ( pthread
->m_isDetached
)
864 // on mac for the running code the correct thread termination is to
867 // terminate the thread
868 thread
->Exit(pthread
->m_exitcode
);
870 return (OSStatus
) NULL
; // pthread->m_exitcode;
874 bool wxThreadInternal::Create(wxThread
*thread
, unsigned int stackSize
)
876 wxMacMPThreadsInitVerify() ;
877 wxASSERT_MSG( m_state
== STATE_NEW
&& !m_tid
,
878 _T("Create()ing thread twice?") );
880 OSStatus err
= noErr
;
883 if ( m_notifyQueueId
== kInvalidID
)
885 OSStatus err
= MPCreateQueue( & m_notifyQueueId
);
888 wxLogSysError(_("Cant create the thread event queue"));
895 err
= MPCreateTask( MacThreadStart
,
906 wxLogSysError(_("Can't create thread"));
910 if ( m_prio
!= WXTHREAD_DEFAULT_PRIORITY
)
918 void wxThreadInternal::SetPriority( int priority
)
924 // Mac priorities range from 1 to 10,000, with a default of 100.
925 // wxWidgets priorities range from 0 to 100 with a default of 50.
926 // We can map wxWidgets to Mac priorities easily by assuming
927 // the former uses a logarithmic scale.
928 const unsigned int macPriority
= ( int)( exp( priority
/ 25.0 * log( 10.0)) + 0.5);
930 MPSetTaskWeight( m_tid
, macPriority
);
934 wxThreadError
wxThreadInternal::Run()
936 wxCHECK_MSG( GetState() == STATE_NEW
, wxTHREAD_RUNNING
,
937 wxT("thread may only be started once after Create()") );
939 SetState(STATE_RUNNING
);
941 // wake up threads waiting for our start
944 return wxTHREAD_NO_ERROR
;
947 void wxThreadInternal::Wait()
949 wxCHECK_RET( !m_isDetached
, _T("can't wait for a detached thread") );
951 // if the thread we're waiting for is waiting for the GUI mutex, we will
952 // deadlock so make sure we release it temporarily
953 if ( wxThread::IsMain() )
957 wxCriticalSectionLocker
lock(m_csJoinFlag
);
959 if ( m_shouldBeJoined
)
965 OSStatus err
= MPWaitOnQueue ( m_notifyQueueId
,
972 wxLogSysError( _( "Cannot wait for thread termination."));
976 // actually param1 would be the address of m_exitcode
977 // but we don't need this here
980 m_shouldBeJoined
= false;
984 // reacquire GUI mutex
985 if ( wxThread::IsMain() )
989 void wxThreadInternal::Pause()
991 // the state is set from the thread which pauses us first, this function
992 // is called later so the state should have been already set
993 wxCHECK_RET( m_state
== STATE_PAUSED
,
994 wxT("thread must first be paused with wxThread::Pause().") );
996 // wait until the semaphore is Post()ed from Resume()
1000 void wxThreadInternal::Resume()
1002 wxCHECK_RET( m_state
== STATE_PAUSED
,
1003 wxT("can't resume thread which is not suspended.") );
1005 // the thread might be not actually paused yet - if there were no call to
1006 // TestDestroy() since the last call to Pause() for example
1007 if ( IsReallyPaused() )
1010 m_semSuspend
.Post();
1013 SetReallyPaused(FALSE
);
1016 SetState(STATE_RUNNING
);
1022 wxThread
*wxThread::This()
1024 wxThread
* thr
= (wxThread
*) MPGetTaskStorageValue( gs_tlsForWXThread
) ;
1028 bool wxThread::IsMain()
1030 return GetCurrentId() == gs_idMainThread
;
1037 void wxThread::Yield()
1039 #if TARGET_API_MAC_OSX
1040 CFRunLoopRunInMode( kCFRunLoopDefaultMode
, 0 , true ) ;
1046 void wxThread::Sleep(unsigned long milliseconds
)
1048 AbsoluteTime wakeup
= AddDurationToAbsolute( milliseconds
, UpTime());
1049 MPDelayUntil( & wakeup
);
1053 int wxThread::GetCPUCount()
1055 return MPProcessors();
1058 unsigned long wxThread::GetCurrentId()
1060 return (unsigned long)MPCurrentTaskID();
1064 bool wxThread::SetConcurrency(size_t level
)
1066 // Cannot be set in MacOS.
1071 wxThread::wxThread(wxThreadKind kind
)
1073 g_numberOfThreads
++;
1074 m_internal
= new wxThreadInternal();
1076 m_isDetached
= (kind
== wxTHREAD_DETACHED
);
1079 wxThread::~wxThread()
1081 wxASSERT_MSG( g_numberOfThreads
>0 , wxT("More threads deleted than created.") ) ;
1082 g_numberOfThreads
--;
1087 // check that the thread either exited or couldn't be created
1088 if ( m_internal
->GetState() != STATE_EXITED
&&
1089 m_internal
->GetState() != STATE_NEW
)
1091 wxLogDebug(_T("The thread %ld is being destroyed although it is still running! The application may crash."), GetId());
1095 #endif // __WXDEBUG__
1097 wxDELETE( m_internal
) ;
1101 wxThreadError
wxThread::Create(unsigned int stackSize
)
1103 wxCriticalSectionLocker
lock(m_critsect
);
1107 m_internal
->Detach() ;
1109 if ( m_internal
->Create(this, stackSize
) == false )
1111 m_internal
->SetState(STATE_EXITED
);
1112 return wxTHREAD_NO_RESOURCE
;
1115 return wxTHREAD_NO_ERROR
;
1118 wxThreadError
wxThread::Run()
1120 wxCriticalSectionLocker
lock(m_critsect
);
1122 wxCHECK_MSG( m_internal
->GetId(), wxTHREAD_MISC_ERROR
,
1123 wxT("must call wxThread::Create() first") );
1125 return m_internal
->Run();
1128 // -----------------------------------------------------------------------------
1130 // -----------------------------------------------------------------------------
1132 wxThreadError
wxThread::Pause()
1134 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR
,
1135 _T("a thread can't pause itself") );
1137 wxCriticalSectionLocker
lock(m_critsect
);
1139 if ( m_internal
->GetState() != STATE_RUNNING
)
1141 wxLogDebug(wxT("Can't pause thread which is not running."));
1143 return wxTHREAD_NOT_RUNNING
;
1146 // just set a flag, the thread will be really paused only during the next
1147 // call to TestDestroy()
1148 m_internal
->SetState(STATE_PAUSED
);
1150 return wxTHREAD_NO_ERROR
;
1153 wxThreadError
wxThread::Resume()
1155 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR
,
1156 _T("a thread can't resume itself") );
1158 wxCriticalSectionLocker
lock(m_critsect
);
1160 wxThreadState state
= m_internal
->GetState();
1165 m_internal
->Resume();
1166 return wxTHREAD_NO_ERROR
;
1168 return wxTHREAD_NO_ERROR
;
1171 wxLogDebug(_T("Attempt to resume a thread which is not paused."));
1173 return wxTHREAD_MISC_ERROR
;
1177 // -----------------------------------------------------------------------------
1179 // -----------------------------------------------------------------------------
1181 wxThread::ExitCode
wxThread::Wait()
1183 wxCHECK_MSG( This() != this, (ExitCode
)-1,
1184 _T("a thread can't wait for itself") );
1186 wxCHECK_MSG( !m_isDetached
, (ExitCode
)-1,
1187 _T("can't wait for detached thread") );
1191 return m_internal
->GetExitCode();
1194 wxThreadError
wxThread::Delete(ExitCode
*rc
)
1196 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR
,
1197 _T("a thread can't delete itself") );
1199 bool isDetached
= m_isDetached
;
1202 wxThreadState state
= m_internal
->GetState();
1204 // ask the thread to stop
1205 m_internal
->SetCancelFlag();
1212 // we need to wake up the thread so that PthreadStart() will
1213 // terminate - right now it's blocking on run semaphore in
1215 m_internal
->SignalRun();
1224 // resume the thread first
1225 m_internal
->Resume();
1232 // wait until the thread stops
1237 // return the exit code of the thread
1238 *rc
= m_internal
->GetExitCode();
1241 //else: can't wait for detached threads
1244 return wxTHREAD_NO_ERROR
;
1247 wxThreadError
wxThread::Kill()
1249 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR
,
1250 _T("a thread can't kill itself") );
1252 switch ( m_internal
->GetState() )
1256 return wxTHREAD_NOT_RUNNING
;
1259 // resume the thread first
1265 OSStatus err
= MPTerminateTask( m_internal
->GetId() , -1 ) ;
1268 wxLogError(_("Failed to terminate a thread."));
1270 return wxTHREAD_MISC_ERROR
;
1279 // this should be retrieved by Wait actually
1280 m_internal
->SetExitCode((void*)-1);
1283 return wxTHREAD_NO_ERROR
;
1287 void wxThread::Exit(ExitCode status
)
1289 wxASSERT_MSG( This() == this,
1290 _T("wxThread::Exit() can only be called in the context of the same thread") );
1292 // don't enter m_critsect before calling OnExit() because the user code
1293 // might deadlock if, for example, it signals a condition in OnExit() (a
1294 // common case) while the main thread calls any of functions entering
1295 // m_critsect on us (almost all of them do)
1298 MPTerminateTask( m_internal
->GetId() , (long) status
) ;
1306 // update the status of the joinable thread
1307 wxCriticalSectionLocker
lock(m_critsect
);
1308 m_internal
->SetState(STATE_EXITED
);
1312 // also test whether we were paused
1313 bool wxThread::TestDestroy()
1315 wxASSERT_MSG( This() == this,
1316 _T("wxThread::TestDestroy() can only be called in the context of the same thread") );
1320 if ( m_internal
->GetState() == STATE_PAUSED
)
1322 m_internal
->SetReallyPaused(TRUE
);
1324 // leave the crit section or the other threads will stop too if they
1325 // try to call any of (seemingly harmless) IsXXX() functions while we
1329 m_internal
->Pause();
1333 // thread wasn't requested to pause, nothing to do
1337 return m_internal
->WasCancelled();
1340 // -----------------------------------------------------------------------------
1342 // -----------------------------------------------------------------------------
1344 void wxThread::SetPriority(unsigned int prio
)
1346 wxCHECK_RET( ((int)WXTHREAD_MIN_PRIORITY
<= (int)prio
) &&
1347 ((int)prio
<= (int)WXTHREAD_MAX_PRIORITY
),
1348 wxT("invalid thread priority") );
1350 wxCriticalSectionLocker
lock(m_critsect
);
1352 switch ( m_internal
->GetState() )
1357 // thread not yet started, priority will be set when it is
1358 m_internal
->SetPriority(prio
);
1363 wxFAIL_MSG(wxT("impossible to set thread priority in this state"));
1367 unsigned int wxThread::GetPriority() const
1369 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
); // const_cast
1371 return m_internal
->GetPriority();
1374 unsigned long wxThread::GetId() const
1376 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
); // const_cast
1378 return (unsigned long)m_internal
->GetId();
1381 // -----------------------------------------------------------------------------
1383 // -----------------------------------------------------------------------------
1385 bool wxThread::IsRunning() const
1387 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
1389 return m_internal
->GetState() == STATE_RUNNING
;
1392 bool wxThread::IsAlive() const
1394 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
1396 switch ( m_internal
->GetState() )
1407 bool wxThread::IsPaused() const
1409 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
1411 return (m_internal
->GetState() == STATE_PAUSED
);
1414 // ----------------------------------------------------------------------------
1415 // Automatic initialization for thread module
1416 // ----------------------------------------------------------------------------
1418 class wxThreadModule
: public wxModule
1421 virtual bool OnInit();
1422 virtual void OnExit();
1425 DECLARE_DYNAMIC_CLASS(wxThreadModule
)
1428 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule
, wxModule
)
1430 bool wxThreadModule::OnInit()
1432 if ( !wxMacMPThreadsInitVerify() )
1437 verify_noerr( MPAllocateTaskStorageIndex( &gs_tlsForWXThread
) ) ;
1438 // main thread's This() is NULL
1439 verify_noerr( MPSetTaskStorageValue( gs_tlsForWXThread
, NULL
) ) ;
1441 gs_idMainThread
= wxThread::GetCurrentId() ;
1443 gs_critsectWaitingForGui
= new wxCriticalSection();
1445 gs_critsectGui
= new wxCriticalSection();
1446 gs_critsectGui
->Enter();
1451 void wxThreadModule::OnExit()
1453 if ( gs_critsectGui
)
1455 gs_critsectGui
->Leave();
1456 delete gs_critsectGui
;
1457 gs_critsectGui
= NULL
;
1460 delete gs_critsectWaitingForGui
;
1461 gs_critsectWaitingForGui
= NULL
;
1464 // ----------------------------------------------------------------------------
1465 // GUI Serialization copied from MSW implementation
1466 // ----------------------------------------------------------------------------
1468 void WXDLLIMPEXP_BASE
wxMutexGuiEnter()
1470 // this would dead lock everything...
1471 wxASSERT_MSG( !wxThread::IsMain(),
1472 wxT("main thread doesn't want to block in wxMutexGuiEnter()!") );
1474 // the order in which we enter the critical sections here is crucial!!
1476 // set the flag telling to the main thread that we want to do some GUI
1478 wxCriticalSectionLocker
enter(*gs_critsectWaitingForGui
);
1480 gs_nWaitingForGui
++;
1483 wxWakeUpMainThread();
1485 // now we may block here because the main thread will soon let us in
1486 // (during the next iteration of OnIdle())
1487 gs_critsectGui
->Enter();
1490 void WXDLLIMPEXP_BASE
wxMutexGuiLeave()
1492 wxCriticalSectionLocker
enter(*gs_critsectWaitingForGui
);
1494 if ( wxThread::IsMain() )
1496 gs_bGuiOwnedByMainThread
= false;
1500 // decrement the number of threads waiting for GUI access now
1501 wxASSERT_MSG( gs_nWaitingForGui
> 0,
1502 wxT("calling wxMutexGuiLeave() without entering it first?") );
1504 gs_nWaitingForGui
--;
1506 wxWakeUpMainThread();
1509 gs_critsectGui
->Leave();
1512 void WXDLLIMPEXP_BASE
wxMutexGuiLeaveOrEnter()
1514 wxASSERT_MSG( wxThread::IsMain(),
1515 wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") );
1517 wxCriticalSectionLocker
enter(*gs_critsectWaitingForGui
);
1519 if ( gs_nWaitingForGui
== 0 )
1521 // no threads are waiting for GUI - so we may acquire the lock without
1522 // any danger (but only if we don't already have it)
1523 if ( !wxGuiOwnedByMainThread() )
1525 gs_critsectGui
->Enter();
1527 gs_bGuiOwnedByMainThread
= true;
1529 //else: already have it, nothing to do
1533 // some threads are waiting, release the GUI lock if we have it
1534 if ( wxGuiOwnedByMainThread() )
1538 //else: some other worker thread is doing GUI
1542 bool WXDLLIMPEXP_BASE
wxGuiOwnedByMainThread()
1544 return gs_bGuiOwnedByMainThread
;
1547 // wake up the main thread
1548 void WXDLLEXPORT
wxWakeUpMainThread()
1553 // ----------------------------------------------------------------------------
1554 // include common implementation code
1555 // ----------------------------------------------------------------------------
1557 #include "wx/thrimpl.cpp"
1559 #endif // wxUSE_THREADS