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"
43 #define INFINITE 0xFFFFFFFF
46 // ----------------------------------------------------------------------------
48 // ----------------------------------------------------------------------------
50 // the possible states of the thread ("=>" shows all possible transitions from
54 STATE_NEW
, // didn't start execution yet (=> RUNNING)
55 STATE_RUNNING
, // thread is running (=> PAUSED, CANCELED)
56 STATE_PAUSED
, // thread is temporarily suspended (=> RUNNING)
57 STATE_CANCELED
, // thread should terminate a.s.a.p. (=> EXITED)
58 STATE_EXITED
// thread is terminating
61 // ----------------------------------------------------------------------------
62 // this module globals
63 // ----------------------------------------------------------------------------
65 static ThreadID gs_idMainThread
= kNoThreadID
;
66 static bool gs_waitingForThread
= FALSE
;
67 size_t g_numberOfThreads
= 0;
69 // ============================================================================
70 // MacOS implementation of thread classes
71 // ============================================================================
78 if ( UMASystemIsInitialized() )
79 ThreadBeginCritical() ;
83 if ( UMASystemIsInitialized() )
88 // ----------------------------------------------------------------------------
89 // wxMutex implementation
90 // ----------------------------------------------------------------------------
95 wxMutexInternal(wxMutexType
WXUNUSED(mutexType
))
97 m_owner
= kNoThreadID
;
105 wxLogDebug(_T("Warning: freeing a locked mutex (%ld locks)."), m_locked
);
109 bool IsOk() const { return true; }
111 wxMutexError
Lock() ;
112 wxMutexError
TryLock() ;
113 wxMutexError
Unlock();
116 wxArrayLong m_waiters
;
120 wxMutexError
wxMutexInternal::Lock()
122 wxMacStCritical critical
;
123 if ( UMASystemIsInitialized() )
126 ThreadID current
= kNoThreadID
;
127 err
= ::MacGetCurrentThread(¤t
);
128 // if we are not the owner, add this thread to the list of waiting threads, stop this thread
129 // and invoke the scheduler to continue executing the owner's thread
130 while ( m_owner
!= kNoThreadID
&& m_owner
!= current
)
132 m_waiters
.Add(current
);
133 err
= ::SetThreadStateEndCritical(kCurrentThreadID
, kStoppedThreadState
, m_owner
);
134 err
= ::ThreadBeginCritical();
140 return wxMUTEX_NO_ERROR
;
143 wxMutexError
wxMutexInternal::TryLock()
145 wxMacStCritical critical
;
146 if ( UMASystemIsInitialized() )
148 ThreadID current
= kNoThreadID
;
149 ::MacGetCurrentThread(¤t
);
150 // if we are not the owner, give an error back
151 if ( m_owner
!= kNoThreadID
&& m_owner
!= current
)
158 return wxMUTEX_NO_ERROR
;
161 wxMutexError
wxMutexInternal::Unlock()
163 if ( UMASystemIsInitialized() )
166 err
= ::ThreadBeginCritical();
171 // this mutex is not owned by anybody anmore
172 m_owner
= kNoThreadID
;
174 // now pass on to the first waiting thread
175 ThreadID firstWaiting
= kNoThreadID
;
177 while (!m_waiters
.IsEmpty() && !found
)
179 firstWaiting
= m_waiters
[0];
180 err
= ::SetThreadState(firstWaiting
, kReadyThreadState
, kNoThreadID
);
181 // in case this was not successful (dead thread), we just loop on and reset the id
182 found
= (err
!= threadNotFoundErr
);
184 firstWaiting
= kNoThreadID
;
185 m_waiters
.RemoveAt(0) ;
187 // now we have a valid firstWaiting thread, which has been scheduled to run next, just end the
188 // critical section and invoke the scheduler
189 err
= ::SetThreadStateEndCritical(kCurrentThreadID
, kReadyThreadState
, firstWaiting
);
196 return wxMUTEX_NO_ERROR
;
199 // --------------------------------------------------------------------------
201 // --------------------------------------------------------------------------
203 // TODO not yet implemented
205 class wxSemaphoreInternal
208 wxSemaphoreInternal(int initialcount
, int maxcount
);
209 ~wxSemaphoreInternal();
211 bool IsOk() const { return true ; }
213 wxSemaError
Wait() { return WaitTimeout(INFINITE
); }
214 wxSemaError
TryWait() { return WaitTimeout(0); }
215 wxSemaError
WaitTimeout(unsigned long milliseconds
);
222 wxSemaphoreInternal::wxSemaphoreInternal(int initialcount
, int maxcount
)
226 // make it practically infinite
231 wxSemaphoreInternal::~wxSemaphoreInternal()
235 wxSemaError
wxSemaphoreInternal::WaitTimeout(unsigned long milliseconds
)
237 return wxSEMA_MISC_ERROR
;
240 wxSemaError
wxSemaphoreInternal::Post()
242 return wxSEMA_MISC_ERROR
;
245 // ----------------------------------------------------------------------------
246 // wxCondition implementation
247 // ----------------------------------------------------------------------------
249 // TODO this is not yet completed
251 class wxConditionInternal
254 wxConditionInternal(wxMutex
& mutex
) : m_mutex(mutex
)
256 m_excessSignals
= 0 ;
258 ~wxConditionInternal()
262 bool IsOk() const { return m_mutex
.IsOk() ; }
266 return WaitTimeout(0xFFFFFFFF );
269 wxCondError
WaitTimeout(unsigned long msectimeout
)
271 wxMacStCritical critical
;
272 if ( m_excessSignals
> 0 )
275 return wxCOND_NO_ERROR
;
277 else if ( msectimeout
== 0 )
279 return wxCOND_MISC_ERROR
;
287 // FIXME this should be MsgWaitForMultipleObjects() as well probably
288 DWORD rc = ::WaitForSingleObject(event, timeout);
292 return rc != WAIT_TIMEOUT;
294 return wxCOND_NO_ERROR
;
298 wxMacStCritical critical
;
299 return wxCOND_NO_ERROR
;
302 wxCondError
Broadcast()
304 wxMacStCritical critical
;
305 return wxCOND_NO_ERROR
;
308 wxArrayLong m_waiters
;
309 wxInt32 m_excessSignals
;
313 // ----------------------------------------------------------------------------
314 // wxCriticalSection implementation
315 // ----------------------------------------------------------------------------
317 // it's implemented as a mutex on mac os, so it is defined in the headers
319 // ----------------------------------------------------------------------------
320 // wxThread implementation
321 // ----------------------------------------------------------------------------
323 // wxThreadInternal class
324 // ----------------------
326 class wxThreadInternal
331 m_tid
= kNoThreadID
;
333 m_priority
= WXTHREAD_DEFAULT_PRIORITY
;
344 // create a new (suspended) thread (for the given thread object)
345 bool Create(wxThread
*thread
, unsigned int stackSize
);
347 // suspend/resume/terminate
350 void Cancel() { m_state
= STATE_CANCELED
; }
353 void SetState(wxThreadState state
) { m_state
= state
; }
354 wxThreadState
GetState() const { return m_state
; }
357 void SetPriority(unsigned int priority
);
358 unsigned int GetPriority() const { return m_priority
; }
360 void SetResult( void *res
) { m_result
= res
; }
361 void *GetResult() { return m_result
; }
363 // thread handle and id
364 ThreadID
GetId() const { return m_tid
; }
367 static pascal void* MacThreadStart(wxThread
* arg
);
370 wxThreadState m_state
; // state, see wxThreadState enum
371 unsigned int m_priority
; // thread priority in "wx" units
372 ThreadID m_tid
; // thread id
374 static ThreadEntryUPP s_threadEntry
;
377 static wxArrayPtrVoid s_threads
;
379 ThreadEntryUPP
wxThreadInternal::s_threadEntry
= NULL
;
380 pascal void* wxThreadInternal::MacThreadStart(wxThread
*thread
)
382 // first of all, check whether we hadn't been cancelled already
383 if ( thread
->m_internal
->GetState() == STATE_EXITED
)
388 void* rc
= thread
->Entry();
390 // enter m_critsect before changing the thread state
391 thread
->m_critsect
.Enter();
392 bool wasCancelled
= thread
->m_internal
->GetState() == STATE_CANCELED
;
393 thread
->m_internal
->SetState(STATE_EXITED
);
394 thread
->m_critsect
.Leave();
398 // if the thread was cancelled (from Delete()), then it the handle is still
400 if ( thread
->IsDetached() && !wasCancelled
)
405 //else: the joinable threads handle will be closed when Wait() is done
409 void wxThreadInternal::SetPriority(unsigned int priority
)
411 // Priorities don't exist on Mac
414 bool wxThreadInternal::Create(wxThread
*thread
, unsigned int stackSize
)
416 if ( s_threadEntry
== NULL
)
418 s_threadEntry
= NewThreadEntryUPP( (ThreadEntryProcPtr
) MacThreadStart
) ;
420 OSErr err
= NewThread( kCooperativeThread
,
430 wxLogSysError(_("Can't create thread"));
434 if ( m_priority
!= WXTHREAD_DEFAULT_PRIORITY
)
436 SetPriority(m_priority
);
444 bool wxThreadInternal::Suspend()
448 ::ThreadBeginCritical();
450 if ( m_state
!= STATE_RUNNING
)
452 ::ThreadEndCritical() ;
453 wxLogSysError(_("Can not suspend thread %x"), m_tid
);
457 m_state
= STATE_PAUSED
;
459 err
= ::SetThreadStateEndCritical(m_tid
, kStoppedThreadState
, kNoThreadID
);
464 bool wxThreadInternal::Resume()
468 err
= MacGetCurrentThread( ¤t
) ;
470 wxASSERT( err
== noErr
) ;
471 wxASSERT( current
!= m_tid
) ;
473 ::ThreadBeginCritical();
474 if ( m_state
!= STATE_PAUSED
&& m_state
!= STATE_NEW
)
476 ::ThreadEndCritical() ;
477 wxLogSysError(_("Can not resume thread %x"), m_tid
);
481 err
= ::SetThreadStateEndCritical(m_tid
, kReadyThreadState
, kNoThreadID
);
482 wxASSERT( err
== noErr
) ;
484 m_state
= STATE_RUNNING
;
485 ::ThreadEndCritical() ;
486 ::YieldToAnyThread() ;
492 wxThread
*wxThread::This()
494 wxMacStCritical critical
;
499 err
= MacGetCurrentThread( ¤t
) ;
501 for ( size_t i
= 0 ; i
< s_threads
.Count() ; ++i
)
503 if ( ( (wxThread
*) s_threads
[i
] )->GetId() == current
)
504 return (wxThread
*) s_threads
[i
] ;
507 wxLogSysError(_("Couldn't get the current thread pointer"));
511 bool wxThread::IsMain()
516 err
= MacGetCurrentThread( ¤t
) ;
517 return current
== gs_idMainThread
;
524 void wxThread::Yield()
526 ::YieldToAnyThread() ;
529 void wxThread::Sleep(unsigned long milliseconds
)
531 clock_t start
= clock();
535 } while( clock() - start
< milliseconds
* CLOCKS_PER_SEC
/ 1000.0 ) ;
538 int wxThread::GetCPUCount()
540 // we will use whatever MP API will be used for the new MP Macs
544 unsigned long wxThread::GetCurrentId()
547 MacGetCurrentThread( ¤t
) ;
548 return (unsigned long)current
;
551 bool wxThread::SetConcurrency(size_t level
)
553 wxASSERT_MSG( IsMain(), _T("should only be called from the main thread") );
555 // ok only for the default one
559 // how many CPUs have we got?
560 if ( GetCPUCount() == 1 )
562 // don't bother with all this complicated stuff - on a single
563 // processor system it doesn't make much sense anyhow
573 wxThread::wxThread(wxThreadKind kind
)
576 m_internal
= new wxThreadInternal();
578 m_isDetached
= kind
== wxTHREAD_DETACHED
;
579 s_threads
.Add( (void*) this ) ;
582 wxThread::~wxThread()
584 if (g_numberOfThreads
>0)
591 wxFAIL_MSG(wxT("More threads deleted than created."));
595 s_threads
.Remove( (void*) this ) ;
596 if (m_internal
!= NULL
) {
602 // create/start thread
603 // -------------------
605 wxThreadError
wxThread::Create(unsigned int stackSize
)
607 wxCriticalSectionLocker
lock(m_critsect
);
609 if ( !m_internal
->Create(this, stackSize
) )
610 return wxTHREAD_NO_RESOURCE
;
612 return wxTHREAD_NO_ERROR
;
615 wxThreadError
wxThread::Run()
617 wxCriticalSectionLocker
lock(m_critsect
);
619 if ( m_internal
->GetState() != STATE_NEW
)
621 // actually, it may be almost any state at all, not only STATE_RUNNING
622 return wxTHREAD_RUNNING
;
625 // the thread has just been created and is still suspended - let it run
629 // suspend/resume thread
630 // ---------------------
632 wxThreadError
wxThread::Pause()
634 wxCriticalSectionLocker
lock(m_critsect
);
636 return m_internal
->Suspend() ? wxTHREAD_NO_ERROR
: wxTHREAD_MISC_ERROR
;
639 wxThreadError
wxThread::Resume()
641 wxCriticalSectionLocker
lock(m_critsect
);
643 return m_internal
->Resume() ? wxTHREAD_NO_ERROR
: wxTHREAD_MISC_ERROR
;
649 wxThread::ExitCode
wxThread::Wait()
651 // although under MacOS we can wait for any thread, it's an error to
652 // wait for a detached one in wxWin API
653 wxCHECK_MSG( !IsDetached(), (ExitCode
)-1,
654 _T("can't wait for detached thread") );
656 ExitCode rc
= (ExitCode
)-1;
665 wxThreadError
wxThread::Delete(ExitCode
*pRc
)
669 // Delete() is always safe to call, so consider all possible states
671 // has the thread started to run?
672 bool shouldResume
= FALSE
;
675 wxCriticalSectionLocker
lock(m_critsect
);
677 if ( m_internal
->GetState() == STATE_NEW
)
679 // WinThreadStart() will see it and terminate immediately
680 m_internal
->SetState(STATE_EXITED
);
686 // is the thread paused?
687 if ( shouldResume
|| IsPaused() )
690 // does is still run?
695 // set flag for wxIsWaitingForThread()
696 gs_waitingForThread
= TRUE
;
703 // ask the thread to terminate
705 wxCriticalSectionLocker
lock(m_critsect
);
707 m_internal
->Cancel();
711 // simply wait for the thread to terminate
712 while( TestDestroy() )
714 ::YieldToAnyThread() ;
717 // simply wait for the thread to terminate
718 while( TestDestroy() )
720 ::YieldToAnyThread() ;
722 #endif // wxUSE_GUI/!wxUSE_GUI
726 gs_waitingForThread
= FALSE
;
736 // if the thread exits normally, this is done in WinThreadStart, but in
737 // this case it would have been too early because
738 // MsgWaitForMultipleObject() would fail if the therad handle was
739 // closed while we were waiting on it, so we must do it here
746 return rc
== (ExitCode
)-1 ? wxTHREAD_MISC_ERROR
: wxTHREAD_NO_ERROR
;
749 wxThreadError
wxThread::Kill()
752 return wxTHREAD_NOT_RUNNING
;
754 // if ( !::TerminateThread(m_internal->GetHandle(), (DWORD)-1) )
756 wxLogSysError(_("Couldn't terminate thread"));
758 return wxTHREAD_MISC_ERROR
;
768 return wxTHREAD_NO_ERROR
;
771 void wxThread::Exit(ExitCode status
)
780 m_internal
->SetResult( status
) ;
783 #if defined(__VISUALC__) || (defined(__BORLANDC__) && (__BORLANDC__ >= 0x500))
784 _endthreadex((unsigned)status);
786 ::ExitThread((DWORD)status);
789 wxFAIL_MSG(wxT("Couldn't return from ExitThread()!"));
795 // since all these calls are execute cooperatively we don't have to use the critical section
797 void wxThread::SetPriority(unsigned int prio
)
799 m_internal
->SetPriority(prio
);
802 unsigned int wxThread::GetPriority() const
804 return m_internal
->GetPriority();
807 unsigned long wxThread::GetId() const
809 return (unsigned long)m_internal
->GetId();
812 bool wxThread::IsRunning() const
814 return m_internal
->GetState() == STATE_RUNNING
;
817 bool wxThread::IsAlive() const
819 return (m_internal
->GetState() == STATE_RUNNING
) ||
820 (m_internal
->GetState() == STATE_PAUSED
);
823 bool wxThread::IsPaused() const
825 return m_internal
->GetState() == STATE_PAUSED
;
828 bool wxThread::TestDestroy()
830 return m_internal
->GetState() == STATE_CANCELED
;
833 // ----------------------------------------------------------------------------
834 // Automatic initialization for thread module
835 // ----------------------------------------------------------------------------
837 class wxThreadModule
: public wxModule
840 virtual bool OnInit();
841 virtual void OnExit();
844 DECLARE_DYNAMIC_CLASS(wxThreadModule
)
847 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule
, wxModule
)
849 bool wxThreadModule::OnInit()
852 bool hasThreadManager
;
853 hasThreadManager
= Gestalt( gestaltThreadMgrAttr
, &response
) == noErr
&& response
& 1;
856 // verify presence of shared library
857 hasThreadManager
= hasThreadManager
&& ((Ptr
)NewThread
!= (Ptr
)kUnresolvedCFragSymbolAddress
);
860 if ( !hasThreadManager
)
862 wxLogSysError( wxT("Thread Support is not available on this System") );
866 // no error return for GetCurrentThreadId()
867 MacGetCurrentThread( &gs_idMainThread
) ;
872 void wxThreadModule::OnExit()
876 // ----------------------------------------------------------------------------
877 // under MacOS we don't have currently preemptive threads, so any thread may access
878 // the GUI at any time
879 // ----------------------------------------------------------------------------
881 void WXDLLEXPORT
wxMutexGuiEnter()
885 void WXDLLEXPORT
wxMutexGuiLeave()
889 void WXDLLEXPORT
wxMutexGuiLeaveOrEnter()
893 bool WXDLLEXPORT
wxGuiOwnedByMainThread()
898 // wake up the main thread
899 void WXDLLEXPORT
wxWakeUpMainThread()
904 bool WXDLLEXPORT
wxIsWaitingForThread()
909 #include "wx/thrimpl.cpp"
911 #endif // wxUSE_THREADS