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 // ----------------------------------------------------------------------------
44 // ----------------------------------------------------------------------------
46 // the possible states of the thread ("=>" shows all possible transitions from
50 STATE_NEW
, // didn't start execution yet (=> RUNNING)
51 STATE_RUNNING
, // thread is running (=> PAUSED, CANCELED)
52 STATE_PAUSED
, // thread is temporarily suspended (=> RUNNING)
53 STATE_CANCELED
, // thread should terminate a.s.a.p. (=> EXITED)
54 STATE_EXITED
// thread is terminating
57 // ----------------------------------------------------------------------------
58 // this module globals
59 // ----------------------------------------------------------------------------
61 static ThreadID gs_idMainThread
= kNoThreadID
;
62 static bool gs_waitingForThread
= FALSE
;
64 // ============================================================================
65 // MacOS implementation of thread classes
66 // ============================================================================
73 if ( UMASystemIsInitialized() )
74 ThreadBeginCritical() ;
78 if ( UMASystemIsInitialized() )
83 // ----------------------------------------------------------------------------
84 // wxMutex implementation
85 // ----------------------------------------------------------------------------
92 m_owner
= kNoThreadID
;
101 wxArrayLong m_waiters
;
106 m_internal
= new wxMutexInternal
;
115 wxLogDebug(_T("Warning: freeing a locked mutex (%d locks)."), m_locked
);
121 wxMutexError
wxMutex::Lock()
123 wxMacStCritical critical
;
124 if ( UMASystemIsInitialized() )
127 ThreadID current
= kNoThreadID
;
128 err
= ::MacGetCurrentThread(¤t
);
129 // if we are not the owner, add this thread to the list of waiting threads, stop this thread
130 // and invoke the scheduler to continue executing the owner's thread
131 while ( m_internal
->m_owner
!= kNoThreadID
&& m_internal
->m_owner
!= current
)
133 m_internal
->m_waiters
.Add(current
);
134 err
= ::SetThreadStateEndCritical(kCurrentThreadID
, kStoppedThreadState
, m_internal
->m_owner
);
135 err
= ::ThreadBeginCritical();
137 m_internal
->m_owner
= current
;
141 return wxMUTEX_NO_ERROR
;
144 wxMutexError
wxMutex::TryLock()
146 wxMacStCritical critical
;
147 if ( UMASystemIsInitialized() )
150 ThreadID current
= kNoThreadID
;
151 ::MacGetCurrentThread(¤t
);
152 // if we are not the owner, give an error back
153 if ( m_internal
->m_owner
!= kNoThreadID
&& m_internal
->m_owner
!= current
)
156 m_internal
->m_owner
= current
;
160 return wxMUTEX_NO_ERROR
;
163 wxMutexError
wxMutex::Unlock()
165 if ( UMASystemIsInitialized() )
168 err
= ::ThreadBeginCritical();
173 // this mutex is not owned by anybody anmore
174 m_internal
->m_owner
= kNoThreadID
;
176 // now pass on to the first waiting thread
177 ThreadID firstWaiting
= kNoThreadID
;
179 while (!m_internal
->m_waiters
.IsEmpty() && !found
)
181 firstWaiting
= m_internal
->m_waiters
[0];
182 err
= ::SetThreadState(firstWaiting
, kReadyThreadState
, kNoThreadID
);
183 // in case this was not successful (dead thread), we just loop on and reset the id
184 found
= (err
!= threadNotFoundErr
);
186 firstWaiting
= kNoThreadID
;
187 m_internal
->m_waiters
.RemoveAt(0) ;
189 // now we have a valid firstWaiting thread, which has been scheduled to run next, just end the
190 // critical section and invoke the scheduler
191 err
= ::SetThreadStateEndCritical(kCurrentThreadID
, kReadyThreadState
, firstWaiting
);
198 return wxMUTEX_NO_ERROR
;
201 // ----------------------------------------------------------------------------
202 // wxCondition implementation
203 // ----------------------------------------------------------------------------
205 class wxConditionInternal
208 wxConditionInternal(wxMutex
& mutex
) : m_mutex(mutex
)
210 m_excessSignals
= 0 ;
212 ~wxConditionInternal()
216 bool Wait(unsigned long msectimeout
)
218 wxMacStCritical critical
;
219 if ( m_excessSignals
> 0 )
224 else if ( msectimeout
== 0 )
234 // FIXME this should be MsgWaitForMultipleObjects() as well probably
235 DWORD rc = ::WaitForSingleObject(event, timeout);
239 return rc != WAIT_TIMEOUT;
245 wxMacStCritical critical
;
248 wxArrayLong m_waiters
;
249 wxInt32 m_excessSignals
;
253 wxCondition::wxCondition(wxMutex
& mutex
)
255 m_internal
= new wxConditionInternal(mutex
);
258 wxCondition::~wxCondition()
263 void wxCondition::Wait()
265 (void)m_internal
->Wait(0xFFFFFFFFL
);
268 bool wxCondition::Wait(unsigned long timeout_millis
)
270 return m_internal
->Wait(timeout_millis
);
273 void wxCondition::Signal()
275 // set the event to signaled: if a thread is already waiting on it, it will
276 // be woken up, otherwise the event will remain in the signaled state until
277 // someone waits on it. In any case, the system will return it to a non
278 // signalled state afterwards. If multiple threads are waiting, only one
280 m_internal
->Signal() ;
283 void wxCondition::Broadcast()
285 // this works because all these threads are already waiting and so each
286 // SetEvent() inside Signal() is really a PulseEvent() because the event
287 // state is immediately returned to non-signaled
288 for ( int i
= 0; i
< m_internal
->m_waiters
.Count(); i
++ )
294 // ----------------------------------------------------------------------------
295 // wxCriticalSection implementation
296 // ----------------------------------------------------------------------------
298 // it's implemented as a mutex on mac os, so it is defined in the headers
300 // ----------------------------------------------------------------------------
301 // wxThread implementation
302 // ----------------------------------------------------------------------------
304 // wxThreadInternal class
305 // ----------------------
307 class wxThreadInternal
312 m_tid
= kNoThreadID
;
314 m_priority
= WXTHREAD_DEFAULT_PRIORITY
;
325 // create a new (suspended) thread (for the given thread object)
326 bool Create(wxThread
*thread
, unsigned int stackSize
);
328 // suspend/resume/terminate
331 void Cancel() { m_state
= STATE_CANCELED
; }
334 void SetState(wxThreadState state
) { m_state
= state
; }
335 wxThreadState
GetState() const { return m_state
; }
338 void SetPriority(unsigned int priority
);
339 unsigned int GetPriority() const { return m_priority
; }
341 void SetResult( void *res
) { m_result
= res
; }
342 void *GetResult() { return m_result
; }
344 // thread handle and id
345 ThreadID
GetId() const { return m_tid
; }
348 static pascal void* MacThreadStart(wxThread
* arg
);
351 wxThreadState m_state
; // state, see wxThreadState enum
352 unsigned int m_priority
; // thread priority in "wx" units
353 ThreadID m_tid
; // thread id
355 static ThreadEntryUPP s_threadEntry
;
358 static wxArrayPtrVoid s_threads
;
360 ThreadEntryUPP
wxThreadInternal::s_threadEntry
= NULL
;
361 pascal void* wxThreadInternal::MacThreadStart(wxThread
*thread
)
363 // first of all, check whether we hadn't been cancelled already
364 if ( thread
->m_internal
->GetState() == STATE_EXITED
)
369 void* rc
= thread
->Entry();
371 // enter m_critsect before changing the thread state
372 thread
->m_critsect
.Enter();
373 bool wasCancelled
= thread
->m_internal
->GetState() == STATE_CANCELED
;
374 thread
->m_internal
->SetState(STATE_EXITED
);
375 thread
->m_critsect
.Leave();
379 // if the thread was cancelled (from Delete()), then it the handle is still
381 if ( thread
->IsDetached() && !wasCancelled
)
386 //else: the joinable threads handle will be closed when Wait() is done
390 void wxThreadInternal::SetPriority(unsigned int priority
)
392 // Priorities don't exist on Mac
395 bool wxThreadInternal::Create(wxThread
*thread
, unsigned int stackSize
)
397 if ( s_threadEntry
== NULL
)
399 s_threadEntry
= NewThreadEntryUPP( (ThreadEntryProcPtr
) MacThreadStart
) ;
401 OSErr err
= NewThread( kCooperativeThread
,
411 wxLogSysError(_("Can't create thread"));
415 if ( m_priority
!= WXTHREAD_DEFAULT_PRIORITY
)
417 SetPriority(m_priority
);
423 bool wxThreadInternal::Suspend()
427 ::ThreadBeginCritical();
429 if ( m_state
!= STATE_RUNNING
)
431 ::ThreadEndCritical() ;
432 wxLogSysError(_("Can not suspend thread %x"), m_tid
);
436 m_state
= STATE_PAUSED
;
438 err
= ::SetThreadStateEndCritical(m_tid
, kStoppedThreadState
, kNoThreadID
);
443 bool wxThreadInternal::Resume()
447 err
= MacGetCurrentThread( ¤t
) ;
449 wxASSERT( err
== noErr
) ;
450 wxASSERT( current
!= m_tid
) ;
452 ::ThreadBeginCritical();
453 if ( m_state
!= STATE_PAUSED
&& m_state
!= STATE_NEW
)
455 ::ThreadEndCritical() ;
456 wxLogSysError(_("Can not resume thread %x"), m_tid
);
460 err
= ::SetThreadStateEndCritical(m_tid
, kReadyThreadState
, kNoThreadID
);
461 wxASSERT( err
== noErr
) ;
463 m_state
= STATE_RUNNING
;
464 ::ThreadEndCritical() ;
465 ::YieldToAnyThread() ;
471 wxThread
*wxThread::This()
473 wxMacStCritical critical
;
478 err
= MacGetCurrentThread( ¤t
) ;
480 for ( int i
= 0 ; i
< s_threads
.Count() ; ++i
)
482 if ( ( (wxThread
*) s_threads
[i
] )->GetId() == current
)
483 return (wxThread
*) s_threads
[i
] ;
486 wxLogSysError(_("Couldn't get the current thread pointer"));
490 bool wxThread::IsMain()
495 err
= MacGetCurrentThread( ¤t
) ;
496 return current
== gs_idMainThread
;
503 void wxThread::Yield()
505 ::YieldToAnyThread() ;
508 void wxThread::Sleep(unsigned long milliseconds
)
510 clock_t start
= clock() ;
514 } while( clock() - start
< milliseconds
/ CLOCKS_PER_SEC
) ;
517 int wxThread::GetCPUCount()
519 // we will use whatever MP API will be used for the new MP Macs
523 unsigned long wxThread::GetCurrentId()
526 MacGetCurrentThread( ¤t
) ;
527 return (unsigned long)current
;
530 bool wxThread::SetConcurrency(size_t level
)
532 wxASSERT_MSG( IsMain(), _T("should only be called from the main thread") );
534 // ok only for the default one
538 // how many CPUs have we got?
539 if ( GetCPUCount() == 1 )
541 // don't bother with all this complicated stuff - on a single
542 // processor system it doesn't make much sense anyhow
552 wxThread::wxThread(wxThreadKind kind
)
554 m_internal
= new wxThreadInternal();
556 m_isDetached
= kind
== wxTHREAD_DETACHED
;
557 s_threads
.Add( (void*) this ) ;
560 wxThread::~wxThread()
562 s_threads
.Remove( (void*) this ) ;
566 // create/start thread
567 // -------------------
569 wxThreadError
wxThread::Create(unsigned int stackSize
)
571 wxCriticalSectionLocker
lock(m_critsect
);
573 if ( !m_internal
->Create(this, stackSize
) )
574 return wxTHREAD_NO_RESOURCE
;
576 return wxTHREAD_NO_ERROR
;
579 wxThreadError
wxThread::Run()
581 wxCriticalSectionLocker
lock(m_critsect
);
583 if ( m_internal
->GetState() != STATE_NEW
)
585 // actually, it may be almost any state at all, not only STATE_RUNNING
586 return wxTHREAD_RUNNING
;
589 // the thread has just been created and is still suspended - let it run
593 // suspend/resume thread
594 // ---------------------
596 wxThreadError
wxThread::Pause()
598 wxCriticalSectionLocker
lock(m_critsect
);
600 return m_internal
->Suspend() ? wxTHREAD_NO_ERROR
: wxTHREAD_MISC_ERROR
;
603 wxThreadError
wxThread::Resume()
605 wxCriticalSectionLocker
lock(m_critsect
);
607 return m_internal
->Resume() ? wxTHREAD_NO_ERROR
: wxTHREAD_MISC_ERROR
;
613 wxThread::ExitCode
wxThread::Wait()
615 // although under MacOS we can wait for any thread, it's an error to
616 // wait for a detached one in wxWin API
617 wxCHECK_MSG( !IsDetached(), (ExitCode
)-1,
618 _T("can't wait for detached thread") );
620 ExitCode rc
= (ExitCode
)-1;
629 wxThreadError
wxThread::Delete(ExitCode
*pRc
)
633 // Delete() is always safe to call, so consider all possible states
635 // has the thread started to run?
636 bool shouldResume
= FALSE
;
639 wxCriticalSectionLocker
lock(m_critsect
);
641 if ( m_internal
->GetState() == STATE_NEW
)
643 // WinThreadStart() will see it and terminate immediately
644 m_internal
->SetState(STATE_EXITED
);
650 // is the thread paused?
651 if ( shouldResume
|| IsPaused() )
654 // does is still run?
659 // set flag for wxIsWaitingForThread()
660 gs_waitingForThread
= TRUE
;
667 // ask the thread to terminate
669 wxCriticalSectionLocker
lock(m_critsect
);
671 m_internal
->Cancel();
675 // simply wait for the thread to terminate
676 while( TestDestroy() )
678 ::YieldToAnyThread() ;
681 // simply wait for the thread to terminate
682 while( TestDestroy() )
684 ::YieldToAnyThread() ;
686 #endif // wxUSE_GUI/!wxUSE_GUI
690 gs_waitingForThread
= FALSE
;
698 // if ( !::GetExitCodeThread(hThread, (LPDWORD)&rc) )
700 wxLogLastError("GetExitCodeThread");
707 // if the thread exits normally, this is done in WinThreadStart, but in
708 // this case it would have been too early because
709 // MsgWaitForMultipleObject() would fail if the therad handle was
710 // closed while we were waiting on it, so we must do it here
714 // wxASSERT_MSG( (DWORD)rc != STILL_ACTIVE,
715 // wxT("thread must be already terminated.") );
720 return rc
== (ExitCode
)-1 ? wxTHREAD_MISC_ERROR
: wxTHREAD_NO_ERROR
;
723 wxThreadError
wxThread::Kill()
726 return wxTHREAD_NOT_RUNNING
;
728 // if ( !::TerminateThread(m_internal->GetHandle(), (DWORD)-1) )
730 wxLogSysError(_("Couldn't terminate thread"));
732 return wxTHREAD_MISC_ERROR
;
742 return wxTHREAD_NO_ERROR
;
745 void wxThread::Exit(ExitCode status
)
754 m_internal
->SetResult( status
) ;
757 #if defined(__VISUALC__) || (defined(__BORLANDC__) && (__BORLANDC__ >= 0x500))
758 _endthreadex((unsigned)status);
760 ::ExitThread((DWORD)status);
763 wxFAIL_MSG(wxT("Couldn't return from ExitThread()!"));
769 // since all these calls are execute cooperatively we don't have to use the critical section
771 void wxThread::SetPriority(unsigned int prio
)
773 m_internal
->SetPriority(prio
);
776 unsigned int wxThread::GetPriority() const
778 return m_internal
->GetPriority();
781 unsigned long wxThread::GetId() const
783 return (unsigned long)m_internal
->GetId();
786 bool wxThread::IsRunning() const
788 return m_internal
->GetState() == STATE_RUNNING
;
791 bool wxThread::IsAlive() const
793 return (m_internal
->GetState() == STATE_RUNNING
) ||
794 (m_internal
->GetState() == STATE_PAUSED
);
797 bool wxThread::IsPaused() const
799 return m_internal
->GetState() == STATE_PAUSED
;
802 bool wxThread::TestDestroy()
804 return m_internal
->GetState() == STATE_CANCELED
;
807 // ----------------------------------------------------------------------------
808 // Automatic initialization for thread module
809 // ----------------------------------------------------------------------------
811 class wxThreadModule
: public wxModule
814 virtual bool OnInit();
815 virtual void OnExit();
818 DECLARE_DYNAMIC_CLASS(wxThreadModule
)
821 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule
, wxModule
)
823 bool wxThreadModule::OnInit()
826 bool hasThreadManager
;
827 hasThreadManager
= Gestalt( gestaltThreadMgrAttr
, &response
) == noErr
&& response
& 1;
830 // verify presence of shared library
831 hasThreadManager
= hasThreadManager
&& ((Ptr
)NewThread
!= (Ptr
)kUnresolvedCFragSymbolAddress
);
834 if ( !hasThreadManager
)
836 wxMessageBox( "Error" , "Thread Support is not available on this System" , wxOK
) ;
840 // no error return for GetCurrentThreadId()
841 MacGetCurrentThread( &gs_idMainThread
) ;
846 void wxThreadModule::OnExit()
850 // ----------------------------------------------------------------------------
851 // under MacOS we don't have currently preemptive threads, so any thread may access
852 // the GUI at any time
853 // ----------------------------------------------------------------------------
855 void WXDLLEXPORT
wxMutexGuiEnter()
859 void WXDLLEXPORT
wxMutexGuiLeave()
863 void WXDLLEXPORT
wxMutexGuiLeaveOrEnter()
867 bool WXDLLEXPORT
wxGuiOwnedByMainThread()
872 // wake up the main thread
873 void WXDLLEXPORT
wxWakeUpMainThread()
878 bool WXDLLEXPORT
wxIsWaitingForThread()
883 #endif // wxUSE_THREADS