mirror of https://github.com/BOINC/boinc.git
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:
parent
61e040a743
commit
ddc3d4eb0b
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue