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"
35 #include <CoreServices/CoreServices.h>
37 #include <DriverServices.h>
38 #include <Multiprocessing.h>
41 #include "wx/mac/uma.h"
44 #include "wx/mac/macnotfy.h"
46 // ----------------------------------------------------------------------------
48 // ----------------------------------------------------------------------------
50 // the possible states of the thread ("=>" shows all possible transitions from
54 STATE_NEW
, // didn't start execution yet (=> RUNNING)
55 STATE_RUNNING
, // thread is running (=> PAUSED, CANCELED)
56 STATE_PAUSED
, // thread is temporarily suspended (=> RUNNING)
57 STATE_CANCELED
, // thread should terminate a.s.a.p. (=> EXITED)
58 STATE_EXITED
// thread is terminating
61 // ----------------------------------------------------------------------------
62 // this module globals
63 // ----------------------------------------------------------------------------
66 // the task ID of the main thread
67 static wxThreadIdType gs_idMainThread
= kInvalidID
;
69 // this is the Per-Task Storage for the pointer to the appropriate wxThread
70 TaskStorageIndex gs_tlsForWXThread
= 0 ;
72 // if it's false, some secondary thread is holding the GUI lock
73 static bool gs_bGuiOwnedByMainThread
= true;
75 // critical section which controls access to all GUI functions: any secondary
76 // thread (i.e. except the main one) must enter this crit section before doing
78 static wxCriticalSection
*gs_critsectGui
= NULL
;
80 // critical section which protects gs_nWaitingForGui variable
81 static wxCriticalSection
*gs_critsectWaitingForGui
= NULL
;
83 // number of threads waiting for GUI in wxMutexGuiEnter()
84 static size_t gs_nWaitingForGui
= 0;
86 // overall number of threads, needed for determining the sleep value of the main
88 size_t g_numberOfThreads
= 0;
94 MPCriticalRegionID gs_guiCritical
= kInvalidID
;
98 // ============================================================================
99 // MacOS implementation of thread classes
100 // ============================================================================
105 The implementation is very close to the phtreads implementation, the reason for
106 using MPServices is the fact that these are also available under OS 9. Thus allowing
107 for one common API for all current builds.
109 As soon as wxThreads are on a 64 bit address space, the TLS must be extended
110 to use two indices one for each 32 bit part as the MP implementation is limited
113 I have three implementations for mutexes :
114 version A based on a binary semaphore, problem - not reentrant, version B based
115 on a critical region, allows for reentrancy, performance implications not
116 yet tested, and third a plain pthreads implementation
118 The same for condition internal, one implementation by Aj Lavin and the other one
119 copied from the thrimpl.cpp which I assume has been more broadly tested, I've just
120 replaced the interlock increment with the appropriate PPC calls
123 // ----------------------------------------------------------------------------
125 // ----------------------------------------------------------------------------
127 wxCriticalSection::wxCriticalSection()
129 MPCreateCriticalRegion( (MPCriticalRegionID
*) &m_critRegion
) ;
132 wxCriticalSection::~wxCriticalSection()
134 MPDeleteCriticalRegion( (MPCriticalRegionID
) m_critRegion
) ;
137 void wxCriticalSection::Enter()
139 MPEnterCriticalRegion( (MPCriticalRegionID
) m_critRegion
, kDurationForever
) ;
142 void wxCriticalSection::Leave()
144 MPExitCriticalRegion((MPCriticalRegionID
) m_critRegion
) ;
147 // ----------------------------------------------------------------------------
148 // wxMutex implementation
149 // ----------------------------------------------------------------------------
151 #if TARGET_API_MAC_OSX
152 #define wxUSE_MAC_SEMAPHORE_MUTEX 0
153 #define wxUSE_MAC_CRITICAL_REGION_MUTEX 1
154 #define wxUSE_MAC_PTHREADS_MUTEX 0
156 #define wxUSE_MAC_SEMAPHORE_MUTEX 0
157 #define wxUSE_MAC_CRITICAL_REGION_MUTEX 1
158 #define wxUSE_MAC_PTHREADS_MUTEX 0
161 #if wxUSE_MAC_PTHREADS_MUTEX
165 class wxMutexInternal
168 wxMutexInternal(wxMutexType mutexType
);
172 wxMutexError
TryLock();
173 wxMutexError
Unlock();
175 bool IsOk() const { return m_isOk
; }
178 pthread_mutex_t m_mutex
;
181 // wxConditionInternal uses our m_mutex
182 friend class wxConditionInternal
;
185 #ifdef HAVE_PTHREAD_MUTEXATTR_T
186 // on some systems pthread_mutexattr_settype() is not in the headers (but it is
187 // in the library, otherwise we wouldn't compile this code at all)
188 extern "C" int pthread_mutexattr_settype(pthread_mutexattr_t
*, int);
191 wxMutexInternal::wxMutexInternal(wxMutexType mutexType
)
196 case wxMUTEX_RECURSIVE
:
197 // support recursive locks like Win32, i.e. a thread can lock a
198 // mutex which it had itself already locked
200 // unfortunately initialization of recursive mutexes is non
201 // portable, so try several methods
202 #ifdef HAVE_PTHREAD_MUTEXATTR_T
204 pthread_mutexattr_t attr
;
205 pthread_mutexattr_init(&attr
);
206 pthread_mutexattr_settype(&attr
, PTHREAD_MUTEX_RECURSIVE
);
208 err
= pthread_mutex_init(&m_mutex
, &attr
);
210 #elif defined(HAVE_PTHREAD_RECURSIVE_MUTEX_INITIALIZER)
211 // we can use this only as initializer so we have to assign it
212 // first to a temp var - assigning directly to m_mutex wouldn't
215 pthread_mutex_t mutex
= PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
;
218 #else // no recursive mutexes
220 #endif // HAVE_PTHREAD_MUTEXATTR_T/...
224 wxFAIL_MSG( _T("unknown mutex type") );
227 case wxMUTEX_DEFAULT
:
228 err
= pthread_mutex_init(&m_mutex
, NULL
);
235 wxLogApiError( wxT("pthread_mutex_init()"), err
);
239 wxMutexInternal::~wxMutexInternal()
243 int err
= pthread_mutex_destroy(&m_mutex
);
246 wxLogApiError( wxT("pthread_mutex_destroy()"), err
);
251 wxMutexError
wxMutexInternal::Lock()
253 int err
= pthread_mutex_lock(&m_mutex
);
257 // only error checking mutexes return this value and so it's an
258 // unexpected situation -- hence use assert, not wxLogDebug
259 wxFAIL_MSG( _T("mutex deadlock prevented") );
260 return wxMUTEX_DEAD_LOCK
;
263 wxLogDebug(_T("pthread_mutex_lock(): mutex not initialized."));
267 return wxMUTEX_NO_ERROR
;
270 wxLogApiError(_T("pthread_mutex_lock()"), err
);
273 return wxMUTEX_MISC_ERROR
;
276 wxMutexError
wxMutexInternal::TryLock()
278 int err
= pthread_mutex_trylock(&m_mutex
);
282 // not an error: mutex is already locked, but we're prepared for
287 wxLogDebug(_T("pthread_mutex_trylock(): mutex not initialized."));
291 return wxMUTEX_NO_ERROR
;
294 wxLogApiError(_T("pthread_mutex_trylock()"), err
);
297 return wxMUTEX_MISC_ERROR
;
300 wxMutexError
wxMutexInternal::Unlock()
302 int err
= pthread_mutex_unlock(&m_mutex
);
306 // we don't own the mutex
307 return wxMUTEX_UNLOCKED
;
310 wxLogDebug(_T("pthread_mutex_unlock(): mutex not initialized."));
314 return wxMUTEX_NO_ERROR
;
317 wxLogApiError(_T("pthread_mutex_unlock()"), err
);
320 return wxMUTEX_MISC_ERROR
;
326 #if wxUSE_MAC_SEMAPHORE_MUTEX
328 class wxMutexInternal
331 wxMutexInternal(wxMutexType mutexType
) ;
333 bool IsOk() const { return m_isOk
; }
335 wxMutexError
Lock() ;
336 wxMutexError
TryLock() ;
337 wxMutexError
Unlock();
339 MPSemaphoreID m_semaphore
;
343 wxMutexInternal::wxMutexInternal(wxMutexType mutexType
)
346 m_semaphore
= kInvalidID
;
348 OSStatus err
= noErr
;
351 case wxMUTEX_DEFAULT
:
353 verify_noerr( MPCreateBinarySemaphore( & m_semaphore
) );
354 m_isOk
= ( m_semaphore
!= kInvalidID
) ;
357 case wxMUTEX_RECURSIVE
:
358 wxFAIL_MSG(wxT("Recursive Mutex not supported yet") ) ;
361 wxFAIL_MSG(wxT("Unknown mutex type") ) ;
366 wxMutexInternal::~wxMutexInternal()
368 if ( m_semaphore
!= kInvalidID
)
369 MPDeleteSemaphore( m_semaphore
);
373 wxMutexError
wxMutexInternal::Lock()
375 wxCHECK_MSG( m_isOk
, wxMUTEX_MISC_ERROR
, wxT("Invalid Mutex") ) ;
376 OSStatus err
= MPWaitOnSemaphore( m_semaphore
, kDurationForever
);
379 wxLogSysError(wxT("Could not lock mutex"));
380 return wxMUTEX_MISC_ERROR
;
383 return wxMUTEX_NO_ERROR
;
386 wxMutexError
wxMutexInternal::TryLock()
388 wxCHECK_MSG( m_isOk
, wxMUTEX_MISC_ERROR
, wxT("Invalid Mutex") ) ;
389 OSStatus err
= MPWaitOnSemaphore( m_semaphore
, kDurationImmediate
);
392 if ( err
== kMPTimeoutErr
)
396 wxLogSysError(wxT("Could not try lock mutex"));
397 return wxMUTEX_MISC_ERROR
;
400 return wxMUTEX_NO_ERROR
;
403 wxMutexError
wxMutexInternal::Unlock()
405 wxCHECK_MSG( m_isOk
, wxMUTEX_MISC_ERROR
, wxT("Invalid Mutex") ) ;
406 OSStatus err
= MPSignalSemaphore( m_semaphore
);
410 wxLogSysError(_("Could not unlock mutex"));
411 return wxMUTEX_MISC_ERROR
;
413 return wxMUTEX_NO_ERROR
;
418 #if wxUSE_MAC_CRITICAL_REGION_MUTEX
420 class wxMutexInternal
423 wxMutexInternal(wxMutexType mutexType
) ;
425 bool IsOk() const { return m_isOk
; }
427 wxMutexError
Lock() ;
428 wxMutexError
TryLock() ;
429 wxMutexError
Unlock();
431 MPCriticalRegionID m_critRegion
;
435 wxMutexInternal::wxMutexInternal(wxMutexType mutexType
)
438 m_critRegion
= kInvalidID
;
440 verify_noerr( MPCreateCriticalRegion( & m_critRegion
) );
441 m_isOk
= ( m_critRegion
!= kInvalidID
) ;
444 wxFAIL_MSG(wxT("Error when creating mutex") ) ;
447 wxMutexInternal::~wxMutexInternal()
449 if ( m_critRegion
!= kInvalidID
)
450 MPDeleteCriticalRegion( m_critRegion
);
454 wxMutexError
wxMutexInternal::Lock()
456 wxCHECK_MSG( m_isOk
, wxMUTEX_MISC_ERROR
, wxT("Invalid Mutex") ) ;
457 OSStatus err
= MPEnterCriticalRegion( m_critRegion
, kDurationForever
);
460 wxLogSysError(wxT("Could not lock mutex"));
461 return wxMUTEX_MISC_ERROR
;
464 return wxMUTEX_NO_ERROR
;
467 wxMutexError
wxMutexInternal::TryLock()
469 wxCHECK_MSG( m_isOk
, wxMUTEX_MISC_ERROR
, wxT("Invalid Mutex") ) ;
470 OSStatus err
= MPEnterCriticalRegion( m_critRegion
, kDurationImmediate
);
473 if ( err
== kMPTimeoutErr
)
477 wxLogSysError(wxT("Could not try lock mutex"));
478 return wxMUTEX_MISC_ERROR
;
481 return wxMUTEX_NO_ERROR
;
484 wxMutexError
wxMutexInternal::Unlock()
486 wxCHECK_MSG( m_isOk
, wxMUTEX_MISC_ERROR
, wxT("Invalid Mutex") ) ;
487 OSStatus err
= MPExitCriticalRegion( m_critRegion
);
491 wxLogSysError(_("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 ~wxSemaphoreInternal();
510 bool IsOk() const { return m_isOk
; }
512 wxSemaError
WaitTimeout(unsigned long milliseconds
);
514 wxSemaError
Wait() { return WaitTimeout( kDurationForever
); }
516 wxSemaError
TryWait()
518 wxSemaError err
= WaitTimeout(kDurationImmediate
);
519 if ( err
== wxSEMA_TIMEOUT
)
526 MPSemaphoreID m_semaphore
;
530 wxSemaphoreInternal::wxSemaphoreInternal(int initialcount
, int maxcount
)
533 m_semaphore
= kInvalidID
;
536 // make it practically infinite
539 verify_noerr( MPCreateSemaphore( maxcount
, initialcount
, & m_semaphore
) );
540 m_isOk
= ( m_semaphore
!= kInvalidID
) ;
543 wxFAIL_MSG(wxT("Error when creating semaphore") ) ;
546 wxSemaphoreInternal::~wxSemaphoreInternal()
548 if( m_semaphore
!= kInvalidID
)
549 MPDeleteSemaphore( m_semaphore
);
553 wxSemaError
wxSemaphoreInternal::WaitTimeout(unsigned long milliseconds
)
555 OSStatus err
= MPWaitOnSemaphore( m_semaphore
, milliseconds
);
558 if ( err
== kMPTimeoutErr
)
560 return wxSEMA_TIMEOUT
;
562 return wxSEMA_MISC_ERROR
;
564 return wxSEMA_NO_ERROR
;
567 wxSemaError
wxSemaphoreInternal::Post()
569 OSStatus err
= MPSignalSemaphore( m_semaphore
);
573 return wxSEMA_MISC_ERROR
;
575 return wxSEMA_NO_ERROR
;
578 // ----------------------------------------------------------------------------
579 // wxCondition implementation
580 // ----------------------------------------------------------------------------
584 class wxConditionInternal
588 wxConditionInternal(wxMutex
& mutex
)
598 ~wxConditionInternal()
602 bool IsOk() const { return m_mutex
.IsOk() ; }
606 return WaitTimeout( kDurationForever
);
609 wxCondError
WaitTimeout(unsigned long msectimeout
);
613 return DoSignal( false);
616 wxCondError
Broadcast()
618 return DoSignal( true);
623 wxCondError
DoSignal( bool signalAll
);
626 wxSemaphoreInternal m_semaphore
; // Signals the waiting threads.
627 wxSemaphoreInternal m_gate
;
628 wxCriticalSection m_varSection
;
629 size_t m_waiters
; // Number of threads waiting for a signal.
630 size_t m_signals
; // Number of signals to send.
631 size_t m_canceled
; // Number of canceled waiters in m_waiters.
635 wxCondError
wxConditionInternal::WaitTimeout(unsigned long msectimeout
)
638 if ( ++ m_waiters
== INT_MAX
)
640 m_varSection
.Enter();
641 m_waiters
-= m_canceled
;
642 m_signals
-= m_canceled
;
644 m_varSection
.Leave();
650 wxSemaError err
= m_semaphore
.WaitTimeout( msectimeout
);
651 wxASSERT( err
== wxSEMA_NO_ERROR
|| err
== wxSEMA_TIMEOUT
);
653 m_varSection
.Enter();
654 if ( err
!= wxSEMA_NO_ERROR
)
656 if ( m_signals
> m_canceled
)
658 // A signal is being sent after we timed out.
660 if ( m_waiters
== m_signals
)
662 // There are no excess waiters to catch the signal, so
663 // we must throw it away.
665 wxSemaError err2
= m_semaphore
.Wait();
666 if ( err2
!= wxSEMA_NO_ERROR
)
668 wxLogSysError(_("Error while waiting on semaphore"));
670 wxASSERT( err2
== wxSEMA_NO_ERROR
);
672 if ( -- m_signals
== m_canceled
)
674 // This was the last signal. open the gate.
675 wxASSERT( m_waiters
== m_canceled
);
681 // There are excess waiters to catch the signal, leave
688 // No signals is being sent.
689 // The gate may be open or closed, so we can't touch m_waiters.
696 // We caught a signal.
697 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
);
706 m_varSection
.Leave();
712 return err
== wxSEMA_TIMEOUT
? wxCOND_TIMEOUT
: wxCOND_MISC_ERROR
;
715 return wxCOND_NO_ERROR
;
719 wxCondError
wxConditionInternal::DoSignal( bool signalAll
)
722 m_varSection
.Enter();
724 wxASSERT( m_signals
== m_canceled
);
726 if ( m_waiters
== m_canceled
)
728 m_varSection
.Leave();
730 return wxCOND_NO_ERROR
;
735 m_waiters
-= m_canceled
;
740 m_signals
= signalAll
? m_waiters
: 1;
741 size_t n
= m_signals
;
743 m_varSection
.Leave();
745 // Let the waiters inherit the gate lock.
749 wxSemaError err
= m_semaphore
.Post();
750 wxASSERT( err
== wxSEMA_NO_ERROR
);
753 return wxCOND_NO_ERROR
;
757 class wxConditionInternal
760 wxConditionInternal(wxMutex
& mutex
);
762 bool IsOk() const { return m_mutex
.IsOk() && m_semaphore
.IsOk(); }
765 wxCondError
WaitTimeout(unsigned long milliseconds
);
767 wxCondError
Signal();
768 wxCondError
Broadcast();
771 // the number of threads currently waiting for this condition
774 // the critical section protecting m_numWaiters
775 wxCriticalSection m_csWaiters
;
778 wxSemaphore m_semaphore
;
780 DECLARE_NO_COPY_CLASS(wxConditionInternal
)
783 wxConditionInternal::wxConditionInternal(wxMutex
& mutex
)
786 // another thread can't access it until we return from ctor, so no need to
787 // protect access to m_numWaiters here
791 wxCondError
wxConditionInternal::Wait()
793 // increment the number of waiters
794 IncrementAtomic(&m_numWaiters
);
798 // a potential race condition can occur here
800 // after a thread increments nwaiters, and unlocks the mutex and before the
801 // semaphore.Wait() is called, if another thread can cause a signal to be
804 // this race condition is handled by using a semaphore and incrementing the
805 // semaphore only if 'nwaiters' is greater that zero since the semaphore,
806 // can 'remember' signals the race condition will not occur
808 // wait ( if necessary ) and decrement semaphore
809 wxSemaError err
= m_semaphore
.Wait();
812 return err
== wxSEMA_NO_ERROR
? wxCOND_NO_ERROR
: wxCOND_MISC_ERROR
;
815 wxCondError
wxConditionInternal::WaitTimeout(unsigned long milliseconds
)
817 IncrementAtomic(&m_numWaiters
);
821 // a race condition can occur at this point in the code
823 // please see the comments in Wait(), for details
825 wxSemaError err
= m_semaphore
.WaitTimeout(milliseconds
);
827 if ( err
== wxSEMA_BUSY
)
829 // another potential race condition exists here it is caused when a
830 // 'waiting' thread timesout, and returns from WaitForSingleObject, but
831 // has not yet decremented 'nwaiters'.
833 // at this point if another thread calls signal() then the semaphore
834 // will be incremented, but the waiting thread will miss it.
836 // to handle this particular case, the waiting thread calls
837 // WaitForSingleObject again with a timeout of 0, after locking
838 // 'nwaiters_mutex'. this call does not block because of the zero
839 // timeout, but will allow the waiting thread to catch the missed
841 wxCriticalSectionLocker
lock(m_csWaiters
);
843 err
= m_semaphore
.WaitTimeout(0);
845 if ( err
!= wxSEMA_NO_ERROR
)
853 return err
== wxSEMA_NO_ERROR
? wxCOND_NO_ERROR
: wxCOND_MISC_ERROR
;
856 wxCondError
wxConditionInternal::Signal()
858 wxCriticalSectionLocker
lock(m_csWaiters
);
860 if ( m_numWaiters
> 0 )
862 // increment the semaphore by 1
863 if ( m_semaphore
.Post() != wxSEMA_NO_ERROR
)
864 return wxCOND_MISC_ERROR
;
869 return wxCOND_NO_ERROR
;
872 wxCondError
wxConditionInternal::Broadcast()
874 wxCriticalSectionLocker
lock(m_csWaiters
);
876 while ( m_numWaiters
> 0 )
878 if ( m_semaphore
.Post() != wxSEMA_NO_ERROR
)
879 return wxCOND_MISC_ERROR
;
884 return wxCOND_NO_ERROR
;
888 // ----------------------------------------------------------------------------
889 // wxCriticalSection implementation
890 // ----------------------------------------------------------------------------
892 // XXX currently implemented as mutex in headers. Change to critical section.
894 // ----------------------------------------------------------------------------
895 // wxThread implementation
896 // ----------------------------------------------------------------------------
898 // wxThreadInternal class
899 // ----------------------
901 class wxThreadInternal
908 m_prio
= WXTHREAD_DEFAULT_PRIORITY
;
909 m_notifyQueueId
= kInvalidID
;
911 m_cancelled
= FALSE
;
913 // set to TRUE only when the thread starts waiting on m_semSuspend
916 // defaults for joinable threads
917 m_shouldBeJoined
= TRUE
;
918 m_isDetached
= FALSE
;
922 if ( m_notifyQueueId
)
924 MPDeleteQueue( m_notifyQueueId
);
925 m_notifyQueueId
= kInvalidID
;
930 static OSStatus
MacThreadStart(void* arg
);
932 // create a new (suspended) thread (for the given thread object)
933 bool Create(wxThread
*thread
, unsigned int stackSize
);
938 // unblock the thread allowing it to run
939 void SignalRun() { m_semRun
.Post(); }
940 // ask the thread to terminate
942 // go to sleep until Resume() is called
949 int GetPriority() const { return m_prio
; }
950 void SetPriority(int prio
) ;
952 wxThreadState
GetState() const { return m_state
; }
953 void SetState(wxThreadState state
) { m_state
= state
; }
955 // Get the ID of this thread's underlying MP Services task.
956 MPTaskID
GetId() const { return m_tid
; }
958 void SetCancelFlag() { m_cancelled
= TRUE
; }
959 bool WasCancelled() const { return m_cancelled
; }
961 void SetExitCode(wxThread::ExitCode exitcode
) { m_exitcode
= exitcode
; }
962 wxThread::ExitCode
GetExitCode() const { return m_exitcode
; }
965 void SetReallyPaused(bool paused
) { m_isPaused
= paused
; }
966 bool IsReallyPaused() const { return m_isPaused
; }
968 // tell the thread that it is a detached one
971 wxCriticalSectionLocker
lock(m_csJoinFlag
);
973 m_shouldBeJoined
= FALSE
;
978 // the thread we're associated with
981 MPTaskID m_tid
; // thread id
982 MPQueueID m_notifyQueueId
; // its notification queue
984 wxThreadState m_state
; // see wxThreadState enum
985 int m_prio
; // in wxWidgets units: from 0 to 100
987 // this flag is set when the thread should terminate
990 // this flag is set when the thread is blocking on m_semSuspend
993 // the thread exit code - only used for joinable (!detached) threads and
994 // is only valid after the thread termination
995 wxThread::ExitCode m_exitcode
;
997 // many threads may call Wait(), but only one of them should call
998 // pthread_join(), so we have to keep track of this
999 wxCriticalSection m_csJoinFlag
;
1000 bool m_shouldBeJoined
;
1003 // this semaphore is posted by Run() and the threads Entry() is not
1004 // called before it is done
1005 wxSemaphore m_semRun
;
1007 // this one is signaled when the thread should resume after having been
1009 wxSemaphore m_semSuspend
;
1012 OSStatus
wxThreadInternal::MacThreadStart(void *parameter
)
1014 wxThread
* thread
= (wxThread
*) parameter
;
1015 wxThreadInternal
*pthread
= thread
->m_internal
;
1017 // add to TLS so that This() will work
1018 verify_noerr( MPSetTaskStorageValue( gs_tlsForWXThread
, (long) thread
) ) ;
1020 // have to declare this before pthread_cleanup_push() which defines a
1024 // wait for the semaphore to be posted from Run()
1025 pthread
->m_semRun
.Wait();
1027 // test whether we should run the run at all - may be it was deleted
1028 // before it started to Run()?
1030 wxCriticalSectionLocker
lock(thread
->m_critsect
);
1032 dontRunAtAll
= pthread
->GetState() == STATE_NEW
&&
1033 pthread
->WasCancelled();
1036 if ( !dontRunAtAll
)
1038 pthread
->m_exitcode
= thread
->Entry();
1041 wxCriticalSectionLocker
lock(thread
->m_critsect
);
1042 pthread
->SetState(STATE_EXITED
);
1048 if ( pthread
->m_isDetached
)
1055 // on mac for the running code the correct thread termination is to
1058 // terminate the thread
1059 thread
->Exit(pthread
->m_exitcode
);
1061 return (OSStatus
) NULL
; // pthread->m_exitcode;
1065 bool wxThreadInternal::Create(wxThread
*thread
, unsigned int stackSize
)
1067 wxASSERT_MSG( m_state
== STATE_NEW
&& !m_tid
,
1068 _T("Create()ing thread twice?") );
1070 OSStatus err
= noErr
;
1073 if ( m_notifyQueueId
== kInvalidID
)
1075 OSStatus err
= MPCreateQueue( & m_notifyQueueId
);
1078 wxLogSysError(_("Cant create the thread event queue"));
1083 m_state
= STATE_NEW
;
1085 err
= MPCreateTask( MacThreadStart
,
1096 wxLogSysError(_("Can't create thread"));
1100 if ( m_prio
!= WXTHREAD_DEFAULT_PRIORITY
)
1102 SetPriority(m_prio
);
1108 void wxThreadInternal::SetPriority( int priority
)
1114 // Mac priorities range from 1 to 10,000, with a default of 100.
1115 // wxWidgets priorities range from 0 to 100 with a default of 50.
1116 // We can map wxWidgets to Mac priorities easily by assuming
1117 // the former uses a logarithmic scale.
1118 const unsigned int macPriority
= ( int)( exp( priority
/ 25.0 * log( 10.0)) + 0.5);
1120 MPSetTaskWeight( m_tid
, macPriority
);
1124 wxThreadError
wxThreadInternal::Run()
1126 wxCHECK_MSG( GetState() == STATE_NEW
, wxTHREAD_RUNNING
,
1127 wxT("thread may only be started once after Create()") );
1129 SetState(STATE_RUNNING
);
1131 // wake up threads waiting for our start
1134 return wxTHREAD_NO_ERROR
;
1137 void wxThreadInternal::Wait()
1139 wxCHECK_RET( !m_isDetached
, _T("can't wait for a detached thread") );
1141 // if the thread we're waiting for is waiting for the GUI mutex, we will
1142 // deadlock so make sure we release it temporarily
1143 if ( wxThread::IsMain() )
1145 // give the thread we're waiting for chance to do the GUI call
1146 // it might be in, we don't do this conditionally as the to be waited on
1147 // thread might have to acquire the mutex later but before terminating
1148 if ( wxGuiOwnedByMainThread() )
1155 wxCriticalSectionLocker
lock(m_csJoinFlag
);
1157 if ( m_shouldBeJoined
)
1163 OSStatus err
= MPWaitOnQueue ( m_notifyQueueId
,
1170 wxLogSysError( _( "Cannot wait for thread termination."));
1174 // actually param1 would be the address of m_exitcode
1175 // but we don't need this here
1178 m_shouldBeJoined
= FALSE
;
1183 void wxThreadInternal::Pause()
1185 // the state is set from the thread which pauses us first, this function
1186 // is called later so the state should have been already set
1187 wxCHECK_RET( m_state
== STATE_PAUSED
,
1188 wxT("thread must first be paused with wxThread::Pause().") );
1190 // wait until the semaphore is Post()ed from Resume()
1191 m_semSuspend
.Wait();
1194 void wxThreadInternal::Resume()
1196 wxCHECK_RET( m_state
== STATE_PAUSED
,
1197 wxT("can't resume thread which is not suspended.") );
1199 // the thread might be not actually paused yet - if there were no call to
1200 // TestDestroy() since the last call to Pause() for example
1201 if ( IsReallyPaused() )
1204 m_semSuspend
.Post();
1207 SetReallyPaused(FALSE
);
1210 SetState(STATE_RUNNING
);
1216 wxThread
*wxThread::This()
1218 wxThread
* thr
= (wxThread
*) MPGetTaskStorageValue( gs_tlsForWXThread
) ;
1222 bool wxThread::IsMain()
1224 return GetCurrentId() == gs_idMainThread
|| gs_idMainThread
== kInvalidID
;
1231 void wxThread::Yield()
1233 #if TARGET_API_MAC_OSX
1234 CFRunLoopRunInMode( kCFRunLoopDefaultMode
, 0 , true ) ;
1240 void wxThread::Sleep(unsigned long milliseconds
)
1242 AbsoluteTime wakeup
= AddDurationToAbsolute( milliseconds
, UpTime());
1243 MPDelayUntil( & wakeup
);
1247 int wxThread::GetCPUCount()
1249 return MPProcessors();
1252 unsigned long wxThread::GetCurrentId()
1254 return (unsigned long)MPCurrentTaskID();
1258 bool wxThread::SetConcurrency(size_t level
)
1260 // Cannot be set in MacOS.
1265 wxThread::wxThread(wxThreadKind kind
)
1267 g_numberOfThreads
++;
1268 m_internal
= new wxThreadInternal();
1270 m_isDetached
= (kind
== wxTHREAD_DETACHED
);
1273 wxThread::~wxThread()
1275 wxASSERT_MSG( g_numberOfThreads
>0 , wxT("More threads deleted than created.") ) ;
1276 g_numberOfThreads
--;
1281 // check that the thread either exited or couldn't be created
1282 if ( m_internal
->GetState() != STATE_EXITED
&&
1283 m_internal
->GetState() != STATE_NEW
)
1285 wxLogDebug(_T("The thread %ld is being destroyed although it is still running! The application may crash."), GetId());
1289 #endif // __WXDEBUG__
1291 wxDELETE( m_internal
) ;
1295 wxThreadError
wxThread::Create(unsigned int stackSize
)
1297 wxCriticalSectionLocker
lock(m_critsect
);
1301 m_internal
->Detach() ;
1303 if ( m_internal
->Create(this, stackSize
) == false )
1305 m_internal
->SetState(STATE_EXITED
);
1306 return wxTHREAD_NO_RESOURCE
;
1309 return wxTHREAD_NO_ERROR
;
1312 wxThreadError
wxThread::Run()
1314 wxCriticalSectionLocker
lock(m_critsect
);
1316 wxCHECK_MSG( m_internal
->GetId(), wxTHREAD_MISC_ERROR
,
1317 wxT("must call wxThread::Create() first") );
1319 return m_internal
->Run();
1322 // -----------------------------------------------------------------------------
1324 // -----------------------------------------------------------------------------
1326 wxThreadError
wxThread::Pause()
1328 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR
,
1329 _T("a thread can't pause itself") );
1331 wxCriticalSectionLocker
lock(m_critsect
);
1333 if ( m_internal
->GetState() != STATE_RUNNING
)
1335 wxLogDebug(wxT("Can't pause thread which is not running."));
1337 return wxTHREAD_NOT_RUNNING
;
1340 // just set a flag, the thread will be really paused only during the next
1341 // call to TestDestroy()
1342 m_internal
->SetState(STATE_PAUSED
);
1344 return wxTHREAD_NO_ERROR
;
1347 wxThreadError
wxThread::Resume()
1349 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR
,
1350 _T("a thread can't resume itself") );
1352 wxCriticalSectionLocker
lock(m_critsect
);
1354 wxThreadState state
= m_internal
->GetState();
1359 m_internal
->Resume();
1360 return wxTHREAD_NO_ERROR
;
1362 return wxTHREAD_NO_ERROR
;
1365 wxLogDebug(_T("Attempt to resume a thread which is not paused."));
1367 return wxTHREAD_MISC_ERROR
;
1371 // -----------------------------------------------------------------------------
1373 // -----------------------------------------------------------------------------
1375 wxThread::ExitCode
wxThread::Wait()
1377 wxCHECK_MSG( This() != this, (ExitCode
)-1,
1378 _T("a thread can't wait for itself") );
1380 wxCHECK_MSG( !m_isDetached
, (ExitCode
)-1,
1381 _T("can't wait for detached thread") );
1385 return m_internal
->GetExitCode();
1388 wxThreadError
wxThread::Delete(ExitCode
*rc
)
1390 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR
,
1391 _T("a thread can't delete itself") );
1393 bool isDetached
= m_isDetached
;
1396 wxThreadState state
= m_internal
->GetState();
1398 // ask the thread to stop
1399 m_internal
->SetCancelFlag();
1406 // we need to wake up the thread so that PthreadStart() will
1407 // terminate - right now it's blocking on run semaphore in
1409 m_internal
->SignalRun();
1418 // resume the thread first
1419 m_internal
->Resume();
1426 // wait until the thread stops
1431 // return the exit code of the thread
1432 *rc
= m_internal
->GetExitCode();
1437 return wxTHREAD_NO_ERROR
;
1440 wxThreadError
wxThread::Kill()
1442 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR
,
1443 _T("a thread can't kill itself") );
1445 switch ( m_internal
->GetState() )
1449 return wxTHREAD_NOT_RUNNING
;
1452 // resume the thread first
1458 OSStatus err
= MPTerminateTask( m_internal
->GetId() , -1 ) ;
1461 wxLogError(_("Failed to terminate a thread."));
1463 return wxTHREAD_MISC_ERROR
;
1472 // this should be retrieved by Wait actually
1473 m_internal
->SetExitCode((void*)-1);
1476 return wxTHREAD_NO_ERROR
;
1480 void wxThread::Exit(ExitCode status
)
1482 wxASSERT_MSG( This() == this,
1483 _T("wxThread::Exit() can only be called in the context of the same thread") );
1485 // don't enter m_critsect before calling OnExit() because the user code
1486 // might deadlock if, for example, it signals a condition in OnExit() (a
1487 // common case) while the main thread calls any of functions entering
1488 // m_critsect on us (almost all of them do)
1491 MPTaskID threadid
= m_internal
->GetId() ;
1499 // update the status of the joinable thread
1500 wxCriticalSectionLocker
lock(m_critsect
);
1501 m_internal
->SetState(STATE_EXITED
);
1503 MPTerminateTask( threadid
, (long) status
) ;
1506 // also test whether we were paused
1507 bool wxThread::TestDestroy()
1509 wxASSERT_MSG( This() == this,
1510 _T("wxThread::TestDestroy() can only be called in the context of the same thread") );
1514 if ( m_internal
->GetState() == STATE_PAUSED
)
1516 m_internal
->SetReallyPaused(TRUE
);
1518 // leave the crit section or the other threads will stop too if they
1519 // try to call any of (seemingly harmless) IsXXX() functions while we
1523 m_internal
->Pause();
1527 // thread wasn't requested to pause, nothing to do
1531 return m_internal
->WasCancelled();
1534 // -----------------------------------------------------------------------------
1536 // -----------------------------------------------------------------------------
1538 void wxThread::SetPriority(unsigned int prio
)
1540 wxCHECK_RET( ((int)WXTHREAD_MIN_PRIORITY
<= (int)prio
) &&
1541 ((int)prio
<= (int)WXTHREAD_MAX_PRIORITY
),
1542 wxT("invalid thread priority") );
1544 wxCriticalSectionLocker
lock(m_critsect
);
1546 switch ( m_internal
->GetState() )
1551 // thread not yet started, priority will be set when it is
1552 m_internal
->SetPriority(prio
);
1557 wxFAIL_MSG(wxT("impossible to set thread priority in this state"));
1561 unsigned int wxThread::GetPriority() const
1563 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
); // const_cast
1565 return m_internal
->GetPriority();
1568 unsigned long wxThread::GetId() const
1570 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
); // const_cast
1572 return (unsigned long)m_internal
->GetId();
1575 // -----------------------------------------------------------------------------
1577 // -----------------------------------------------------------------------------
1579 bool wxThread::IsRunning() const
1581 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
1583 return m_internal
->GetState() == STATE_RUNNING
;
1586 bool wxThread::IsAlive() const
1588 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
1590 switch ( m_internal
->GetState() )
1601 bool wxThread::IsPaused() const
1603 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
1605 return (m_internal
->GetState() == STATE_PAUSED
);
1608 // ----------------------------------------------------------------------------
1609 // Automatic initialization for thread module
1610 // ----------------------------------------------------------------------------
1612 class wxThreadModule
: public wxModule
1615 virtual bool OnInit();
1616 virtual void OnExit();
1619 DECLARE_DYNAMIC_CLASS(wxThreadModule
)
1622 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule
, wxModule
)
1624 bool wxThreadModule::OnInit()
1626 bool hasThreadManager
= false ;
1627 hasThreadManager
= MPLibraryIsLoaded();
1629 if ( !hasThreadManager
)
1631 wxLogError( _("MP Thread Support is not available on this System" ) ) ;
1635 verify_noerr( MPAllocateTaskStorageIndex( &gs_tlsForWXThread
) ) ;
1636 // main thread's This() is NULL
1637 verify_noerr( MPSetTaskStorageValue( gs_tlsForWXThread
, 0 ) ) ;
1639 gs_idMainThread
= wxThread::GetCurrentId() ;
1641 gs_critsectWaitingForGui
= new wxCriticalSection();
1643 gs_critsectGui
= new wxCriticalSection();
1644 gs_critsectGui
->Enter();
1649 void wxThreadModule::OnExit()
1651 if ( gs_critsectGui
)
1653 if ( !wxGuiOwnedByMainThread() )
1655 gs_critsectGui
->Enter();
1656 gs_bGuiOwnedByMainThread
= true;
1658 gs_critsectGui
->Leave();
1659 delete gs_critsectGui
;
1660 gs_critsectGui
= NULL
;
1663 delete gs_critsectWaitingForGui
;
1664 gs_critsectWaitingForGui
= NULL
;
1667 // ----------------------------------------------------------------------------
1668 // GUI Serialization copied from MSW implementation
1669 // ----------------------------------------------------------------------------
1671 void WXDLLIMPEXP_BASE
wxMutexGuiEnter()
1673 // this would dead lock everything...
1674 wxASSERT_MSG( !wxThread::IsMain(),
1675 wxT("main thread doesn't want to block in wxMutexGuiEnter()!") );
1677 // the order in which we enter the critical sections here is crucial!!
1679 // set the flag telling to the main thread that we want to do some GUI
1681 wxCriticalSectionLocker
enter(*gs_critsectWaitingForGui
);
1683 gs_nWaitingForGui
++;
1686 wxWakeUpMainThread();
1688 // now we may block here because the main thread will soon let us in
1689 // (during the next iteration of OnIdle())
1690 gs_critsectGui
->Enter();
1693 void WXDLLIMPEXP_BASE
wxMutexGuiLeave()
1695 wxCriticalSectionLocker
enter(*gs_critsectWaitingForGui
);
1697 if ( wxThread::IsMain() )
1699 gs_bGuiOwnedByMainThread
= false;
1703 // decrement the number of threads waiting for GUI access now
1704 wxASSERT_MSG( gs_nWaitingForGui
> 0,
1705 wxT("calling wxMutexGuiLeave() without entering it first?") );
1707 gs_nWaitingForGui
--;
1709 wxWakeUpMainThread();
1712 gs_critsectGui
->Leave();
1715 void WXDLLIMPEXP_BASE
wxMutexGuiLeaveOrEnter()
1717 wxASSERT_MSG( wxThread::IsMain(),
1718 wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") );
1720 if( !gs_critsectWaitingForGui
)
1723 wxCriticalSectionLocker
enter(*gs_critsectWaitingForGui
);
1725 if ( gs_nWaitingForGui
== 0 )
1727 // no threads are waiting for GUI - so we may acquire the lock without
1728 // any danger (but only if we don't already have it)
1729 if ( !wxGuiOwnedByMainThread() )
1731 gs_critsectGui
->Enter();
1733 gs_bGuiOwnedByMainThread
= true;
1735 //else: already have it, nothing to do
1739 // some threads are waiting, release the GUI lock if we have it
1740 if ( wxGuiOwnedByMainThread() )
1744 //else: some other worker thread is doing GUI
1748 bool WXDLLIMPEXP_BASE
wxGuiOwnedByMainThread()
1750 return gs_bGuiOwnedByMainThread
;
1753 // wake up the main thread
1754 void WXDLLEXPORT
wxWakeUpMainThread()
1759 // ----------------------------------------------------------------------------
1760 // include common implementation code
1761 // ----------------------------------------------------------------------------
1763 #include "wx/thrimpl.cpp"
1765 #endif // wxUSE_THREADS