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 /////////////////////////////////////////////////////////////////////////////
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"
39 #include "wx/mac/uma.h"
42 #define INFINITE 0xFFFFFFFF
44 // ----------------------------------------------------------------------------
46 // ----------------------------------------------------------------------------
48 // the possible states of the thread ("=>" shows all possible transitions from
52 STATE_NEW
, // didn't start execution yet (=> RUNNING)
53 STATE_RUNNING
, // thread is running (=> PAUSED, CANCELED)
54 STATE_PAUSED
, // thread is temporarily suspended (=> RUNNING)
55 STATE_CANCELED
, // thread should terminate a.s.a.p. (=> EXITED)
56 STATE_EXITED
// thread is terminating
59 // ----------------------------------------------------------------------------
60 // this module globals
61 // ----------------------------------------------------------------------------
63 static ThreadID gs_idMainThread
= kNoThreadID
;
64 static bool gs_waitingForThread
= FALSE
;
66 // ============================================================================
67 // MacOS implementation of thread classes
68 // ============================================================================
75 if ( UMASystemIsInitialized() )
76 ThreadBeginCritical() ;
80 if ( UMASystemIsInitialized() )
85 // ----------------------------------------------------------------------------
86 // wxMutex implementation
87 // ----------------------------------------------------------------------------
92 wxMutexInternal(wxMutexType
WXUNUSED(mutexType
))
94 m_owner
= kNoThreadID
;
102 wxLogDebug(_T("Warning: freeing a locked mutex (%ld locks)."), m_locked
);
106 bool IsOk() const { return true; }
108 wxMutexError
Lock() ;
109 wxMutexError
TryLock() ;
110 wxMutexError
Unlock();
113 wxArrayLong m_waiters
;
117 wxMutexError
wxMutexInternal::Lock()
119 wxMacStCritical critical
;
120 if ( UMASystemIsInitialized() )
123 ThreadID current
= kNoThreadID
;
124 err
= ::MacGetCurrentThread(¤t
);
125 // if we are not the owner, add this thread to the list of waiting threads, stop this thread
126 // and invoke the scheduler to continue executing the owner's thread
127 while ( m_owner
!= kNoThreadID
&& m_owner
!= current
)
129 m_waiters
.Add(current
);
130 err
= ::SetThreadStateEndCritical(kCurrentThreadID
, kStoppedThreadState
, m_owner
);
131 err
= ::ThreadBeginCritical();
137 return wxMUTEX_NO_ERROR
;
140 wxMutexError
wxMutexInternal::TryLock()
142 wxMacStCritical critical
;
143 if ( UMASystemIsInitialized() )
145 ThreadID current
= kNoThreadID
;
146 ::MacGetCurrentThread(¤t
);
147 // if we are not the owner, give an error back
148 if ( m_owner
!= kNoThreadID
&& m_owner
!= current
)
155 return wxMUTEX_NO_ERROR
;
158 wxMutexError
wxMutexInternal::Unlock()
160 if ( UMASystemIsInitialized() )
163 err
= ::ThreadBeginCritical();
168 // this mutex is not owned by anybody anmore
169 m_owner
= kNoThreadID
;
171 // now pass on to the first waiting thread
172 ThreadID firstWaiting
= kNoThreadID
;
174 while (!m_waiters
.IsEmpty() && !found
)
176 firstWaiting
= m_waiters
[0];
177 err
= ::SetThreadState(firstWaiting
, kReadyThreadState
, kNoThreadID
);
178 // in case this was not successful (dead thread), we just loop on and reset the id
179 found
= (err
!= threadNotFoundErr
);
181 firstWaiting
= kNoThreadID
;
182 m_waiters
.RemoveAt(0) ;
184 // now we have a valid firstWaiting thread, which has been scheduled to run next, just end the
185 // critical section and invoke the scheduler
186 err
= ::SetThreadStateEndCritical(kCurrentThreadID
, kReadyThreadState
, firstWaiting
);
193 return wxMUTEX_NO_ERROR
;
196 // --------------------------------------------------------------------------
198 // --------------------------------------------------------------------------
200 // TODO not yet implemented
202 class wxSemaphoreInternal
205 wxSemaphoreInternal(int initialcount
, int maxcount
);
206 ~wxSemaphoreInternal();
208 bool IsOk() const { return true ; }
210 wxSemaError
Wait() { return WaitTimeout(INFINITE
); }
211 wxSemaError
TryWait() { return WaitTimeout(0); }
212 wxSemaError
WaitTimeout(unsigned long milliseconds
);
219 wxSemaphoreInternal::wxSemaphoreInternal(int initialcount
, int maxcount
)
223 // make it practically infinite
228 wxSemaphoreInternal::~wxSemaphoreInternal()
232 wxSemaError
wxSemaphoreInternal::WaitTimeout(unsigned long milliseconds
)
234 return wxSEMA_MISC_ERROR
;
237 wxSemaError
wxSemaphoreInternal::Post()
239 return wxSEMA_MISC_ERROR
;
242 // ----------------------------------------------------------------------------
243 // wxCondition implementation
244 // ----------------------------------------------------------------------------
246 // TODO this is not yet completed
248 class wxConditionInternal
251 wxConditionInternal(wxMutex
& mutex
) : m_mutex(mutex
)
253 m_excessSignals
= 0 ;
255 ~wxConditionInternal()
259 bool IsOk() const { return m_mutex
.IsOk() ; }
263 return WaitTimeout(0xFFFFFFFF );
266 wxCondError
WaitTimeout(unsigned long msectimeout
)
268 wxMacStCritical critical
;
269 if ( m_excessSignals
> 0 )
272 return wxCOND_NO_ERROR
;
274 else if ( msectimeout
== 0 )
276 return wxCOND_MISC_ERROR
;
284 // FIXME this should be MsgWaitForMultipleObjects() as well probably
285 DWORD rc = ::WaitForSingleObject(event, timeout);
289 return rc != WAIT_TIMEOUT;
291 return wxCOND_NO_ERROR
;
295 wxMacStCritical critical
;
296 return wxCOND_NO_ERROR
;
299 wxCondError
Broadcast()
301 wxMacStCritical critical
;
302 return wxCOND_NO_ERROR
;
305 wxArrayLong m_waiters
;
306 wxInt32 m_excessSignals
;
310 // ----------------------------------------------------------------------------
311 // wxCriticalSection implementation
312 // ----------------------------------------------------------------------------
314 // it's implemented as a mutex on mac os, so it is defined in the headers
316 // ----------------------------------------------------------------------------
317 // wxThread implementation
318 // ----------------------------------------------------------------------------
320 // wxThreadInternal class
321 // ----------------------
323 class wxThreadInternal
328 m_tid
= kNoThreadID
;
330 m_priority
= WXTHREAD_DEFAULT_PRIORITY
;
341 // create a new (suspended) thread (for the given thread object)
342 bool Create(wxThread
*thread
, unsigned int stackSize
);
344 // suspend/resume/terminate
347 void Cancel() { m_state
= STATE_CANCELED
; }
350 void SetState(wxThreadState state
) { m_state
= state
; }
351 wxThreadState
GetState() const { return m_state
; }
354 void SetPriority(unsigned int priority
);
355 unsigned int GetPriority() const { return m_priority
; }
357 void SetResult( void *res
) { m_result
= res
; }
358 void *GetResult() { return m_result
; }
360 // thread handle and id
361 ThreadID
GetId() const { return m_tid
; }
364 static pascal void* MacThreadStart(wxThread
* arg
);
367 wxThreadState m_state
; // state, see wxThreadState enum
368 unsigned int m_priority
; // thread priority in "wx" units
369 ThreadID m_tid
; // thread id
371 static ThreadEntryUPP s_threadEntry
;
374 static wxArrayPtrVoid s_threads
;
376 ThreadEntryUPP
wxThreadInternal::s_threadEntry
= NULL
;
377 pascal void* wxThreadInternal::MacThreadStart(wxThread
*thread
)
379 // first of all, check whether we hadn't been cancelled already
380 if ( thread
->m_internal
->GetState() == STATE_EXITED
)
385 void* rc
= thread
->Entry();
387 // enter m_critsect before changing the thread state
388 thread
->m_critsect
.Enter();
389 bool wasCancelled
= thread
->m_internal
->GetState() == STATE_CANCELED
;
390 thread
->m_internal
->SetState(STATE_EXITED
);
391 thread
->m_critsect
.Leave();
395 // if the thread was cancelled (from Delete()), then it the handle is still
397 if ( thread
->IsDetached() && !wasCancelled
)
402 //else: the joinable threads handle will be closed when Wait() is done
406 void wxThreadInternal::SetPriority(unsigned int priority
)
408 // Priorities don't exist on Mac
411 bool wxThreadInternal::Create(wxThread
*thread
, unsigned int stackSize
)
413 if ( s_threadEntry
== NULL
)
415 s_threadEntry
= NewThreadEntryUPP( (ThreadEntryProcPtr
) MacThreadStart
) ;
417 OSErr err
= NewThread( kCooperativeThread
,
427 wxLogSysError(_("Can't create thread"));
431 if ( m_priority
!= WXTHREAD_DEFAULT_PRIORITY
)
433 SetPriority(m_priority
);
439 bool wxThreadInternal::Suspend()
443 ::ThreadBeginCritical();
445 if ( m_state
!= STATE_RUNNING
)
447 ::ThreadEndCritical() ;
448 wxLogSysError(_("Can not suspend thread %x"), m_tid
);
452 m_state
= STATE_PAUSED
;
454 err
= ::SetThreadStateEndCritical(m_tid
, kStoppedThreadState
, kNoThreadID
);
459 bool wxThreadInternal::Resume()
463 err
= MacGetCurrentThread( ¤t
) ;
465 wxASSERT( err
== noErr
) ;
466 wxASSERT( current
!= m_tid
) ;
468 ::ThreadBeginCritical();
469 if ( m_state
!= STATE_PAUSED
&& m_state
!= STATE_NEW
)
471 ::ThreadEndCritical() ;
472 wxLogSysError(_("Can not resume thread %x"), m_tid
);
476 err
= ::SetThreadStateEndCritical(m_tid
, kReadyThreadState
, kNoThreadID
);
477 wxASSERT( err
== noErr
) ;
479 m_state
= STATE_RUNNING
;
480 ::ThreadEndCritical() ;
481 ::YieldToAnyThread() ;
487 wxThread
*wxThread::This()
489 wxMacStCritical critical
;
494 err
= MacGetCurrentThread( ¤t
) ;
496 for ( size_t i
= 0 ; i
< s_threads
.Count() ; ++i
)
498 if ( ( (wxThread
*) s_threads
[i
] )->GetId() == current
)
499 return (wxThread
*) s_threads
[i
] ;
502 wxLogSysError(_("Couldn't get the current thread pointer"));
506 bool wxThread::IsMain()
511 err
= MacGetCurrentThread( ¤t
) ;
512 return current
== gs_idMainThread
;
519 void wxThread::Yield()
521 ::YieldToAnyThread() ;
524 void wxThread::Sleep(unsigned long milliseconds
)
526 clock_t start
= clock();
530 } while( clock() - start
< milliseconds
/ 1000.0 * CLOCKS_PER_SEC
) ;
533 int wxThread::GetCPUCount()
535 // we will use whatever MP API will be used for the new MP Macs
539 unsigned long wxThread::GetCurrentId()
542 MacGetCurrentThread( ¤t
) ;
543 return (unsigned long)current
;
546 bool wxThread::SetConcurrency(size_t level
)
548 wxASSERT_MSG( IsMain(), _T("should only be called from the main thread") );
550 // ok only for the default one
554 // how many CPUs have we got?
555 if ( GetCPUCount() == 1 )
557 // don't bother with all this complicated stuff - on a single
558 // processor system it doesn't make much sense anyhow
568 wxThread::wxThread(wxThreadKind kind
)
570 m_internal
= new wxThreadInternal();
572 m_isDetached
= kind
== wxTHREAD_DETACHED
;
573 s_threads
.Add( (void*) this ) ;
576 wxThread::~wxThread()
578 s_threads
.Remove( (void*) this ) ;
579 if (m_internal
!= NULL
) {
585 // create/start thread
586 // -------------------
588 wxThreadError
wxThread::Create(unsigned int stackSize
)
590 wxCriticalSectionLocker
lock(m_critsect
);
592 if ( !m_internal
->Create(this, stackSize
) )
593 return wxTHREAD_NO_RESOURCE
;
595 return wxTHREAD_NO_ERROR
;
598 wxThreadError
wxThread::Run()
600 wxCriticalSectionLocker
lock(m_critsect
);
602 if ( m_internal
->GetState() != STATE_NEW
)
604 // actually, it may be almost any state at all, not only STATE_RUNNING
605 return wxTHREAD_RUNNING
;
608 // the thread has just been created and is still suspended - let it run
612 // suspend/resume thread
613 // ---------------------
615 wxThreadError
wxThread::Pause()
617 wxCriticalSectionLocker
lock(m_critsect
);
619 return m_internal
->Suspend() ? wxTHREAD_NO_ERROR
: wxTHREAD_MISC_ERROR
;
622 wxThreadError
wxThread::Resume()
624 wxCriticalSectionLocker
lock(m_critsect
);
626 return m_internal
->Resume() ? wxTHREAD_NO_ERROR
: wxTHREAD_MISC_ERROR
;
632 wxThread::ExitCode
wxThread::Wait()
634 // although under MacOS we can wait for any thread, it's an error to
635 // wait for a detached one in wxWin API
636 wxCHECK_MSG( !IsDetached(), (ExitCode
)-1,
637 _T("can't wait for detached thread") );
639 ExitCode rc
= (ExitCode
)-1;
648 wxThreadError
wxThread::Delete(ExitCode
*pRc
)
652 // Delete() is always safe to call, so consider all possible states
654 // has the thread started to run?
655 bool shouldResume
= FALSE
;
658 wxCriticalSectionLocker
lock(m_critsect
);
660 if ( m_internal
->GetState() == STATE_NEW
)
662 // WinThreadStart() will see it and terminate immediately
663 m_internal
->SetState(STATE_EXITED
);
669 // is the thread paused?
670 if ( shouldResume
|| IsPaused() )
673 // does is still run?
678 // set flag for wxIsWaitingForThread()
679 gs_waitingForThread
= TRUE
;
686 // ask the thread to terminate
688 wxCriticalSectionLocker
lock(m_critsect
);
690 m_internal
->Cancel();
694 // simply wait for the thread to terminate
695 while( TestDestroy() )
697 ::YieldToAnyThread() ;
700 // simply wait for the thread to terminate
701 while( TestDestroy() )
703 ::YieldToAnyThread() ;
705 #endif // wxUSE_GUI/!wxUSE_GUI
709 gs_waitingForThread
= FALSE
;
717 // if ( !::GetExitCodeThread(hThread, (LPDWORD)&rc) )
719 wxLogLastError("GetExitCodeThread");
726 // if the thread exits normally, this is done in WinThreadStart, but in
727 // this case it would have been too early because
728 // MsgWaitForMultipleObject() would fail if the therad handle was
729 // closed while we were waiting on it, so we must do it here
733 // wxASSERT_MSG( (DWORD)rc != STILL_ACTIVE,
734 // wxT("thread must be already terminated.") );
739 return rc
== (ExitCode
)-1 ? wxTHREAD_MISC_ERROR
: wxTHREAD_NO_ERROR
;
742 wxThreadError
wxThread::Kill()
745 return wxTHREAD_NOT_RUNNING
;
747 // if ( !::TerminateThread(m_internal->GetHandle(), (DWORD)-1) )
749 wxLogSysError(_("Couldn't terminate thread"));
751 return wxTHREAD_MISC_ERROR
;
761 return wxTHREAD_NO_ERROR
;
764 void wxThread::Exit(ExitCode status
)
773 m_internal
->SetResult( status
) ;
776 #if defined(__VISUALC__) || (defined(__BORLANDC__) && (__BORLANDC__ >= 0x500))
777 _endthreadex((unsigned)status);
779 ::ExitThread((DWORD)status);
782 wxFAIL_MSG(wxT("Couldn't return from ExitThread()!"));
788 // since all these calls are execute cooperatively we don't have to use the critical section
790 void wxThread::SetPriority(unsigned int prio
)
792 m_internal
->SetPriority(prio
);
795 unsigned int wxThread::GetPriority() const
797 return m_internal
->GetPriority();
800 unsigned long wxThread::GetId() const
802 return (unsigned long)m_internal
->GetId();
805 bool wxThread::IsRunning() const
807 return m_internal
->GetState() == STATE_RUNNING
;
810 bool wxThread::IsAlive() const
812 return (m_internal
->GetState() == STATE_RUNNING
) ||
813 (m_internal
->GetState() == STATE_PAUSED
);
816 bool wxThread::IsPaused() const
818 return m_internal
->GetState() == STATE_PAUSED
;
821 bool wxThread::TestDestroy()
823 return m_internal
->GetState() == STATE_CANCELED
;
826 // ----------------------------------------------------------------------------
827 // Automatic initialization for thread module
828 // ----------------------------------------------------------------------------
830 class wxThreadModule
: public wxModule
833 virtual bool OnInit();
834 virtual void OnExit();
837 DECLARE_DYNAMIC_CLASS(wxThreadModule
)
840 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule
, wxModule
)
842 bool wxThreadModule::OnInit()
845 bool hasThreadManager
;
846 hasThreadManager
= Gestalt( gestaltThreadMgrAttr
, &response
) == noErr
&& response
& 1;
849 // verify presence of shared library
850 hasThreadManager
= hasThreadManager
&& ((Ptr
)NewThread
!= (Ptr
)kUnresolvedCFragSymbolAddress
);
853 if ( !hasThreadManager
)
855 wxMessageBox( "Error" , "Thread Support is not available on this System" , wxOK
) ;
859 // no error return for GetCurrentThreadId()
860 MacGetCurrentThread( &gs_idMainThread
) ;
865 void wxThreadModule::OnExit()
869 // ----------------------------------------------------------------------------
870 // under MacOS we don't have currently preemptive threads, so any thread may access
871 // the GUI at any time
872 // ----------------------------------------------------------------------------
874 void WXDLLEXPORT
wxMutexGuiEnter()
878 void WXDLLEXPORT
wxMutexGuiLeave()
882 void WXDLLEXPORT
wxMutexGuiLeaveOrEnter()
886 bool WXDLLEXPORT
wxGuiOwnedByMainThread()
891 // wake up the main thread
892 void WXDLLEXPORT
wxWakeUpMainThread()
897 bool WXDLLEXPORT
wxIsWaitingForThread()
902 #include "wx/thrimpl.cpp"
904 #endif // wxUSE_THREADS