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"
41 #include "wx/mac/uma.h"
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 // ----------------------------------------------------------------------------
94 m_owner
= kNoThreadID
;
103 wxArrayLong m_waiters
;
108 m_internal
= new wxMutexInternal
;
117 wxLogDebug(_T("Warning: freeing a locked mutex (%d locks)."), m_locked
);
123 wxMutexError
wxMutex::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_internal
->m_owner
!= kNoThreadID
&& m_internal
->m_owner
!= current
)
135 m_internal
->m_waiters
.Add(current
);
136 err
= ::SetThreadStateEndCritical(kCurrentThreadID
, kStoppedThreadState
, m_internal
->m_owner
);
137 err
= ::ThreadBeginCritical();
139 m_internal
->m_owner
= current
;
143 return wxMUTEX_NO_ERROR
;
146 wxMutexError
wxMutex::TryLock()
148 wxMacStCritical critical
;
149 if ( UMASystemIsInitialized() )
152 ThreadID current
= kNoThreadID
;
153 ::MacGetCurrentThread(¤t
);
154 // if we are not the owner, give an error back
155 if ( m_internal
->m_owner
!= kNoThreadID
&& m_internal
->m_owner
!= current
)
158 m_internal
->m_owner
= current
;
162 return wxMUTEX_NO_ERROR
;
165 wxMutexError
wxMutex::Unlock()
167 if ( UMASystemIsInitialized() )
170 err
= ::ThreadBeginCritical();
175 // this mutex is not owned by anybody anmore
176 m_internal
->m_owner
= kNoThreadID
;
178 // now pass on to the first waiting thread
179 ThreadID firstWaiting
= kNoThreadID
;
181 while (!m_internal
->m_waiters
.IsEmpty() && !found
)
183 firstWaiting
= m_internal
->m_waiters
[0];
184 err
= ::SetThreadState(firstWaiting
, kReadyThreadState
, kNoThreadID
);
185 // in case this was not successful (dead thread), we just loop on and reset the id
186 found
= (err
!= threadNotFoundErr
);
188 firstWaiting
= kNoThreadID
;
189 m_internal
->m_waiters
.RemoveAt(0) ;
191 // now we have a valid firstWaiting thread, which has been scheduled to run next, just end the
192 // critical section and invoke the scheduler
193 err
= ::SetThreadStateEndCritical(kCurrentThreadID
, kReadyThreadState
, firstWaiting
);
200 return wxMUTEX_NO_ERROR
;
203 // ----------------------------------------------------------------------------
204 // wxCondition implementation
205 // ----------------------------------------------------------------------------
207 class wxConditionInternal
210 wxConditionInternal()
212 m_excessSignals
= 0 ;
214 ~wxConditionInternal()
218 bool Wait(unsigned long msectimeout
)
220 wxMacStCritical critical
;
221 if ( m_excessSignals
> 0 )
226 else if ( msectimeout
== 0 )
236 // FIXME this should be MsgWaitForMultipleObjects() as well probably
237 DWORD rc = ::WaitForSingleObject(event, timeout);
241 return rc != WAIT_TIMEOUT;
247 wxMacStCritical critical
;
250 wxArrayLong m_waiters
;
251 wxInt32 m_excessSignals
;
254 wxCondition::wxCondition()
256 m_internal
= new wxConditionInternal
;
259 wxCondition::~wxCondition()
264 void wxCondition::Wait()
266 (void)m_internal
->Wait(0xFFFFFFFFL
);
269 bool wxCondition::Wait(unsigned long sec
,
272 return m_internal
->Wait(sec
*1000 + nsec
/1000000);
275 void wxCondition::Signal()
277 // set the event to signaled: if a thread is already waiting on it, it will
278 // be woken up, otherwise the event will remain in the signaled state until
279 // someone waits on it. In any case, the system will return it to a non
280 // signalled state afterwards. If multiple threads are waiting, only one
282 m_internal
->Signal() ;
285 void wxCondition::Broadcast()
287 // this works because all these threads are already waiting and so each
288 // SetEvent() inside Signal() is really a PulseEvent() because the event
289 // state is immediately returned to non-signaled
290 for ( int i
= 0; i
< m_internal
->m_waiters
.Count(); i
++ )
296 // ----------------------------------------------------------------------------
297 // wxCriticalSection implementation
298 // ----------------------------------------------------------------------------
300 // it's implemented as a mutex on mac os, so it is defined in the headers
302 // ----------------------------------------------------------------------------
303 // wxThread implementation
304 // ----------------------------------------------------------------------------
306 // wxThreadInternal class
307 // ----------------------
309 class wxThreadInternal
314 m_tid
= kNoThreadID
;
316 m_priority
= WXTHREAD_DEFAULT_PRIORITY
;
327 // create a new (suspended) thread (for the given thread object)
328 bool Create(wxThread
*thread
, unsigned int stackSize
);
330 // suspend/resume/terminate
333 void Cancel() { m_state
= STATE_CANCELED
; }
336 void SetState(wxThreadState state
) { m_state
= state
; }
337 wxThreadState
GetState() const { return m_state
; }
340 void SetPriority(unsigned int priority
);
341 unsigned int GetPriority() const { return m_priority
; }
343 void SetResult( void *res
) { m_result
= res
; }
344 void *GetResult() { return m_result
; }
346 // thread handle and id
347 ThreadID
GetId() const { return m_tid
; }
350 static pascal void* MacThreadStart(wxThread
* arg
);
353 wxThreadState m_state
; // state, see wxThreadState enum
354 unsigned int m_priority
; // thread priority in "wx" units
355 ThreadID m_tid
; // thread id
357 static ThreadEntryUPP s_threadEntry
;
360 static wxArrayPtrVoid s_threads
;
362 ThreadEntryUPP
wxThreadInternal::s_threadEntry
= NULL
;
363 pascal void* wxThreadInternal::MacThreadStart(wxThread
*thread
)
365 // first of all, check whether we hadn't been cancelled already
366 if ( thread
->m_internal
->GetState() == STATE_EXITED
)
371 void* rc
= thread
->Entry();
373 // enter m_critsect before changing the thread state
374 thread
->m_critsect
.Enter();
375 bool wasCancelled
= thread
->m_internal
->GetState() == STATE_CANCELED
;
376 thread
->m_internal
->SetState(STATE_EXITED
);
377 thread
->m_critsect
.Leave();
381 // if the thread was cancelled (from Delete()), then it the handle is still
383 if ( thread
->IsDetached() && !wasCancelled
)
388 //else: the joinable threads handle will be closed when Wait() is done
392 void wxThreadInternal::SetPriority(unsigned int priority
)
394 // Priorities don't exist on Mac
397 bool wxThreadInternal::Create(wxThread
*thread
, unsigned int stackSize
)
399 if ( s_threadEntry
== NULL
)
401 s_threadEntry
= NewThreadEntryUPP( (ThreadEntryProcPtr
) MacThreadStart
) ;
403 OSErr err
= NewThread( kCooperativeThread
,
413 wxLogSysError(_("Can't create thread"));
417 if ( m_priority
!= WXTHREAD_DEFAULT_PRIORITY
)
419 SetPriority(m_priority
);
425 bool wxThreadInternal::Suspend()
429 ::ThreadBeginCritical();
431 if ( m_state
!= STATE_RUNNING
)
433 ::ThreadEndCritical() ;
434 wxLogSysError(_("Can not suspend thread %x"), m_tid
);
438 m_state
= STATE_PAUSED
;
440 err
= ::SetThreadStateEndCritical(m_tid
, kStoppedThreadState
, kNoThreadID
);
445 bool wxThreadInternal::Resume()
449 err
= MacGetCurrentThread( ¤t
) ;
451 wxASSERT( err
== noErr
) ;
452 wxASSERT( current
!= m_tid
) ;
454 ::ThreadBeginCritical();
455 if ( m_state
!= STATE_PAUSED
&& m_state
!= STATE_NEW
)
457 ::ThreadEndCritical() ;
458 wxLogSysError(_("Can not resume thread %x"), m_tid
);
462 err
= ::SetThreadStateEndCritical(m_tid
, kReadyThreadState
, kNoThreadID
);
463 wxASSERT( err
== noErr
) ;
465 m_state
= STATE_RUNNING
;
466 ::ThreadEndCritical() ;
467 ::YieldToAnyThread() ;
473 wxThread
*wxThread::This()
475 wxMacStCritical critical
;
480 err
= MacGetCurrentThread( ¤t
) ;
482 for ( int i
= 0 ; i
< s_threads
.Count() ; ++i
)
484 if ( ( (wxThread
*) s_threads
[i
] )->GetId() == current
)
485 return (wxThread
*) s_threads
[i
] ;
488 wxLogSysError(_("Couldn't get the current thread pointer"));
492 bool wxThread::IsMain()
497 err
= MacGetCurrentThread( ¤t
) ;
498 return current
== gs_idMainThread
;
505 void wxThread::Yield()
507 ::YieldToAnyThread() ;
510 void wxThread::Sleep(unsigned long milliseconds
)
512 clock_t start
= clock() ;
516 } while( clock() - start
< milliseconds
/ CLOCKS_PER_SEC
) ;
519 int wxThread::GetCPUCount()
521 // we will use whatever MP API will be used for the new MP Macs
525 unsigned long wxThread::GetCurrentId()
528 MacGetCurrentThread( ¤t
) ;
529 return (unsigned long)current
;
532 bool wxThread::SetConcurrency(size_t level
)
534 wxASSERT_MSG( IsMain(), _T("should only be called from the main thread") );
536 // ok only for the default one
540 // how many CPUs have we got?
541 if ( GetCPUCount() == 1 )
543 // don't bother with all this complicated stuff - on a single
544 // processor system it doesn't make much sense anyhow
554 wxThread::wxThread(wxThreadKind kind
)
556 m_internal
= new wxThreadInternal();
558 m_isDetached
= kind
== wxTHREAD_DETACHED
;
559 s_threads
.Add( (void*) this ) ;
562 wxThread::~wxThread()
564 s_threads
.Remove( (void*) this ) ;
568 // create/start thread
569 // -------------------
571 wxThreadError
wxThread::Create(unsigned int stackSize
)
573 wxCriticalSectionLocker
lock(m_critsect
);
575 if ( !m_internal
->Create(this, stackSize
) )
576 return wxTHREAD_NO_RESOURCE
;
578 return wxTHREAD_NO_ERROR
;
581 wxThreadError
wxThread::Run()
583 wxCriticalSectionLocker
lock(m_critsect
);
585 if ( m_internal
->GetState() != STATE_NEW
)
587 // actually, it may be almost any state at all, not only STATE_RUNNING
588 return wxTHREAD_RUNNING
;
591 // the thread has just been created and is still suspended - let it run
595 // suspend/resume thread
596 // ---------------------
598 wxThreadError
wxThread::Pause()
600 wxCriticalSectionLocker
lock(m_critsect
);
602 return m_internal
->Suspend() ? wxTHREAD_NO_ERROR
: wxTHREAD_MISC_ERROR
;
605 wxThreadError
wxThread::Resume()
607 wxCriticalSectionLocker
lock(m_critsect
);
609 return m_internal
->Resume() ? wxTHREAD_NO_ERROR
: wxTHREAD_MISC_ERROR
;
615 wxThread::ExitCode
wxThread::Wait()
617 // although under MacOS we can wait for any thread, it's an error to
618 // wait for a detached one in wxWin API
619 wxCHECK_MSG( !IsDetached(), (ExitCode
)-1,
620 _T("can't wait for detached thread") );
622 ExitCode rc
= (ExitCode
)-1;
631 wxThreadError
wxThread::Delete(ExitCode
*pRc
)
635 // Delete() is always safe to call, so consider all possible states
637 // has the thread started to run?
638 bool shouldResume
= FALSE
;
641 wxCriticalSectionLocker
lock(m_critsect
);
643 if ( m_internal
->GetState() == STATE_NEW
)
645 // WinThreadStart() will see it and terminate immediately
646 m_internal
->SetState(STATE_EXITED
);
652 // is the thread paused?
653 if ( shouldResume
|| IsPaused() )
656 // does is still run?
661 // set flag for wxIsWaitingForThread()
662 gs_waitingForThread
= TRUE
;
669 // ask the thread to terminate
671 wxCriticalSectionLocker
lock(m_critsect
);
673 m_internal
->Cancel();
677 // simply wait for the thread to terminate
678 while( TestDestroy() )
680 ::YieldToAnyThread() ;
683 // simply wait for the thread to terminate
684 while( TestDestroy() )
686 ::YieldToAnyThread() ;
688 #endif // wxUSE_GUI/!wxUSE_GUI
692 gs_waitingForThread
= FALSE
;
700 // if ( !::GetExitCodeThread(hThread, (LPDWORD)&rc) )
702 wxLogLastError("GetExitCodeThread");
709 // if the thread exits normally, this is done in WinThreadStart, but in
710 // this case it would have been too early because
711 // MsgWaitForMultipleObject() would fail if the therad handle was
712 // closed while we were waiting on it, so we must do it here
716 // wxASSERT_MSG( (DWORD)rc != STILL_ACTIVE,
717 // wxT("thread must be already terminated.") );
722 return rc
== (ExitCode
)-1 ? wxTHREAD_MISC_ERROR
: wxTHREAD_NO_ERROR
;
725 wxThreadError
wxThread::Kill()
728 return wxTHREAD_NOT_RUNNING
;
730 // if ( !::TerminateThread(m_internal->GetHandle(), (DWORD)-1) )
732 wxLogSysError(_("Couldn't terminate thread"));
734 return wxTHREAD_MISC_ERROR
;
744 return wxTHREAD_NO_ERROR
;
747 void wxThread::Exit(ExitCode status
)
756 m_internal
->SetResult( status
) ;
759 #if defined(__VISUALC__) || (defined(__BORLANDC__) && (__BORLANDC__ >= 0x500))
760 _endthreadex((unsigned)status);
762 ::ExitThread((DWORD)status);
765 wxFAIL_MSG(wxT("Couldn't return from ExitThread()!"));
771 // since all these calls are execute cooperatively we don't have to use the critical section
773 void wxThread::SetPriority(unsigned int prio
)
775 m_internal
->SetPriority(prio
);
778 unsigned int wxThread::GetPriority() const
780 return m_internal
->GetPriority();
783 unsigned long wxThread::GetId() const
785 return (unsigned long)m_internal
->GetId();
788 bool wxThread::IsRunning() const
790 return m_internal
->GetState() == STATE_RUNNING
;
793 bool wxThread::IsAlive() const
795 return (m_internal
->GetState() == STATE_RUNNING
) ||
796 (m_internal
->GetState() == STATE_PAUSED
);
799 bool wxThread::IsPaused() const
801 return m_internal
->GetState() == STATE_PAUSED
;
804 bool wxThread::TestDestroy()
806 return m_internal
->GetState() == STATE_CANCELED
;
809 // ----------------------------------------------------------------------------
810 // Automatic initialization for thread module
811 // ----------------------------------------------------------------------------
813 class wxThreadModule
: public wxModule
816 virtual bool OnInit();
817 virtual void OnExit();
820 DECLARE_DYNAMIC_CLASS(wxThreadModule
)
823 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule
, wxModule
)
825 bool wxThreadModule::OnInit()
828 bool hasThreadManager
;
829 hasThreadManager
= Gestalt( gestaltThreadMgrAttr
, &response
) == noErr
&& response
& 1;
832 // verify presence of shared library
833 hasThreadManager
= hasThreadManager
&& ((Ptr
)NewThread
!= (Ptr
)kUnresolvedCFragSymbolAddress
);
836 if ( !hasThreadManager
)
838 wxMessageBox( "Error" , "Thread Support is not available on this System" , wxOK
) ;
842 // no error return for GetCurrentThreadId()
843 MacGetCurrentThread( &gs_idMainThread
) ;
848 void wxThreadModule::OnExit()
852 // ----------------------------------------------------------------------------
853 // under MacOS we don't have currently preemptive threads, so any thread may access
854 // the GUI at any time
855 // ----------------------------------------------------------------------------
857 void WXDLLEXPORT
wxMutexGuiEnter()
861 void WXDLLEXPORT
wxMutexGuiLeave()
865 void WXDLLEXPORT
wxMutexGuiLeaveOrEnter()
869 bool WXDLLEXPORT
wxGuiOwnedByMainThread()
874 // wake up the main thread
875 void WXDLLEXPORT
wxWakeUpMainThread()
880 bool WXDLLEXPORT
wxIsWaitingForThread()
885 #endif // wxUSE_THREADS