1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/mac/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 static wxThreadIdType gs_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()
111 MPCreateCriticalRegion( (MPCriticalRegionID
*) &m_critRegion
);
114 wxCriticalSection::~wxCriticalSection()
116 MPDeleteCriticalRegion( (MPCriticalRegionID
) m_critRegion
);
119 void wxCriticalSection::Enter()
121 MPEnterCriticalRegion( (MPCriticalRegionID
) m_critRegion
, kDurationForever
);
124 void wxCriticalSection::Leave()
126 MPExitCriticalRegion( (MPCriticalRegionID
) m_critRegion
);
129 // ----------------------------------------------------------------------------
130 // wxMutex implementation
131 // ----------------------------------------------------------------------------
133 #define wxUSE_MAC_SEMAPHORE_MUTEX 0
134 #define wxUSE_MAC_CRITICAL_REGION_MUTEX 1
135 #define wxUSE_MAC_PTHREADS_MUTEX 0
137 #if wxUSE_MAC_PTHREADS_MUTEX
142 class wxMutexInternal
145 wxMutexInternal( wxMutexType mutexType
);
149 wxMutexError
TryLock();
150 wxMutexError
Unlock();
156 pthread_mutex_t m_mutex
;
159 // wxConditionInternal uses our m_mutex
160 friend class wxConditionInternal
;
163 #ifdef HAVE_PTHREAD_MUTEXATTR_T
164 // on some systems pthread_mutexattr_settype() is not in the headers (but it is
165 // in the library, otherwise we wouldn't compile this code at all)
166 extern "C" int pthread_mutexattr_settype( pthread_mutexattr_t
*, int );
169 wxMutexInternal::wxMutexInternal( wxMutexType mutexType
)
174 case wxMUTEX_RECURSIVE
:
175 // support recursive locks like Win32, i.e. a thread can lock a
176 // mutex which it had itself already locked
178 // unfortunately initialization of recursive mutexes is non
179 // portable, so try several methods
180 #ifdef HAVE_PTHREAD_MUTEXATTR_T
182 pthread_mutexattr_t attr
;
183 pthread_mutexattr_init( &attr
);
184 pthread_mutexattr_settype( &attr
, PTHREAD_MUTEX_RECURSIVE
);
186 err
= pthread_mutex_init( &m_mutex
, &attr
);
188 #elif defined(HAVE_PTHREAD_RECURSIVE_MUTEX_INITIALIZER)
189 // we can use this only as initializer so we have to assign it
190 // first to a temp var - assigning directly to m_mutex wouldn't
193 pthread_mutex_t mutex
= PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
;
196 #else // no recursive mutexes
198 #endif // HAVE_PTHREAD_MUTEXATTR_T/...
202 wxFAIL_MSG( wxT("unknown mutex type") );
205 case wxMUTEX_DEFAULT
:
206 err
= pthread_mutex_init( &m_mutex
, NULL
);
213 wxLogApiError( wxT("pthread_mutex_init()"), err
);
217 wxMutexInternal::~wxMutexInternal()
221 int err
= pthread_mutex_destroy( &m_mutex
);
224 wxLogApiError( wxT("pthread_mutex_destroy()"), err
);
229 wxMutexError
wxMutexInternal::Lock()
231 int err
= pthread_mutex_lock( &m_mutex
);
235 // only error checking mutexes return this value and so it's an
236 // unexpected situation -- hence use assert, not wxLogDebug
237 wxFAIL_MSG( wxT("mutex deadlock prevented") );
238 return wxMUTEX_DEAD_LOCK
;
241 wxLogDebug( wxT("pthread_mutex_lock(): mutex not initialized.") );
245 return wxMUTEX_NO_ERROR
;
248 wxLogApiError( wxT("pthread_mutex_lock()"), err
);
251 return wxMUTEX_MISC_ERROR
;
254 wxMutexError
wxMutexInternal::TryLock()
256 int err
= pthread_mutex_trylock( &m_mutex
);
260 // not an error: mutex is already locked, but we're prepared for this case
264 wxLogDebug( wxT("pthread_mutex_trylock(): mutex not initialized.") );
268 return wxMUTEX_NO_ERROR
;
271 wxLogApiError( wxT("pthread_mutex_trylock()"), err
);
274 return wxMUTEX_MISC_ERROR
;
277 wxMutexError
wxMutexInternal::Unlock()
279 int err
= pthread_mutex_unlock( &m_mutex
);
283 // we don't own the mutex
284 return wxMUTEX_UNLOCKED
;
287 wxLogDebug( wxT("pthread_mutex_unlock(): mutex not initialized.") );
291 return wxMUTEX_NO_ERROR
;
294 wxLogApiError( wxT("pthread_mutex_unlock()"), err
);
297 return wxMUTEX_MISC_ERROR
;
302 #if wxUSE_MAC_SEMAPHORE_MUTEX
304 class wxMutexInternal
307 wxMutexInternal( wxMutexType mutexType
);
308 virtual ~wxMutexInternal();
314 wxMutexError
TryLock();
315 wxMutexError
Unlock();
318 MPSemaphoreID m_semaphore
;
322 wxMutexInternal::wxMutexInternal(wxMutexType mutexType
)
325 m_semaphore
= kInvalidID
;
326 OSStatus err
= noErr
;
330 case wxMUTEX_DEFAULT
:
331 verify_noerr( MPCreateBinarySemaphore( &m_semaphore
) );
332 m_isOk
= ( m_semaphore
!= kInvalidID
);
335 case wxMUTEX_RECURSIVE
:
336 wxFAIL_MSG( wxT("Recursive Mutex not supported yet") );
340 wxFAIL_MSG( wxT("Unknown mutex type") );
345 wxMutexInternal::~wxMutexInternal()
347 if ( m_semaphore
!= kInvalidID
)
348 MPDeleteSemaphore( m_semaphore
);
353 wxMutexError
wxMutexInternal::Lock()
355 wxCHECK_MSG( m_isOk
, wxMUTEX_MISC_ERROR
, wxT("Invalid Mutex") );
356 OSStatus err
= MPWaitOnSemaphore( m_semaphore
, kDurationForever
);
359 wxLogSysError( wxT("Could not lock mutex") );
361 return wxMUTEX_MISC_ERROR
;
364 return wxMUTEX_NO_ERROR
;
367 wxMutexError
wxMutexInternal::TryLock()
369 wxCHECK_MSG( m_isOk
, wxMUTEX_MISC_ERROR
, wxT("Invalid Mutex") );
370 OSStatus err
= MPWaitOnSemaphore( m_semaphore
, kDurationImmediate
);
373 if (err
== kMPTimeoutErr
)
376 wxLogSysError( wxT("Could not try lock mutex") );
378 return wxMUTEX_MISC_ERROR
;
381 return wxMUTEX_NO_ERROR
;
384 wxMutexError
wxMutexInternal::Unlock()
386 wxCHECK_MSG( m_isOk
, wxMUTEX_MISC_ERROR
, wxT("Invalid Mutex") );
387 OSStatus err
= MPSignalSemaphore( m_semaphore
);
392 wxLogSysError( wxT("Could not unlock mutex") );
393 return wxMUTEX_MISC_ERROR
;
396 return wxMUTEX_NO_ERROR
;
401 #if wxUSE_MAC_CRITICAL_REGION_MUTEX
403 class wxMutexInternal
406 wxMutexInternal( wxMutexType mutexType
);
407 virtual ~wxMutexInternal();
409 bool IsOk() const { return m_isOk
; }
411 wxMutexError
Lock() { return Lock(kDurationForever
); }
412 wxMutexError
Lock(unsigned long ms
);
413 wxMutexError
TryLock();
414 wxMutexError
Unlock();
417 MPCriticalRegionID m_critRegion
;
421 wxMutexInternal::wxMutexInternal( wxMutexType
WXUNUSED(mutexType
) )
424 m_critRegion
= kInvalidID
;
426 verify_noerr( MPCreateCriticalRegion( &m_critRegion
) );
427 m_isOk
= ( m_critRegion
!= kInvalidID
);
430 wxFAIL_MSG( wxT("Error when creating mutex") );
434 wxMutexInternal::~wxMutexInternal()
436 if ( m_critRegion
!= kInvalidID
)
437 MPDeleteCriticalRegion( m_critRegion
);
442 wxMutexError
wxMutexInternal::Lock(unsigned long ms
)
444 wxCHECK_MSG( m_isOk
, wxMUTEX_MISC_ERROR
, wxT("Invalid Mutex") );
446 OSStatus err
= MPEnterCriticalRegion( m_critRegion
, ms
);
453 wxASSERT_MSG( ms
!= kDurationForever
, wxT("unexpected timeout") );
454 return wxMUTEX_TIMEOUT
;
457 wxLogSysError(wxT("Could not lock mutex"));
458 return wxMUTEX_MISC_ERROR
;
461 return wxMUTEX_NO_ERROR
;
464 wxMutexError
wxMutexInternal::TryLock()
466 wxCHECK_MSG( m_isOk
, wxMUTEX_MISC_ERROR
, wxT("Invalid Mutex") ) ;
468 OSStatus err
= MPEnterCriticalRegion( m_critRegion
, kDurationImmediate
);
471 if ( err
== kMPTimeoutErr
)
474 wxLogSysError( wxT("Could not try lock mutex") );
475 return wxMUTEX_MISC_ERROR
;
478 return wxMUTEX_NO_ERROR
;
481 wxMutexError
wxMutexInternal::Unlock()
483 wxCHECK_MSG( m_isOk
, wxMUTEX_MISC_ERROR
, wxT("Invalid Mutex") ) ;
485 OSStatus err
= MPExitCriticalRegion( m_critRegion
);
490 wxLogSysError( wxT("Could not unlock mutex") );
492 return wxMUTEX_MISC_ERROR
;
495 return wxMUTEX_NO_ERROR
;
500 // --------------------------------------------------------------------------
502 // --------------------------------------------------------------------------
504 class wxSemaphoreInternal
507 wxSemaphoreInternal( int initialcount
, int maxcount
);
508 virtual ~wxSemaphoreInternal();
514 wxSemaError
WaitTimeout( unsigned long milliseconds
);
517 { return WaitTimeout( kDurationForever
); }
519 wxSemaError
TryWait()
521 wxSemaError err
= WaitTimeout( kDurationImmediate
);
522 if (err
== wxSEMA_TIMEOUT
)
529 MPSemaphoreID m_semaphore
;
533 wxSemaphoreInternal::wxSemaphoreInternal( int initialcount
, int maxcount
)
536 m_semaphore
= kInvalidID
;
538 // make it practically infinite
541 verify_noerr( MPCreateSemaphore( maxcount
, initialcount
, &m_semaphore
) );
542 m_isOk
= ( m_semaphore
!= kInvalidID
);
546 wxFAIL_MSG( wxT("Error when creating semaphore") );
550 wxSemaphoreInternal::~wxSemaphoreInternal()
552 if (m_semaphore
!= kInvalidID
)
553 MPDeleteSemaphore( m_semaphore
);
558 wxSemaError
wxSemaphoreInternal::WaitTimeout( unsigned long milliseconds
)
560 OSStatus err
= MPWaitOnSemaphore( m_semaphore
, milliseconds
);
563 if (err
== kMPTimeoutErr
)
564 return wxSEMA_TIMEOUT
;
566 return wxSEMA_MISC_ERROR
;
569 return wxSEMA_NO_ERROR
;
572 wxSemaError
wxSemaphoreInternal::Post()
574 OSStatus err
= MPSignalSemaphore( m_semaphore
);
577 return wxSEMA_MISC_ERROR
;
579 return wxSEMA_NO_ERROR
;
582 // ----------------------------------------------------------------------------
583 // wxCondition implementation
584 // ----------------------------------------------------------------------------
588 class wxConditionInternal
591 wxConditionInternal( wxMutex
& mutex
)
602 virtual ~wxConditionInternal() {}
605 { return m_mutex
.IsOk(); }
608 { return WaitTimeout( kDurationForever
); }
610 wxCondError
WaitTimeout( unsigned long msectimeout
);
613 { return DoSignal( false); }
615 wxCondError
Broadcast()
616 { return DoSignal( true ); }
619 wxCondError
DoSignal( bool signalAll
);
622 wxSemaphoreInternal m_semaphore
; // Signals the waiting threads.
623 wxSemaphoreInternal m_gate
;
624 wxCriticalSection m_varSection
;
625 size_t m_waiters
; // Number of threads waiting for a signal.
626 size_t m_signals
; // Number of signals to send.
627 size_t m_canceled
; // Number of canceled waiters in m_waiters.
630 wxCondError
wxConditionInternal::WaitTimeout( unsigned long msectimeout
)
634 if ( ++ m_waiters
== INT_MAX
)
636 m_varSection
.Enter();
638 m_waiters
-= m_canceled
;
639 m_signals
-= m_canceled
;
642 m_varSection
.Leave();
648 wxSemaError err
= m_semaphore
.WaitTimeout( msectimeout
);
649 wxASSERT( err
== wxSEMA_NO_ERROR
|| err
== wxSEMA_TIMEOUT
);
651 m_varSection
.Enter();
653 if ( err
!= wxSEMA_NO_ERROR
)
655 if ( m_signals
> m_canceled
)
657 // A signal is being sent after we timed out.
658 if ( m_waiters
== m_signals
)
660 // There are no excess waiters to catch the signal, so
661 // we must throw it away.
662 wxSemaError err2
= m_semaphore
.Wait();
663 if ( err2
!= wxSEMA_NO_ERROR
)
665 wxLogSysError( wx("Error while waiting on semaphore") );
668 wxASSERT( err2
== wxSEMA_NO_ERROR
);
671 if ( --m_signals
== m_canceled
)
673 // This was the last signal. open the gate.
674 wxASSERT( m_waiters
== m_canceled
);
680 // There are excess waiters to catch the signal, leave it be.
686 // No signals is being sent:
687 // the gate may be open or closed, so we can't touch m_waiters.
694 // We caught a signal.
695 wxASSERT( m_signals
> m_canceled
);
699 if ( --m_signals
== m_canceled
)
701 // This was the last signal. open the gate.
702 wxASSERT( m_waiters
== m_canceled
);
708 m_varSection
.Leave();
712 return err
== wxSEMA_TIMEOUT
? wxCOND_TIMEOUT
: wxCOND_MISC_ERROR
;
714 return wxCOND_NO_ERROR
;
718 wxCondError
wxConditionInternal::DoSignal( bool signalAll
)
721 m_varSection
.Enter();
723 wxASSERT( m_signals
== m_canceled
);
725 if ( m_waiters
== m_canceled
)
727 m_varSection
.Leave();
729 return wxCOND_NO_ERROR
;
734 m_waiters
-= m_canceled
;
739 m_signals
= signalAll
? m_waiters
: 1;
740 size_t n
= m_signals
;
742 m_varSection
.Leave();
744 // Let the waiters inherit the gate lock.
748 wxSemaError err
= m_semaphore
.Post();
749 wxASSERT( err
== wxSEMA_NO_ERROR
);
753 return wxCOND_NO_ERROR
;
757 class wxConditionInternal
760 wxConditionInternal( wxMutex
& mutex
);
763 { return m_mutex
.IsOk() && m_semaphore
.IsOk(); }
766 wxCondError
WaitTimeout( unsigned long milliseconds
);
768 wxCondError
Signal();
769 wxCondError
Broadcast();
772 // the number of threads currently waiting for this condition
775 // the critical section protecting m_numWaiters
776 wxCriticalSection m_csWaiters
;
779 wxSemaphore m_semaphore
;
781 DECLARE_NO_COPY_CLASS(wxConditionInternal
)
784 wxConditionInternal::wxConditionInternal( wxMutex
& mutex
)
787 // another thread can't access it until we return from ctor, so no need to
788 // protect access to m_numWaiters here
792 wxCondError
wxConditionInternal::Wait()
794 // increment the number of waiters
795 IncrementAtomic( &m_numWaiters
);
799 // a potential race condition can occur here
801 // after a thread increments nwaiters, and unlocks the mutex and before the
802 // semaphore.Wait() is called, if another thread can cause a signal to be
805 // this race condition is handled by using a semaphore and incrementing the
806 // semaphore only if 'nwaiters' is greater that zero since the semaphore,
807 // can 'remember' signals the race condition will not occur
809 // wait ( if necessary ) and decrement semaphore
810 wxSemaError err
= m_semaphore
.Wait();
813 return err
== wxSEMA_NO_ERROR
? wxCOND_NO_ERROR
: wxCOND_MISC_ERROR
;
816 wxCondError
wxConditionInternal::WaitTimeout( unsigned long milliseconds
)
818 IncrementAtomic( &m_numWaiters
);
822 // a race condition can occur at this point in the code
824 // please see the comments in Wait(), for details
826 wxSemaError err
= m_semaphore
.WaitTimeout(milliseconds
);
828 if ( err
== wxSEMA_TIMEOUT
)
830 // another potential race condition exists here it is caused when a
831 // 'waiting' thread timesout, and returns from WaitForSingleObject, but
832 // has not yet decremented 'nwaiters'.
834 // at this point if another thread calls signal() then the semaphore
835 // will be incremented, but the waiting thread will miss it.
837 // to handle this particular case, the waiting thread calls
838 // WaitForSingleObject again with a timeout of 0, after locking
839 // 'nwaiters_mutex'. this call does not block because of the zero
840 // timeout, but will allow the waiting thread to catch the missed
842 wxCriticalSectionLocker
lock(m_csWaiters
);
844 err
= m_semaphore
.WaitTimeout(0);
846 if ( err
!= wxSEMA_NO_ERROR
)
854 return err
== wxSEMA_NO_ERROR
? wxCOND_NO_ERROR
: wxCOND_MISC_ERROR
;
857 wxCondError
wxConditionInternal::Signal()
859 wxCriticalSectionLocker
lock(m_csWaiters
);
861 if ( m_numWaiters
> 0 )
863 // increment the semaphore by 1
864 if ( m_semaphore
.Post() != wxSEMA_NO_ERROR
)
865 return wxCOND_MISC_ERROR
;
870 return wxCOND_NO_ERROR
;
873 wxCondError
wxConditionInternal::Broadcast()
875 wxCriticalSectionLocker
lock(m_csWaiters
);
877 while ( m_numWaiters
> 0 )
879 if ( m_semaphore
.Post() != wxSEMA_NO_ERROR
)
880 return wxCOND_MISC_ERROR
;
885 return wxCOND_NO_ERROR
;
889 // ----------------------------------------------------------------------------
890 // wxCriticalSection implementation
891 // ----------------------------------------------------------------------------
893 // XXX currently implemented as mutex in headers. Change to critical section.
895 // ----------------------------------------------------------------------------
896 // wxThread implementation
897 // ----------------------------------------------------------------------------
899 // wxThreadInternal class
900 // ----------------------
902 class wxThreadInternal
909 m_prio
= WXTHREAD_DEFAULT_PRIORITY
;
910 m_notifyQueueId
= kInvalidID
;
912 m_cancelled
= false ;
914 // set to true only when the thread starts waiting on m_semSuspend
917 // defaults for joinable threads
918 m_shouldBeJoined
= true;
919 m_isDetached
= false;
922 virtual ~wxThreadInternal()
924 if ( m_notifyQueueId
)
926 MPDeleteQueue( m_notifyQueueId
);
927 m_notifyQueueId
= kInvalidID
;
932 static OSStatus
MacThreadStart(void* arg
);
934 // create a new (suspended) thread (for the given thread object)
935 bool Create(wxThread
*thread
, unsigned int stackSize
);
942 // unblock the thread allowing it to run
943 void SignalRun() { m_semRun
.Post(); }
945 // ask the thread to terminate
948 // go to sleep until Resume() is called
956 int GetPriority() const
958 void SetPriority(int prio
);
961 wxThreadState
GetState() const
963 void SetState(wxThreadState state
)
966 // Get the ID of this thread's underlying MP Services task.
967 MPTaskID
GetId() const
971 { m_cancelled
= true; }
973 bool WasCancelled() const
974 { return m_cancelled
; }
977 void SetExitCode(wxThread::ExitCode exitcode
)
978 { m_exitcode
= exitcode
; }
979 wxThread::ExitCode
GetExitCode() const
980 { return m_exitcode
; }
983 void SetReallyPaused(bool paused
)
984 { m_isPaused
= paused
; }
985 bool IsReallyPaused() const
986 { return m_isPaused
; }
988 // tell the thread that it is a detached one
991 wxCriticalSectionLocker
lock(m_csJoinFlag
);
993 m_shouldBeJoined
= false;
998 // the thread we're associated with
1001 MPTaskID m_tid
; // thread id
1002 MPQueueID m_notifyQueueId
; // its notification queue
1004 wxThreadState m_state
; // see wxThreadState enum
1005 int m_prio
; // in wxWidgets units: from 0 to 100
1007 // this flag is set when the thread should terminate
1010 // this flag is set when the thread is blocking on m_semSuspend
1013 // the thread exit code - only used for joinable (!detached) threads and
1014 // is only valid after the thread termination
1015 wxThread::ExitCode m_exitcode
;
1017 // many threads may call Wait(), but only one of them should call
1018 // pthread_join(), so we have to keep track of this
1019 wxCriticalSection m_csJoinFlag
;
1020 bool m_shouldBeJoined
;
1023 // this semaphore is posted by Run() and the threads Entry() is not
1024 // called before it is done
1025 wxSemaphore m_semRun
;
1027 // this one is signaled when the thread should resume after having been
1029 wxSemaphore m_semSuspend
;
1032 OSStatus
wxThreadInternal::MacThreadStart(void *parameter
)
1034 wxThread
* thread
= (wxThread
*) parameter
;
1035 wxThreadInternal
*pthread
= thread
->m_internal
;
1037 // add to TLS so that This() will work
1038 verify_noerr( MPSetTaskStorageValue( gs_tlsForWXThread
, (TaskStorageValue
) thread
) ) ;
1040 // have to declare this before pthread_cleanup_push() which defines a
1044 // wait for the semaphore to be posted from Run()
1045 pthread
->m_semRun
.Wait();
1047 // test whether we should run the run at all - may be it was deleted
1048 // before it started to Run()?
1050 wxCriticalSectionLocker
lock(thread
->m_critsect
);
1052 dontRunAtAll
= pthread
->GetState() == STATE_NEW
&&
1053 pthread
->WasCancelled();
1056 if ( !dontRunAtAll
)
1058 pthread
->m_exitcode
= thread
->Entry();
1061 wxCriticalSectionLocker
lock(thread
->m_critsect
);
1062 pthread
->SetState( STATE_EXITED
);
1068 if ( pthread
->m_isDetached
)
1075 // on Mac for the running code,
1076 // the correct thread termination is to return
1078 // terminate the thread
1079 thread
->Exit( pthread
->m_exitcode
);
1081 return (OSStatus
) NULL
; // pthread->m_exitcode;
1085 bool wxThreadInternal::Create( wxThread
*thread
, unsigned int stackSize
)
1087 wxASSERT_MSG( m_state
== STATE_NEW
&& !m_tid
,
1088 wxT("Create()ing thread twice?") );
1090 OSStatus err
= noErr
;
1093 if ( m_notifyQueueId
== kInvalidID
)
1095 OSStatus err
= MPCreateQueue( &m_notifyQueueId
);
1098 wxLogSysError( wxT("Cant create the thread event queue") );
1104 m_state
= STATE_NEW
;
1107 MacThreadStart
, (void*)m_thread
, stackSize
,
1108 m_notifyQueueId
, &m_exitcode
, 0, 0, &m_tid
);
1112 wxLogSysError( wxT("Can't create thread") );
1117 if ( m_prio
!= WXTHREAD_DEFAULT_PRIORITY
)
1118 SetPriority( m_prio
);
1123 void wxThreadInternal::SetPriority( int priority
)
1129 // Mac priorities range from 1 to 10,000, with a default of 100.
1130 // wxWidgets priorities range from 0 to 100 with a default of 50.
1131 // We can map wxWidgets to Mac priorities easily by assuming
1132 // the former uses a logarithmic scale.
1133 const unsigned int macPriority
= (int)( exp( priority
/ 25.0 * log( 10.0)) + 0.5);
1135 MPSetTaskWeight( m_tid
, macPriority
);
1139 wxThreadError
wxThreadInternal::Run()
1141 wxCHECK_MSG( GetState() == STATE_NEW
, wxTHREAD_RUNNING
,
1142 wxT("thread may only be started once after Create()") );
1144 SetState( STATE_RUNNING
);
1146 // wake up threads waiting for our start
1149 return wxTHREAD_NO_ERROR
;
1152 void wxThreadInternal::Wait()
1154 wxCHECK_RET( !m_isDetached
, wxT("can't wait for a detached thread") );
1156 // if the thread we're waiting for is waiting for the GUI mutex, we will
1157 // deadlock so make sure we release it temporarily
1158 if ( wxThread::IsMain() )
1160 // give the thread we're waiting for chance to do the GUI call
1161 // it might be in, we don't do this conditionally as the to be waited on
1162 // thread might have to acquire the mutex later but before terminating
1163 if ( wxGuiOwnedByMainThread() )
1168 wxCriticalSectionLocker
lock(m_csJoinFlag
);
1170 if ( m_shouldBeJoined
)
1172 void *param1
, *param2
, *rc
;
1174 OSStatus err
= MPWaitOnQueue(
1182 wxLogSysError( wxT( "Cannot wait for thread termination."));
1186 // actually param1 would be the address of m_exitcode
1187 // but we don't need this here
1190 m_shouldBeJoined
= false;
1195 void wxThreadInternal::Pause()
1197 // the state is set from the thread which pauses us first, this function
1198 // is called later so the state should have been already set
1199 wxCHECK_RET( m_state
== STATE_PAUSED
,
1200 wxT("thread must first be paused with wxThread::Pause().") );
1202 // wait until the semaphore is Post()ed from Resume()
1203 m_semSuspend
.Wait();
1206 void wxThreadInternal::Resume()
1208 wxCHECK_RET( m_state
== STATE_PAUSED
,
1209 wxT("can't resume thread which is not suspended.") );
1211 // the thread might be not actually paused yet - if there were no call to
1212 // TestDestroy() since the last call to Pause() for example
1213 if ( IsReallyPaused() )
1216 m_semSuspend
.Post();
1219 SetReallyPaused( false );
1222 SetState( STATE_RUNNING
);
1228 wxThread
*wxThread::This()
1230 wxThread
* thr
= (wxThread
*) MPGetTaskStorageValue( gs_tlsForWXThread
) ;
1235 bool wxThread::IsMain()
1237 return GetCurrentId() == gs_idMainThread
|| gs_idMainThread
== kInvalidID
;
1244 void wxThread::Yield()
1246 CFRunLoopRunInMode( kCFRunLoopDefaultMode
, 0 , true ) ;
1251 void wxThread::Sleep( unsigned long milliseconds
)
1253 AbsoluteTime wakeup
= AddDurationToAbsolute( milliseconds
, UpTime() );
1254 MPDelayUntil( &wakeup
);
1257 int wxThread::GetCPUCount()
1259 return MPProcessors();
1262 unsigned long wxThread::GetCurrentId()
1264 return (unsigned long)MPCurrentTaskID();
1267 bool wxThread::SetConcurrency( size_t WXUNUSED(level
) )
1269 // Cannot be set in MacOS.
1273 wxThread::wxThread( wxThreadKind kind
)
1275 g_numberOfThreads
++;
1276 m_internal
= new wxThreadInternal();
1278 m_isDetached
= (kind
== wxTHREAD_DETACHED
);
1281 wxThread::~wxThread()
1283 wxASSERT_MSG( g_numberOfThreads
>0 , wxT("More threads deleted than created.") ) ;
1285 g_numberOfThreads
--;
1290 // check that the thread either exited or couldn't be created
1291 if ( m_internal
->GetState() != STATE_EXITED
&&
1292 m_internal
->GetState() != STATE_NEW
)
1295 wxT("The thread %ld is being destroyed although it is still running! The application may crash."),
1302 wxDELETE( m_internal
) ;
1305 wxThreadError
wxThread::Create( unsigned int stackSize
)
1307 wxCriticalSectionLocker
lock(m_critsect
);
1310 m_internal
->Detach() ;
1312 if ( !m_internal
->Create(this, stackSize
) )
1314 m_internal
->SetState( STATE_EXITED
);
1316 return wxTHREAD_NO_RESOURCE
;
1319 return wxTHREAD_NO_ERROR
;
1322 wxThreadError
wxThread::Run()
1324 wxCriticalSectionLocker
lock(m_critsect
);
1326 wxCHECK_MSG( m_internal
->GetId(), wxTHREAD_MISC_ERROR
,
1327 wxT("must call wxThread::Create() first") );
1329 return m_internal
->Run();
1332 // -----------------------------------------------------------------------------
1334 // -----------------------------------------------------------------------------
1336 wxThreadError
wxThread::Pause()
1338 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR
,
1339 _T("a thread can't pause itself") );
1341 wxCriticalSectionLocker
lock(m_critsect
);
1343 if ( m_internal
->GetState() != STATE_RUNNING
)
1345 wxLogDebug( wxT("Can't pause thread which is not running.") );
1347 return wxTHREAD_NOT_RUNNING
;
1350 // just set a flag, the thread will be really paused only during the next
1351 // call to TestDestroy()
1352 m_internal
->SetState( STATE_PAUSED
);
1354 return wxTHREAD_NO_ERROR
;
1357 wxThreadError
wxThread::Resume()
1359 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR
,
1360 wxT("a thread can't resume itself") );
1362 wxCriticalSectionLocker
lock(m_critsect
);
1364 wxThreadState state
= m_internal
->GetState();
1369 m_internal
->Resume();
1370 return wxTHREAD_NO_ERROR
;
1373 return wxTHREAD_NO_ERROR
;
1376 wxLogDebug( wxT("Attempt to resume a thread which is not paused.") );
1378 return wxTHREAD_MISC_ERROR
;
1382 // -----------------------------------------------------------------------------
1384 // -----------------------------------------------------------------------------
1386 wxThread::ExitCode
wxThread::Wait()
1388 wxCHECK_MSG( This() != this, (ExitCode
)-1,
1389 wxT("a thread can't wait for itself") );
1391 wxCHECK_MSG( !m_isDetached
, (ExitCode
)-1,
1392 wxT("can't wait for detached thread") );
1396 return m_internal
->GetExitCode();
1399 wxThreadError
wxThread::Delete(ExitCode
*rc
)
1401 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR
,
1402 wxT("a thread can't delete itself") );
1404 bool isDetached
= m_isDetached
;
1407 wxThreadState state
= m_internal
->GetState();
1409 // ask the thread to stop
1410 m_internal
->SetCancelFlag();
1417 // we need to wake up the thread so that PthreadStart() will
1418 // terminate - right now it's blocking on run semaphore in
1420 m_internal
->SignalRun();
1429 // resume the thread first
1430 m_internal
->Resume();
1437 // wait until the thread stops
1442 // return the exit code of the thread
1443 *rc
= m_internal
->GetExitCode();
1448 return wxTHREAD_NO_ERROR
;
1451 wxThreadError
wxThread::Kill()
1453 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR
,
1454 wxT("a thread can't kill itself") );
1456 switch ( m_internal
->GetState() )
1460 return wxTHREAD_NOT_RUNNING
;
1463 // resume the thread first
1469 OSStatus err
= MPTerminateTask( m_internal
->GetId() , -1 ) ;
1472 wxLogError( wxT("Failed to terminate a thread.") );
1474 return wxTHREAD_MISC_ERROR
;
1483 // this should be retrieved by Wait actually
1484 m_internal
->SetExitCode( (void*)-1 );
1487 return wxTHREAD_NO_ERROR
;
1491 void wxThread::Exit( ExitCode status
)
1493 wxASSERT_MSG( This() == this,
1494 wxT("wxThread::Exit() can only be called in the context of the same thread") );
1496 // don't enter m_critsect before calling OnExit() because the user code
1497 // might deadlock if, for example, it signals a condition in OnExit() (a
1498 // common case) while the main thread calls any of functions entering
1499 // m_critsect on us (almost all of them do)
1502 MPTaskID threadid
= m_internal
->GetId();
1510 // update the status of the joinable thread
1511 wxCriticalSectionLocker
lock( m_critsect
);
1512 m_internal
->SetState( STATE_EXITED
);
1515 MPTerminateTask( threadid
, (long)status
);
1518 // also test whether we were paused
1519 bool wxThread::TestDestroy()
1521 wxASSERT_MSG( This() == this,
1522 wxT("wxThread::TestDestroy() can only be called in the context of the same thread") );
1526 if ( m_internal
->GetState() == STATE_PAUSED
)
1528 m_internal
->SetReallyPaused( true );
1530 // leave the crit section or the other threads will stop too if they attempt
1531 // to call any of (seemingly harmless) IsXXX() functions while we sleep
1534 m_internal
->Pause();
1538 // thread wasn't requested to pause, nothing to do
1542 return m_internal
->WasCancelled();
1545 // -----------------------------------------------------------------------------
1547 // -----------------------------------------------------------------------------
1549 void wxThread::SetPriority(unsigned int prio
)
1551 wxCHECK_RET( ((int)WXTHREAD_MIN_PRIORITY
<= (int)prio
) &&
1552 ((int)prio
<= (int)WXTHREAD_MAX_PRIORITY
),
1553 wxT("invalid thread priority") );
1555 wxCriticalSectionLocker
lock(m_critsect
);
1557 switch ( m_internal
->GetState() )
1562 // thread not yet started, priority will be set when it is
1563 m_internal
->SetPriority( prio
);
1568 wxFAIL_MSG( wxT("impossible to set thread priority in this state") );
1572 unsigned int wxThread::GetPriority() const
1574 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
); // const_cast
1576 return m_internal
->GetPriority();
1579 unsigned long wxThread::GetId() const
1581 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
); // const_cast
1583 return (unsigned long)m_internal
->GetId();
1586 // -----------------------------------------------------------------------------
1588 // -----------------------------------------------------------------------------
1590 bool wxThread::IsRunning() const
1592 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
1594 return m_internal
->GetState() == STATE_RUNNING
;
1597 bool wxThread::IsAlive() const
1599 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
1601 switch ( m_internal
->GetState() )
1612 bool wxThread::IsPaused() const
1614 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
1616 return (m_internal
->GetState() == STATE_PAUSED
);
1619 // ----------------------------------------------------------------------------
1620 // Automatic initialization for thread module
1621 // ----------------------------------------------------------------------------
1623 class wxThreadModule
: public wxModule
1626 virtual bool OnInit();
1627 virtual void OnExit();
1630 DECLARE_DYNAMIC_CLASS(wxThreadModule
)
1633 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule
, wxModule
)
1635 bool wxThreadModule::OnInit()
1637 bool hasThreadManager
=
1639 true ; // TODO VERIFY IN NEXT BUILD
1641 MPLibraryIsLoaded();
1644 if ( !hasThreadManager
)
1646 wxLogError( wxT("MP thread support is not available on this system" ) ) ;
1651 // main thread's This() is NULL
1652 verify_noerr( MPAllocateTaskStorageIndex( &gs_tlsForWXThread
) ) ;
1653 verify_noerr( MPSetTaskStorageValue( gs_tlsForWXThread
, 0 ) ) ;
1655 gs_idMainThread
= wxThread::GetCurrentId();
1656 gs_critsectWaitingForGui
= new wxCriticalSection();
1658 gs_critsectGui
= new wxCriticalSection();
1659 gs_critsectGui
->Enter();
1664 void wxThreadModule::OnExit()
1666 if ( gs_critsectGui
)
1668 if ( !wxGuiOwnedByMainThread() )
1670 gs_critsectGui
->Enter();
1671 gs_bGuiOwnedByMainThread
= true;
1674 gs_critsectGui
->Leave();
1675 delete gs_critsectGui
;
1676 gs_critsectGui
= NULL
;
1679 delete gs_critsectWaitingForGui
;
1680 gs_critsectWaitingForGui
= NULL
;
1683 // ----------------------------------------------------------------------------
1684 // GUI Serialization copied from MSW implementation
1685 // ----------------------------------------------------------------------------
1687 void wxMutexGuiEnterImpl()
1689 // this would dead lock everything...
1690 wxASSERT_MSG( !wxThread::IsMain(),
1691 wxT("main thread doesn't want to block in wxMutexGuiEnter()!") );
1693 // the order in which we enter the critical sections here is crucial!!
1695 // set the flag telling to the main thread that we want to do some GUI
1697 wxCriticalSectionLocker
enter(*gs_critsectWaitingForGui
);
1699 gs_nWaitingForGui
++;
1702 wxWakeUpMainThread();
1704 // now we may block here because the main thread will soon let us in
1705 // (during the next iteration of OnIdle())
1706 gs_critsectGui
->Enter();
1709 void wxMutexGuiLeaveImpl()
1711 wxCriticalSectionLocker
enter(*gs_critsectWaitingForGui
);
1713 if ( wxThread::IsMain() )
1715 gs_bGuiOwnedByMainThread
= false;
1719 // decrement the number of threads waiting for GUI access now
1720 wxASSERT_MSG( gs_nWaitingForGui
> 0,
1721 wxT("calling wxMutexGuiLeave() without entering it first?") );
1723 gs_nWaitingForGui
--;
1725 wxWakeUpMainThread();
1728 gs_critsectGui
->Leave();
1731 void WXDLLIMPEXP_BASE
wxMutexGuiLeaveOrEnter()
1733 wxASSERT_MSG( wxThread::IsMain(),
1734 wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") );
1736 if ( !gs_critsectWaitingForGui
)
1739 wxCriticalSectionLocker
enter(*gs_critsectWaitingForGui
);
1741 if ( gs_nWaitingForGui
== 0 )
1743 // no threads are waiting for GUI - so we may acquire the lock without
1744 // any danger (but only if we don't already have it)
1745 if ( !wxGuiOwnedByMainThread() )
1747 gs_critsectGui
->Enter();
1749 gs_bGuiOwnedByMainThread
= true;
1751 //else: already have it, nothing to do
1755 // some threads are waiting, release the GUI lock if we have it
1756 if ( wxGuiOwnedByMainThread() )
1758 //else: some other worker thread is doing GUI
1762 bool WXDLLIMPEXP_BASE
wxGuiOwnedByMainThread()
1764 return gs_bGuiOwnedByMainThread
;
1767 // wake up the main thread
1768 void WXDLLEXPORT
wxWakeUpMainThread()
1773 // ----------------------------------------------------------------------------
1774 // include common implementation code
1775 // ----------------------------------------------------------------------------
1777 #include "wx/thrimpl.cpp"
1779 #endif // wxUSE_THREADS