MGR: In Async RPC logic, use posix mutexes and condition instead of wxMutex and wxCondition, as this appears to fix an intermittent hang in wxCondition::Wait()

svn path=/trunk/boinc/; revision=18333
This commit is contained in:
Charlie Fenton 2009-06-08 22:44:03 +00:00
parent 61e040a743
commit ddc3d4eb0b
5 changed files with 294 additions and 20 deletions

View File

@ -5187,3 +5187,12 @@ David 8 June 2009
clientgui/
DltItemProperties.cpp
Charlie 8 June 2009
- MGR: In Async RPC logic, use posix mutexes and conditions instead of
wxWidgets implementations, as this appears to fix an intermittent
hang in wxCondition::Wait().
clientgui/
AsyncRPC.cpp, .h
MainDocument.cpp. .h

View File

@ -33,6 +33,216 @@
#include "error_numbers.h"
#include "util.h"
#ifdef __WXMAC__
#ifdef HAVE_PTHREAD_MUTEXATTR_T
// on some systems pthread_mutexattr_settype() is not in the headers (but it is
// in the library, otherwise we wouldn't compile this code at all)
extern "C" int pthread_mutexattr_settype( pthread_mutexattr_t *, int );
#endif
BOINC_Mutex::BOINC_Mutex( wxMutexType mutexType )
{
int err;
switch ( mutexType )
{
case wxMUTEX_RECURSIVE:
// support recursive locks like Win32, i.e. a thread can lock a
// mutex which it had itself already locked
//
// unfortunately initialization of recursive mutexes is non
// portable, so try several methods
#ifdef HAVE_PTHREAD_MUTEXATTR_T
{
pthread_mutexattr_t attr;
pthread_mutexattr_init( &attr );
pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE );
err = pthread_mutex_init( &m_mutex, &attr );
}
#elif defined(HAVE_PTHREAD_RECURSIVE_MUTEX_INITIALIZER)
// we can use this only as initializer so we have to assign it
// first to a temp var - assigning directly to m_mutex wouldn't
// even compile
{
pthread_mutex_t mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
m_mutex = mutex;
}
#else // no recursive mutexes
err = EINVAL;
#endif // HAVE_PTHREAD_MUTEXATTR_T/...
break;
default:
wxFAIL_MSG( wxT("unknown mutex type") );
// fall through
case wxMUTEX_DEFAULT:
err = pthread_mutex_init( &m_mutex, NULL );
break;
}
m_isOk = err == 0;
if ( !m_isOk )
{
wxLogApiError( wxT("pthread_mutex_init()"), err );
}
}
BOINC_Mutex::~BOINC_Mutex()
{
if ( m_isOk )
{
int err = pthread_mutex_destroy( &m_mutex );
if ( err != 0 )
{
wxLogApiError( wxT("pthread_mutex_destroy()"), err );
}
}
}
wxMutexError BOINC_Mutex::Lock()
{
int err = pthread_mutex_lock( &m_mutex );
switch ( err )
{
case EDEADLK:
// only error checking mutexes return this value and so it's an
// unexpected situation -- hence use assert, not wxLogDebug
wxFAIL_MSG( wxT("mutex deadlock prevented") );
return wxMUTEX_DEAD_LOCK;
case EINVAL:
wxLogDebug( wxT("pthread_mutex_lock(): mutex not initialized.") );
break;
case 0:
return wxMUTEX_NO_ERROR;
default:
wxLogApiError( wxT("pthread_mutex_lock()"), err );
}
return wxMUTEX_MISC_ERROR;
}
wxMutexError BOINC_Mutex::TryLock()
{
int err = pthread_mutex_trylock( &m_mutex );
switch ( err )
{
case EBUSY:
// not an error: mutex is already locked, but we're prepared for this case
return wxMUTEX_BUSY;
case EINVAL:
wxLogDebug( wxT("pthread_mutex_trylock(): mutex not initialized.") );
break;
case 0:
return wxMUTEX_NO_ERROR;
default:
wxLogApiError( wxT("pthread_mutex_trylock()"), err );
}
return wxMUTEX_MISC_ERROR;
}
wxMutexError BOINC_Mutex::Unlock()
{
int err = pthread_mutex_unlock( &m_mutex );
switch ( err )
{
case EPERM:
// we don't own the mutex
return wxMUTEX_UNLOCKED;
case EINVAL:
wxLogDebug( wxT("pthread_mutex_unlock(): mutex not initialized.") );
break;
case 0:
return wxMUTEX_NO_ERROR;
default:
wxLogApiError( wxT("pthread_mutex_unlock()"), err );
}
return wxMUTEX_MISC_ERROR;
}
// wxMac wxCondition has bugs, so use native UNIX implementation
BOINC_Condition::BOINC_Condition(BOINC_Mutex& mutex)
: m_BOINC_Mutex(mutex) {
int err;
err = pthread_cond_init(&m_cond, NULL);
mb_initOK = (err == 0);
}
BOINC_Condition::~BOINC_Condition() {
pthread_cond_destroy(&m_cond);
mb_initOK = false;
}
wxCondError BOINC_Condition::Wait(){
int err;
err = pthread_cond_wait(&m_cond, &m_BOINC_Mutex.m_mutex);
switch (err) {
case 0:
return wxCOND_NO_ERROR;
case EINVAL:
return wxCOND_INVALID;
case ETIMEDOUT:
return wxCOND_TIMEOUT;
default:
return wxCOND_MISC_ERROR;
}
return wxCOND_NO_ERROR;
}
wxCondError BOINC_Condition::WaitTimeout(unsigned long milliseconds) {
int err;
wxLongLong curtime = wxGetLocalTimeMillis();
curtime += milliseconds;
wxLongLong temp = curtime / 1000;
int sec = temp.GetLo();
temp *= 1000;
temp = curtime - temp;
int millis = temp.GetLo();
timespec tspec;
tspec.tv_sec = sec;
tspec.tv_nsec = millis * 1000L * 1000L;
err = pthread_cond_timedwait(&m_cond, &m_BOINC_Mutex.m_mutex, &tspec);
switch (err) {
case 0:
return wxCOND_NO_ERROR;
case EINVAL:
return wxCOND_INVALID;
case ETIMEDOUT:
return wxCOND_TIMEOUT;
default:
return wxCOND_MISC_ERROR;
}
return wxCOND_NO_ERROR;
}
void BOINC_Condition::Signal() {
pthread_cond_signal(&m_cond);
}
void BOINC_Condition::Broadcast() {
pthread_cond_broadcast(&m_cond);
}
#endif
// Delay in milliseconds before showing AsyncRPCDlg
#define RPC_WAIT_DLG_DELAY 1500
@ -111,10 +321,10 @@ int AsyncRPC::RPC_Wait(RPC_SELECTOR which_rpc, void *arg1, void *arg2,
RPCThread::RPCThread(CMainDocument *pDoc,
wxMutex* pRPC_Thread_Mutex,
wxCondition* pRPC_Thread_Condition,
wxMutex* pRPC_Request_Mutex,
wxCondition* pRPC_Request_Condition)
BOINC_Mutex* pRPC_Thread_Mutex,
BOINC_Condition* pRPC_Thread_Condition,
BOINC_Mutex* pRPC_Request_Mutex,
BOINC_Condition* pRPC_Request_Condition)
: wxThread() {
m_pDoc = pDoc;
m_pRPC_Thread_Mutex = pRPC_Thread_Mutex;

View File

@ -22,6 +22,61 @@
#pragma interface "AsyncRPC.cpp"
#endif
#ifndef __WXMAC__
#define BOINC_Condition wxCondition
#define BOINC_Mutex wxMutex
#else
// Adapted from wxMac-2.8.10
#include <pthread.h>
class BOINC_Mutex
{
public:
BOINC_Mutex( wxMutexType mutexType = wxMUTEX_DEFAULT );
~BOINC_Mutex();
wxMutexError Lock();
wxMutexError TryLock();
wxMutexError Unlock();
bool IsOk() const
{ return m_isOk; }
private:
pthread_mutex_t m_mutex;
bool m_isOk;
// BOINC_Condition uses our m_mutex
friend class BOINC_Condition;
};
// Adapted from wxMac-2.8.10 but using native pthread_cond_*()
class BOINC_Condition
{
public:
BOINC_Condition(BOINC_Mutex& mutex);
~BOINC_Condition();
bool IsOk() const { return (m_BOINC_Mutex.IsOk() && mb_initOK); }
wxCondError Wait();
wxCondError WaitTimeout(unsigned long milliseconds);
void Signal();
void Broadcast();
private:
BOINC_Mutex& m_BOINC_Mutex;
pthread_cond_t m_cond;
bool mb_initOK;
DECLARE_NO_COPY_CLASS(BOINC_Condition)
};
#endif
class CMainDocument; // Forward declaration
@ -288,20 +343,20 @@ class RPCThread : public wxThread
{
public:
RPCThread(CMainDocument *pDoc,
wxMutex* pRPC_Thread_Mutex,
wxCondition* pRPC_Thread_Condition,
wxMutex* pRPC_Request_Mutex,
wxCondition* RPC_Request_Condition
BOINC_Mutex* pRPC_Thread_Mutex,
BOINC_Condition* pRPC_Thread_Condition,
BOINC_Mutex* pRPC_Request_Mutex,
BOINC_Condition* RPC_Request_Condition
);
virtual void *Entry();
private:
int ProcessRPCRequest();
CMainDocument* m_pDoc;
wxMutex* m_pRPC_Thread_Mutex;
wxCondition* m_pRPC_Thread_Condition;
wxMutex* m_pRPC_Request_Mutex;
wxCondition* m_pRPC_Request_Condition;
BOINC_Mutex* m_pRPC_Thread_Mutex;
BOINC_Condition* m_pRPC_Thread_Condition;
BOINC_Mutex* m_pRPC_Request_Mutex;
BOINC_Condition* m_pRPC_Request_Condition;
};

View File

@ -440,16 +440,16 @@ int CMainDocument::OnInit() {
current_rpc_request.clear();
m_pRPC_Thread_Mutex = new wxMutex();
m_pRPC_Thread_Mutex = new BOINC_Mutex();
wxASSERT(m_pRPC_Thread_Mutex);
m_pRPC_Thread_Condition = new wxCondition(*m_pRPC_Thread_Mutex);
m_pRPC_Thread_Condition = new BOINC_Condition(*m_pRPC_Thread_Mutex);
wxASSERT(m_pRPC_Thread_Condition);
m_pRPC_Request_Mutex = new wxMutex();
m_pRPC_Request_Mutex = new BOINC_Mutex();
wxASSERT(m_pRPC_Request_Mutex);
m_pRPC_Request_Condition = new wxCondition(*m_pRPC_Request_Mutex);
m_pRPC_Request_Condition = new BOINC_Condition(*m_pRPC_Request_Mutex);
wxASSERT(m_pRPC_Request_Condition);
m_RPCThread = new RPCThread(this,

View File

@ -194,10 +194,10 @@ private:
bool m_bWaitingForRPC;
bool m_bNeedRefresh;
bool m_bNeedTaskBarRefresh;
wxMutex* m_pRPC_Thread_Mutex;
wxCondition* m_pRPC_Thread_Condition;
wxMutex* m_pRPC_Request_Mutex;
wxCondition* m_pRPC_Request_Condition;
BOINC_Mutex* m_pRPC_Thread_Mutex;
BOINC_Condition* m_pRPC_Thread_Condition;
BOINC_Mutex* m_pRPC_Request_Mutex;
BOINC_Condition* m_pRPC_Request_Condition;
//
// Project Tab