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 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
14 #pragma implementation "thread.h"
17 // ----------------------------------------------------------------------------
19 // ----------------------------------------------------------------------------
21 // For compilers that support precompilation, includes "wx.h".
22 #include "wx/wxprec.h"
24 #if defined(__BORLANDC__)
34 #include "wx/module.h"
35 #include "wx/thread.h"
38 #if TARGET_API_MAC_OSX
39 #include <CoreServices/CoreServices.h>
41 #include <DriverServices.h>
42 #include <Multiprocessing.h>
45 #include "wx/mac/uma.h"
48 #include "wx/mac/macnotfy.h"
50 // ----------------------------------------------------------------------------
52 // ----------------------------------------------------------------------------
54 // the possible states of the thread ("=>" shows all possible transitions from
58 STATE_NEW
, // didn't start execution yet (=> RUNNING)
59 STATE_RUNNING
, // thread is running (=> PAUSED, CANCELED)
60 STATE_PAUSED
, // thread is temporarily suspended (=> RUNNING)
61 STATE_CANCELED
, // thread should terminate a.s.a.p. (=> EXITED)
62 STATE_EXITED
// thread is terminating
65 // ----------------------------------------------------------------------------
66 // this module globals
67 // ----------------------------------------------------------------------------
70 // the task ID of the main thread
71 static wxThreadIdType gs_idMainThread
= kInvalidID
;
73 // this is the Per-Task Storage for the pointer to the appropriate wxThread
74 TaskStorageIndex gs_tlsForWXThread
= 0 ;
76 // if it's false, some secondary thread is holding the GUI lock
77 static bool gs_bGuiOwnedByMainThread
= true;
79 // critical section which controls access to all GUI functions: any secondary
80 // thread (i.e. except the main one) must enter this crit section before doing
82 static wxCriticalSection
*gs_critsectGui
= NULL
;
84 // critical section which protects gs_nWaitingForGui variable
85 static wxCriticalSection
*gs_critsectWaitingForGui
= NULL
;
87 // number of threads waiting for GUI in wxMutexGuiEnter()
88 static size_t gs_nWaitingForGui
= 0;
90 // overall number of threads, needed for determining the sleep value of the main
92 size_t g_numberOfThreads
= 0;
98 MPCriticalRegionID gs_guiCritical
= kInvalidID
;
102 // ============================================================================
103 // MacOS implementation of thread classes
104 // ============================================================================
109 The implementation is very close to the phtreads implementation, the reason for
110 using MPServices is the fact that these are also available under OS 9. Thus allowing
111 for one common API for all current builds.
113 As soon as wxThreads are on a 64 bit address space, the TLS must be extended
114 to use two indices one for each 32 bit part as the MP implementation is limited
117 I have three implementations for mutexes :
118 version A based on a binary semaphore, problem - not reentrant, version B based
119 on a critical region, allows for reentrancy, performance implications not
120 yet tested, and third a plain pthreads implementation
122 The same for condition internal, one implementation by Aj Lavin and the other one
123 copied from the thrimpl.cpp which I assume has been more broadly tested, I've just
124 replaced the interlock increment with the appropriate PPC calls
127 // ----------------------------------------------------------------------------
129 // ----------------------------------------------------------------------------
131 wxCriticalSection::wxCriticalSection()
133 MPCreateCriticalRegion( (MPCriticalRegionID
*) &m_critRegion
) ;
136 wxCriticalSection::~wxCriticalSection()
138 MPDeleteCriticalRegion( (MPCriticalRegionID
) m_critRegion
) ;
141 void wxCriticalSection::Enter()
143 MPEnterCriticalRegion( (MPCriticalRegionID
) m_critRegion
, kDurationForever
) ;
146 void wxCriticalSection::Leave()
148 MPExitCriticalRegion((MPCriticalRegionID
) m_critRegion
) ;
151 // ----------------------------------------------------------------------------
152 // wxMutex implementation
153 // ----------------------------------------------------------------------------
155 #if TARGET_API_MAC_OSX
156 #define wxUSE_MAC_SEMAPHORE_MUTEX 0
157 #define wxUSE_MAC_CRITICAL_REGION_MUTEX 1
158 #define wxUSE_MAC_PTHREADS_MUTEX 0
160 #define wxUSE_MAC_SEMAPHORE_MUTEX 0
161 #define wxUSE_MAC_CRITICAL_REGION_MUTEX 1
162 #define wxUSE_MAC_PTHREADS_MUTEX 0
165 #if wxUSE_MAC_PTHREADS_MUTEX
169 class wxMutexInternal
172 wxMutexInternal(wxMutexType mutexType
);
176 wxMutexError
TryLock();
177 wxMutexError
Unlock();
179 bool IsOk() const { return m_isOk
; }
182 pthread_mutex_t m_mutex
;
185 // wxConditionInternal uses our m_mutex
186 friend class wxConditionInternal
;
189 #ifdef HAVE_PTHREAD_MUTEXATTR_T
190 // on some systems pthread_mutexattr_settype() is not in the headers (but it is
191 // in the library, otherwise we wouldn't compile this code at all)
192 extern "C" int pthread_mutexattr_settype(pthread_mutexattr_t
*, int);
195 wxMutexInternal::wxMutexInternal(wxMutexType mutexType
)
200 case wxMUTEX_RECURSIVE
:
201 // support recursive locks like Win32, i.e. a thread can lock a
202 // mutex which it had itself already locked
204 // unfortunately initialization of recursive mutexes is non
205 // portable, so try several methods
206 #ifdef HAVE_PTHREAD_MUTEXATTR_T
208 pthread_mutexattr_t attr
;
209 pthread_mutexattr_init(&attr
);
210 pthread_mutexattr_settype(&attr
, PTHREAD_MUTEX_RECURSIVE
);
212 err
= pthread_mutex_init(&m_mutex
, &attr
);
214 #elif defined(HAVE_PTHREAD_RECURSIVE_MUTEX_INITIALIZER)
215 // we can use this only as initializer so we have to assign it
216 // first to a temp var - assigning directly to m_mutex wouldn't
219 pthread_mutex_t mutex
= PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
;
222 #else // no recursive mutexes
224 #endif // HAVE_PTHREAD_MUTEXATTR_T/...
228 wxFAIL_MSG( _T("unknown mutex type") );
231 case wxMUTEX_DEFAULT
:
232 err
= pthread_mutex_init(&m_mutex
, NULL
);
239 wxLogApiError( wxT("pthread_mutex_init()"), err
);
243 wxMutexInternal::~wxMutexInternal()
247 int err
= pthread_mutex_destroy(&m_mutex
);
250 wxLogApiError( wxT("pthread_mutex_destroy()"), err
);
255 wxMutexError
wxMutexInternal::Lock()
257 int err
= pthread_mutex_lock(&m_mutex
);
261 // only error checking mutexes return this value and so it's an
262 // unexpected situation -- hence use assert, not wxLogDebug
263 wxFAIL_MSG( _T("mutex deadlock prevented") );
264 return wxMUTEX_DEAD_LOCK
;
267 wxLogDebug(_T("pthread_mutex_lock(): mutex not initialized."));
271 return wxMUTEX_NO_ERROR
;
274 wxLogApiError(_T("pthread_mutex_lock()"), err
);
277 return wxMUTEX_MISC_ERROR
;
280 wxMutexError
wxMutexInternal::TryLock()
282 int err
= pthread_mutex_trylock(&m_mutex
);
286 // not an error: mutex is already locked, but we're prepared for
291 wxLogDebug(_T("pthread_mutex_trylock(): mutex not initialized."));
295 return wxMUTEX_NO_ERROR
;
298 wxLogApiError(_T("pthread_mutex_trylock()"), err
);
301 return wxMUTEX_MISC_ERROR
;
304 wxMutexError
wxMutexInternal::Unlock()
306 int err
= pthread_mutex_unlock(&m_mutex
);
310 // we don't own the mutex
311 return wxMUTEX_UNLOCKED
;
314 wxLogDebug(_T("pthread_mutex_unlock(): mutex not initialized."));
318 return wxMUTEX_NO_ERROR
;
321 wxLogApiError(_T("pthread_mutex_unlock()"), err
);
324 return wxMUTEX_MISC_ERROR
;
330 #if wxUSE_MAC_SEMAPHORE_MUTEX
332 class wxMutexInternal
335 wxMutexInternal(wxMutexType mutexType
) ;
337 bool IsOk() const { return m_isOk
; }
339 wxMutexError
Lock() ;
340 wxMutexError
TryLock() ;
341 wxMutexError
Unlock();
343 MPSemaphoreID m_semaphore
;
347 wxMutexInternal::wxMutexInternal(wxMutexType mutexType
)
350 m_semaphore
= kInvalidID
;
352 OSStatus err
= noErr
;
355 case wxMUTEX_DEFAULT
:
357 verify_noerr( MPCreateBinarySemaphore( & m_semaphore
) );
358 m_isOk
= ( m_semaphore
!= kInvalidID
) ;
361 case wxMUTEX_RECURSIVE
:
362 wxFAIL_MSG(wxT("Recursive Mutex not supported yet") ) ;
365 wxFAIL_MSG(wxT("Unknown mutex type") ) ;
370 wxMutexInternal::~wxMutexInternal()
372 if ( m_semaphore
!= kInvalidID
)
373 MPDeleteSemaphore( m_semaphore
);
377 wxMutexError
wxMutexInternal::Lock()
379 wxCHECK_MSG( m_isOk
, wxMUTEX_MISC_ERROR
, wxT("Invalid Mutex") ) ;
380 OSStatus err
= MPWaitOnSemaphore( m_semaphore
, kDurationForever
);
383 wxLogSysError(wxT("Could not lock mutex"));
384 return wxMUTEX_MISC_ERROR
;
387 return wxMUTEX_NO_ERROR
;
390 wxMutexError
wxMutexInternal::TryLock()
392 wxCHECK_MSG( m_isOk
, wxMUTEX_MISC_ERROR
, wxT("Invalid Mutex") ) ;
393 OSStatus err
= MPWaitOnSemaphore( m_semaphore
, kDurationImmediate
);
396 if ( err
== kMPTimeoutErr
)
400 wxLogSysError(wxT("Could not try lock mutex"));
401 return wxMUTEX_MISC_ERROR
;
404 return wxMUTEX_NO_ERROR
;
407 wxMutexError
wxMutexInternal::Unlock()
409 wxCHECK_MSG( m_isOk
, wxMUTEX_MISC_ERROR
, wxT("Invalid Mutex") ) ;
410 OSStatus err
= MPSignalSemaphore( m_semaphore
);
414 wxLogSysError(_("Could not unlock mutex"));
415 return wxMUTEX_MISC_ERROR
;
417 return wxMUTEX_NO_ERROR
;
422 #if wxUSE_MAC_CRITICAL_REGION_MUTEX
424 class wxMutexInternal
427 wxMutexInternal(wxMutexType mutexType
) ;
429 bool IsOk() const { return m_isOk
; }
431 wxMutexError
Lock() ;
432 wxMutexError
TryLock() ;
433 wxMutexError
Unlock();
435 MPCriticalRegionID m_critRegion
;
439 wxMutexInternal::wxMutexInternal(wxMutexType mutexType
)
442 m_critRegion
= kInvalidID
;
444 verify_noerr( MPCreateCriticalRegion( & m_critRegion
) );
445 m_isOk
= ( m_critRegion
!= kInvalidID
) ;
448 wxFAIL_MSG(wxT("Error when creating mutex") ) ;
451 wxMutexInternal::~wxMutexInternal()
453 if ( m_critRegion
!= kInvalidID
)
454 MPDeleteCriticalRegion( m_critRegion
);
458 wxMutexError
wxMutexInternal::Lock()
460 wxCHECK_MSG( m_isOk
, wxMUTEX_MISC_ERROR
, wxT("Invalid Mutex") ) ;
461 OSStatus err
= MPEnterCriticalRegion( m_critRegion
, kDurationForever
);
464 wxLogSysError(wxT("Could not lock mutex"));
465 return wxMUTEX_MISC_ERROR
;
468 return wxMUTEX_NO_ERROR
;
471 wxMutexError
wxMutexInternal::TryLock()
473 wxCHECK_MSG( m_isOk
, wxMUTEX_MISC_ERROR
, wxT("Invalid Mutex") ) ;
474 OSStatus err
= MPEnterCriticalRegion( m_critRegion
, kDurationImmediate
);
477 if ( err
== kMPTimeoutErr
)
481 wxLogSysError(wxT("Could not try lock mutex"));
482 return wxMUTEX_MISC_ERROR
;
485 return wxMUTEX_NO_ERROR
;
488 wxMutexError
wxMutexInternal::Unlock()
490 wxCHECK_MSG( m_isOk
, wxMUTEX_MISC_ERROR
, wxT("Invalid Mutex") ) ;
491 OSStatus err
= MPExitCriticalRegion( m_critRegion
);
495 wxLogSysError(_("Could not unlock mutex"));
496 return wxMUTEX_MISC_ERROR
;
499 return wxMUTEX_NO_ERROR
;
504 // --------------------------------------------------------------------------
506 // --------------------------------------------------------------------------
508 class wxSemaphoreInternal
511 wxSemaphoreInternal(int initialcount
, int maxcount
);
512 ~wxSemaphoreInternal();
514 bool IsOk() const { return m_isOk
; }
516 wxSemaError
WaitTimeout(unsigned long milliseconds
);
518 wxSemaError
Wait() { return WaitTimeout( kDurationForever
); }
520 wxSemaError
TryWait()
522 wxSemaError err
= WaitTimeout(kDurationImmediate
);
523 if ( err
== wxSEMA_TIMEOUT
)
530 MPSemaphoreID m_semaphore
;
534 wxSemaphoreInternal::wxSemaphoreInternal(int initialcount
, int maxcount
)
537 m_semaphore
= kInvalidID
;
540 // make it practically infinite
543 verify_noerr( MPCreateSemaphore( maxcount
, initialcount
, & m_semaphore
) );
544 m_isOk
= ( m_semaphore
!= kInvalidID
) ;
547 wxFAIL_MSG(wxT("Error when creating semaphore") ) ;
550 wxSemaphoreInternal::~wxSemaphoreInternal()
552 if( m_semaphore
!= kInvalidID
)
553 MPDeleteSemaphore( m_semaphore
);
557 wxSemaError
wxSemaphoreInternal::WaitTimeout(unsigned long milliseconds
)
559 OSStatus err
= MPWaitOnSemaphore( m_semaphore
, milliseconds
);
562 if ( err
== kMPTimeoutErr
)
564 return wxSEMA_TIMEOUT
;
566 return wxSEMA_MISC_ERROR
;
568 return wxSEMA_NO_ERROR
;
571 wxSemaError
wxSemaphoreInternal::Post()
573 OSStatus err
= MPSignalSemaphore( m_semaphore
);
577 return wxSEMA_MISC_ERROR
;
579 return wxSEMA_NO_ERROR
;
582 // ----------------------------------------------------------------------------
583 // wxCondition implementation
584 // ----------------------------------------------------------------------------
588 class wxConditionInternal
592 wxConditionInternal(wxMutex
& mutex
)
602 ~wxConditionInternal()
606 bool IsOk() const { return m_mutex
.IsOk() ; }
610 return WaitTimeout( kDurationForever
);
613 wxCondError
WaitTimeout(unsigned long msectimeout
);
617 return DoSignal( false);
620 wxCondError
Broadcast()
622 return DoSignal( true);
627 wxCondError
DoSignal( bool signalAll
);
630 wxSemaphoreInternal m_semaphore
; // Signals the waiting threads.
631 wxSemaphoreInternal m_gate
;
632 wxCriticalSection m_varSection
;
633 size_t m_waiters
; // Number of threads waiting for a signal.
634 size_t m_signals
; // Number of signals to send.
635 size_t m_canceled
; // Number of canceled waiters in m_waiters.
639 wxCondError
wxConditionInternal::WaitTimeout(unsigned long msectimeout
)
642 if ( ++ m_waiters
== INT_MAX
)
644 m_varSection
.Enter();
645 m_waiters
-= m_canceled
;
646 m_signals
-= m_canceled
;
648 m_varSection
.Leave();
654 wxSemaError err
= m_semaphore
.WaitTimeout( msectimeout
);
655 wxASSERT( err
== wxSEMA_NO_ERROR
|| err
== wxSEMA_TIMEOUT
);
657 m_varSection
.Enter();
658 if ( err
!= wxSEMA_NO_ERROR
)
660 if ( m_signals
> m_canceled
)
662 // A signal is being sent after we timed out.
664 if ( m_waiters
== m_signals
)
666 // There are no excess waiters to catch the signal, so
667 // we must throw it away.
669 wxSemaError err2
= m_semaphore
.Wait();
670 if ( err2
!= wxSEMA_NO_ERROR
)
672 wxLogSysError(_("Error while waiting on semaphore"));
674 wxASSERT( err2
== wxSEMA_NO_ERROR
);
676 if ( -- m_signals
== m_canceled
)
678 // This was the last signal. open the gate.
679 wxASSERT( m_waiters
== m_canceled
);
685 // There are excess waiters to catch the signal, leave
692 // No signals is being sent.
693 // The gate may be open or closed, so we can't touch m_waiters.
700 // We caught a signal.
701 wxASSERT( m_signals
> m_canceled
);
703 if ( -- m_signals
== m_canceled
)
705 // This was the last signal. open the gate.
706 wxASSERT( m_waiters
== m_canceled
);
710 m_varSection
.Leave();
716 return err
== wxSEMA_TIMEOUT
? wxCOND_TIMEOUT
: wxCOND_MISC_ERROR
;
719 return wxCOND_NO_ERROR
;
723 wxCondError
wxConditionInternal::DoSignal( bool signalAll
)
726 m_varSection
.Enter();
728 wxASSERT( m_signals
== m_canceled
);
730 if ( m_waiters
== m_canceled
)
732 m_varSection
.Leave();
734 return wxCOND_NO_ERROR
;
739 m_waiters
-= m_canceled
;
744 m_signals
= signalAll
? m_waiters
: 1;
745 size_t n
= m_signals
;
747 m_varSection
.Leave();
749 // Let the waiters inherit the gate lock.
753 wxSemaError err
= m_semaphore
.Post();
754 wxASSERT( err
== wxSEMA_NO_ERROR
);
757 return wxCOND_NO_ERROR
;
761 class wxConditionInternal
764 wxConditionInternal(wxMutex
& mutex
);
766 bool IsOk() const { return m_mutex
.IsOk() && m_semaphore
.IsOk(); }
769 wxCondError
WaitTimeout(unsigned long milliseconds
);
771 wxCondError
Signal();
772 wxCondError
Broadcast();
775 // the number of threads currently waiting for this condition
778 // the critical section protecting m_numWaiters
779 wxCriticalSection m_csWaiters
;
782 wxSemaphore m_semaphore
;
784 DECLARE_NO_COPY_CLASS(wxConditionInternal
)
787 wxConditionInternal::wxConditionInternal(wxMutex
& mutex
)
790 // another thread can't access it until we return from ctor, so no need to
791 // protect access to m_numWaiters here
795 wxCondError
wxConditionInternal::Wait()
797 // increment the number of waiters
798 IncrementAtomic(&m_numWaiters
);
802 // a potential race condition can occur here
804 // after a thread increments nwaiters, and unlocks the mutex and before the
805 // semaphore.Wait() is called, if another thread can cause a signal to be
808 // this race condition is handled by using a semaphore and incrementing the
809 // semaphore only if 'nwaiters' is greater that zero since the semaphore,
810 // can 'remember' signals the race condition will not occur
812 // wait ( if necessary ) and decrement semaphore
813 wxSemaError err
= m_semaphore
.Wait();
816 return err
== wxSEMA_NO_ERROR
? wxCOND_NO_ERROR
: wxCOND_MISC_ERROR
;
819 wxCondError
wxConditionInternal::WaitTimeout(unsigned long milliseconds
)
821 IncrementAtomic(&m_numWaiters
);
825 // a race condition can occur at this point in the code
827 // please see the comments in Wait(), for details
829 wxSemaError err
= m_semaphore
.WaitTimeout(milliseconds
);
831 if ( err
== wxSEMA_BUSY
)
833 // another potential race condition exists here it is caused when a
834 // 'waiting' thread timesout, and returns from WaitForSingleObject, but
835 // has not yet decremented 'nwaiters'.
837 // at this point if another thread calls signal() then the semaphore
838 // will be incremented, but the waiting thread will miss it.
840 // to handle this particular case, the waiting thread calls
841 // WaitForSingleObject again with a timeout of 0, after locking
842 // 'nwaiters_mutex'. this call does not block because of the zero
843 // timeout, but will allow the waiting thread to catch the missed
845 wxCriticalSectionLocker
lock(m_csWaiters
);
847 err
= m_semaphore
.WaitTimeout(0);
849 if ( err
!= wxSEMA_NO_ERROR
)
857 return err
== wxSEMA_NO_ERROR
? wxCOND_NO_ERROR
: wxCOND_MISC_ERROR
;
860 wxCondError
wxConditionInternal::Signal()
862 wxCriticalSectionLocker
lock(m_csWaiters
);
864 if ( m_numWaiters
> 0 )
866 // increment the semaphore by 1
867 if ( m_semaphore
.Post() != wxSEMA_NO_ERROR
)
868 return wxCOND_MISC_ERROR
;
873 return wxCOND_NO_ERROR
;
876 wxCondError
wxConditionInternal::Broadcast()
878 wxCriticalSectionLocker
lock(m_csWaiters
);
880 while ( m_numWaiters
> 0 )
882 if ( m_semaphore
.Post() != wxSEMA_NO_ERROR
)
883 return wxCOND_MISC_ERROR
;
888 return wxCOND_NO_ERROR
;
892 // ----------------------------------------------------------------------------
893 // wxCriticalSection implementation
894 // ----------------------------------------------------------------------------
896 // XXX currently implemented as mutex in headers. Change to critical section.
898 // ----------------------------------------------------------------------------
899 // wxThread implementation
900 // ----------------------------------------------------------------------------
902 // wxThreadInternal class
903 // ----------------------
905 class wxThreadInternal
912 m_prio
= WXTHREAD_DEFAULT_PRIORITY
;
913 m_notifyQueueId
= kInvalidID
;
915 m_cancelled
= FALSE
;
917 // set to TRUE only when the thread starts waiting on m_semSuspend
920 // defaults for joinable threads
921 m_shouldBeJoined
= TRUE
;
922 m_isDetached
= FALSE
;
926 if ( m_notifyQueueId
)
928 MPDeleteQueue( m_notifyQueueId
);
929 m_notifyQueueId
= kInvalidID
;
934 static OSStatus
MacThreadStart(void* arg
);
936 // create a new (suspended) thread (for the given thread object)
937 bool Create(wxThread
*thread
, unsigned int stackSize
);
942 // unblock the thread allowing it to run
943 void SignalRun() { m_semRun
.Post(); }
944 // ask the thread to terminate
946 // go to sleep until Resume() is called
953 int GetPriority() const { return m_prio
; }
954 void SetPriority(int prio
) ;
956 wxThreadState
GetState() const { return m_state
; }
957 void SetState(wxThreadState state
) { m_state
= state
; }
959 // Get the ID of this thread's underlying MP Services task.
960 MPTaskID
GetId() const { return m_tid
; }
962 void SetCancelFlag() { m_cancelled
= TRUE
; }
963 bool WasCancelled() const { return m_cancelled
; }
965 void SetExitCode(wxThread::ExitCode exitcode
) { m_exitcode
= exitcode
; }
966 wxThread::ExitCode
GetExitCode() const { return m_exitcode
; }
969 void SetReallyPaused(bool paused
) { m_isPaused
= paused
; }
970 bool IsReallyPaused() const { return m_isPaused
; }
972 // tell the thread that it is a detached one
975 wxCriticalSectionLocker
lock(m_csJoinFlag
);
977 m_shouldBeJoined
= FALSE
;
982 // the thread we're associated with
985 MPTaskID m_tid
; // thread id
986 MPQueueID m_notifyQueueId
; // its notification queue
988 wxThreadState m_state
; // see wxThreadState enum
989 int m_prio
; // in wxWidgets units: from 0 to 100
991 // this flag is set when the thread should terminate
994 // this flag is set when the thread is blocking on m_semSuspend
997 // the thread exit code - only used for joinable (!detached) threads and
998 // is only valid after the thread termination
999 wxThread::ExitCode m_exitcode
;
1001 // many threads may call Wait(), but only one of them should call
1002 // pthread_join(), so we have to keep track of this
1003 wxCriticalSection m_csJoinFlag
;
1004 bool m_shouldBeJoined
;
1007 // this semaphore is posted by Run() and the threads Entry() is not
1008 // called before it is done
1009 wxSemaphore m_semRun
;
1011 // this one is signaled when the thread should resume after having been
1013 wxSemaphore m_semSuspend
;
1016 OSStatus
wxThreadInternal::MacThreadStart(void *parameter
)
1018 wxThread
* thread
= (wxThread
*) parameter
;
1019 wxThreadInternal
*pthread
= thread
->m_internal
;
1021 // add to TLS so that This() will work
1022 verify_noerr( MPSetTaskStorageValue( gs_tlsForWXThread
, (long) thread
) ) ;
1024 // have to declare this before pthread_cleanup_push() which defines a
1028 // wait for the semaphore to be posted from Run()
1029 pthread
->m_semRun
.Wait();
1031 // test whether we should run the run at all - may be it was deleted
1032 // before it started to Run()?
1034 wxCriticalSectionLocker
lock(thread
->m_critsect
);
1036 dontRunAtAll
= pthread
->GetState() == STATE_NEW
&&
1037 pthread
->WasCancelled();
1040 if ( !dontRunAtAll
)
1042 pthread
->m_exitcode
= thread
->Entry();
1045 wxCriticalSectionLocker
lock(thread
->m_critsect
);
1046 pthread
->SetState(STATE_EXITED
);
1052 if ( pthread
->m_isDetached
)
1059 // on mac for the running code the correct thread termination is to
1062 // terminate the thread
1063 thread
->Exit(pthread
->m_exitcode
);
1065 return (OSStatus
) NULL
; // pthread->m_exitcode;
1069 bool wxThreadInternal::Create(wxThread
*thread
, unsigned int stackSize
)
1071 wxASSERT_MSG( m_state
== STATE_NEW
&& !m_tid
,
1072 _T("Create()ing thread twice?") );
1074 OSStatus err
= noErr
;
1077 if ( m_notifyQueueId
== kInvalidID
)
1079 OSStatus err
= MPCreateQueue( & m_notifyQueueId
);
1082 wxLogSysError(_("Cant create the thread event queue"));
1087 m_state
= STATE_NEW
;
1089 err
= MPCreateTask( MacThreadStart
,
1100 wxLogSysError(_("Can't create thread"));
1104 if ( m_prio
!= WXTHREAD_DEFAULT_PRIORITY
)
1106 SetPriority(m_prio
);
1112 void wxThreadInternal::SetPriority( int priority
)
1118 // Mac priorities range from 1 to 10,000, with a default of 100.
1119 // wxWidgets priorities range from 0 to 100 with a default of 50.
1120 // We can map wxWidgets to Mac priorities easily by assuming
1121 // the former uses a logarithmic scale.
1122 const unsigned int macPriority
= ( int)( exp( priority
/ 25.0 * log( 10.0)) + 0.5);
1124 MPSetTaskWeight( m_tid
, macPriority
);
1128 wxThreadError
wxThreadInternal::Run()
1130 wxCHECK_MSG( GetState() == STATE_NEW
, wxTHREAD_RUNNING
,
1131 wxT("thread may only be started once after Create()") );
1133 SetState(STATE_RUNNING
);
1135 // wake up threads waiting for our start
1138 return wxTHREAD_NO_ERROR
;
1141 void wxThreadInternal::Wait()
1143 wxCHECK_RET( !m_isDetached
, _T("can't wait for a detached thread") );
1145 // if the thread we're waiting for is waiting for the GUI mutex, we will
1146 // deadlock so make sure we release it temporarily
1147 if ( wxThread::IsMain() )
1149 // give the thread we're waiting for chance to do the GUI call
1150 // it might be in, we don't do this conditionally as the to be waited on
1151 // thread might have to acquire the mutex later but before terminating
1152 if ( wxGuiOwnedByMainThread() )
1159 wxCriticalSectionLocker
lock(m_csJoinFlag
);
1161 if ( m_shouldBeJoined
)
1167 OSStatus err
= MPWaitOnQueue ( m_notifyQueueId
,
1174 wxLogSysError( _( "Cannot wait for thread termination."));
1178 // actually param1 would be the address of m_exitcode
1179 // but we don't need this here
1182 m_shouldBeJoined
= FALSE
;
1187 void wxThreadInternal::Pause()
1189 // the state is set from the thread which pauses us first, this function
1190 // is called later so the state should have been already set
1191 wxCHECK_RET( m_state
== STATE_PAUSED
,
1192 wxT("thread must first be paused with wxThread::Pause().") );
1194 // wait until the semaphore is Post()ed from Resume()
1195 m_semSuspend
.Wait();
1198 void wxThreadInternal::Resume()
1200 wxCHECK_RET( m_state
== STATE_PAUSED
,
1201 wxT("can't resume thread which is not suspended.") );
1203 // the thread might be not actually paused yet - if there were no call to
1204 // TestDestroy() since the last call to Pause() for example
1205 if ( IsReallyPaused() )
1208 m_semSuspend
.Post();
1211 SetReallyPaused(FALSE
);
1214 SetState(STATE_RUNNING
);
1220 wxThread
*wxThread::This()
1222 wxThread
* thr
= (wxThread
*) MPGetTaskStorageValue( gs_tlsForWXThread
) ;
1226 bool wxThread::IsMain()
1228 return GetCurrentId() == gs_idMainThread
|| gs_idMainThread
== kInvalidID
;
1235 void wxThread::Yield()
1237 #if TARGET_API_MAC_OSX
1238 CFRunLoopRunInMode( kCFRunLoopDefaultMode
, 0 , true ) ;
1244 void wxThread::Sleep(unsigned long milliseconds
)
1246 AbsoluteTime wakeup
= AddDurationToAbsolute( milliseconds
, UpTime());
1247 MPDelayUntil( & wakeup
);
1251 int wxThread::GetCPUCount()
1253 return MPProcessors();
1256 unsigned long wxThread::GetCurrentId()
1258 return (unsigned long)MPCurrentTaskID();
1262 bool wxThread::SetConcurrency(size_t level
)
1264 // Cannot be set in MacOS.
1269 wxThread::wxThread(wxThreadKind kind
)
1271 g_numberOfThreads
++;
1272 m_internal
= new wxThreadInternal();
1274 m_isDetached
= (kind
== wxTHREAD_DETACHED
);
1277 wxThread::~wxThread()
1279 wxASSERT_MSG( g_numberOfThreads
>0 , wxT("More threads deleted than created.") ) ;
1280 g_numberOfThreads
--;
1285 // check that the thread either exited or couldn't be created
1286 if ( m_internal
->GetState() != STATE_EXITED
&&
1287 m_internal
->GetState() != STATE_NEW
)
1289 wxLogDebug(_T("The thread %ld is being destroyed although it is still running! The application may crash."), GetId());
1293 #endif // __WXDEBUG__
1295 wxDELETE( m_internal
) ;
1299 wxThreadError
wxThread::Create(unsigned int stackSize
)
1301 wxCriticalSectionLocker
lock(m_critsect
);
1305 m_internal
->Detach() ;
1307 if ( m_internal
->Create(this, stackSize
) == false )
1309 m_internal
->SetState(STATE_EXITED
);
1310 return wxTHREAD_NO_RESOURCE
;
1313 return wxTHREAD_NO_ERROR
;
1316 wxThreadError
wxThread::Run()
1318 wxCriticalSectionLocker
lock(m_critsect
);
1320 wxCHECK_MSG( m_internal
->GetId(), wxTHREAD_MISC_ERROR
,
1321 wxT("must call wxThread::Create() first") );
1323 return m_internal
->Run();
1326 // -----------------------------------------------------------------------------
1328 // -----------------------------------------------------------------------------
1330 wxThreadError
wxThread::Pause()
1332 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR
,
1333 _T("a thread can't pause itself") );
1335 wxCriticalSectionLocker
lock(m_critsect
);
1337 if ( m_internal
->GetState() != STATE_RUNNING
)
1339 wxLogDebug(wxT("Can't pause thread which is not running."));
1341 return wxTHREAD_NOT_RUNNING
;
1344 // just set a flag, the thread will be really paused only during the next
1345 // call to TestDestroy()
1346 m_internal
->SetState(STATE_PAUSED
);
1348 return wxTHREAD_NO_ERROR
;
1351 wxThreadError
wxThread::Resume()
1353 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR
,
1354 _T("a thread can't resume itself") );
1356 wxCriticalSectionLocker
lock(m_critsect
);
1358 wxThreadState state
= m_internal
->GetState();
1363 m_internal
->Resume();
1364 return wxTHREAD_NO_ERROR
;
1366 return wxTHREAD_NO_ERROR
;
1369 wxLogDebug(_T("Attempt to resume a thread which is not paused."));
1371 return wxTHREAD_MISC_ERROR
;
1375 // -----------------------------------------------------------------------------
1377 // -----------------------------------------------------------------------------
1379 wxThread::ExitCode
wxThread::Wait()
1381 wxCHECK_MSG( This() != this, (ExitCode
)-1,
1382 _T("a thread can't wait for itself") );
1384 wxCHECK_MSG( !m_isDetached
, (ExitCode
)-1,
1385 _T("can't wait for detached thread") );
1389 return m_internal
->GetExitCode();
1392 wxThreadError
wxThread::Delete(ExitCode
*rc
)
1394 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR
,
1395 _T("a thread can't delete itself") );
1397 bool isDetached
= m_isDetached
;
1400 wxThreadState state
= m_internal
->GetState();
1402 // ask the thread to stop
1403 m_internal
->SetCancelFlag();
1410 // we need to wake up the thread so that PthreadStart() will
1411 // terminate - right now it's blocking on run semaphore in
1413 m_internal
->SignalRun();
1422 // resume the thread first
1423 m_internal
->Resume();
1430 // wait until the thread stops
1435 // return the exit code of the thread
1436 *rc
= m_internal
->GetExitCode();
1441 return wxTHREAD_NO_ERROR
;
1444 wxThreadError
wxThread::Kill()
1446 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR
,
1447 _T("a thread can't kill itself") );
1449 switch ( m_internal
->GetState() )
1453 return wxTHREAD_NOT_RUNNING
;
1456 // resume the thread first
1462 OSStatus err
= MPTerminateTask( m_internal
->GetId() , -1 ) ;
1465 wxLogError(_("Failed to terminate a thread."));
1467 return wxTHREAD_MISC_ERROR
;
1476 // this should be retrieved by Wait actually
1477 m_internal
->SetExitCode((void*)-1);
1480 return wxTHREAD_NO_ERROR
;
1484 void wxThread::Exit(ExitCode status
)
1486 wxASSERT_MSG( This() == this,
1487 _T("wxThread::Exit() can only be called in the context of the same thread") );
1489 // don't enter m_critsect before calling OnExit() because the user code
1490 // might deadlock if, for example, it signals a condition in OnExit() (a
1491 // common case) while the main thread calls any of functions entering
1492 // m_critsect on us (almost all of them do)
1495 MPTaskID threadid
= m_internal
->GetId() ;
1503 // update the status of the joinable thread
1504 wxCriticalSectionLocker
lock(m_critsect
);
1505 m_internal
->SetState(STATE_EXITED
);
1507 MPTerminateTask( threadid
, (long) status
) ;
1510 // also test whether we were paused
1511 bool wxThread::TestDestroy()
1513 wxASSERT_MSG( This() == this,
1514 _T("wxThread::TestDestroy() can only be called in the context of the same thread") );
1518 if ( m_internal
->GetState() == STATE_PAUSED
)
1520 m_internal
->SetReallyPaused(TRUE
);
1522 // leave the crit section or the other threads will stop too if they
1523 // try to call any of (seemingly harmless) IsXXX() functions while we
1527 m_internal
->Pause();
1531 // thread wasn't requested to pause, nothing to do
1535 return m_internal
->WasCancelled();
1538 // -----------------------------------------------------------------------------
1540 // -----------------------------------------------------------------------------
1542 void wxThread::SetPriority(unsigned int prio
)
1544 wxCHECK_RET( ((int)WXTHREAD_MIN_PRIORITY
<= (int)prio
) &&
1545 ((int)prio
<= (int)WXTHREAD_MAX_PRIORITY
),
1546 wxT("invalid thread priority") );
1548 wxCriticalSectionLocker
lock(m_critsect
);
1550 switch ( m_internal
->GetState() )
1555 // thread not yet started, priority will be set when it is
1556 m_internal
->SetPriority(prio
);
1561 wxFAIL_MSG(wxT("impossible to set thread priority in this state"));
1565 unsigned int wxThread::GetPriority() const
1567 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
); // const_cast
1569 return m_internal
->GetPriority();
1572 unsigned long wxThread::GetId() const
1574 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
); // const_cast
1576 return (unsigned long)m_internal
->GetId();
1579 // -----------------------------------------------------------------------------
1581 // -----------------------------------------------------------------------------
1583 bool wxThread::IsRunning() const
1585 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
1587 return m_internal
->GetState() == STATE_RUNNING
;
1590 bool wxThread::IsAlive() const
1592 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
1594 switch ( m_internal
->GetState() )
1605 bool wxThread::IsPaused() const
1607 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
1609 return (m_internal
->GetState() == STATE_PAUSED
);
1612 // ----------------------------------------------------------------------------
1613 // Automatic initialization for thread module
1614 // ----------------------------------------------------------------------------
1616 class wxThreadModule
: public wxModule
1619 virtual bool OnInit();
1620 virtual void OnExit();
1623 DECLARE_DYNAMIC_CLASS(wxThreadModule
)
1626 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule
, wxModule
)
1628 bool wxThreadModule::OnInit()
1630 bool hasThreadManager
= false ;
1631 hasThreadManager
= MPLibraryIsLoaded();
1633 if ( !hasThreadManager
)
1635 wxLogError( _("MP Thread Support is not available on this System" ) ) ;
1639 verify_noerr( MPAllocateTaskStorageIndex( &gs_tlsForWXThread
) ) ;
1640 // main thread's This() is NULL
1641 verify_noerr( MPSetTaskStorageValue( gs_tlsForWXThread
, 0 ) ) ;
1643 gs_idMainThread
= wxThread::GetCurrentId() ;
1645 gs_critsectWaitingForGui
= new wxCriticalSection();
1647 gs_critsectGui
= new wxCriticalSection();
1648 gs_critsectGui
->Enter();
1653 void wxThreadModule::OnExit()
1655 if ( gs_critsectGui
)
1657 if ( !wxGuiOwnedByMainThread() )
1659 gs_critsectGui
->Enter();
1660 gs_bGuiOwnedByMainThread
= true;
1662 gs_critsectGui
->Leave();
1663 delete gs_critsectGui
;
1664 gs_critsectGui
= NULL
;
1667 delete gs_critsectWaitingForGui
;
1668 gs_critsectWaitingForGui
= NULL
;
1671 // ----------------------------------------------------------------------------
1672 // GUI Serialization copied from MSW implementation
1673 // ----------------------------------------------------------------------------
1675 void WXDLLIMPEXP_BASE
wxMutexGuiEnter()
1677 // this would dead lock everything...
1678 wxASSERT_MSG( !wxThread::IsMain(),
1679 wxT("main thread doesn't want to block in wxMutexGuiEnter()!") );
1681 // the order in which we enter the critical sections here is crucial!!
1683 // set the flag telling to the main thread that we want to do some GUI
1685 wxCriticalSectionLocker
enter(*gs_critsectWaitingForGui
);
1687 gs_nWaitingForGui
++;
1690 wxWakeUpMainThread();
1692 // now we may block here because the main thread will soon let us in
1693 // (during the next iteration of OnIdle())
1694 gs_critsectGui
->Enter();
1697 void WXDLLIMPEXP_BASE
wxMutexGuiLeave()
1699 wxCriticalSectionLocker
enter(*gs_critsectWaitingForGui
);
1701 if ( wxThread::IsMain() )
1703 gs_bGuiOwnedByMainThread
= false;
1707 // decrement the number of threads waiting for GUI access now
1708 wxASSERT_MSG( gs_nWaitingForGui
> 0,
1709 wxT("calling wxMutexGuiLeave() without entering it first?") );
1711 gs_nWaitingForGui
--;
1713 wxWakeUpMainThread();
1716 gs_critsectGui
->Leave();
1719 void WXDLLIMPEXP_BASE
wxMutexGuiLeaveOrEnter()
1721 wxASSERT_MSG( wxThread::IsMain(),
1722 wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") );
1724 wxCriticalSectionLocker
enter(*gs_critsectWaitingForGui
);
1726 if ( gs_nWaitingForGui
== 0 )
1728 // no threads are waiting for GUI - so we may acquire the lock without
1729 // any danger (but only if we don't already have it)
1730 if ( !wxGuiOwnedByMainThread() )
1732 gs_critsectGui
->Enter();
1734 gs_bGuiOwnedByMainThread
= true;
1736 //else: already have it, nothing to do
1740 // some threads are waiting, release the GUI lock if we have it
1741 if ( wxGuiOwnedByMainThread() )
1745 //else: some other worker thread is doing GUI
1749 bool WXDLLIMPEXP_BASE
wxGuiOwnedByMainThread()
1751 return gs_bGuiOwnedByMainThread
;
1754 // wake up the main thread
1755 void WXDLLEXPORT
wxWakeUpMainThread()
1760 // ----------------------------------------------------------------------------
1761 // include common implementation code
1762 // ----------------------------------------------------------------------------
1764 #include "wx/thrimpl.cpp"
1766 #endif // wxUSE_THREADS