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"
37 // ----------------------------------------------------------------------------
39 // ----------------------------------------------------------------------------
41 // the possible states of the thread ("=>" shows all possible transitions from
45 STATE_NEW
, // didn't start execution yet (=> RUNNING)
46 STATE_RUNNING
, // thread is running (=> PAUSED, CANCELED)
47 STATE_PAUSED
, // thread is temporarily suspended (=> RUNNING)
48 STATE_CANCELED
, // thread should terminate a.s.a.p. (=> EXITED)
49 STATE_EXITED
// thread is terminating
52 // ----------------------------------------------------------------------------
53 // this module globals
54 // ----------------------------------------------------------------------------
56 static ThreadID gs_idMainThread
= kNoThreadID
;
57 static bool gs_waitingForThread
= FALSE
;
59 // ============================================================================
60 // MacOS implementation of thread classes
61 // ============================================================================
68 ThreadBeginCritical() ;
76 // ----------------------------------------------------------------------------
77 // wxMutex implementation
78 // ----------------------------------------------------------------------------
85 m_owner
= kNoThreadID
;
94 wxArrayLong m_waiters
;
99 m_internal
= new wxMutexInternal
;
108 wxLogDebug(_T("Warning: freeing a locked mutex (%d locks)."), m_locked
);
114 wxMutexError
wxMutex::Lock()
116 wxMacStCritical critical
;
119 ThreadID current
= kNoThreadID
;
120 err
= ::MacGetCurrentThread(¤t
);
121 // if we are not the owner, add this thread to the list of waiting threads, stop this thread
122 // and invoke the scheduler to continue executing the owner's thread
123 while ( m_internal
->m_owner
!= kNoThreadID
&& m_internal
->m_owner
!= current
)
125 m_internal
->m_waiters
.Add(current
);
126 err
= ::SetThreadStateEndCritical(kCurrentThreadID
, kStoppedThreadState
, m_internal
->m_owner
);
127 err
= ::ThreadBeginCritical();
129 m_internal
->m_owner
= current
;
132 return wxMUTEX_NO_ERROR
;
135 wxMutexError
wxMutex::TryLock()
137 wxMacStCritical critical
;
140 ThreadID current
= kNoThreadID
;
141 ::MacGetCurrentThread(¤t
);
142 // if we are not the owner, give an error back
143 if ( m_internal
->m_owner
!= kNoThreadID
&& m_internal
->m_owner
!= current
)
146 m_internal
->m_owner
= current
;
149 return wxMUTEX_NO_ERROR
;
152 wxMutexError
wxMutex::Unlock()
155 err
= ::ThreadBeginCritical();
160 // this mutex is not owned by anybody anmore
161 m_internal
->m_owner
= kNoThreadID
;
163 // now pass on to the first waiting thread
164 ThreadID firstWaiting
= kNoThreadID
;
166 while (!m_internal
->m_waiters
.IsEmpty() && !found
)
168 firstWaiting
= m_internal
->m_waiters
[0];
169 err
= ::SetThreadState(firstWaiting
, kReadyThreadState
, kNoThreadID
);
170 // in case this was not successful (dead thread), we just loop on and reset the id
171 found
= (err
!= threadNotFoundErr
);
173 firstWaiting
= kNoThreadID
;
174 m_internal
->m_waiters
.RemoveAt(0) ;
176 // now we have a valid firstWaiting thread, which has been scheduled to run next, just end the
177 // critical section and invoke the scheduler
178 err
= ::SetThreadStateEndCritical(kCurrentThreadID
, kReadyThreadState
, firstWaiting
);
180 return wxMUTEX_NO_ERROR
;
183 // ----------------------------------------------------------------------------
184 // wxCondition implementation
185 // ----------------------------------------------------------------------------
187 class wxConditionInternal
190 wxConditionInternal()
192 m_excessSignals
= 0 ;
194 ~wxConditionInternal()
198 bool Wait(unsigned long msectimeout
)
200 wxMacStCritical critical
;
201 if ( m_excessSignals
> 0 )
206 else if ( msectimeout
== 0 )
216 // FIXME this should be MsgWaitForMultipleObjects() as well probably
217 DWORD rc = ::WaitForSingleObject(event, timeout);
221 return rc != WAIT_TIMEOUT;
227 wxMacStCritical critical
;
230 wxArrayLong m_waiters
;
231 wxInt32 m_excessSignals
;
234 wxCondition::wxCondition()
236 m_internal
= new wxConditionInternal
;
239 wxCondition::~wxCondition()
244 void wxCondition::Wait()
246 (void)m_internal
->Wait(0xFFFFFFFFL
);
249 bool wxCondition::Wait(unsigned long sec
,
252 return m_internal
->Wait(sec
*1000 + nsec
/1000000);
255 void wxCondition::Signal()
257 // set the event to signaled: if a thread is already waiting on it, it will
258 // be woken up, otherwise the event will remain in the signaled state until
259 // someone waits on it. In any case, the system will return it to a non
260 // signalled state afterwards. If multiple threads are waiting, only one
262 m_internal
->Signal() ;
265 void wxCondition::Broadcast()
267 // this works because all these threads are already waiting and so each
268 // SetEvent() inside Signal() is really a PulseEvent() because the event
269 // state is immediately returned to non-signaled
270 for ( int i
= 0; i
< m_internal
->m_waiters
.Count(); i
++ )
276 // ----------------------------------------------------------------------------
277 // wxCriticalSection implementation
278 // ----------------------------------------------------------------------------
280 // it's implemented as a mutex on mac os, so it is defined in the headers
282 // ----------------------------------------------------------------------------
283 // wxThread implementation
284 // ----------------------------------------------------------------------------
286 // wxThreadInternal class
287 // ----------------------
289 class wxThreadInternal
294 m_tid
= kNoThreadID
;
296 m_priority
= WXTHREAD_DEFAULT_PRIORITY
;
307 // create a new (suspended) thread (for the given thread object)
308 bool Create(wxThread
*thread
, unsigned int stackSize
);
310 // suspend/resume/terminate
313 void Cancel() { m_state
= STATE_CANCELED
; }
316 void SetState(wxThreadState state
) { m_state
= state
; }
317 wxThreadState
GetState() const { return m_state
; }
320 void SetPriority(unsigned int priority
);
321 unsigned int GetPriority() const { return m_priority
; }
323 void SetResult( void *res
) { m_result
= res
; }
324 void *GetResult() { return m_result
; }
326 // thread handle and id
327 ThreadID
GetId() const { return m_tid
; }
330 static pascal void* MacThreadStart(wxThread
* arg
);
333 wxThreadState m_state
; // state, see wxThreadState enum
334 unsigned int m_priority
; // thread priority in "wx" units
335 ThreadID m_tid
; // thread id
337 static ThreadEntryUPP s_threadEntry
;
340 static wxArrayPtrVoid s_threads
;
342 ThreadEntryUPP
wxThreadInternal::s_threadEntry
= NULL
;
343 pascal void* wxThreadInternal::MacThreadStart(wxThread
*thread
)
345 // first of all, check whether we hadn't been cancelled already
346 if ( thread
->m_internal
->GetState() == STATE_EXITED
)
351 void* rc
= thread
->Entry();
353 // enter m_critsect before changing the thread state
354 thread
->m_critsect
.Enter();
355 bool wasCancelled
= thread
->m_internal
->GetState() == STATE_CANCELED
;
356 thread
->m_internal
->SetState(STATE_EXITED
);
357 thread
->m_critsect
.Leave();
361 // if the thread was cancelled (from Delete()), then it the handle is still
363 if ( thread
->IsDetached() && !wasCancelled
)
368 //else: the joinable threads handle will be closed when Wait() is done
372 void wxThreadInternal::SetPriority(unsigned int priority
)
374 // Priorities don't exist on Mac
377 bool wxThreadInternal::Create(wxThread
*thread
, unsigned int stackSize
)
379 if ( s_threadEntry
== NULL
)
381 s_threadEntry
= NewThreadEntryUPP( (ThreadEntryProcPtr
) MacThreadStart
) ;
383 OSErr err
= NewThread( kCooperativeThread
,
393 wxLogSysError(_("Can't create thread"));
397 if ( m_priority
!= WXTHREAD_DEFAULT_PRIORITY
)
399 SetPriority(m_priority
);
405 bool wxThreadInternal::Suspend()
409 ::ThreadBeginCritical();
411 if ( m_state
!= STATE_RUNNING
)
413 ::ThreadEndCritical() ;
414 wxLogSysError(_("Can not suspend thread %x"), m_tid
);
418 m_state
= STATE_PAUSED
;
420 err
= ::SetThreadStateEndCritical(m_tid
, kStoppedThreadState
, kNoThreadID
);
425 bool wxThreadInternal::Resume()
429 err
= MacGetCurrentThread( ¤t
) ;
431 wxASSERT( err
== noErr
) ;
432 wxASSERT( current
!= m_tid
) ;
434 ::ThreadBeginCritical();
435 if ( m_state
!= STATE_PAUSED
&& m_state
!= STATE_NEW
)
437 ::ThreadEndCritical() ;
438 wxLogSysError(_("Can not resume thread %x"), m_tid
);
442 err
= ::SetThreadStateEndCritical(m_tid
, kReadyThreadState
, kNoThreadID
);
443 wxASSERT( err
== noErr
) ;
445 m_state
= STATE_RUNNING
;
446 ::ThreadEndCritical() ;
447 ::YieldToAnyThread() ;
453 wxThread
*wxThread::This()
455 wxMacStCritical critical
;
460 err
= MacGetCurrentThread( ¤t
) ;
462 for ( int i
= 0 ; i
< s_threads
.Count() ; ++i
)
464 if ( ( (wxThread
*) s_threads
[i
] )->GetId() == current
)
465 return (wxThread
*) s_threads
[i
] ;
468 wxLogSysError(_("Couldn't get the current thread pointer"));
472 bool wxThread::IsMain()
477 err
= MacGetCurrentThread( ¤t
) ;
478 return current
== gs_idMainThread
;
485 void wxThread::Yield()
487 ::YieldToAnyThread() ;
490 void wxThread::Sleep(unsigned long milliseconds
)
492 clock_t start
= clock() ;
496 } while( clock() - start
< milliseconds
/ CLOCKS_PER_SEC
) ;
499 int wxThread::GetCPUCount()
501 // we will use whatever MP API will be used for the new MP Macs
505 bool wxThread::SetConcurrency(size_t level
)
507 wxASSERT_MSG( IsMain(), _T("should only be called from the main thread") );
509 // ok only for the default one
513 // how many CPUs have we got?
514 if ( GetCPUCount() == 1 )
516 // don't bother with all this complicated stuff - on a single
517 // processor system it doesn't make much sense anyhow
527 wxThread::wxThread(wxThreadKind kind
)
529 m_internal
= new wxThreadInternal();
531 m_isDetached
= kind
== wxTHREAD_DETACHED
;
532 s_threads
.Add( (void*) this ) ;
535 wxThread::~wxThread()
537 s_threads
.Remove( (void*) this ) ;
541 // create/start thread
542 // -------------------
544 wxThreadError
wxThread::Create(unsigned int stackSize
)
546 wxCriticalSectionLocker
lock(m_critsect
);
548 if ( !m_internal
->Create(this, stackSize
) )
549 return wxTHREAD_NO_RESOURCE
;
551 return wxTHREAD_NO_ERROR
;
554 wxThreadError
wxThread::Run()
556 wxCriticalSectionLocker
lock(m_critsect
);
558 if ( m_internal
->GetState() != STATE_NEW
)
560 // actually, it may be almost any state at all, not only STATE_RUNNING
561 return wxTHREAD_RUNNING
;
564 // the thread has just been created and is still suspended - let it run
568 // suspend/resume thread
569 // ---------------------
571 wxThreadError
wxThread::Pause()
573 wxCriticalSectionLocker
lock(m_critsect
);
575 return m_internal
->Suspend() ? wxTHREAD_NO_ERROR
: wxTHREAD_MISC_ERROR
;
578 wxThreadError
wxThread::Resume()
580 wxCriticalSectionLocker
lock(m_critsect
);
582 return m_internal
->Resume() ? wxTHREAD_NO_ERROR
: wxTHREAD_MISC_ERROR
;
588 wxThread::ExitCode
wxThread::Wait()
590 // although under MacOS we can wait for any thread, it's an error to
591 // wait for a detached one in wxWin API
592 wxCHECK_MSG( !IsDetached(), (ExitCode
)-1,
593 _T("can't wait for detached thread") );
595 ExitCode rc
= (ExitCode
)-1;
604 wxThreadError
wxThread::Delete(ExitCode
*pRc
)
608 // Delete() is always safe to call, so consider all possible states
610 // has the thread started to run?
611 bool shouldResume
= FALSE
;
614 wxCriticalSectionLocker
lock(m_critsect
);
616 if ( m_internal
->GetState() == STATE_NEW
)
618 // WinThreadStart() will see it and terminate immediately
619 m_internal
->SetState(STATE_EXITED
);
625 // is the thread paused?
626 if ( shouldResume
|| IsPaused() )
629 // does is still run?
634 // set flag for wxIsWaitingForThread()
635 gs_waitingForThread
= TRUE
;
642 // ask the thread to terminate
644 wxCriticalSectionLocker
lock(m_critsect
);
646 m_internal
->Cancel();
650 // simply wait for the thread to terminate
651 while( TestDestroy() )
653 ::YieldToAnyThread() ;
656 // simply wait for the thread to terminate
657 while( TestDestroy() )
659 ::YieldToAnyThread() ;
661 #endif // wxUSE_GUI/!wxUSE_GUI
665 gs_waitingForThread
= FALSE
;
673 // if ( !::GetExitCodeThread(hThread, (LPDWORD)&rc) )
675 wxLogLastError("GetExitCodeThread");
682 // if the thread exits normally, this is done in WinThreadStart, but in
683 // this case it would have been too early because
684 // MsgWaitForMultipleObject() would fail if the therad handle was
685 // closed while we were waiting on it, so we must do it here
689 // wxASSERT_MSG( (DWORD)rc != STILL_ACTIVE,
690 // wxT("thread must be already terminated.") );
695 return rc
== (ExitCode
)-1 ? wxTHREAD_MISC_ERROR
: wxTHREAD_NO_ERROR
;
698 wxThreadError
wxThread::Kill()
701 return wxTHREAD_NOT_RUNNING
;
703 // if ( !::TerminateThread(m_internal->GetHandle(), (DWORD)-1) )
705 wxLogSysError(_("Couldn't terminate thread"));
707 return wxTHREAD_MISC_ERROR
;
717 return wxTHREAD_NO_ERROR
;
720 void wxThread::Exit(ExitCode status
)
729 m_internal
->SetResult( status
) ;
732 #if defined(__VISUALC__) || (defined(__BORLANDC__) && (__BORLANDC__ >= 0x500))
733 _endthreadex((unsigned)status);
735 ::ExitThread((DWORD)status);
738 wxFAIL_MSG(wxT("Couldn't return from ExitThread()!"));
744 // since all these calls are execute cooperatively we don't have to use the critical section
746 void wxThread::SetPriority(unsigned int prio
)
748 m_internal
->SetPriority(prio
);
751 unsigned int wxThread::GetPriority() const
753 return m_internal
->GetPriority();
756 unsigned long wxThread::GetId() const
758 return (unsigned long)m_internal
->GetId();
761 bool wxThread::IsRunning() const
763 return m_internal
->GetState() == STATE_RUNNING
;
766 bool wxThread::IsAlive() const
768 return (m_internal
->GetState() == STATE_RUNNING
) ||
769 (m_internal
->GetState() == STATE_PAUSED
);
772 bool wxThread::IsPaused() const
774 return m_internal
->GetState() == STATE_PAUSED
;
777 bool wxThread::TestDestroy()
779 return m_internal
->GetState() == STATE_CANCELED
;
782 // ----------------------------------------------------------------------------
783 // Automatic initialization for thread module
784 // ----------------------------------------------------------------------------
786 class wxThreadModule
: public wxModule
789 virtual bool OnInit();
790 virtual void OnExit();
793 DECLARE_DYNAMIC_CLASS(wxThreadModule
)
796 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule
, wxModule
)
798 bool wxThreadModule::OnInit()
801 bool hasThreadManager
;
802 hasThreadManager
= Gestalt( gestaltThreadMgrAttr
, &response
) == noErr
&& response
& 1;
805 // verify presence of shared library
806 hasThreadManager
= hasThreadManager
&& ((Ptr
)NewThread
!= (Ptr
)kUnresolvedCFragSymbolAddress
);
809 if ( !hasThreadManager
)
811 wxMessageBox( "Error" , "Thread Support is not available on this System" , wxOK
) ;
815 // no error return for GetCurrentThreadId()
816 MacGetCurrentThread( &gs_idMainThread
) ;
821 void wxThreadModule::OnExit()
825 // ----------------------------------------------------------------------------
826 // under MacOS we don't have currently preemptive threads, so any thread may access
827 // the GUI at any time
828 // ----------------------------------------------------------------------------
830 void WXDLLEXPORT
wxMutexGuiEnter()
834 void WXDLLEXPORT
wxMutexGuiLeave()
838 void WXDLLEXPORT
wxMutexGuiLeaveOrEnter()
842 bool WXDLLEXPORT
wxGuiOwnedByMainThread()
847 // wake up the main thread
848 void WXDLLEXPORT
wxWakeUpMainThread()
853 bool WXDLLEXPORT
wxIsWaitingForThread()
858 #endif // wxUSE_THREADS