1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxThread Implementation
4 // Author: Original from Wolfram Gloger/Guilhem Lavaux
5 // Modified by: Vadim Zeitlin to make it work :-)
8 // Copyright: (c) Wolfram Gloger (1996, 1997); Guilhem Lavaux (1998),
9 // Vadim Zeitlin (1999)
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/msw/private.h"
36 #include "wx/module.h"
37 #include "wx/thread.h"
39 // the possible states of the thread ("=>" shows all possible transitions from
43 STATE_NEW
, // didn't start execution yet (=> RUNNING)
44 STATE_RUNNING
, // thread is running (=> PAUSED, CANCELED)
45 STATE_PAUSED
, // thread is temporarily suspended (=> RUNNING)
46 STATE_CANCELED
, // thread should terminate a.s.a.p. (=> EXITED)
47 STATE_EXITED
// thread is terminating
50 // ----------------------------------------------------------------------------
52 // ----------------------------------------------------------------------------
54 // TLS index of the slot where we store the pointer to the current thread
55 static DWORD s_tlsThisThread
= 0xFFFFFFFF;
57 // id of the main thread - the one which can call GUI functions without first
58 // calling wxMutexGuiEnter()
59 static DWORD s_idMainThread
= 0;
61 // if it's FALSE, some secondary thread is holding the GUI lock
62 static bool s_bGuiOwnedByMainThread
= TRUE
;
64 // critical section which controls access to all GUI functions: any secondary
65 // thread (i.e. except the main one) must enter this crit section before doing
67 static wxCriticalSection
*s_critsectGui
= NULL
;
69 // critical section which protects s_nWaitingForGui variable
70 static wxCriticalSection
*s_critsectWaitingForGui
= NULL
;
72 // number of threads waiting for GUI in wxMutexGuiEnter()
73 static size_t s_nWaitingForGui
= 0;
75 // are we waiting for a thread termination?
76 static bool s_waitingForThread
= FALSE
;
78 // ============================================================================
79 // Windows implementation of thread classes
80 // ============================================================================
82 // ----------------------------------------------------------------------------
83 // wxMutex implementation
84 // ----------------------------------------------------------------------------
94 p_internal
= new wxMutexInternal
;
95 p_internal
->p_mutex
= CreateMutex(NULL
, FALSE
, NULL
);
96 if ( !p_internal
->p_mutex
)
98 wxLogSysError(_("Can not create mutex."));
107 wxLogDebug(wxT("Warning: freeing a locked mutex (%d locks)."), m_locked
);
108 CloseHandle(p_internal
->p_mutex
);
111 wxMutexError
wxMutex::Lock()
115 ret
= WaitForSingleObject(p_internal
->p_mutex
, INFINITE
);
126 wxLogSysError(_("Couldn't acquire a mutex lock"));
127 return wxMUTEX_MISC_ERROR
;
131 wxFAIL_MSG(wxT("impossible return value in wxMutex::Lock"));
135 return wxMUTEX_NO_ERROR
;
138 wxMutexError
wxMutex::TryLock()
142 ret
= WaitForSingleObject(p_internal
->p_mutex
, 0);
143 if (ret
== WAIT_TIMEOUT
|| ret
== WAIT_ABANDONED
)
147 return wxMUTEX_NO_ERROR
;
150 wxMutexError
wxMutex::Unlock()
155 BOOL ret
= ReleaseMutex(p_internal
->p_mutex
);
158 wxLogSysError(_("Couldn't release a mutex"));
159 return wxMUTEX_MISC_ERROR
;
162 return wxMUTEX_NO_ERROR
;
165 // ----------------------------------------------------------------------------
166 // wxCondition implementation
167 // ----------------------------------------------------------------------------
169 class wxConditionInternal
176 wxCondition::wxCondition()
178 p_internal
= new wxConditionInternal
;
179 p_internal
->event
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
180 if ( !p_internal
->event
)
182 wxLogSysError(_("Can not create event object."));
185 p_internal
->waiters
= 0;
188 wxCondition::~wxCondition()
190 CloseHandle(p_internal
->event
);
193 void wxCondition::Wait(wxMutex
& mutex
)
196 p_internal
->waiters
++;
197 WaitForSingleObject(p_internal
->event
, INFINITE
);
198 p_internal
->waiters
--;
202 bool wxCondition::Wait(wxMutex
& mutex
,
209 p_internal
->waiters
++;
210 ret
= WaitForSingleObject(p_internal
->event
, (sec
*1000)+(nsec
/1000000));
211 p_internal
->waiters
--;
214 return (ret
!= WAIT_TIMEOUT
);
217 void wxCondition::Signal()
219 SetEvent(p_internal
->event
);
222 void wxCondition::Broadcast()
226 for (i
=0;i
<p_internal
->waiters
;i
++)
228 if ( SetEvent(p_internal
->event
) == 0 )
230 wxLogSysError(_("Couldn't change the state of event object."));
235 // ----------------------------------------------------------------------------
236 // wxCriticalSection implementation
237 // ----------------------------------------------------------------------------
239 wxCriticalSection::wxCriticalSection()
241 wxASSERT_MSG( sizeof(CRITICAL_SECTION
) == sizeof(m_buffer
),
242 _T("must increase buffer size in wx/thread.h") );
244 ::InitializeCriticalSection((CRITICAL_SECTION
*)m_buffer
);
247 wxCriticalSection::~wxCriticalSection()
249 ::DeleteCriticalSection((CRITICAL_SECTION
*)m_buffer
);
252 void wxCriticalSection::Enter()
254 ::EnterCriticalSection((CRITICAL_SECTION
*)m_buffer
);
257 void wxCriticalSection::Leave()
259 ::LeaveCriticalSection((CRITICAL_SECTION
*)m_buffer
);
262 // ----------------------------------------------------------------------------
263 // wxThread implementation
264 // ----------------------------------------------------------------------------
266 // wxThreadInternal class
267 // ----------------------
269 class wxThreadInternal
276 m_priority
= WXTHREAD_DEFAULT_PRIORITY
;
279 // create a new (suspended) thread (for the given thread object)
280 bool Create(wxThread
*thread
);
282 // suspend/resume/terminate
285 void Cancel() { m_state
= STATE_CANCELED
; }
288 void SetState(wxThreadState state
) { m_state
= state
; }
289 wxThreadState
GetState() const { return m_state
; }
292 void SetPriority(unsigned int priority
) { m_priority
= priority
; }
293 unsigned int GetPriority() const { return m_priority
; }
295 // thread handle and id
296 HANDLE
GetHandle() const { return m_hThread
; }
297 DWORD
GetId() const { return m_tid
; }
300 static DWORD
WinThreadStart(wxThread
*thread
);
303 HANDLE m_hThread
; // handle of the thread
304 wxThreadState m_state
; // state, see wxThreadState enum
305 unsigned int m_priority
; // thread priority in "wx" units
306 DWORD m_tid
; // thread id
309 DWORD
wxThreadInternal::WinThreadStart(wxThread
*thread
)
311 // store the thread object in the TLS
312 if ( !::TlsSetValue(s_tlsThisThread
, thread
) )
314 wxLogSysError(_("Can not start thread: error writing TLS."));
319 DWORD ret
= (DWORD
)thread
->Entry();
320 thread
->p_internal
->SetState(STATE_EXITED
);
328 bool wxThreadInternal::Create(wxThread
*thread
)
330 m_hThread
= ::CreateThread
332 NULL
, // default security
333 0, // default stack size
334 (LPTHREAD_START_ROUTINE
) // thread entry point
335 wxThreadInternal::WinThreadStart
, //
336 (LPVOID
)thread
, // parameter
337 CREATE_SUSPENDED
, // flags
338 &m_tid
// [out] thread id
341 if ( m_hThread
== NULL
)
343 wxLogSysError(_("Can't create thread"));
348 // translate wxWindows priority to the Windows one
350 if (m_priority
<= 20)
351 win_priority
= THREAD_PRIORITY_LOWEST
;
352 else if (m_priority
<= 40)
353 win_priority
= THREAD_PRIORITY_BELOW_NORMAL
;
354 else if (m_priority
<= 60)
355 win_priority
= THREAD_PRIORITY_NORMAL
;
356 else if (m_priority
<= 80)
357 win_priority
= THREAD_PRIORITY_ABOVE_NORMAL
;
358 else if (m_priority
<= 100)
359 win_priority
= THREAD_PRIORITY_HIGHEST
;
362 wxFAIL_MSG(wxT("invalid value of thread priority parameter"));
363 win_priority
= THREAD_PRIORITY_NORMAL
;
366 if ( ::SetThreadPriority(m_hThread
, win_priority
) == 0 )
368 wxLogSysError(_("Can't set thread priority"));
374 bool wxThreadInternal::Suspend()
376 DWORD nSuspendCount
= ::SuspendThread(m_hThread
);
377 if ( nSuspendCount
== (DWORD
)-1 )
379 wxLogSysError(_("Can not suspend thread %x"), m_hThread
);
384 m_state
= STATE_PAUSED
;
389 bool wxThreadInternal::Resume()
391 DWORD nSuspendCount
= ::ResumeThread(m_hThread
);
392 if ( nSuspendCount
== (DWORD
)-1 )
394 wxLogSysError(_("Can not resume thread %x"), m_hThread
);
399 m_state
= STATE_RUNNING
;
407 wxThread
*wxThread::This()
409 wxThread
*thread
= (wxThread
*)::TlsGetValue(s_tlsThisThread
);
411 // be careful, 0 may be a valid return value as well
412 if ( !thread
&& (::GetLastError() != NO_ERROR
) )
414 wxLogSysError(_("Couldn't get the current thread pointer"));
422 bool wxThread::IsMain()
424 return ::GetCurrentThreadId() == s_idMainThread
;
431 void wxThread::Yield()
433 // 0 argument to Sleep() is special
437 void wxThread::Sleep(unsigned long milliseconds
)
439 ::Sleep(milliseconds
);
442 // create/start thread
443 // -------------------
445 wxThreadError
wxThread::Create()
447 if ( !p_internal
->Create(this) )
448 return wxTHREAD_NO_RESOURCE
;
450 return wxTHREAD_NO_ERROR
;
453 wxThreadError
wxThread::Run()
455 wxCriticalSectionLocker
lock(m_critsect
);
457 if ( p_internal
->GetState() != STATE_NEW
)
459 // actually, it may be almost any state at all, not only STATE_RUNNING
460 return wxTHREAD_RUNNING
;
466 // suspend/resume thread
467 // ---------------------
469 wxThreadError
wxThread::Pause()
471 wxCriticalSectionLocker
lock(m_critsect
);
473 return p_internal
->Suspend() ? wxTHREAD_NO_ERROR
: wxTHREAD_MISC_ERROR
;
476 wxThreadError
wxThread::Resume()
478 wxCriticalSectionLocker
lock(m_critsect
);
480 return p_internal
->Resume() ? wxTHREAD_NO_ERROR
: wxTHREAD_MISC_ERROR
;
486 wxThread::ExitCode
wxThread::Delete()
490 // Delete() is always safe to call, so consider all possible states
498 // set flag for wxIsWaitingForThread()
499 s_waitingForThread
= TRUE
;
506 wxCriticalSectionLocker
lock(m_critsect
);
508 p_internal
->Cancel();
509 hThread
= p_internal
->GetHandle();
512 // we can't just wait for the thread to terminate because it might be
513 // calling some GUI functions and so it will never terminate before we
514 // process the Windows messages that result from these functions
518 result
= ::MsgWaitForMultipleObjects
520 1, // number of objects to wait for
521 &hThread
, // the objects
522 FALSE
, // don't wait for all objects
523 INFINITE
, // no timeout
524 QS_ALLEVENTS
// return as soon as there are any events
531 wxLogSysError(_("Can not wait for thread termination"));
536 // thread we're waiting for terminated
539 case WAIT_OBJECT_0
+ 1:
540 // new message arrived, process it
541 if ( !wxTheApp
->DoMessage() )
543 // WM_QUIT received: kill the thread
551 // give the thread we're waiting for chance to exit
552 // from the GUI call it might have been in
553 if ( (s_nWaitingForGui
> 0) && wxGuiOwnedByMainThread() )
562 wxFAIL_MSG(wxT("unexpected result of MsgWaitForMultipleObject"));
564 } while ( result
!= WAIT_OBJECT_0
);
568 s_waitingForThread
= FALSE
;
573 if ( !::GetExitCodeThread(hThread
, (LPDWORD
)&rc
) )
575 wxLogLastError("GetExitCodeThread");
580 wxASSERT_MSG( (LPVOID
)rc
!= (LPVOID
)STILL_ACTIVE
,
581 wxT("thread must be already terminated.") );
583 ::CloseHandle(hThread
);
589 wxThreadError
wxThread::Kill()
592 return wxTHREAD_NOT_RUNNING
;
594 if ( !::TerminateThread(p_internal
->GetHandle(), (DWORD
)-1) )
596 wxLogSysError(_("Couldn't terminate thread"));
598 return wxTHREAD_MISC_ERROR
;
603 return wxTHREAD_NO_ERROR
;
606 void wxThread::Exit(void *status
)
610 ::ExitThread((DWORD
)status
);
612 wxFAIL_MSG(wxT("Couldn't return from ExitThread()!"));
615 void wxThread::SetPriority(unsigned int prio
)
617 wxCriticalSectionLocker
lock(m_critsect
);
619 p_internal
->SetPriority(prio
);
622 unsigned int wxThread::GetPriority() const
624 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
626 return p_internal
->GetPriority();
629 unsigned long wxThread::GetID() const
631 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
633 return (unsigned long)p_internal
->GetId();
636 bool wxThread::IsRunning() const
638 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
640 return p_internal
->GetState() == STATE_RUNNING
;
643 bool wxThread::IsAlive() const
645 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
647 return (p_internal
->GetState() == STATE_RUNNING
) ||
648 (p_internal
->GetState() == STATE_PAUSED
);
651 bool wxThread::IsPaused() const
653 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
655 return (p_internal
->GetState() == STATE_PAUSED
);
658 bool wxThread::TestDestroy()
660 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
662 return p_internal
->GetState() == STATE_CANCELED
;
667 p_internal
= new wxThreadInternal();
670 wxThread::~wxThread()
675 // ----------------------------------------------------------------------------
676 // Automatic initialization for thread module
677 // ----------------------------------------------------------------------------
679 class wxThreadModule
: public wxModule
682 virtual bool OnInit();
683 virtual void OnExit();
686 DECLARE_DYNAMIC_CLASS(wxThreadModule
)
689 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule
, wxModule
)
691 bool wxThreadModule::OnInit()
693 // allocate TLS index for storing the pointer to the current thread
694 s_tlsThisThread
= ::TlsAlloc();
695 if ( s_tlsThisThread
== 0xFFFFFFFF )
697 // in normal circumstances it will only happen if all other
698 // TLS_MINIMUM_AVAILABLE (>= 64) indices are already taken - in other
699 // words, this should never happen
700 wxLogSysError(_("Thread module initialization failed: "
701 "impossible to allocate index in thread "
707 // main thread doesn't have associated wxThread object, so store 0 in the
709 if ( !::TlsSetValue(s_tlsThisThread
, (LPVOID
)0) )
711 ::TlsFree(s_tlsThisThread
);
712 s_tlsThisThread
= 0xFFFFFFFF;
714 wxLogSysError(_("Thread module initialization failed: "
715 "can not store value in thread local storage"));
720 s_critsectWaitingForGui
= new wxCriticalSection();
722 s_critsectGui
= new wxCriticalSection();
723 s_critsectGui
->Enter();
725 // no error return for GetCurrentThreadId()
726 s_idMainThread
= ::GetCurrentThreadId();
731 void wxThreadModule::OnExit()
733 if ( !::TlsFree(s_tlsThisThread
) )
735 wxLogLastError("TlsFree failed.");
740 s_critsectGui
->Leave();
741 delete s_critsectGui
;
742 s_critsectGui
= NULL
;
745 wxDELETE(s_critsectWaitingForGui
);
748 // ----------------------------------------------------------------------------
749 // under Windows, these functions are implemented usign a critical section and
750 // not a mutex, so the names are a bit confusing
751 // ----------------------------------------------------------------------------
753 void WXDLLEXPORT
wxMutexGuiEnter()
755 // this would dead lock everything...
756 wxASSERT_MSG( !wxThread::IsMain(),
757 wxT("main thread doesn't want to block in wxMutexGuiEnter()!") );
759 // the order in which we enter the critical sections here is crucial!!
761 // set the flag telling to the main thread that we want to do some GUI
763 wxCriticalSectionLocker
enter(*s_critsectWaitingForGui
);
768 wxWakeUpMainThread();
770 // now we may block here because the main thread will soon let us in
771 // (during the next iteration of OnIdle())
772 s_critsectGui
->Enter();
775 void WXDLLEXPORT
wxMutexGuiLeave()
777 wxCriticalSectionLocker
enter(*s_critsectWaitingForGui
);
779 if ( wxThread::IsMain() )
781 s_bGuiOwnedByMainThread
= FALSE
;
785 // decrement the number of waiters now
786 wxASSERT_MSG( s_nWaitingForGui
> 0,
787 wxT("calling wxMutexGuiLeave() without entering it first?") );
791 wxWakeUpMainThread();
794 s_critsectGui
->Leave();
797 void WXDLLEXPORT
wxMutexGuiLeaveOrEnter()
799 wxASSERT_MSG( wxThread::IsMain(),
800 wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") );
802 wxCriticalSectionLocker
enter(*s_critsectWaitingForGui
);
804 if ( s_nWaitingForGui
== 0 )
806 // no threads are waiting for GUI - so we may acquire the lock without
807 // any danger (but only if we don't already have it)
808 if ( !wxGuiOwnedByMainThread() )
810 s_critsectGui
->Enter();
812 s_bGuiOwnedByMainThread
= TRUE
;
814 //else: already have it, nothing to do
818 // some threads are waiting, release the GUI lock if we have it
819 if ( wxGuiOwnedByMainThread() )
823 //else: some other worker thread is doing GUI
827 bool WXDLLEXPORT
wxGuiOwnedByMainThread()
829 return s_bGuiOwnedByMainThread
;
832 // wake up the main thread if it's in ::GetMessage()
833 void WXDLLEXPORT
wxWakeUpMainThread()
835 // sending any message would do - hopefully WM_NULL is harmless enough
836 if ( !::PostThreadMessage(s_idMainThread
, WM_NULL
, 0, 0) )
838 // should never happen
839 wxLogLastError("PostThreadMessage(WM_NULL)");
843 bool WXDLLEXPORT
wxIsWaitingForThread()
845 return s_waitingForThread
;
848 #endif // wxUSE_THREADS