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"
38 #include "wx/mac/private.h"
41 // ----------------------------------------------------------------------------
43 // ----------------------------------------------------------------------------
45 // the possible states of the thread ("=>" shows all possible transitions from
49 STATE_NEW
, // didn't start execution yet (=> RUNNING)
50 STATE_RUNNING
, // thread is running (=> PAUSED, CANCELED)
51 STATE_PAUSED
, // thread is temporarily suspended (=> RUNNING)
52 STATE_CANCELED
, // thread should terminate a.s.a.p. (=> EXITED)
53 STATE_EXITED
// thread is terminating
56 // ----------------------------------------------------------------------------
57 // this module globals
58 // ----------------------------------------------------------------------------
60 static ThreadID gs_idMainThread
= kNoThreadID
;
61 static bool gs_waitingForThread
= FALSE
;
63 // ============================================================================
64 // MacOS implementation of thread classes
65 // ============================================================================
72 ThreadBeginCritical() ;
80 // ----------------------------------------------------------------------------
81 // wxMutex implementation
82 // ----------------------------------------------------------------------------
89 m_owner
= kNoThreadID
;
98 wxArrayLong m_waiters
;
103 m_internal
= new wxMutexInternal
;
112 wxLogDebug(_T("Warning: freeing a locked mutex (%d locks)."), m_locked
);
118 wxMutexError
wxMutex::Lock()
120 wxMacStCritical critical
;
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_internal
->m_owner
!= kNoThreadID
&& m_internal
->m_owner
!= current
)
129 m_internal
->m_waiters
.Add(current
);
130 err
= ::SetThreadStateEndCritical(kCurrentThreadID
, kStoppedThreadState
, m_internal
->m_owner
);
131 err
= ::ThreadBeginCritical();
133 m_internal
->m_owner
= current
;
136 return wxMUTEX_NO_ERROR
;
139 wxMutexError
wxMutex::TryLock()
141 wxMacStCritical critical
;
144 ThreadID current
= kNoThreadID
;
145 ::MacGetCurrentThread(¤t
);
146 // if we are not the owner, give an error back
147 if ( m_internal
->m_owner
!= kNoThreadID
&& m_internal
->m_owner
!= current
)
150 m_internal
->m_owner
= current
;
153 return wxMUTEX_NO_ERROR
;
156 wxMutexError
wxMutex::Unlock()
159 err
= ::ThreadBeginCritical();
164 // this mutex is not owned by anybody anmore
165 m_internal
->m_owner
= kNoThreadID
;
167 // now pass on to the first waiting thread
168 ThreadID firstWaiting
= kNoThreadID
;
170 while (!m_internal
->m_waiters
.IsEmpty() && !found
)
172 firstWaiting
= m_internal
->m_waiters
[0];
173 err
= ::SetThreadState(firstWaiting
, kReadyThreadState
, kNoThreadID
);
174 // in case this was not successful (dead thread), we just loop on and reset the id
175 found
= (err
!= threadNotFoundErr
);
177 firstWaiting
= kNoThreadID
;
178 m_internal
->m_waiters
.RemoveAt(0) ;
180 // now we have a valid firstWaiting thread, which has been scheduled to run next, just end the
181 // critical section and invoke the scheduler
182 err
= ::SetThreadStateEndCritical(kCurrentThreadID
, kReadyThreadState
, firstWaiting
);
184 return wxMUTEX_NO_ERROR
;
187 // ----------------------------------------------------------------------------
188 // wxCondition implementation
189 // ----------------------------------------------------------------------------
191 class wxConditionInternal
194 wxConditionInternal()
196 m_excessSignals
= 0 ;
198 ~wxConditionInternal()
202 bool Wait(unsigned long msectimeout
)
204 wxMacStCritical critical
;
205 if ( m_excessSignals
> 0 )
210 else if ( msectimeout
== 0 )
220 // FIXME this should be MsgWaitForMultipleObjects() as well probably
221 DWORD rc = ::WaitForSingleObject(event, timeout);
225 return rc != WAIT_TIMEOUT;
231 wxMacStCritical critical
;
234 wxArrayLong m_waiters
;
235 wxInt32 m_excessSignals
;
238 wxCondition::wxCondition()
240 m_internal
= new wxConditionInternal
;
243 wxCondition::~wxCondition()
248 void wxCondition::Wait()
250 (void)m_internal
->Wait(0xFFFFFFFFL
);
253 bool wxCondition::Wait(unsigned long sec
,
256 return m_internal
->Wait(sec
*1000 + nsec
/1000000);
259 void wxCondition::Signal()
261 // set the event to signaled: if a thread is already waiting on it, it will
262 // be woken up, otherwise the event will remain in the signaled state until
263 // someone waits on it. In any case, the system will return it to a non
264 // signalled state afterwards. If multiple threads are waiting, only one
266 m_internal
->Signal() ;
269 void wxCondition::Broadcast()
271 // this works because all these threads are already waiting and so each
272 // SetEvent() inside Signal() is really a PulseEvent() because the event
273 // state is immediately returned to non-signaled
274 for ( int i
= 0; i
< m_internal
->m_waiters
.Count(); i
++ )
280 // ----------------------------------------------------------------------------
281 // wxCriticalSection implementation
282 // ----------------------------------------------------------------------------
284 // it's implemented as a mutex on mac os, so it is defined in the headers
286 // ----------------------------------------------------------------------------
287 // wxThread implementation
288 // ----------------------------------------------------------------------------
290 // wxThreadInternal class
291 // ----------------------
293 class wxThreadInternal
298 m_tid
= kNoThreadID
;
300 m_priority
= WXTHREAD_DEFAULT_PRIORITY
;
311 // create a new (suspended) thread (for the given thread object)
312 bool Create(wxThread
*thread
, unsigned int stackSize
);
314 // suspend/resume/terminate
317 void Cancel() { m_state
= STATE_CANCELED
; }
320 void SetState(wxThreadState state
) { m_state
= state
; }
321 wxThreadState
GetState() const { return m_state
; }
324 void SetPriority(unsigned int priority
);
325 unsigned int GetPriority() const { return m_priority
; }
327 void SetResult( void *res
) { m_result
= res
; }
328 void *GetResult() { return m_result
; }
330 // thread handle and id
331 ThreadID
GetId() const { return m_tid
; }
334 static pascal void* MacThreadStart(wxThread
* arg
);
337 wxThreadState m_state
; // state, see wxThreadState enum
338 unsigned int m_priority
; // thread priority in "wx" units
339 ThreadID m_tid
; // thread id
341 static ThreadEntryUPP s_threadEntry
;
344 static wxArrayPtrVoid s_threads
;
346 ThreadEntryUPP
wxThreadInternal::s_threadEntry
= NULL
;
347 pascal void* wxThreadInternal::MacThreadStart(wxThread
*thread
)
349 // first of all, check whether we hadn't been cancelled already
350 if ( thread
->m_internal
->GetState() == STATE_EXITED
)
355 void* rc
= thread
->Entry();
357 // enter m_critsect before changing the thread state
358 thread
->m_critsect
.Enter();
359 bool wasCancelled
= thread
->m_internal
->GetState() == STATE_CANCELED
;
360 thread
->m_internal
->SetState(STATE_EXITED
);
361 thread
->m_critsect
.Leave();
365 // if the thread was cancelled (from Delete()), then it the handle is still
367 if ( thread
->IsDetached() && !wasCancelled
)
372 //else: the joinable threads handle will be closed when Wait() is done
376 void wxThreadInternal::SetPriority(unsigned int priority
)
378 // Priorities don't exist on Mac
381 bool wxThreadInternal::Create(wxThread
*thread
, unsigned int stackSize
)
383 if ( s_threadEntry
== NULL
)
385 s_threadEntry
= NewThreadEntryUPP( (ThreadEntryProcPtr
) MacThreadStart
) ;
387 OSErr err
= NewThread( kCooperativeThread
,
397 wxLogSysError(_("Can't create thread"));
401 if ( m_priority
!= WXTHREAD_DEFAULT_PRIORITY
)
403 SetPriority(m_priority
);
409 bool wxThreadInternal::Suspend()
413 ::ThreadBeginCritical();
415 if ( m_state
!= STATE_RUNNING
)
417 ::ThreadEndCritical() ;
418 wxLogSysError(_("Can not suspend thread %x"), m_tid
);
422 m_state
= STATE_PAUSED
;
424 err
= ::SetThreadStateEndCritical(m_tid
, kStoppedThreadState
, kNoThreadID
);
429 bool wxThreadInternal::Resume()
433 err
= MacGetCurrentThread( ¤t
) ;
435 wxASSERT( err
== noErr
) ;
436 wxASSERT( current
!= m_tid
) ;
438 ::ThreadBeginCritical();
439 if ( m_state
!= STATE_PAUSED
&& m_state
!= STATE_NEW
)
441 ::ThreadEndCritical() ;
442 wxLogSysError(_("Can not resume thread %x"), m_tid
);
446 err
= ::SetThreadStateEndCritical(m_tid
, kReadyThreadState
, kNoThreadID
);
447 wxASSERT( err
== noErr
) ;
449 m_state
= STATE_RUNNING
;
450 ::ThreadEndCritical() ;
451 ::YieldToAnyThread() ;
457 wxThread
*wxThread::This()
459 wxMacStCritical critical
;
464 err
= MacGetCurrentThread( ¤t
) ;
466 for ( int i
= 0 ; i
< s_threads
.Count() ; ++i
)
468 if ( ( (wxThread
*) s_threads
[i
] )->GetId() == current
)
469 return (wxThread
*) s_threads
[i
] ;
472 wxLogSysError(_("Couldn't get the current thread pointer"));
476 bool wxThread::IsMain()
481 err
= MacGetCurrentThread( ¤t
) ;
482 return current
== gs_idMainThread
;
489 void wxThread::Yield()
491 ::YieldToAnyThread() ;
494 void wxThread::Sleep(unsigned long milliseconds
)
496 clock_t start
= clock() ;
500 } while( clock() - start
< milliseconds
/ CLOCKS_PER_SEC
) ;
503 int wxThread::GetCPUCount()
505 // we will use whatever MP API will be used for the new MP Macs
509 bool wxThread::SetConcurrency(size_t level
)
511 wxASSERT_MSG( IsMain(), _T("should only be called from the main thread") );
513 // ok only for the default one
517 // how many CPUs have we got?
518 if ( GetCPUCount() == 1 )
520 // don't bother with all this complicated stuff - on a single
521 // processor system it doesn't make much sense anyhow
531 wxThread::wxThread(wxThreadKind kind
)
533 m_internal
= new wxThreadInternal();
535 m_isDetached
= kind
== wxTHREAD_DETACHED
;
536 s_threads
.Add( (void*) this ) ;
539 wxThread::~wxThread()
541 s_threads
.Remove( (void*) this ) ;
545 // create/start thread
546 // -------------------
548 wxThreadError
wxThread::Create(unsigned int stackSize
)
550 wxCriticalSectionLocker
lock(m_critsect
);
552 if ( !m_internal
->Create(this, stackSize
) )
553 return wxTHREAD_NO_RESOURCE
;
555 return wxTHREAD_NO_ERROR
;
558 wxThreadError
wxThread::Run()
560 wxCriticalSectionLocker
lock(m_critsect
);
562 if ( m_internal
->GetState() != STATE_NEW
)
564 // actually, it may be almost any state at all, not only STATE_RUNNING
565 return wxTHREAD_RUNNING
;
568 // the thread has just been created and is still suspended - let it run
572 // suspend/resume thread
573 // ---------------------
575 wxThreadError
wxThread::Pause()
577 wxCriticalSectionLocker
lock(m_critsect
);
579 return m_internal
->Suspend() ? wxTHREAD_NO_ERROR
: wxTHREAD_MISC_ERROR
;
582 wxThreadError
wxThread::Resume()
584 wxCriticalSectionLocker
lock(m_critsect
);
586 return m_internal
->Resume() ? wxTHREAD_NO_ERROR
: wxTHREAD_MISC_ERROR
;
592 wxThread::ExitCode
wxThread::Wait()
594 // although under MacOS we can wait for any thread, it's an error to
595 // wait for a detached one in wxWin API
596 wxCHECK_MSG( !IsDetached(), (ExitCode
)-1,
597 _T("can't wait for detached thread") );
599 ExitCode rc
= (ExitCode
)-1;
608 wxThreadError
wxThread::Delete(ExitCode
*pRc
)
612 // Delete() is always safe to call, so consider all possible states
614 // has the thread started to run?
615 bool shouldResume
= FALSE
;
618 wxCriticalSectionLocker
lock(m_critsect
);
620 if ( m_internal
->GetState() == STATE_NEW
)
622 // WinThreadStart() will see it and terminate immediately
623 m_internal
->SetState(STATE_EXITED
);
629 // is the thread paused?
630 if ( shouldResume
|| IsPaused() )
633 // does is still run?
638 // set flag for wxIsWaitingForThread()
639 gs_waitingForThread
= TRUE
;
646 // ask the thread to terminate
648 wxCriticalSectionLocker
lock(m_critsect
);
650 m_internal
->Cancel();
654 // simply wait for the thread to terminate
655 while( TestDestroy() )
657 ::YieldToAnyThread() ;
660 // simply wait for the thread to terminate
661 while( TestDestroy() )
663 ::YieldToAnyThread() ;
665 #endif // wxUSE_GUI/!wxUSE_GUI
669 gs_waitingForThread
= FALSE
;
677 // if ( !::GetExitCodeThread(hThread, (LPDWORD)&rc) )
679 wxLogLastError("GetExitCodeThread");
686 // if the thread exits normally, this is done in WinThreadStart, but in
687 // this case it would have been too early because
688 // MsgWaitForMultipleObject() would fail if the therad handle was
689 // closed while we were waiting on it, so we must do it here
693 // wxASSERT_MSG( (DWORD)rc != STILL_ACTIVE,
694 // wxT("thread must be already terminated.") );
699 return rc
== (ExitCode
)-1 ? wxTHREAD_MISC_ERROR
: wxTHREAD_NO_ERROR
;
702 wxThreadError
wxThread::Kill()
705 return wxTHREAD_NOT_RUNNING
;
707 // if ( !::TerminateThread(m_internal->GetHandle(), (DWORD)-1) )
709 wxLogSysError(_("Couldn't terminate thread"));
711 return wxTHREAD_MISC_ERROR
;
721 return wxTHREAD_NO_ERROR
;
724 void wxThread::Exit(ExitCode status
)
733 m_internal
->SetResult( status
) ;
736 #if defined(__VISUALC__) || (defined(__BORLANDC__) && (__BORLANDC__ >= 0x500))
737 _endthreadex((unsigned)status);
739 ::ExitThread((DWORD)status);
742 wxFAIL_MSG(wxT("Couldn't return from ExitThread()!"));
748 // since all these calls are execute cooperatively we don't have to use the critical section
750 void wxThread::SetPriority(unsigned int prio
)
752 m_internal
->SetPriority(prio
);
755 unsigned int wxThread::GetPriority() const
757 return m_internal
->GetPriority();
760 unsigned long wxThread::GetId() const
762 return (unsigned long)m_internal
->GetId();
765 bool wxThread::IsRunning() const
767 return m_internal
->GetState() == STATE_RUNNING
;
770 bool wxThread::IsAlive() const
772 return (m_internal
->GetState() == STATE_RUNNING
) ||
773 (m_internal
->GetState() == STATE_PAUSED
);
776 bool wxThread::IsPaused() const
778 return m_internal
->GetState() == STATE_PAUSED
;
781 bool wxThread::TestDestroy()
783 return m_internal
->GetState() == STATE_CANCELED
;
786 // ----------------------------------------------------------------------------
787 // Automatic initialization for thread module
788 // ----------------------------------------------------------------------------
790 class wxThreadModule
: public wxModule
793 virtual bool OnInit();
794 virtual void OnExit();
797 DECLARE_DYNAMIC_CLASS(wxThreadModule
)
800 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule
, wxModule
)
802 bool wxThreadModule::OnInit()
805 bool hasThreadManager
;
806 hasThreadManager
= Gestalt( gestaltThreadMgrAttr
, &response
) == noErr
&& response
& 1;
809 // verify presence of shared library
810 hasThreadManager
= hasThreadManager
&& ((Ptr
)NewThread
!= (Ptr
)kUnresolvedCFragSymbolAddress
);
813 if ( !hasThreadManager
)
815 wxMessageBox( "Error" , "Thread Support is not available on this System" , wxOK
) ;
819 // no error return for GetCurrentThreadId()
820 MacGetCurrentThread( &gs_idMainThread
) ;
825 void wxThreadModule::OnExit()
829 // ----------------------------------------------------------------------------
830 // under MacOS we don't have currently preemptive threads, so any thread may access
831 // the GUI at any time
832 // ----------------------------------------------------------------------------
834 void WXDLLEXPORT
wxMutexGuiEnter()
838 void WXDLLEXPORT
wxMutexGuiLeave()
842 void WXDLLEXPORT
wxMutexGuiLeaveOrEnter()
846 bool WXDLLEXPORT
wxGuiOwnedByMainThread()
851 // wake up the main thread
852 void WXDLLEXPORT
wxWakeUpMainThread()
857 bool WXDLLEXPORT
wxIsWaitingForThread()
862 #endif // wxUSE_THREADS