* Added thread cleanup safeness: thread can be explicitely killed safely now
on Unix. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@2467 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
12
configure.in
12
configure.in
@@ -1437,6 +1437,18 @@ if test "$wxUSE_THREADS" = "1"; then
|
|||||||
AC_DEFINE(HAVE_PTHREAD_CANCEL),
|
AC_DEFINE(HAVE_PTHREAD_CANCEL),
|
||||||
AC_MSG_WARN(wxThread::Kill() will not work properly))
|
AC_MSG_WARN(wxThread::Kill() will not work properly))
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([for pthread_cleanup_push/pop])
|
||||||
|
AC_TRY_COMPILE([#include <pthread.h>],
|
||||||
|
[
|
||||||
|
pthread_cleanup_push(NULL, NULL);
|
||||||
|
pthread_cleanup_pop(0);
|
||||||
|
],
|
||||||
|
[AC_MSG_RESULT(yes)
|
||||||
|
AC_DEFINE(HAVE_THREAD_CLEANUP_FUNCTIONS)
|
||||||
|
],
|
||||||
|
[AC_MSG_RESULT(no)]
|
||||||
|
)
|
||||||
|
|
||||||
THREADS_LINK="-l$THREADS_LINK"
|
THREADS_LINK="-l$THREADS_LINK"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@@ -231,6 +231,11 @@ public:
|
|||||||
// thread entry function
|
// thread entry function
|
||||||
static void *PthreadStart(void *ptr);
|
static void *PthreadStart(void *ptr);
|
||||||
|
|
||||||
|
#if HAVE_THREAD_CLEANUP_FUNCTIONS
|
||||||
|
// thread exit function
|
||||||
|
static void PthreadCleanup(void *ptr);
|
||||||
|
#endif
|
||||||
|
|
||||||
// thread actions
|
// thread actions
|
||||||
// start the thread
|
// start the thread
|
||||||
wxThreadError Run();
|
wxThreadError Run();
|
||||||
@@ -289,6 +294,7 @@ void *wxThreadInternal::PthreadStart(void *ptr)
|
|||||||
{
|
{
|
||||||
wxThread *thread = (wxThread *)ptr;
|
wxThread *thread = (wxThread *)ptr;
|
||||||
wxThreadInternal *pthread = thread->p_internal;
|
wxThreadInternal *pthread = thread->p_internal;
|
||||||
|
void *status;
|
||||||
|
|
||||||
int rc = pthread_setspecific(gs_keySelf, thread);
|
int rc = pthread_setspecific(gs_keySelf, thread);
|
||||||
if ( rc != 0 )
|
if ( rc != 0 )
|
||||||
@@ -297,6 +303,10 @@ void *wxThreadInternal::PthreadStart(void *ptr)
|
|||||||
|
|
||||||
return (void *)-1;
|
return (void *)-1;
|
||||||
}
|
}
|
||||||
|
#if HAVE_THREAD_CLEANUP_FUNCTIONS
|
||||||
|
// Install the cleanup handler.
|
||||||
|
pthread_cleanup_push(wxThreadInternal::PthreadCleanup, ptr);
|
||||||
|
#endif
|
||||||
|
|
||||||
// wait for the condition to be signaled from Run()
|
// wait for the condition to be signaled from Run()
|
||||||
// mutex state: currently locked by the thread which created us
|
// mutex state: currently locked by the thread which created us
|
||||||
@@ -305,7 +315,11 @@ void *wxThreadInternal::PthreadStart(void *ptr)
|
|||||||
// mutex state: locked again on exit of Wait()
|
// mutex state: locked again on exit of Wait()
|
||||||
|
|
||||||
// call the main entry
|
// call the main entry
|
||||||
void* status = thread->Entry();
|
status = thread->Entry();
|
||||||
|
|
||||||
|
#if HAVE_THREAD_CLEANUP_FUNCTIONS
|
||||||
|
pthread_cleanup_pop(FALSE);
|
||||||
|
#endif
|
||||||
|
|
||||||
// terminate the thread
|
// terminate the thread
|
||||||
thread->Exit(status);
|
thread->Exit(status);
|
||||||
@@ -315,6 +329,28 @@ void *wxThreadInternal::PthreadStart(void *ptr)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if HAVE_THREAD_CLEANUP_FUNCTIONS
|
||||||
|
// Only called when the thread is explicitely killed.
|
||||||
|
|
||||||
|
void wxThreadInternal::PthreadCleanup(void *ptr)
|
||||||
|
{
|
||||||
|
wxThread *thread = (wxThread *) ptr;
|
||||||
|
|
||||||
|
// The thread is already considered as finished.
|
||||||
|
if (thread->p_internal->GetState() == STATE_EXITED)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// first call user-level clean up code
|
||||||
|
thread->OnExit();
|
||||||
|
|
||||||
|
// next wake up the threads waiting for us (OTOH, this function won't retur
|
||||||
|
// until someone waited for us!)
|
||||||
|
thread->p_internal->SetState(STATE_EXITED);
|
||||||
|
|
||||||
|
thread->p_internal->SignalExit();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
wxThreadInternal::wxThreadInternal()
|
wxThreadInternal::wxThreadInternal()
|
||||||
{
|
{
|
||||||
m_state = STATE_NEW;
|
m_state = STATE_NEW;
|
||||||
@@ -367,9 +403,11 @@ void wxThreadInternal::Wait()
|
|||||||
if ( wxThread::IsMain() )
|
if ( wxThread::IsMain() )
|
||||||
wxMutexGuiLeave();
|
wxMutexGuiLeave();
|
||||||
|
|
||||||
|
printf("Entering wait ...\n");
|
||||||
// entering Wait() releases the mutex thus allowing SignalExit() to acquire
|
// entering Wait() releases the mutex thus allowing SignalExit() to acquire
|
||||||
// it and to signal us its termination
|
// it and to signal us its termination
|
||||||
m_cond.Wait(m_mutex);
|
m_cond.Wait(m_mutex);
|
||||||
|
printf("Exiting wait ...\n");
|
||||||
|
|
||||||
// mutex is still in the locked state - relocked on exit from Wait(), so
|
// mutex is still in the locked state - relocked on exit from Wait(), so
|
||||||
// unlock it - we don't need it any more, the thread has already terminated
|
// unlock it - we don't need it any more, the thread has already terminated
|
||||||
@@ -382,18 +420,21 @@ void wxThreadInternal::Wait()
|
|||||||
|
|
||||||
void wxThreadInternal::SignalExit()
|
void wxThreadInternal::SignalExit()
|
||||||
{
|
{
|
||||||
|
printf("SignalExit\n");
|
||||||
// GL: Unlock mutexSuspend here.
|
// GL: Unlock mutexSuspend here.
|
||||||
m_mutexSuspend.Unlock();
|
m_mutexSuspend.Unlock();
|
||||||
|
|
||||||
// as mutex is currently locked, this will block until some other thread
|
// as mutex is currently locked, this will block until some other thread
|
||||||
// (normally the same which created this one) unlocks it by entering Wait()
|
// (normally the same which created this one) unlocks it by entering Wait()
|
||||||
m_mutex.Lock();
|
m_mutex.Lock();
|
||||||
|
printf("Mutex acquired\n");
|
||||||
|
|
||||||
// wake up all the threads waiting for our termination
|
// wake up all the threads waiting for our termination
|
||||||
m_cond.Broadcast();
|
m_cond.Broadcast();
|
||||||
|
|
||||||
// after this call mutex will be finally unlocked
|
// after this call mutex will be finally unlocked
|
||||||
m_mutex.Unlock();
|
m_mutex.Unlock();
|
||||||
|
printf("Mutex unacquired\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxThreadInternal::Pause()
|
void wxThreadInternal::Pause()
|
||||||
@@ -672,16 +713,20 @@ void wxThread::Exit(void *status)
|
|||||||
{
|
{
|
||||||
// first call user-level clean up code
|
// first call user-level clean up code
|
||||||
OnExit();
|
OnExit();
|
||||||
|
printf(" ... OnExit()\n");
|
||||||
|
|
||||||
// next wake up the threads waiting for us (OTOH, this function won't return
|
// next wake up the threads waiting for us (OTOH, this function won't return
|
||||||
// until someone waited for us!)
|
// until someone waited for us!)
|
||||||
p_internal->SetState(STATE_EXITED);
|
|
||||||
|
|
||||||
p_internal->SignalExit();
|
p_internal->SignalExit();
|
||||||
|
printf(" ... SignalExit()\n");
|
||||||
|
|
||||||
|
p_internal->SetState(STATE_EXITED);
|
||||||
|
printf(" ... SetState()\n");
|
||||||
|
|
||||||
// delete both C++ thread object and terminate the OS thread object
|
// delete both C++ thread object and terminate the OS thread object
|
||||||
// GL: This is very ugly and buggy ...
|
// GL: This is very ugly and buggy ...
|
||||||
// delete this;
|
// delete this;
|
||||||
|
printf(" ... Exit\n");
|
||||||
pthread_exit(status);
|
pthread_exit(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user