// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
-#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
- #pragma implementation "thread.h"
-#endif
-
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
wxSemaphoreInternal::wxSemaphoreInternal(int initialcount, int maxcount)
{
-#ifndef __WXWINCE__
+#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 300)
if ( maxcount == 0 )
{
// make it practically infinite
wxSemaError wxSemaphoreInternal::Post()
{
-#ifndef __WXWINCE__
+#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 300)
if ( !::ReleaseSemaphore(m_semaphore, 1, NULL /* ptr to previous count */) )
#endif
{
// first of all, check whether we hadn't been cancelled already and don't
// start the user code at all then
- if ( thread->m_internal->GetState() == STATE_EXITED )
+ const bool hasExited = thread->m_internal->GetState() == STATE_EXITED;
+
+ if ( hasExited )
{
rc = (THREAD_RETVAL)-1;
}
}
rc = (THREAD_RETVAL)thread->Entry();
+ }
+
+ thread->OnExit();
+ // save IsDetached because thread object can be deleted by joinable
+ // threads after state is changed to STATE_EXITED.
+ bool isDetached = thread->IsDetached();
+
+ if ( !hasExited )
+ {
// enter m_critsect before changing the thread state
wxCriticalSectionLocker lock(thread->m_critsect);
-
thread->m_internal->SetState(STATE_EXITED);
}
- thread->OnExit();
-
// the thread may delete itself now if it wants, we don't need it any more
- thread->m_internal->LetDie();
+ if ( isDetached )
+ thread->m_internal->LetDie();
return rc;
}
{
m_priority = priority;
- // translate wxWindows priority to the Windows one
+ // translate wxWidgets priority to the Windows one
int win_priority;
if (m_priority <= 20)
win_priority = THREAD_PRIORITY_LOWEST;
wxThread::ExitCode rc = 0;
- // Delete() is always safe to call, so consider all possible states
-
- // we might need to resume the thread, but we might also not need to cancel
- // it if it doesn't run yet
- bool shouldResume = false,
- isRunning = false;
+ // we might need to resume the thread if it's currently stopped
+ bool shouldResume = false;
- // check if the thread already started to run
+ // as Delete() (which calls us) is always safe to call we need to consider
+ // all possible states
{
wxCriticalSectionLocker lock(cs);
// to let it run
m_state = STATE_EXITED;
- Resume(); // it knows about STATE_EXITED special case
-
+ // we must call Resume() as the thread hasn't been initially
+ // resumed yet (and as Resume() it knows about STATE_EXITED
+ // special case, it won't touch it and WinThreadStart() will
+ // just exit immediately)
+ shouldResume = true;
shouldDelete = false;
}
-
- isRunning = true;
-
- // shouldResume is correctly set to false here
- }
- else if ( m_state == STATE_EXITED )
- {
- return wxTHREAD_NOT_RUNNING;
+ //else: shouldResume is correctly set to false here, wait until
+ // someone else runs the thread and it finishes
}
- else // running (but maybe paused or cancelled)
+ else // running, paused, cancelled or even exited
{
shouldResume = m_state == STATE_PAUSED;
}
if ( shouldResume )
Resume();
- // is it still running?
- if ( isRunning || m_state == STATE_RUNNING )
+ // ask the thread to terminate
+ if ( shouldDelete )
+ {
+ wxCriticalSectionLocker lock(cs);
+
+ Cancel();
+ }
+
+
+ // now wait for thread to finish
+ if ( wxThread::IsMain() )
+ {
+ // set flag for wxIsWaitingForThread()
+ gs_waitingForThread = true;
+ }
+
+ // we can't just wait for the thread to terminate because it might be
+ // calling some GUI functions and so it will never terminate before we
+ // process the Windows messages that result from these functions
+ // (note that even in console applications we might have to process
+ // messages if we use wxExecute() or timers or ...)
+ DWORD result wxDUMMY_INITIALIZE(0);
+ do
{
if ( wxThread::IsMain() )
{
- // set flag for wxIsWaitingForThread()
- gs_waitingForThread = true;
+ // give the thread we're waiting for chance to do the GUI call
+ // it might be in
+ if ( (gs_nWaitingForGui > 0) && wxGuiOwnedByMainThread() )
+ {
+ wxMutexGuiLeave();
+ }
}
- // ask the thread to terminate
- if ( shouldDelete )
- {
- wxCriticalSectionLocker lock(cs);
+#if !defined(QS_ALLPOSTMESSAGE)
+#define QS_ALLPOSTMESSAGE 0
+#endif
- Cancel();
- }
+ result = ::MsgWaitForMultipleObjects
+ (
+ 1, // number of objects to wait for
+ &m_hThread, // the objects
+ false, // don't wait for all objects
+ INFINITE, // no timeout
+ QS_ALLINPUT|QS_ALLPOSTMESSAGE // return as soon as there are any events
+ );
- // we can't just wait for the thread to terminate because it might be
- // calling some GUI functions and so it will never terminate before we
- // process the Windows messages that result from these functions
- // (note that even in console applications we might have to process
- // messages if we use wxExecute() or timers or ...)
- DWORD result wxDUMMY_INITIALIZE(0);
- do
+ switch ( result )
{
- if ( wxThread::IsMain() )
- {
- // give the thread we're waiting for chance to do the GUI call
- // it might be in
- if ( (gs_nWaitingForGui > 0) && wxGuiOwnedByMainThread() )
+ case 0xFFFFFFFF:
+ // error
+ wxLogSysError(_("Can not wait for thread termination"));
+ Kill();
+ return wxTHREAD_KILLED;
+
+ case WAIT_OBJECT_0:
+ // thread we're waiting for terminated
+ break;
+
+ case WAIT_OBJECT_0 + 1:
+ // new message arrived, process it -- but only if we're the
+ // main thread as we don't support processing messages in
+ // the other ones
+ //
+ // NB: we still must include QS_ALLINPUT even when waiting
+ // in a secondary thread because if it had created some
+ // window somehow (possible not even using wxWidgets)
+ // the system might dead lock then
+ if ( wxThread::IsMain() )
{
- wxMutexGuiLeave();
- }
- }
+ // it looks that sometimes WAIT_OBJECT_0 + 1 is
+ // returned but there are no messages in the thread
+ // queue -- prevent DoMessageFromThreadWait() from
+ // blocking inside ::GetMessage() forever in this case
+ ::PostMessage(NULL, WM_NULL, 0, 0);
- result = ::MsgWaitForMultipleObjects
- (
- 1, // number of objects to wait for
- &m_hThread, // the objects
- false, // don't wait for all objects
- INFINITE, // no timeout
- QS_ALLINPUT | // return as soon as there are any events
- QS_ALLPOSTMESSAGE
- );
-
- switch ( result )
- {
- case 0xFFFFFFFF:
- // error
- wxLogSysError(_("Can not wait for thread termination"));
- Kill();
- return wxTHREAD_KILLED;
-
- case WAIT_OBJECT_0:
- // thread we're waiting for terminated
- break;
-
- case WAIT_OBJECT_0 + 1:
- // new message arrived, process it -- but only if we're the
- // main thread as we don't support processing messages in
- // the other ones
- //
- // NB: we still must include QS_ALLINPUT even when waiting
- // in a secondary thread because if it had created some
- // window somehow (possible not even using wxWindows)
- // the system might dead lock then
- if ( wxThread::IsMain() )
+ wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits()
+ : NULL;
+
+ if ( traits && !traits->DoMessageFromThreadWait() )
{
- // it looks that sometimes WAIT_OBJECT_0 + 1 is
- // returned but there are no messages in the thread
- // queue -- prevent DoMessageFromThreadWait() from
- // blocking inside ::GetMessage() forever in this case
- ::PostMessage(NULL, WM_NULL, 0, 0);
-
- wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits()
- : NULL;
-
- if ( traits && !traits->DoMessageFromThreadWait() )
- {
- // WM_QUIT received: kill the thread
- Kill();
-
- return wxTHREAD_KILLED;
- }
- }
- break;
+ // WM_QUIT received: kill the thread
+ Kill();
- default:
- wxFAIL_MSG(wxT("unexpected result of MsgWaitForMultipleObject"));
- }
- } while ( result != WAIT_OBJECT_0 );
+ return wxTHREAD_KILLED;
+ }
+ }
+ break;
- if ( wxThread::IsMain() )
- {
- gs_waitingForThread = false;
+ default:
+ wxFAIL_MSG(wxT("unexpected result of MsgWaitForMultipleObject"));
}
+ } while ( result != WAIT_OBJECT_0 );
+
+ if ( wxThread::IsMain() )
+ {
+ gs_waitingForThread = false;
}
+
// although the thread might be already in the EXITED state it might not
// have terminated yet and so we are not sure that it has actually
// terminated if the "if" above hadn't been taken
- do
+ for ( ;; )
{
if ( !::GetExitCodeThread(m_hThread, (LPDWORD)&rc) )
{
wxLogLastError(wxT("GetExitCodeThread"));
rc = (wxThread::ExitCode)-1;
+
+ break;
}
- } while ( (DWORD)rc == STILL_ACTIVE );
+
+ if ( (DWORD)rc != STILL_ACTIVE )
+ break;
+
+ // give the other thread some time to terminate, otherwise we may be
+ // starving it
+ ::Sleep(1);
+ }
if ( pRc )
*pRc = rc;
// don't change the state from STATE_EXITED because it's special and means
// we are going to terminate without running any user code - if we did it,
- // the codei n Delete() wouldn't work
+ // the code in WaitForTerminate() wouldn't work
if ( m_state != STATE_EXITED )
{
m_state = STATE_RUNNING;
bool wxThread::IsMain()
{
- return ::GetCurrentThreadId() == gs_idMainThread;
+ return ::GetCurrentThreadId() == gs_idMainThread || gs_idMainThread == 0;
}
void wxThread::Yield()
return (unsigned long)::GetCurrentThreadId();
}
-bool wxThread::SetConcurrency(size_t level)
+bool wxThread::SetConcurrency(size_t WXUNUSED_IN_WINCE(level))
{
-#ifndef __WXWINCE__
+#ifdef __WXWINCE__
+ return false;
+#else
wxASSERT_MSG( IsMain(), _T("should only be called from the main thread") );
// ok only for the default one
// get system affinity mask first
HANDLE hProcess = ::GetCurrentProcess();
- DWORD dwProcMask, dwSysMask;
+ DWORD_PTR dwProcMask, dwSysMask;
if ( ::GetProcessAffinityMask(hProcess, &dwProcMask, &dwSysMask) == 0 )
{
wxLogLastError(_T("GetProcessAffinityMask"));
dwProcMask |= bit;
// another process added
- if ( !--level )
+ if ( --level == 0 )
{
// and that's enough
break;
return false;
}
-#endif
+
return true;
+#endif // __WXWINCE__/!__WXWINCE__
}
// ctor and dtor