1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxThread Implementation
4 // Author: Original from Wolfram Gloger/Guilhem Lavaux/Vadim Zeitlin
5 // Modified by: 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 "wx/mac/uma.h"
36 #include "wx/mac/macnotfy.h"
40 #define INFINITE 0xFFFFFFFF
43 // ----------------------------------------------------------------------------
45 // ----------------------------------------------------------------------------
47 // the possible states of the thread ("=>" shows all possible transitions from
51 STATE_NEW
, // didn't start execution yet (=> RUNNING)
52 STATE_RUNNING
, // thread is running (=> PAUSED, CANCELED)
53 STATE_PAUSED
, // thread is temporarily suspended (=> RUNNING)
54 STATE_CANCELED
, // thread should terminate a.s.a.p. (=> EXITED)
55 STATE_EXITED
// thread is terminating
58 // ----------------------------------------------------------------------------
59 // this module globals
60 // ----------------------------------------------------------------------------
62 static ThreadID gs_idMainThread
= kNoThreadID
;
63 static bool gs_waitingForThread
= FALSE
;
64 size_t g_numberOfThreads
= 0;
66 // ============================================================================
67 // MacOS implementation of thread classes
68 // ============================================================================
75 if ( UMASystemIsInitialized() )
77 OSErr err
= ThreadBeginCritical() ;
78 wxASSERT( err
== noErr
) ;
83 if ( UMASystemIsInitialized() )
85 OSErr err
= ThreadEndCritical() ;
86 wxASSERT( err
== noErr
) ;
91 // ----------------------------------------------------------------------------
92 // wxMutex implementation
93 // ----------------------------------------------------------------------------
98 wxMutexInternal(wxMutexType
WXUNUSED(mutexType
))
100 m_owner
= kNoThreadID
;
108 wxLogDebug(_T("Warning: freeing a locked mutex (%ld locks)."), m_locked
);
112 bool IsOk() const { return true; }
114 wxMutexError
Lock() ;
115 wxMutexError
TryLock() ;
116 wxMutexError
Unlock();
119 wxArrayLong m_waiters
;
123 wxMutexError
wxMutexInternal::Lock()
125 wxMacStCritical critical
;
126 if ( UMASystemIsInitialized() )
129 ThreadID current
= kNoThreadID
;
130 err
= ::MacGetCurrentThread(¤t
);
131 // if we are not the owner, add this thread to the list of waiting threads, stop this thread
132 // and invoke the scheduler to continue executing the owner's thread
133 while ( m_owner
!= kNoThreadID
&& m_owner
!= current
)
135 m_waiters
.Add(current
);
136 err
= ::SetThreadStateEndCritical(kCurrentThreadID
, kStoppedThreadState
, m_owner
);
137 err
= ::ThreadBeginCritical();
138 wxASSERT( err
== noErr
) ;
144 return wxMUTEX_NO_ERROR
;
147 wxMutexError
wxMutexInternal::TryLock()
149 wxMacStCritical critical
;
150 if ( UMASystemIsInitialized() )
152 ThreadID current
= kNoThreadID
;
153 ::MacGetCurrentThread(¤t
);
154 // if we are not the owner, give an error back
155 if ( m_owner
!= kNoThreadID
&& m_owner
!= current
)
162 return wxMUTEX_NO_ERROR
;
165 wxMutexError
wxMutexInternal::Unlock()
167 if ( UMASystemIsInitialized() )
170 err
= ::ThreadBeginCritical();
171 wxASSERT( err
== noErr
) ;
176 // this mutex is not owned by anybody anmore
177 m_owner
= kNoThreadID
;
179 // now pass on to the first waiting thread
180 ThreadID firstWaiting
= kNoThreadID
;
182 while (!m_waiters
.IsEmpty() && !found
)
184 firstWaiting
= m_waiters
[0];
185 err
= ::SetThreadState(firstWaiting
, kReadyThreadState
, kNoThreadID
);
186 // in case this was not successful (dead thread), we just loop on and reset the id
187 found
= (err
!= threadNotFoundErr
);
189 firstWaiting
= kNoThreadID
;
190 m_waiters
.RemoveAt(0) ;
192 // now we have a valid firstWaiting thread, which has been scheduled to run next, just end the
193 // critical section and invoke the scheduler
194 err
= ::SetThreadStateEndCritical(kCurrentThreadID
, kReadyThreadState
, firstWaiting
);
201 return wxMUTEX_NO_ERROR
;
204 // --------------------------------------------------------------------------
206 // --------------------------------------------------------------------------
208 // TODO not yet implemented
210 class wxSemaphoreInternal
213 wxSemaphoreInternal(int initialcount
, int maxcount
);
214 ~wxSemaphoreInternal();
216 bool IsOk() const { return true ; }
218 wxSemaError
Wait() { return WaitTimeout(INFINITE
); }
219 wxSemaError
TryWait() { return WaitTimeout(0); }
220 wxSemaError
WaitTimeout(unsigned long milliseconds
);
227 wxSemaphoreInternal::wxSemaphoreInternal(int initialcount
, int maxcount
)
231 // make it practically infinite
236 wxSemaphoreInternal::~wxSemaphoreInternal()
240 wxSemaError
wxSemaphoreInternal::WaitTimeout(unsigned long milliseconds
)
242 return wxSEMA_MISC_ERROR
;
245 wxSemaError
wxSemaphoreInternal::Post()
247 return wxSEMA_MISC_ERROR
;
250 // ----------------------------------------------------------------------------
251 // wxCondition implementation
252 // ----------------------------------------------------------------------------
254 // TODO this is not yet completed
256 class wxConditionInternal
259 wxConditionInternal(wxMutex
& mutex
) : m_mutex(mutex
)
261 m_excessSignals
= 0 ;
263 ~wxConditionInternal()
267 bool IsOk() const { return m_mutex
.IsOk() ; }
271 return WaitTimeout(0xFFFFFFFF );
274 wxCondError
WaitTimeout(unsigned long msectimeout
)
276 wxMacStCritical critical
;
277 if ( m_excessSignals
> 0 )
280 return wxCOND_NO_ERROR
;
282 else if ( msectimeout
== 0 )
284 return wxCOND_MISC_ERROR
;
292 // FIXME this should be MsgWaitForMultipleObjects() as well probably
293 DWORD rc = ::WaitForSingleObject(event, timeout);
297 return rc != WAIT_TIMEOUT;
299 return wxCOND_NO_ERROR
;
303 wxMacStCritical critical
;
304 return wxCOND_NO_ERROR
;
307 wxCondError
Broadcast()
309 wxMacStCritical critical
;
310 return wxCOND_NO_ERROR
;
313 wxArrayLong m_waiters
;
314 wxInt32 m_excessSignals
;
318 // ----------------------------------------------------------------------------
319 // wxCriticalSection implementation
320 // ----------------------------------------------------------------------------
322 // it's implemented as a mutex on mac os, so it is defined in the headers
324 // ----------------------------------------------------------------------------
325 // wxThread implementation
326 // ----------------------------------------------------------------------------
328 // wxThreadInternal class
329 // ----------------------
331 class wxThreadInternal
336 m_tid
= kNoThreadID
;
338 m_priority
= WXTHREAD_DEFAULT_PRIORITY
;
349 // create a new (suspended) thread (for the given thread object)
350 bool Create(wxThread
*thread
, unsigned int stackSize
);
352 // suspend/resume/terminate
355 void Cancel() { m_state
= STATE_CANCELED
; }
358 void SetState(wxThreadState state
) { m_state
= state
; }
359 wxThreadState
GetState() const { return m_state
; }
362 void SetPriority(unsigned int priority
);
363 unsigned int GetPriority() const { return m_priority
; }
365 void SetResult( void *res
) { m_result
= res
; }
366 void *GetResult() { return m_result
; }
368 // thread handle and id
369 ThreadID
GetId() const { return m_tid
; }
372 static pascal void* MacThreadStart(wxThread
* arg
);
375 wxThreadState m_state
; // state, see wxThreadState enum
376 unsigned int m_priority
; // thread priority in "wx" units
377 ThreadID m_tid
; // thread id
379 static ThreadEntryUPP s_threadEntry
;
382 static wxArrayPtrVoid s_threads
;
384 ThreadEntryUPP
wxThreadInternal::s_threadEntry
= NULL
;
385 pascal void* wxThreadInternal::MacThreadStart(wxThread
*thread
)
387 // first of all, check whether we hadn't been cancelled already
388 if ( thread
->m_internal
->GetState() == STATE_EXITED
)
393 void* rc
= thread
->Entry();
395 // enter m_critsect before changing the thread state
396 thread
->m_critsect
.Enter();
397 bool wasCancelled
= thread
->m_internal
->GetState() == STATE_CANCELED
;
398 thread
->m_internal
->SetState(STATE_EXITED
);
399 thread
->m_critsect
.Leave();
403 // if the thread was cancelled (from Delete()), then it the handle is still
405 if ( thread
->IsDetached() && !wasCancelled
)
410 //else: the joinable threads handle will be closed when Wait() is done
414 void wxThreadInternal::SetPriority(unsigned int priority
)
416 // Priorities don't exist on Mac
419 bool wxThreadInternal::Create(wxThread
*thread
, unsigned int stackSize
)
421 if ( s_threadEntry
== NULL
)
423 s_threadEntry
= NewThreadEntryUPP( (ThreadEntryProcPtr
) MacThreadStart
) ;
425 OSErr err
= NewThread( kCooperativeThread
,
435 wxLogSysError(_("Can't create thread"));
439 if ( m_priority
!= WXTHREAD_DEFAULT_PRIORITY
)
441 SetPriority(m_priority
);
449 bool wxThreadInternal::Suspend()
453 err
= ::ThreadBeginCritical();
454 wxASSERT( err
== noErr
) ;
456 if ( m_state
!= STATE_RUNNING
)
458 err
= ::ThreadEndCritical() ;
459 wxASSERT( err
== noErr
) ;
460 wxLogSysError(_("Can not suspend thread %x"), m_tid
);
464 m_state
= STATE_PAUSED
;
466 err
= ::SetThreadStateEndCritical(m_tid
, kStoppedThreadState
, kNoThreadID
);
471 bool wxThreadInternal::Resume()
475 err
= MacGetCurrentThread( ¤t
) ;
477 wxASSERT( err
== noErr
) ;
478 wxASSERT( current
!= m_tid
) ;
480 err
= ::ThreadBeginCritical();
481 wxASSERT( err
== noErr
) ;
483 if ( m_state
!= STATE_PAUSED
&& m_state
!= STATE_NEW
)
485 err
= ::ThreadEndCritical() ;
486 wxASSERT( err
== noErr
) ;
487 wxLogSysError(_("Can not resume thread %x"), m_tid
);
491 err
= ::SetThreadStateEndCritical(m_tid
, kReadyThreadState
, kNoThreadID
);
493 m_state
= STATE_RUNNING
;
494 err
= ::ThreadEndCritical() ;
495 wxASSERT( err
== noErr
) ;
496 ::YieldToAnyThread() ;
502 wxThread
*wxThread::This()
504 wxMacStCritical critical
;
509 err
= MacGetCurrentThread( ¤t
) ;
511 for ( size_t i
= 0 ; i
< s_threads
.Count() ; ++i
)
513 if ( ( (wxThread
*) s_threads
[i
] )->GetId() == current
)
514 return (wxThread
*) s_threads
[i
] ;
517 wxLogSysError(_("Couldn't get the current thread pointer"));
521 bool wxThread::IsMain()
526 err
= MacGetCurrentThread( ¤t
) ;
527 return current
== gs_idMainThread
;
534 void wxThread::Yield()
536 ::YieldToAnyThread() ;
539 void wxThread::Sleep(unsigned long milliseconds
)
541 UnsignedWide start
, now
;
543 Microseconds(&start
);
545 double mssleep
= milliseconds
* 1000 ;
546 double msstart
, msnow
;
547 msstart
= (start
.hi
* 4294967296.0 + start
.lo
) ;
553 msnow
= (now
.hi
* 4294967296.0 + now
.lo
) ;
554 } while( msnow
- msstart
< mssleep
);
557 int wxThread::GetCPUCount()
559 // we will use whatever MP API will be used for the new MP Macs
563 unsigned long wxThread::GetCurrentId()
566 MacGetCurrentThread( ¤t
) ;
567 return (unsigned long)current
;
570 bool wxThread::SetConcurrency(size_t level
)
572 wxASSERT_MSG( IsMain(), _T("should only be called from the main thread") );
574 // ok only for the default one
578 // how many CPUs have we got?
579 if ( GetCPUCount() == 1 )
581 // don't bother with all this complicated stuff - on a single
582 // processor system it doesn't make much sense anyhow
592 wxThread::wxThread(wxThreadKind kind
)
595 m_internal
= new wxThreadInternal();
597 m_isDetached
= kind
== wxTHREAD_DETACHED
;
598 s_threads
.Add( (void*) this ) ;
601 wxThread::~wxThread()
603 if (g_numberOfThreads
>0)
610 wxFAIL_MSG(wxT("More threads deleted than created."));
614 s_threads
.Remove( (void*) this ) ;
615 if (m_internal
!= NULL
) {
621 // create/start thread
622 // -------------------
624 wxThreadError
wxThread::Create(unsigned int stackSize
)
626 wxCriticalSectionLocker
lock(m_critsect
);
628 if ( !m_internal
->Create(this, stackSize
) )
629 return wxTHREAD_NO_RESOURCE
;
631 return wxTHREAD_NO_ERROR
;
634 wxThreadError
wxThread::Run()
636 wxCriticalSectionLocker
lock(m_critsect
);
638 if ( m_internal
->GetState() != STATE_NEW
)
640 // actually, it may be almost any state at all, not only STATE_RUNNING
641 return wxTHREAD_RUNNING
;
644 // the thread has just been created and is still suspended - let it run
648 // suspend/resume thread
649 // ---------------------
651 wxThreadError
wxThread::Pause()
653 wxCriticalSectionLocker
lock(m_critsect
);
655 return m_internal
->Suspend() ? wxTHREAD_NO_ERROR
: wxTHREAD_MISC_ERROR
;
658 wxThreadError
wxThread::Resume()
660 wxCriticalSectionLocker
lock(m_critsect
);
662 return m_internal
->Resume() ? wxTHREAD_NO_ERROR
: wxTHREAD_MISC_ERROR
;
668 wxThread::ExitCode
wxThread::Wait()
670 // although under MacOS we can wait for any thread, it's an error to
671 // wait for a detached one in wxWin API
672 wxCHECK_MSG( !IsDetached(), (ExitCode
)-1,
673 _T("can't wait for detached thread") );
675 ExitCode rc
= (ExitCode
)-1;
684 wxThreadError
wxThread::Delete(ExitCode
*pRc
)
688 // Delete() is always safe to call, so consider all possible states
690 // has the thread started to run?
691 bool shouldResume
= FALSE
;
694 wxCriticalSectionLocker
lock(m_critsect
);
696 if ( m_internal
->GetState() == STATE_NEW
)
698 // WinThreadStart() will see it and terminate immediately
699 m_internal
->SetState(STATE_EXITED
);
705 // is the thread paused?
706 if ( shouldResume
|| IsPaused() )
709 // does is still run?
714 // set flag for wxIsWaitingForThread()
715 gs_waitingForThread
= TRUE
;
722 // ask the thread to terminate
724 wxCriticalSectionLocker
lock(m_critsect
);
726 m_internal
->Cancel();
730 // simply wait for the thread to terminate
731 while( TestDestroy() )
733 ::YieldToAnyThread() ;
736 // simply wait for the thread to terminate
737 while( TestDestroy() )
739 ::YieldToAnyThread() ;
741 #endif // wxUSE_GUI/!wxUSE_GUI
745 gs_waitingForThread
= FALSE
;
755 // if the thread exits normally, this is done in WinThreadStart, but in
756 // this case it would have been too early because
757 // MsgWaitForMultipleObject() would fail if the therad handle was
758 // closed while we were waiting on it, so we must do it here
765 return rc
== (ExitCode
)-1 ? wxTHREAD_MISC_ERROR
: wxTHREAD_NO_ERROR
;
768 wxThreadError
wxThread::Kill()
771 return wxTHREAD_NOT_RUNNING
;
773 // if ( !::TerminateThread(m_internal->GetHandle(), (DWORD)-1) )
775 wxLogSysError(_("Couldn't terminate thread"));
777 return wxTHREAD_MISC_ERROR
;
787 return wxTHREAD_NO_ERROR
;
790 void wxThread::Exit(ExitCode status
)
799 m_internal
->SetResult( status
) ;
802 #if defined(__VISUALC__) || (defined(__BORLANDC__) && (__BORLANDC__ >= 0x500))
803 _endthreadex((unsigned)status);
805 ::ExitThread((DWORD)status);
808 wxFAIL_MSG(wxT("Couldn't return from ExitThread()!"));
814 // since all these calls are execute cooperatively we don't have to use the critical section
816 void wxThread::SetPriority(unsigned int prio
)
818 m_internal
->SetPriority(prio
);
821 unsigned int wxThread::GetPriority() const
823 return m_internal
->GetPriority();
826 unsigned long wxThread::GetId() const
828 return (unsigned long)m_internal
->GetId();
831 bool wxThread::IsRunning() const
833 return m_internal
->GetState() == STATE_RUNNING
;
836 bool wxThread::IsAlive() const
838 return (m_internal
->GetState() == STATE_RUNNING
) ||
839 (m_internal
->GetState() == STATE_PAUSED
);
842 bool wxThread::IsPaused() const
844 return m_internal
->GetState() == STATE_PAUSED
;
847 bool wxThread::TestDestroy()
849 return m_internal
->GetState() == STATE_CANCELED
;
852 // ----------------------------------------------------------------------------
853 // Automatic initialization for thread module
854 // ----------------------------------------------------------------------------
856 class wxThreadModule
: public wxModule
859 virtual bool OnInit();
860 virtual void OnExit();
863 DECLARE_DYNAMIC_CLASS(wxThreadModule
)
866 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule
, wxModule
)
868 bool wxThreadModule::OnInit()
871 bool hasThreadManager
;
872 hasThreadManager
= Gestalt( gestaltThreadMgrAttr
, &response
) == noErr
&& response
& 1;
875 // verify presence of shared library
876 hasThreadManager
= hasThreadManager
&& ((Ptr
)NewThread
!= (Ptr
)kUnresolvedCFragSymbolAddress
);
879 if ( !hasThreadManager
)
881 wxLogSysError( wxT("Thread Support is not available on this System") );
885 // no error return for GetCurrentThreadId()
886 MacGetCurrentThread( &gs_idMainThread
) ;
891 void wxThreadModule::OnExit()
895 // ----------------------------------------------------------------------------
896 // under MacOS we don't have currently preemptive threads, so any thread may access
897 // the GUI at any time
898 // ----------------------------------------------------------------------------
900 void WXDLLEXPORT
wxMutexGuiEnter()
904 void WXDLLEXPORT
wxMutexGuiLeave()
908 void WXDLLEXPORT
wxMutexGuiLeaveOrEnter()
912 bool WXDLLEXPORT
wxGuiOwnedByMainThread()
917 // wake up the main thread
918 void WXDLLEXPORT
wxWakeUpMainThread()
923 bool WXDLLEXPORT
wxIsWaitingForThread()
928 #include "wx/thrimpl.cpp"
930 #endif // wxUSE_THREADS