1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/carbon/thread.cpp
3 // Purpose: wxThread Implementation
4 // Author: Original from Wolfram Gloger/Guilhem Lavaux/Vadim Zeitlin
5 // Modified by: Aj Lavin, Stefan Csomor
7 // Copyright: (c) Wolfram Gloger (1996, 1997); Guilhem Lavaux (1998),
8 // Vadim Zeitlin (1999), Stefan Csomor (2000)
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 #include "wx/wxprec.h"
14 #if defined(__BORLANDC__)
20 #include "wx/module.h"
25 #include "wx/thread.h"
27 #if wxOSX_USE_COCOA_OR_CARBON
28 #include <CoreServices/CoreServices.h>
30 #include <Foundation/Foundation.h>
33 #include "wx/osx/uma.h"
35 // the possible states of the thread:
36 // ("=>" shows all possible transitions from this state)
39 STATE_NEW
, // didn't start execution yet (=> RUNNING)
40 STATE_RUNNING
, // thread is running (=> PAUSED, CANCELED)
41 STATE_PAUSED
, // thread is temporarily suspended (=> RUNNING)
42 STATE_CANCELED
, // thread should terminate a.s.a.p. (=> EXITED)
43 STATE_EXITED
// thread is terminating
46 // ----------------------------------------------------------------------------
48 // ----------------------------------------------------------------------------
50 // the task ID of the main thread
51 wxThreadIdType
wxThread::ms_idMainThread
= kInvalidID
;
53 // this is the Per-Task Storage for the pointer to the appropriate wxThread
54 TaskStorageIndex gs_tlsForWXThread
= 0;
56 // if it's false, some secondary thread is holding the GUI lock
57 static bool gs_bGuiOwnedByMainThread
= true;
59 // critical section which controls access to all GUI functions: any secondary
60 // thread (i.e. except the main one) must enter this crit section before doing
62 static wxCriticalSection
*gs_critsectGui
= NULL
;
64 // critical section which protects gs_nWaitingForGui variable
65 static wxCriticalSection
*gs_critsectWaitingForGui
= NULL
;
67 // number of threads waiting for GUI in wxMutexGuiEnter()
68 static size_t gs_nWaitingForGui
= 0;
70 // overall number of threads, needed for determining
71 // the sleep value of the main event loop
72 size_t g_numberOfThreads
= 0;
76 MPCriticalRegionID gs_guiCritical
= kInvalidID
;
79 // ============================================================================
80 // MacOS implementation of thread classes
81 // ============================================================================
86 The implementation is very close to the phtreads implementation, the reason for
87 using MPServices is the fact that these are also available under OS 9. Thus allowing
88 for one common API for all current builds.
90 As soon as wxThreads are on a 64 bit address space, the TLS must be extended
91 to use two indices one for each 32 bit part as the MP implementation is limited
94 I have three implementations for mutexes :
95 version A based on a binary semaphore, problem - not reentrant, version B based
96 on a critical region, allows for reentrancy, performance implications not
97 yet tested, and third a plain pthreads implementation
99 The same for condition internal, one implementation by Aj Lavin and the other one
100 copied from the thrimpl.cpp which I assume has been more broadly tested, I've just
101 replaced the interlock increment with the appropriate PPC calls
104 // ----------------------------------------------------------------------------
106 // ----------------------------------------------------------------------------
108 wxCriticalSection::wxCriticalSection( wxCriticalSectionType
WXUNUSED(critSecType
) )
110 MPCreateCriticalRegion( (MPCriticalRegionID
*) &m_critRegion
);
113 wxCriticalSection::~wxCriticalSection()
115 MPDeleteCriticalRegion( (MPCriticalRegionID
) m_critRegion
);
118 void wxCriticalSection::Enter()
120 MPEnterCriticalRegion( (MPCriticalRegionID
) m_critRegion
, kDurationForever
);
123 bool wxCriticalSection::TryEnter()
125 return MPEnterCriticalRegion( (MPCriticalRegionID
) m_critRegion
, kDurationImmediate
) == noErr
;
128 void wxCriticalSection::Leave()
130 MPExitCriticalRegion( (MPCriticalRegionID
) m_critRegion
);
133 // ----------------------------------------------------------------------------
134 // wxMutex implementation
135 // ----------------------------------------------------------------------------
137 #define wxUSE_MAC_SEMAPHORE_MUTEX 0
138 #define wxUSE_MAC_CRITICAL_REGION_MUTEX 1
139 #define wxUSE_MAC_PTHREADS_MUTEX 0
141 #if wxUSE_MAC_CRITICAL_REGION_MUTEX
143 class wxMutexInternal
146 wxMutexInternal( wxMutexType mutexType
);
147 virtual ~wxMutexInternal();
149 bool IsOk() const { return m_isOk
; }
151 wxMutexError
Lock() { return Lock(kDurationForever
); }
152 wxMutexError
Lock(unsigned long ms
);
153 wxMutexError
TryLock();
154 wxMutexError
Unlock();
157 MPCriticalRegionID m_critRegion
;
161 wxMutexInternal::wxMutexInternal( wxMutexType
WXUNUSED(mutexType
) )
164 m_critRegion
= kInvalidID
;
166 verify_noerr( MPCreateCriticalRegion( &m_critRegion
) );
167 m_isOk
= ( m_critRegion
!= kInvalidID
);
170 wxFAIL_MSG( wxT("Error when creating mutex") );
174 wxMutexInternal::~wxMutexInternal()
176 if ( m_critRegion
!= kInvalidID
)
177 MPDeleteCriticalRegion( m_critRegion
);
182 wxMutexError
wxMutexInternal::Lock(unsigned long ms
)
184 wxCHECK_MSG( m_isOk
, wxMUTEX_MISC_ERROR
, wxT("Invalid Mutex") );
186 OSStatus err
= MPEnterCriticalRegion( m_critRegion
, ms
);
193 wxASSERT_MSG( ms
!= kDurationForever
, wxT("unexpected timeout") );
194 return wxMUTEX_TIMEOUT
;
197 wxLogSysError(wxT("Could not lock mutex"));
198 return wxMUTEX_MISC_ERROR
;
201 return wxMUTEX_NO_ERROR
;
204 wxMutexError
wxMutexInternal::TryLock()
206 wxCHECK_MSG( m_isOk
, wxMUTEX_MISC_ERROR
, wxT("Invalid Mutex") ) ;
208 OSStatus err
= MPEnterCriticalRegion( m_critRegion
, kDurationImmediate
);
211 if ( err
== kMPTimeoutErr
)
214 wxLogSysError( wxT("Could not try lock mutex") );
215 return wxMUTEX_MISC_ERROR
;
218 return wxMUTEX_NO_ERROR
;
221 wxMutexError
wxMutexInternal::Unlock()
223 wxCHECK_MSG( m_isOk
, wxMUTEX_MISC_ERROR
, wxT("Invalid Mutex") ) ;
225 OSStatus err
= MPExitCriticalRegion( m_critRegion
);
230 wxLogSysError( wxT("Could not unlock mutex") );
232 return wxMUTEX_MISC_ERROR
;
235 return wxMUTEX_NO_ERROR
;
240 // --------------------------------------------------------------------------
242 // --------------------------------------------------------------------------
244 class wxSemaphoreInternal
247 wxSemaphoreInternal( int initialcount
, int maxcount
);
248 virtual ~wxSemaphoreInternal();
254 wxSemaError
WaitTimeout( unsigned long milliseconds
);
257 { return WaitTimeout( kDurationForever
); }
259 wxSemaError
TryWait()
261 wxSemaError err
= WaitTimeout( kDurationImmediate
);
262 if (err
== wxSEMA_TIMEOUT
)
269 MPSemaphoreID m_semaphore
;
273 wxSemaphoreInternal::wxSemaphoreInternal( int initialcount
, int maxcount
)
276 m_semaphore
= kInvalidID
;
278 // make it practically infinite
281 verify_noerr( MPCreateSemaphore( maxcount
, initialcount
, &m_semaphore
) );
282 m_isOk
= ( m_semaphore
!= kInvalidID
);
286 wxFAIL_MSG( wxT("Error when creating semaphore") );
290 wxSemaphoreInternal::~wxSemaphoreInternal()
292 if (m_semaphore
!= kInvalidID
)
293 MPDeleteSemaphore( m_semaphore
);
298 wxSemaError
wxSemaphoreInternal::WaitTimeout( unsigned long milliseconds
)
300 OSStatus err
= MPWaitOnSemaphore( m_semaphore
, milliseconds
);
303 if (err
== kMPTimeoutErr
)
304 return wxSEMA_TIMEOUT
;
306 return wxSEMA_MISC_ERROR
;
309 return wxSEMA_NO_ERROR
;
312 wxSemaError
wxSemaphoreInternal::Post()
314 OSStatus err
= MPSignalSemaphore( m_semaphore
);
317 return wxSEMA_MISC_ERROR
;
319 return wxSEMA_NO_ERROR
;
322 // ----------------------------------------------------------------------------
323 // wxCondition implementation
324 // ----------------------------------------------------------------------------
326 class wxConditionInternal
329 wxConditionInternal( wxMutex
& mutex
);
332 { return m_mutex
.IsOk() && m_semaphore
.IsOk(); }
335 wxCondError
WaitTimeout( unsigned long milliseconds
);
337 wxCondError
Signal();
338 wxCondError
Broadcast();
341 // the number of threads currently waiting for this condition
344 // the critical section protecting m_numWaiters
345 wxCriticalSection m_csWaiters
;
348 wxSemaphore m_semaphore
;
350 wxDECLARE_NO_COPY_CLASS(wxConditionInternal
);
353 wxConditionInternal::wxConditionInternal( wxMutex
& mutex
)
356 // another thread can't access it until we return from ctor, so no need to
357 // protect access to m_numWaiters here
361 wxCondError
wxConditionInternal::Wait()
363 // increment the number of waiters
364 IncrementAtomic( &m_numWaiters
);
368 // a potential race condition can occur here
370 // after a thread increments nwaiters, and unlocks the mutex and before the
371 // semaphore.Wait() is called, if another thread can cause a signal to be
374 // this race condition is handled by using a semaphore and incrementing the
375 // semaphore only if 'nwaiters' is greater that zero since the semaphore,
376 // can 'remember' signals the race condition will not occur
378 // wait ( if necessary ) and decrement semaphore
379 wxSemaError err
= m_semaphore
.Wait();
382 return err
== wxSEMA_NO_ERROR
? wxCOND_NO_ERROR
: wxCOND_MISC_ERROR
;
385 wxCondError
wxConditionInternal::WaitTimeout( unsigned long milliseconds
)
387 IncrementAtomic( &m_numWaiters
);
391 // a race condition can occur at this point in the code
393 // please see the comments in Wait(), for details
395 wxSemaError err
= m_semaphore
.WaitTimeout(milliseconds
);
397 if ( err
== wxSEMA_TIMEOUT
)
399 // another potential race condition exists here it is caused when a
400 // 'waiting' thread timesout, and returns from WaitForSingleObject, but
401 // has not yet decremented 'nwaiters'.
403 // at this point if another thread calls signal() then the semaphore
404 // will be incremented, but the waiting thread will miss it.
406 // to handle this particular case, the waiting thread calls
407 // WaitForSingleObject again with a timeout of 0, after locking
408 // 'nwaiters_mutex'. this call does not block because of the zero
409 // timeout, but will allow the waiting thread to catch the missed
411 wxCriticalSectionLocker
lock(m_csWaiters
);
413 err
= m_semaphore
.WaitTimeout(0);
415 if ( err
!= wxSEMA_NO_ERROR
)
423 return err
== wxSEMA_NO_ERROR
? wxCOND_NO_ERROR
: wxCOND_MISC_ERROR
;
426 wxCondError
wxConditionInternal::Signal()
428 wxCriticalSectionLocker
lock(m_csWaiters
);
430 if ( m_numWaiters
> 0 )
432 // increment the semaphore by 1
433 if ( m_semaphore
.Post() != wxSEMA_NO_ERROR
)
434 return wxCOND_MISC_ERROR
;
439 return wxCOND_NO_ERROR
;
442 wxCondError
wxConditionInternal::Broadcast()
444 wxCriticalSectionLocker
lock(m_csWaiters
);
446 while ( m_numWaiters
> 0 )
448 if ( m_semaphore
.Post() != wxSEMA_NO_ERROR
)
449 return wxCOND_MISC_ERROR
;
454 return wxCOND_NO_ERROR
;
457 // ----------------------------------------------------------------------------
458 // wxCriticalSection implementation
459 // ----------------------------------------------------------------------------
461 // XXX currently implemented as mutex in headers. Change to critical section.
463 // ----------------------------------------------------------------------------
464 // wxThread implementation
465 // ----------------------------------------------------------------------------
467 // wxThreadInternal class
468 // ----------------------
470 class wxThreadInternal
477 m_prio
= wxPRIORITY_DEFAULT
;
478 m_notifyQueueId
= kInvalidID
;
480 m_cancelled
= false ;
482 // set to true only when the thread starts waiting on m_semSuspend
485 // defaults for joinable threads
486 m_shouldBeJoined
= true;
487 m_isDetached
= false;
490 virtual ~wxThreadInternal()
492 if ( m_notifyQueueId
)
494 MPDeleteQueue( m_notifyQueueId
);
495 m_notifyQueueId
= kInvalidID
;
500 static OSStatus
MacThreadStart(void* arg
);
502 // create a new (suspended) thread (for the given thread object)
503 bool Create(wxThread
*thread
, unsigned int stackSize
);
510 // unblock the thread allowing it to run
511 void SignalRun() { m_semRun
.Post(); }
513 // ask the thread to terminate
516 // go to sleep until Resume() is called
524 int GetPriority() const
526 void SetPriority(int prio
);
529 wxThreadState
GetState() const
531 void SetState(wxThreadState state
)
534 // Get the ID of this thread's underlying MP Services task.
535 MPTaskID
GetId() const
539 { m_cancelled
= true; }
541 bool WasCancelled() const
542 { return m_cancelled
; }
545 void SetExitCode(wxThread::ExitCode exitcode
)
546 { m_exitcode
= exitcode
; }
547 wxThread::ExitCode
GetExitCode() const
548 { return m_exitcode
; }
551 void SetReallyPaused(bool paused
)
552 { m_isPaused
= paused
; }
553 bool IsReallyPaused() const
554 { return m_isPaused
; }
556 // tell the thread that it is a detached one
559 wxCriticalSectionLocker
lock(m_csJoinFlag
);
561 m_shouldBeJoined
= false;
566 // the thread we're associated with
569 MPTaskID m_tid
; // thread id
570 MPQueueID m_notifyQueueId
; // its notification queue
572 wxThreadState m_state
; // see wxThreadState enum
573 int m_prio
; // in wxWidgets units: from 0 to 100
575 // this flag is set when the thread should terminate
578 // this flag is set when the thread is blocking on m_semSuspend
581 // the thread exit code - only used for joinable (!detached) threads and
582 // is only valid after the thread termination
583 wxThread::ExitCode m_exitcode
;
585 // many threads may call Wait(), but only one of them should call
586 // pthread_join(), so we have to keep track of this
587 wxCriticalSection m_csJoinFlag
;
588 bool m_shouldBeJoined
;
591 // this semaphore is posted by Run() and the threads Entry() is not
592 // called before it is done
593 wxSemaphore m_semRun
;
595 // this one is signaled when the thread should resume after having been
597 wxSemaphore m_semSuspend
;
600 OSStatus
wxThreadInternal::MacThreadStart(void *parameter
)
602 wxThread
* thread
= (wxThread
*) parameter
;
603 wxThreadInternal
*pthread
= thread
->m_internal
;
605 // add to TLS so that This() will work
606 verify_noerr( MPSetTaskStorageValue( gs_tlsForWXThread
, (TaskStorageValue
) thread
) ) ;
608 // have to declare this before pthread_cleanup_push() which defines a
612 // wait for the semaphore to be posted from Run()
613 pthread
->m_semRun
.Wait();
615 // test whether we should run the run at all - may be it was deleted
616 // before it started to Run()?
618 wxCriticalSectionLocker
lock(thread
->m_critsect
);
620 dontRunAtAll
= pthread
->GetState() == STATE_NEW
&&
621 pthread
->WasCancelled();
626 pthread
->m_exitcode
= thread
->CallEntry();
629 wxCriticalSectionLocker
lock(thread
->m_critsect
);
630 pthread
->SetState( STATE_EXITED
);
636 if ( pthread
->m_isDetached
)
643 // on Mac for the running code,
644 // the correct thread termination is to return
646 // terminate the thread
647 thread
->Exit( pthread
->m_exitcode
);
649 return (OSStatus
) NULL
; // pthread->m_exitcode;
653 bool wxThreadInternal::Create( wxThread
*thread
, unsigned int stackSize
)
655 wxASSERT_MSG( m_state
== STATE_NEW
&& !m_tid
,
656 wxT("Create()ing thread twice?") );
658 if ( thread
->IsDetached() )
661 OSStatus err
= noErr
;
664 if ( m_notifyQueueId
== kInvalidID
)
666 OSStatus err
= MPCreateQueue( &m_notifyQueueId
);
669 wxLogSysError( wxT("Can't create the thread event queue") );
678 MacThreadStart
, (void*)m_thread
, stackSize
,
679 m_notifyQueueId
, &m_exitcode
, 0, 0, &m_tid
);
683 wxLogSysError( wxT("Can't create thread") );
688 if ( m_prio
!= wxPRIORITY_DEFAULT
)
689 SetPriority( m_prio
);
694 void wxThreadInternal::SetPriority( int priority
)
700 // Mac priorities range from 1 to 10,000, with a default of 100.
701 // wxWidgets priorities range from 0 to 100 with a default of 50.
702 // We can map wxWidgets to Mac priorities easily by assuming
703 // the former uses a logarithmic scale.
704 const unsigned int macPriority
= (int)( exp( priority
/ 25.0 * log( 10.0)) + 0.5);
706 MPSetTaskWeight( m_tid
, macPriority
);
710 wxThreadError
wxThreadInternal::Run()
712 wxCHECK_MSG( GetState() == STATE_NEW
, wxTHREAD_RUNNING
,
713 wxT("thread may only be started once after Create()") );
715 SetState( STATE_RUNNING
);
717 // wake up threads waiting for our start
720 return wxTHREAD_NO_ERROR
;
723 void wxThreadInternal::Wait()
725 wxCHECK_RET( !m_isDetached
, wxT("can't wait for a detached thread") );
727 // if the thread we're waiting for is waiting for the GUI mutex, we will
728 // deadlock so make sure we release it temporarily
729 if ( wxThread::IsMain() )
731 // give the thread we're waiting for chance to do the GUI call
732 // it might be in, we don't do this conditionally as the to be waited on
733 // thread might have to acquire the mutex later but before terminating
734 if ( wxGuiOwnedByMainThread() )
739 wxCriticalSectionLocker
lock(m_csJoinFlag
);
741 if ( m_shouldBeJoined
)
743 void *param1
, *param2
, *rc
;
745 OSStatus err
= MPWaitOnQueue(
753 wxLogSysError( wxT( "Cannot wait for thread termination."));
757 // actually param1 would be the address of m_exitcode
758 // but we don't need this here
761 m_shouldBeJoined
= false;
766 void wxThreadInternal::Pause()
768 // the state is set from the thread which pauses us first, this function
769 // is called later so the state should have been already set
770 wxCHECK_RET( m_state
== STATE_PAUSED
,
771 wxT("thread must first be paused with wxThread::Pause().") );
773 // wait until the semaphore is Post()ed from Resume()
777 void wxThreadInternal::Resume()
779 wxCHECK_RET( m_state
== STATE_PAUSED
,
780 wxT("can't resume thread which is not suspended.") );
782 // the thread might be not actually paused yet - if there were no call to
783 // TestDestroy() since the last call to Pause() for example
784 if ( IsReallyPaused() )
790 SetReallyPaused( false );
793 SetState( STATE_RUNNING
);
799 wxThread
*wxThread::This()
801 wxThread
* thr
= (wxThread
*) MPGetTaskStorageValue( gs_tlsForWXThread
) ;
810 void wxThread::Yield()
812 CFRunLoopRunInMode( kCFRunLoopDefaultMode
, 0 , true ) ;
817 void wxThread::Sleep( unsigned long milliseconds
)
819 AbsoluteTime wakeup
= AddDurationToAbsolute( milliseconds
, UpTime() );
820 MPDelayUntil( &wakeup
);
823 int wxThread::GetCPUCount()
825 return MPProcessors();
828 unsigned long wxThread::GetCurrentId()
830 return (unsigned long)MPCurrentTaskID();
833 bool wxThread::SetConcurrency( size_t WXUNUSED(level
) )
835 // Cannot be set in MacOS.
839 wxThread::wxThread( wxThreadKind kind
)
842 m_internal
= new wxThreadInternal();
844 m_isDetached
= (kind
== wxTHREAD_DETACHED
);
847 wxThread::~wxThread()
849 wxASSERT_MSG( g_numberOfThreads
>0 , wxT("More threads deleted than created.") ) ;
855 // check that the thread either exited or couldn't be created
856 if ( m_internal
->GetState() != STATE_EXITED
&&
857 m_internal
->GetState() != STATE_NEW
)
860 wxT("The thread %ld is being destroyed although it is still running! The application may crash."),
866 wxDELETE( m_internal
) ;
869 wxThreadError
wxThread::Create( unsigned int stackSize
)
871 wxCriticalSectionLocker
lock(m_critsect
);
873 if ( !m_internal
->Create(this, stackSize
) )
875 m_internal
->SetState( STATE_EXITED
);
876 return wxTHREAD_NO_RESOURCE
;
879 return wxTHREAD_NO_ERROR
;
882 wxThreadError
wxThread::Run()
884 wxCriticalSectionLocker
lock(m_critsect
);
886 // Create the thread if it wasn't created yet with an explicit
888 if ( m_internal
->GetId() == kInvalidID
)
890 if ( !m_internal
->Create(this, stackSize
) )
892 m_internal
->SetState( STATE_EXITED
);
893 return wxTHREAD_NO_RESOURCE
;
897 wxCHECK_MSG( m_internal
->GetId(), wxTHREAD_MISC_ERROR
,
898 wxT("must call wxThread::Create() first") );
900 return m_internal
->Run();
903 // -----------------------------------------------------------------------------
905 // -----------------------------------------------------------------------------
907 wxThreadError
wxThread::Pause()
909 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR
,
910 wxT("a thread can't pause itself") );
912 wxCriticalSectionLocker
lock(m_critsect
);
914 if ( m_internal
->GetState() != STATE_RUNNING
)
916 wxLogDebug( wxT("Can't pause thread which is not running.") );
918 return wxTHREAD_NOT_RUNNING
;
921 // just set a flag, the thread will be really paused only during the next
922 // call to TestDestroy()
923 m_internal
->SetState( STATE_PAUSED
);
925 return wxTHREAD_NO_ERROR
;
928 wxThreadError
wxThread::Resume()
930 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR
,
931 wxT("a thread can't resume itself") );
933 wxCriticalSectionLocker
lock(m_critsect
);
935 wxThreadState state
= m_internal
->GetState();
940 m_internal
->Resume();
941 return wxTHREAD_NO_ERROR
;
944 return wxTHREAD_NO_ERROR
;
947 wxLogDebug( wxT("Attempt to resume a thread which is not paused.") );
949 return wxTHREAD_MISC_ERROR
;
953 // -----------------------------------------------------------------------------
955 // -----------------------------------------------------------------------------
957 wxThread::ExitCode
wxThread::Wait(wxThreadWait
WXUNUSED(waitMode
))
959 wxCHECK_MSG( This() != this, (ExitCode
)-1,
960 wxT("a thread can't wait for itself") );
962 wxCHECK_MSG( !m_isDetached
, (ExitCode
)-1,
963 wxT("can't wait for detached thread") );
967 return m_internal
->GetExitCode();
970 wxThreadError
wxThread::Delete(ExitCode
*rc
, wxThreadWait
WXUNUSED(waitMode
))
972 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR
,
973 wxT("a thread can't delete itself") );
975 bool isDetached
= m_isDetached
;
978 wxThreadState state
= m_internal
->GetState();
980 // ask the thread to stop
981 m_internal
->SetCancelFlag();
988 // we need to wake up the thread so that PthreadStart() will
989 // terminate - right now it's blocking on run semaphore in
991 m_internal
->SignalRun();
1000 // resume the thread first
1001 m_internal
->Resume();
1008 // wait until the thread stops
1013 // return the exit code of the thread
1014 *rc
= m_internal
->GetExitCode();
1019 return wxTHREAD_NO_ERROR
;
1022 wxThreadError
wxThread::Kill()
1024 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR
,
1025 wxT("a thread can't kill itself") );
1027 switch ( m_internal
->GetState() )
1031 return wxTHREAD_NOT_RUNNING
;
1034 // resume the thread first
1040 OSStatus err
= MPTerminateTask( m_internal
->GetId() , -1 ) ;
1043 wxLogError( wxT("Failed to terminate a thread.") );
1045 return wxTHREAD_MISC_ERROR
;
1054 // this should be retrieved by Wait actually
1055 m_internal
->SetExitCode( (void*)-1 );
1058 return wxTHREAD_NO_ERROR
;
1062 void wxThread::Exit( ExitCode status
)
1064 wxASSERT_MSG( This() == this,
1065 wxT("wxThread::Exit() can only be called in the context of the same thread") );
1067 // don't enter m_critsect before calling OnExit() because the user code
1068 // might deadlock if, for example, it signals a condition in OnExit() (a
1069 // common case) while the main thread calls any of functions entering
1070 // m_critsect on us (almost all of them do)
1073 MPTaskID threadid
= m_internal
->GetId();
1081 // update the status of the joinable thread
1082 wxCriticalSectionLocker
lock( m_critsect
);
1083 m_internal
->SetState( STATE_EXITED
);
1086 MPTerminateTask( threadid
, (long)status
);
1089 // also test whether we were paused
1090 bool wxThread::TestDestroy()
1092 wxASSERT_MSG( This() == this,
1093 wxT("wxThread::TestDestroy() can only be called in the context of the same thread") );
1097 if ( m_internal
->GetState() == STATE_PAUSED
)
1099 m_internal
->SetReallyPaused( true );
1101 // leave the crit section or the other threads will stop too if they attempt
1102 // to call any of (seemingly harmless) IsXXX() functions while we sleep
1105 m_internal
->Pause();
1109 // thread wasn't requested to pause, nothing to do
1113 return m_internal
->WasCancelled();
1116 // -----------------------------------------------------------------------------
1118 // -----------------------------------------------------------------------------
1120 void wxThread::SetPriority(unsigned int prio
)
1122 wxCHECK_RET( wxPRIORITY_MIN
<= prio
&& prio
<= wxPRIORITY_MAX
,
1123 wxT("invalid thread priority") );
1125 wxCriticalSectionLocker
lock(m_critsect
);
1127 switch ( m_internal
->GetState() )
1132 // thread not yet started, priority will be set when it is
1133 m_internal
->SetPriority( prio
);
1138 wxFAIL_MSG( wxT("impossible to set thread priority in this state") );
1142 unsigned int wxThread::GetPriority() const
1144 wxCriticalSectionLocker
lock(const_cast<wxCriticalSection
&>(m_critsect
));
1146 return m_internal
->GetPriority();
1149 unsigned long wxThread::GetId() const
1151 wxCriticalSectionLocker
lock(const_cast<wxCriticalSection
&>(m_critsect
));
1153 return (unsigned long)m_internal
->GetId();
1156 // -----------------------------------------------------------------------------
1158 // -----------------------------------------------------------------------------
1160 bool wxThread::IsRunning() const
1162 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
1164 return m_internal
->GetState() == STATE_RUNNING
;
1167 bool wxThread::IsAlive() const
1169 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
1171 switch ( m_internal
->GetState() )
1182 bool wxThread::IsPaused() const
1184 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
1186 return (m_internal
->GetState() == STATE_PAUSED
);
1189 // ----------------------------------------------------------------------------
1190 // Automatic initialization for thread module
1191 // ----------------------------------------------------------------------------
1193 class wxThreadModule
: public wxModule
1196 virtual bool OnInit();
1197 virtual void OnExit();
1200 DECLARE_DYNAMIC_CLASS(wxThreadModule
)
1203 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule
, wxModule
)
1205 bool wxThreadModule::OnInit()
1207 bool hasThreadManager
=
1209 true ; // TODO VERIFY IN NEXT BUILD
1211 MPLibraryIsLoaded();
1214 if ( !hasThreadManager
)
1216 wxLogError( wxT("MP thread support is not available on this system" ) ) ;
1221 // main thread's This() is NULL
1222 verify_noerr( MPAllocateTaskStorageIndex( &gs_tlsForWXThread
) ) ;
1223 verify_noerr( MPSetTaskStorageValue( gs_tlsForWXThread
, 0 ) ) ;
1225 wxThread::ms_idMainThread
= wxThread::GetCurrentId();
1226 gs_critsectWaitingForGui
= new wxCriticalSection();
1228 gs_critsectGui
= new wxCriticalSection();
1229 gs_critsectGui
->Enter();
1234 void wxThreadModule::OnExit()
1236 if ( gs_critsectGui
)
1238 if ( !wxGuiOwnedByMainThread() )
1240 gs_critsectGui
->Enter();
1241 gs_bGuiOwnedByMainThread
= true;
1244 gs_critsectGui
->Leave();
1245 wxDELETE(gs_critsectGui
);
1248 wxDELETE(gs_critsectWaitingForGui
);
1251 // ----------------------------------------------------------------------------
1252 // GUI Serialization copied from MSW implementation
1253 // ----------------------------------------------------------------------------
1255 void wxMutexGuiEnterImpl()
1257 // this would dead lock everything...
1258 wxASSERT_MSG( !wxThread::IsMain(),
1259 wxT("main thread doesn't want to block in wxMutexGuiEnter()!") );
1261 // the order in which we enter the critical sections here is crucial!!
1263 // set the flag telling to the main thread that we want to do some GUI
1265 wxCriticalSectionLocker
enter(*gs_critsectWaitingForGui
);
1267 gs_nWaitingForGui
++;
1270 wxWakeUpMainThread();
1272 // now we may block here because the main thread will soon let us in
1273 // (during the next iteration of OnIdle())
1274 gs_critsectGui
->Enter();
1277 void wxMutexGuiLeaveImpl()
1279 wxCriticalSectionLocker
enter(*gs_critsectWaitingForGui
);
1281 if ( wxThread::IsMain() )
1283 gs_bGuiOwnedByMainThread
= false;
1287 // decrement the number of threads waiting for GUI access now
1288 wxASSERT_MSG( gs_nWaitingForGui
> 0,
1289 wxT("calling wxMutexGuiLeave() without entering it first?") );
1291 gs_nWaitingForGui
--;
1293 wxWakeUpMainThread();
1296 gs_critsectGui
->Leave();
1299 void WXDLLIMPEXP_BASE
wxMutexGuiLeaveOrEnter()
1301 wxASSERT_MSG( wxThread::IsMain(),
1302 wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") );
1304 if ( !gs_critsectWaitingForGui
)
1307 wxCriticalSectionLocker
enter(*gs_critsectWaitingForGui
);
1309 if ( gs_nWaitingForGui
== 0 )
1311 // no threads are waiting for GUI - so we may acquire the lock without
1312 // any danger (but only if we don't already have it)
1313 if ( !wxGuiOwnedByMainThread() )
1315 gs_critsectGui
->Enter();
1317 gs_bGuiOwnedByMainThread
= true;
1319 //else: already have it, nothing to do
1323 // some threads are waiting, release the GUI lock if we have it
1324 if ( wxGuiOwnedByMainThread() )
1326 //else: some other worker thread is doing GUI
1330 bool WXDLLIMPEXP_BASE
wxGuiOwnedByMainThread()
1332 return gs_bGuiOwnedByMainThread
;
1335 // wake up the main thread
1336 void WXDLLEXPORT
wxWakeUpMainThread()
1341 // ----------------------------------------------------------------------------
1342 // include common implementation code
1343 // ----------------------------------------------------------------------------
1345 #include "wx/thrimpl.cpp"
1347 #endif // wxUSE_THREADS