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"
40 #include "wx/mac/macnotfy.h"
44 #define INFINITE 0xFFFFFFFF
47 // ----------------------------------------------------------------------------
49 // ----------------------------------------------------------------------------
51 // the possible states of the thread ("=>" shows all possible transitions from
55 STATE_NEW
, // didn't start execution yet (=> RUNNING)
56 STATE_RUNNING
, // thread is running (=> PAUSED, CANCELED)
57 STATE_PAUSED
, // thread is temporarily suspended (=> RUNNING)
58 STATE_CANCELED
, // thread should terminate a.s.a.p. (=> EXITED)
59 STATE_EXITED
// thread is terminating
62 // ----------------------------------------------------------------------------
63 // this module globals
64 // ----------------------------------------------------------------------------
66 static ThreadID gs_idMainThread
= kNoThreadID
;
67 static bool gs_waitingForThread
= FALSE
;
68 size_t g_numberOfThreads
= 0;
70 // ============================================================================
71 // MacOS implementation of thread classes
72 // ============================================================================
79 if ( UMASystemIsInitialized() )
81 OSErr err
= ThreadBeginCritical() ;
82 wxASSERT( err
== noErr
) ;
87 if ( UMASystemIsInitialized() )
89 OSErr err
= ThreadEndCritical() ;
90 wxASSERT( err
== noErr
) ;
95 // ----------------------------------------------------------------------------
96 // wxMutex implementation
97 // ----------------------------------------------------------------------------
102 wxMutexInternal(wxMutexType
WXUNUSED(mutexType
))
104 m_owner
= kNoThreadID
;
112 wxLogDebug(_T("Warning: freeing a locked mutex (%ld locks)."), m_locked
);
116 bool IsOk() const { return true; }
118 wxMutexError
Lock() ;
119 wxMutexError
TryLock() ;
120 wxMutexError
Unlock();
123 wxArrayLong m_waiters
;
127 wxMutexError
wxMutexInternal::Lock()
129 wxMacStCritical critical
;
130 if ( UMASystemIsInitialized() )
133 ThreadID current
= kNoThreadID
;
134 err
= ::MacGetCurrentThread(¤t
);
135 // if we are not the owner, add this thread to the list of waiting threads, stop this thread
136 // and invoke the scheduler to continue executing the owner's thread
137 while ( m_owner
!= kNoThreadID
&& m_owner
!= current
)
139 m_waiters
.Add(current
);
140 err
= ::SetThreadStateEndCritical(kCurrentThreadID
, kStoppedThreadState
, m_owner
);
141 err
= ::ThreadBeginCritical();
142 wxASSERT( err
== noErr
) ;
148 return wxMUTEX_NO_ERROR
;
151 wxMutexError
wxMutexInternal::TryLock()
153 wxMacStCritical critical
;
154 if ( UMASystemIsInitialized() )
156 ThreadID current
= kNoThreadID
;
157 ::MacGetCurrentThread(¤t
);
158 // if we are not the owner, give an error back
159 if ( m_owner
!= kNoThreadID
&& m_owner
!= current
)
166 return wxMUTEX_NO_ERROR
;
169 wxMutexError
wxMutexInternal::Unlock()
171 if ( UMASystemIsInitialized() )
174 err
= ::ThreadBeginCritical();
175 wxASSERT( err
== noErr
) ;
180 // this mutex is not owned by anybody anmore
181 m_owner
= kNoThreadID
;
183 // now pass on to the first waiting thread
184 ThreadID firstWaiting
= kNoThreadID
;
186 while (!m_waiters
.IsEmpty() && !found
)
188 firstWaiting
= m_waiters
[0];
189 err
= ::SetThreadState(firstWaiting
, kReadyThreadState
, kNoThreadID
);
190 // in case this was not successful (dead thread), we just loop on and reset the id
191 found
= (err
!= threadNotFoundErr
);
193 firstWaiting
= kNoThreadID
;
194 m_waiters
.RemoveAt(0) ;
196 // now we have a valid firstWaiting thread, which has been scheduled to run next, just end the
197 // critical section and invoke the scheduler
198 err
= ::SetThreadStateEndCritical(kCurrentThreadID
, kReadyThreadState
, firstWaiting
);
205 return wxMUTEX_NO_ERROR
;
208 // --------------------------------------------------------------------------
210 // --------------------------------------------------------------------------
212 // TODO not yet implemented
214 class wxSemaphoreInternal
217 wxSemaphoreInternal(int initialcount
, int maxcount
);
218 ~wxSemaphoreInternal();
220 bool IsOk() const { return true ; }
222 wxSemaError
Wait() { return WaitTimeout(INFINITE
); }
223 wxSemaError
TryWait() { return WaitTimeout(0); }
224 wxSemaError
WaitTimeout(unsigned long milliseconds
);
231 wxSemaphoreInternal::wxSemaphoreInternal(int initialcount
, int maxcount
)
235 // make it practically infinite
240 wxSemaphoreInternal::~wxSemaphoreInternal()
244 wxSemaError
wxSemaphoreInternal::WaitTimeout(unsigned long milliseconds
)
246 return wxSEMA_MISC_ERROR
;
249 wxSemaError
wxSemaphoreInternal::Post()
251 return wxSEMA_MISC_ERROR
;
254 // ----------------------------------------------------------------------------
255 // wxCondition implementation
256 // ----------------------------------------------------------------------------
258 // TODO this is not yet completed
260 class wxConditionInternal
263 wxConditionInternal(wxMutex
& mutex
) : m_mutex(mutex
)
265 m_excessSignals
= 0 ;
267 ~wxConditionInternal()
271 bool IsOk() const { return m_mutex
.IsOk() ; }
275 return WaitTimeout(0xFFFFFFFF );
278 wxCondError
WaitTimeout(unsigned long msectimeout
)
280 wxMacStCritical critical
;
281 if ( m_excessSignals
> 0 )
284 return wxCOND_NO_ERROR
;
286 else if ( msectimeout
== 0 )
288 return wxCOND_MISC_ERROR
;
296 // FIXME this should be MsgWaitForMultipleObjects() as well probably
297 DWORD rc = ::WaitForSingleObject(event, timeout);
301 return rc != WAIT_TIMEOUT;
303 return wxCOND_NO_ERROR
;
307 wxMacStCritical critical
;
308 return wxCOND_NO_ERROR
;
311 wxCondError
Broadcast()
313 wxMacStCritical critical
;
314 return wxCOND_NO_ERROR
;
317 wxArrayLong m_waiters
;
318 wxInt32 m_excessSignals
;
322 // ----------------------------------------------------------------------------
323 // wxCriticalSection implementation
324 // ----------------------------------------------------------------------------
326 // it's implemented as a mutex on mac os, so it is defined in the headers
328 // ----------------------------------------------------------------------------
329 // wxThread implementation
330 // ----------------------------------------------------------------------------
332 // wxThreadInternal class
333 // ----------------------
335 class wxThreadInternal
340 m_tid
= kNoThreadID
;
342 m_priority
= WXTHREAD_DEFAULT_PRIORITY
;
353 // create a new (suspended) thread (for the given thread object)
354 bool Create(wxThread
*thread
, unsigned int stackSize
);
356 // suspend/resume/terminate
359 void Cancel() { m_state
= STATE_CANCELED
; }
362 void SetState(wxThreadState state
) { m_state
= state
; }
363 wxThreadState
GetState() const { return m_state
; }
366 void SetPriority(unsigned int priority
);
367 unsigned int GetPriority() const { return m_priority
; }
369 void SetResult( void *res
) { m_result
= res
; }
370 void *GetResult() { return m_result
; }
372 // thread handle and id
373 ThreadID
GetId() const { return m_tid
; }
376 static pascal void* MacThreadStart(wxThread
* arg
);
379 wxThreadState m_state
; // state, see wxThreadState enum
380 unsigned int m_priority
; // thread priority in "wx" units
381 ThreadID m_tid
; // thread id
383 static ThreadEntryUPP s_threadEntry
;
386 static wxArrayPtrVoid s_threads
;
388 ThreadEntryUPP
wxThreadInternal::s_threadEntry
= NULL
;
389 pascal void* wxThreadInternal::MacThreadStart(wxThread
*thread
)
391 // first of all, check whether we hadn't been cancelled already
392 if ( thread
->m_internal
->GetState() == STATE_EXITED
)
397 void* rc
= thread
->Entry();
399 // enter m_critsect before changing the thread state
400 thread
->m_critsect
.Enter();
401 bool wasCancelled
= thread
->m_internal
->GetState() == STATE_CANCELED
;
402 thread
->m_internal
->SetState(STATE_EXITED
);
403 thread
->m_critsect
.Leave();
407 // if the thread was cancelled (from Delete()), then it the handle is still
409 if ( thread
->IsDetached() && !wasCancelled
)
414 //else: the joinable threads handle will be closed when Wait() is done
418 void wxThreadInternal::SetPriority(unsigned int priority
)
420 // Priorities don't exist on Mac
423 bool wxThreadInternal::Create(wxThread
*thread
, unsigned int stackSize
)
425 if ( s_threadEntry
== NULL
)
427 s_threadEntry
= NewThreadEntryUPP( (ThreadEntryProcPtr
) MacThreadStart
) ;
429 OSErr err
= NewThread( kCooperativeThread
,
439 wxLogSysError(_("Can't create thread"));
443 if ( m_priority
!= WXTHREAD_DEFAULT_PRIORITY
)
445 SetPriority(m_priority
);
453 bool wxThreadInternal::Suspend()
457 err
= ::ThreadBeginCritical();
458 wxASSERT( err
== noErr
) ;
460 if ( m_state
!= STATE_RUNNING
)
462 err
= ::ThreadEndCritical() ;
463 wxASSERT( err
== noErr
) ;
464 wxLogSysError(_("Can not suspend thread %x"), m_tid
);
468 m_state
= STATE_PAUSED
;
470 err
= ::SetThreadStateEndCritical(m_tid
, kStoppedThreadState
, kNoThreadID
);
475 bool wxThreadInternal::Resume()
479 err
= MacGetCurrentThread( ¤t
) ;
481 wxASSERT( err
== noErr
) ;
482 wxASSERT( current
!= m_tid
) ;
484 err
= ::ThreadBeginCritical();
485 wxASSERT( err
== noErr
) ;
487 if ( m_state
!= STATE_PAUSED
&& m_state
!= STATE_NEW
)
489 err
= ::ThreadEndCritical() ;
490 wxASSERT( err
== noErr
) ;
491 wxLogSysError(_("Can not resume thread %x"), m_tid
);
495 err
= ::SetThreadStateEndCritical(m_tid
, kReadyThreadState
, kNoThreadID
);
497 m_state
= STATE_RUNNING
;
498 err
= ::ThreadEndCritical() ;
499 wxASSERT( err
== noErr
) ;
500 ::YieldToAnyThread() ;
506 wxThread
*wxThread::This()
508 wxMacStCritical critical
;
513 err
= MacGetCurrentThread( ¤t
) ;
515 for ( size_t i
= 0 ; i
< s_threads
.Count() ; ++i
)
517 if ( ( (wxThread
*) s_threads
[i
] )->GetId() == current
)
518 return (wxThread
*) s_threads
[i
] ;
521 wxLogSysError(_("Couldn't get the current thread pointer"));
525 bool wxThread::IsMain()
530 err
= MacGetCurrentThread( ¤t
) ;
531 return current
== gs_idMainThread
;
538 void wxThread::Yield()
540 ::YieldToAnyThread() ;
543 void wxThread::Sleep(unsigned long milliseconds
)
545 UnsignedWide start
, now
;
547 Microseconds(&start
);
549 double mssleep
= milliseconds
* 1000 ;
550 double msstart
, msnow
;
551 msstart
= (start
.hi
* 4294967296.0 + start
.lo
) ;
557 msnow
= (now
.hi
* 4294967296.0 + now
.lo
) ;
558 } while( msnow
- msstart
< mssleep
);
561 int wxThread::GetCPUCount()
563 // we will use whatever MP API will be used for the new MP Macs
567 unsigned long wxThread::GetCurrentId()
570 MacGetCurrentThread( ¤t
) ;
571 return (unsigned long)current
;
574 bool wxThread::SetConcurrency(size_t level
)
576 wxASSERT_MSG( IsMain(), _T("should only be called from the main thread") );
578 // ok only for the default one
582 // how many CPUs have we got?
583 if ( GetCPUCount() == 1 )
585 // don't bother with all this complicated stuff - on a single
586 // processor system it doesn't make much sense anyhow
596 wxThread::wxThread(wxThreadKind kind
)
599 m_internal
= new wxThreadInternal();
601 m_isDetached
= kind
== wxTHREAD_DETACHED
;
602 s_threads
.Add( (void*) this ) ;
605 wxThread::~wxThread()
607 if (g_numberOfThreads
>0)
614 wxFAIL_MSG(wxT("More threads deleted than created."));
618 s_threads
.Remove( (void*) this ) ;
619 if (m_internal
!= NULL
) {
625 // create/start thread
626 // -------------------
628 wxThreadError
wxThread::Create(unsigned int stackSize
)
630 wxCriticalSectionLocker
lock(m_critsect
);
632 if ( !m_internal
->Create(this, stackSize
) )
633 return wxTHREAD_NO_RESOURCE
;
635 return wxTHREAD_NO_ERROR
;
638 wxThreadError
wxThread::Run()
640 wxCriticalSectionLocker
lock(m_critsect
);
642 if ( m_internal
->GetState() != STATE_NEW
)
644 // actually, it may be almost any state at all, not only STATE_RUNNING
645 return wxTHREAD_RUNNING
;
648 // the thread has just been created and is still suspended - let it run
652 // suspend/resume thread
653 // ---------------------
655 wxThreadError
wxThread::Pause()
657 wxCriticalSectionLocker
lock(m_critsect
);
659 return m_internal
->Suspend() ? wxTHREAD_NO_ERROR
: wxTHREAD_MISC_ERROR
;
662 wxThreadError
wxThread::Resume()
664 wxCriticalSectionLocker
lock(m_critsect
);
666 return m_internal
->Resume() ? wxTHREAD_NO_ERROR
: wxTHREAD_MISC_ERROR
;
672 wxThread::ExitCode
wxThread::Wait()
674 // although under MacOS we can wait for any thread, it's an error to
675 // wait for a detached one in wxWin API
676 wxCHECK_MSG( !IsDetached(), (ExitCode
)-1,
677 _T("can't wait for detached thread") );
679 ExitCode rc
= (ExitCode
)-1;
688 wxThreadError
wxThread::Delete(ExitCode
*pRc
)
692 // Delete() is always safe to call, so consider all possible states
694 // has the thread started to run?
695 bool shouldResume
= FALSE
;
698 wxCriticalSectionLocker
lock(m_critsect
);
700 if ( m_internal
->GetState() == STATE_NEW
)
702 // WinThreadStart() will see it and terminate immediately
703 m_internal
->SetState(STATE_EXITED
);
709 // is the thread paused?
710 if ( shouldResume
|| IsPaused() )
713 // does is still run?
718 // set flag for wxIsWaitingForThread()
719 gs_waitingForThread
= TRUE
;
726 // ask the thread to terminate
728 wxCriticalSectionLocker
lock(m_critsect
);
730 m_internal
->Cancel();
734 // simply wait for the thread to terminate
735 while( TestDestroy() )
737 ::YieldToAnyThread() ;
740 // simply wait for the thread to terminate
741 while( TestDestroy() )
743 ::YieldToAnyThread() ;
745 #endif // wxUSE_GUI/!wxUSE_GUI
749 gs_waitingForThread
= FALSE
;
759 // if the thread exits normally, this is done in WinThreadStart, but in
760 // this case it would have been too early because
761 // MsgWaitForMultipleObject() would fail if the therad handle was
762 // closed while we were waiting on it, so we must do it here
769 return rc
== (ExitCode
)-1 ? wxTHREAD_MISC_ERROR
: wxTHREAD_NO_ERROR
;
772 wxThreadError
wxThread::Kill()
775 return wxTHREAD_NOT_RUNNING
;
777 // if ( !::TerminateThread(m_internal->GetHandle(), (DWORD)-1) )
779 wxLogSysError(_("Couldn't terminate thread"));
781 return wxTHREAD_MISC_ERROR
;
791 return wxTHREAD_NO_ERROR
;
794 void wxThread::Exit(ExitCode status
)
803 m_internal
->SetResult( status
) ;
806 #if defined(__VISUALC__) || (defined(__BORLANDC__) && (__BORLANDC__ >= 0x500))
807 _endthreadex((unsigned)status);
809 ::ExitThread((DWORD)status);
812 wxFAIL_MSG(wxT("Couldn't return from ExitThread()!"));
818 // since all these calls are execute cooperatively we don't have to use the critical section
820 void wxThread::SetPriority(unsigned int prio
)
822 m_internal
->SetPriority(prio
);
825 unsigned int wxThread::GetPriority() const
827 return m_internal
->GetPriority();
830 unsigned long wxThread::GetId() const
832 return (unsigned long)m_internal
->GetId();
835 bool wxThread::IsRunning() const
837 return m_internal
->GetState() == STATE_RUNNING
;
840 bool wxThread::IsAlive() const
842 return (m_internal
->GetState() == STATE_RUNNING
) ||
843 (m_internal
->GetState() == STATE_PAUSED
);
846 bool wxThread::IsPaused() const
848 return m_internal
->GetState() == STATE_PAUSED
;
851 bool wxThread::TestDestroy()
853 return m_internal
->GetState() == STATE_CANCELED
;
856 // ----------------------------------------------------------------------------
857 // Automatic initialization for thread module
858 // ----------------------------------------------------------------------------
860 class wxThreadModule
: public wxModule
863 virtual bool OnInit();
864 virtual void OnExit();
867 DECLARE_DYNAMIC_CLASS(wxThreadModule
)
870 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule
, wxModule
)
872 bool wxThreadModule::OnInit()
875 bool hasThreadManager
;
876 hasThreadManager
= Gestalt( gestaltThreadMgrAttr
, &response
) == noErr
&& response
& 1;
879 // verify presence of shared library
880 hasThreadManager
= hasThreadManager
&& ((Ptr
)NewThread
!= (Ptr
)kUnresolvedCFragSymbolAddress
);
883 if ( !hasThreadManager
)
885 wxLogSysError( wxT("Thread Support is not available on this System") );
889 // no error return for GetCurrentThreadId()
890 MacGetCurrentThread( &gs_idMainThread
) ;
895 void wxThreadModule::OnExit()
899 // ----------------------------------------------------------------------------
900 // under MacOS we don't have currently preemptive threads, so any thread may access
901 // the GUI at any time
902 // ----------------------------------------------------------------------------
904 void WXDLLEXPORT
wxMutexGuiEnter()
908 void WXDLLEXPORT
wxMutexGuiLeave()
912 void WXDLLEXPORT
wxMutexGuiLeaveOrEnter()
916 bool WXDLLEXPORT
wxGuiOwnedByMainThread()
921 // wake up the main thread
922 void WXDLLEXPORT
wxWakeUpMainThread()
927 bool WXDLLEXPORT
wxIsWaitingForThread()
932 #include "wx/thrimpl.cpp"
934 #endif // wxUSE_THREADS