X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/a243da29c8135be476e47a035a81e695bbb21e26..abd474ea63667f727940a009cc3e0b23ba9f418f:/src/unix/threadpsx.cpp diff --git a/src/unix/threadpsx.cpp b/src/unix/threadpsx.cpp index 700fd19324..22fefee76d 100644 --- a/src/unix/threadpsx.cpp +++ b/src/unix/threadpsx.cpp @@ -45,6 +45,7 @@ #include #include #include +#include // needed for at least __QNX__ #ifdef HAVE_SCHED_H #include #endif @@ -56,16 +57,11 @@ // we use wxFFile under Linux in GetCPUCount() #ifdef __LINUX__ #include "wx/ffile.h" - // For setpriority. - #include - #include + #include // for setpriority() #endif -#ifdef __VMS - #define THR_ID(thr) ((long long)(thr)->GetId()) -#else - #define THR_ID(thr) ((long)(thr)->GetId()) -#endif +#define THR_ID_CAST(id) (reinterpret_cast(id)) +#define THR_ID(thr) THR_ID_CAST((thr)->GetId()) // ---------------------------------------------------------------------------- // constants @@ -138,10 +134,12 @@ static wxMutex *gs_mutexDeleteThread = NULL; // gs_nThreadsBeingDeleted will have been deleted static wxCondition *gs_condAllDeleted = NULL; +#ifndef __WXOSX__ // this mutex must be acquired before any call to a GUI function // (it's not inside #if wxUSE_GUI because this file is compiled as part // of wxBase) static wxMutex *gs_mutexGui = NULL; +#endif // when we wait for a thread to exit, we're blocking on a condition which the // thread signals in its SignalExit() method -- but this condition can't be a @@ -594,14 +592,14 @@ wxSemaError wxSemaphoreInternal::Wait() { wxLogTrace(TRACE_SEMA, wxT("Thread %p waiting for semaphore to become signalled"), - wxThread::GetCurrentId()); + THR_ID_CAST(wxThread::GetCurrentId())); if ( m_cond.Wait() != wxCOND_NO_ERROR ) return wxSEMA_MISC_ERROR; wxLogTrace(TRACE_SEMA, wxT("Thread %p finished waiting for semaphore, count = %lu"), - wxThread::GetCurrentId(), (unsigned long)m_count); + THR_ID_CAST(wxThread::GetCurrentId()), (unsigned long)m_count); } m_count--; @@ -668,7 +666,7 @@ wxSemaError wxSemaphoreInternal::Post() wxLogTrace(TRACE_SEMA, wxT("Thread %p about to signal semaphore, count = %lu"), - wxThread::GetCurrentId(), (unsigned long)m_count); + THR_ID_CAST(wxThread::GetCurrentId()), (unsigned long)m_count); return m_cond.Signal() == wxCOND_NO_ERROR ? wxSEMA_NO_ERROR : wxSEMA_MISC_ERROR; @@ -734,7 +732,7 @@ public: }; wxLogTrace(TRACE_THREADS, wxT("Thread %p: %s => %s."), - GetId(), stateNames[m_state], stateNames[state]); + THR_ID(this), stateNames[m_state], stateNames[state]); #endif // wxUSE_LOG_TRACE m_state = state; @@ -976,7 +974,17 @@ void wxThreadInternal::Wait() // if the thread we're waiting for is waiting for the GUI mutex, we will // deadlock so make sure we release it temporarily if ( wxThread::IsMain() ) + { +#ifdef __WXOSX__ + // give the thread we're waiting for chance to do the GUI call + // it might be in, we don't do this conditionally as the to be waited on + // thread might have to acquire the mutex later but before terminating + if ( wxGuiOwnedByMainThread() ) + wxMutexGuiLeave(); +#else wxMutexGuiLeave(); +#endif + } wxLogTrace(TRACE_THREADS, wxT("Starting to wait for thread %p to exit."), @@ -1006,9 +1014,11 @@ void wxThreadInternal::Wait() } } +#ifndef __WXOSX__ // reacquire GUI mutex if ( wxThread::IsMain() ) wxMutexGuiEnter(); +#endif } void wxThreadInternal::Pause() @@ -1393,7 +1403,7 @@ wxThreadError wxThread::Resume() { case STATE_PAUSED: wxLogTrace(TRACE_THREADS, wxT("Thread %p suspended, resuming."), - GetId()); + THR_ID(this)); m_internal->Resume(); @@ -1401,7 +1411,7 @@ wxThreadError wxThread::Resume() case STATE_EXITED: wxLogTrace(TRACE_THREADS, wxT("Thread %p exited, won't resume."), - GetId()); + THR_ID(this)); return wxTHREAD_NO_ERROR; default: @@ -1415,7 +1425,7 @@ wxThreadError wxThread::Resume() // exiting thread // ----------------------------------------------------------------------------- -wxThread::ExitCode wxThread::Wait() +wxThread::ExitCode wxThread::Wait(wxThreadWait WXUNUSED(waitMode)) { wxCHECK_MSG( This() != this, (ExitCode)-1, wxT("a thread can't wait for itself") ); @@ -1428,7 +1438,7 @@ wxThread::ExitCode wxThread::Wait() return m_internal->GetExitCode(); } -wxThreadError wxThread::Delete(ExitCode *rc) +wxThreadError wxThread::Delete(ExitCode *rc, wxThreadWait WXUNUSED(waitMode)) { wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR, wxT("a thread can't delete itself") ); @@ -1443,6 +1453,8 @@ wxThreadError wxThread::Delete(ExitCode *rc) m_critsect.Leave(); + OnDelete(); + switch ( state ) { case STATE_NEW: @@ -1478,6 +1490,11 @@ wxThreadError wxThread::Delete(ExitCode *rc) //else: can't wait for detached threads } + if (state == STATE_NEW) + return wxTHREAD_MISC_ERROR; + // for coherency with the MSW implementation, signal the user that + // Delete() was called on a thread which didn't start to run yet. + return wxTHREAD_NO_ERROR; } @@ -1486,6 +1503,8 @@ wxThreadError wxThread::Kill() wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR, wxT("a thread can't kill itself") ); + OnKill(); + switch ( m_internal->GetState() ) { case STATE_NEW: @@ -1617,8 +1636,8 @@ wxThread::~wxThread() if ( m_internal->GetState() != STATE_EXITED && m_internal->GetState() != STATE_NEW ) { - wxLogDebug(wxT("The thread %ld is being destroyed although it is still running! The application may crash."), - (long)GetId()); + wxLogDebug(wxT("The thread %p is being destroyed although it is still running! The application may crash."), + THR_ID(this)); } m_critsect.Leave(); @@ -1670,6 +1689,11 @@ bool wxThread::IsPaused() const // wxThreadModule //-------------------------------------------------------------------- +#ifdef __WXOSX__ +void wxOSXThreadModuleOnInit(); +void wxOSXThreadModuleOnExit(); +#endif + class wxThreadModule : public wxModule { public: @@ -1696,8 +1720,12 @@ bool wxThreadModule::OnInit() gs_mutexAllThreads = new wxMutex(); +#ifdef __WXOSX__ + wxOSXThreadModuleOnInit(); +#else gs_mutexGui = new wxMutex(); gs_mutexGui->Lock(); +#endif gs_mutexDeleteThread = new wxMutex(); gs_condAllDeleted = new wxCondition(*gs_mutexDeleteThread); @@ -1750,9 +1778,13 @@ void wxThreadModule::OnExit() delete gs_mutexAllThreads; +#ifdef __WXOSX__ + wxOSXThreadModuleOnExit(); +#else // destroy GUI mutex gs_mutexGui->Unlock(); delete gs_mutexGui; +#endif // and free TLD slot (void)pthread_key_delete(gs_keySelf); @@ -1778,14 +1810,15 @@ static void ScheduleThreadForDeletion() static void DeleteThread(wxThread *This) { - // gs_mutexDeleteThread should be unlocked before signalling the condition - // or wxThreadModule::OnExit() would deadlock - wxMutexLocker locker( *gs_mutexDeleteThread ); - - wxLogTrace(TRACE_THREADS, wxT("Thread %p auto deletes."), This->GetId()); + wxLogTrace(TRACE_THREADS, wxT("Thread %p auto deletes."), THR_ID(This)); delete This; + // only lock gs_mutexDeleteThread after deleting the thread to avoid + // calling out into user code with it locked as this may result in + // deadlocks if the thread dtor deletes another thread (see #11501) + wxMutexLocker locker( *gs_mutexDeleteThread ); + wxCHECK_RET( gs_nThreadsBeingDeleted > 0, wxT("no threads scheduled for deletion, yet we delete one?") ); @@ -1799,6 +1832,8 @@ static void DeleteThread(wxThread *This) } } +#ifndef __WXOSX__ + void wxMutexGuiEnterImpl() { gs_mutexGui->Lock(); @@ -1809,6 +1844,8 @@ void wxMutexGuiLeaveImpl() gs_mutexGui->Unlock(); } +#endif + // ---------------------------------------------------------------------------- // include common implementation code // ----------------------------------------------------------------------------