Added API and -Dd command line parameter to disable taking the global mutex when (un)locking a Mutex or Semaphore.

This provides better performance and reduces mutex contention on expense of some thread safety and ease of debugging.


git-svn-id: http://yate.null.ro/svn/yate/trunk@3801 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
paulc 2010-11-09 19:52:51 +00:00
parent 242ae2be8d
commit 0883e02e29
4 changed files with 71 additions and 31 deletions

View File

@ -99,6 +99,9 @@ Abort (coredumps if allowed) if bugs are encountered
.B \-Dm .B \-Dm
Attempt to debug mutex deadlocks by setting a maximum 10s limit, if repeated halves the limit Attempt to debug mutex deadlocks by setting a maximum 10s limit, if repeated halves the limit
.TP .TP
.B \-Dd
Disable some locking debugging and safety features, improves performance instead
.TP
.B \-Dl .B \-Dl
Attempt to load modules without having their symbols globally visible Attempt to load modules without having their symbols globally visible
.TP .TP

View File

@ -1490,6 +1490,7 @@ static void usage(bool client, FILE* f)
" -D[options] Special debugging options\n" " -D[options] Special debugging options\n"
" a Abort if bugs are encountered\n" " a Abort if bugs are encountered\n"
" m Attempt to debug mutex deadlocks\n" " m Attempt to debug mutex deadlocks\n"
" d Disable locking debugging and safety features\n"
#ifdef RTLD_GLOBAL #ifdef RTLD_GLOBAL
" l Try to keep module symbols local\n" " l Try to keep module symbols local\n"
#endif #endif
@ -1745,6 +1746,9 @@ int Engine::main(int argc, const char** argv, const char** env, RunMode mode, bo
Lockable::wait(lockWait); Lockable::wait(lockWait);
} }
break; break;
case 'd':
Lockable::disableSafety();
break;
#ifdef RTLD_GLOBAL #ifdef RTLD_GLOBAL
case 'l': case 'l':
s_localsymbol = true; s_localsymbol = true;

View File

@ -131,6 +131,7 @@ HMUTEX GlobalMutex::s_mutex;
static GlobalMutex s_global; static GlobalMutex s_global;
static unsigned long s_maxwait = 0; static unsigned long s_maxwait = 0;
static bool s_unsafe = MUTEX_STATIC_UNSAFE; static bool s_unsafe = MUTEX_STATIC_UNSAFE;
static bool s_safety = true;
volatile int MutexPrivate::s_count = 0; volatile int MutexPrivate::s_count = 0;
volatile int MutexPrivate::s_locks = 0; volatile int MutexPrivate::s_locks = 0;
@ -217,7 +218,8 @@ MutexPrivate::~MutexPrivate()
if (m_locked) { if (m_locked) {
warn = true; warn = true;
m_locked--; m_locked--;
s_locks--; if (s_safety)
s_locks--;
#ifdef _WINDOWS #ifdef _WINDOWS
::ReleaseMutex(m_mutex); ::ReleaseMutex(m_mutex);
#else #else
@ -248,13 +250,16 @@ bool MutexPrivate::lock(long maxwait)
maxwait = (long)s_maxwait; maxwait = (long)s_maxwait;
warn = true; warn = true;
} }
GlobalMutex::lock(); if (s_safety)
GlobalMutex::lock();
ref(); ref();
m_waiting++;
Thread* thr = Thread::current(); Thread* thr = Thread::current();
if (thr) if (thr)
thr->m_locking = true; thr->m_locking = true;
GlobalMutex::unlock(); if (s_safety) {
m_waiting++;
GlobalMutex::unlock();
}
#ifdef _WINDOWS #ifdef _WINDOWS
DWORD ms = 0; DWORD ms = 0;
if (maxwait < 0) if (maxwait < 0)
@ -295,12 +300,15 @@ bool MutexPrivate::lock(long maxwait)
#endif // HAVE_TIMEDLOCK #endif // HAVE_TIMEDLOCK
} }
#endif // _WINDOWS #endif // _WINDOWS
GlobalMutex::lock(); if (s_safety) {
GlobalMutex::lock();
m_waiting--;
}
if (thr) if (thr)
thr->m_locking = false; thr->m_locking = false;
m_waiting--;
if (rval) { if (rval) {
s_locks++; if (s_safety)
s_locks++;
m_locked++; m_locked++;
if (thr) { if (thr) {
thr->m_locks++; thr->m_locks++;
@ -311,7 +319,8 @@ bool MutexPrivate::lock(long maxwait)
} }
else else
deref(); deref();
GlobalMutex::unlock(); if (s_safety)
GlobalMutex::unlock();
if (warn && !rval) if (warn && !rval)
Debug(DebugFail,"Thread '%s' could not lock mutex '%s' owned by '%s' waited by %u others for %lu usec!", Debug(DebugFail,"Thread '%s' could not lock mutex '%s' owned by '%s' waited by %u others for %lu usec!",
Thread::currentName(),m_name,m_owner,m_waiting,maxwait); Thread::currentName(),m_name,m_owner,m_waiting,maxwait);
@ -322,7 +331,8 @@ bool MutexPrivate::unlock()
{ {
bool ok = false; bool ok = false;
// Hope we don't hit a bug related to the debug mutex! // Hope we don't hit a bug related to the debug mutex!
GlobalMutex::lock(); if (s_safety)
GlobalMutex::lock();
if (m_locked) { if (m_locked) {
Thread* thr = Thread::current(); Thread* thr = Thread::current();
if (thr) if (thr)
@ -334,12 +344,14 @@ bool MutexPrivate::unlock()
m_name,tname,m_owner,this); m_name,tname,m_owner,this);
m_owner = 0; m_owner = 0;
} }
int locks = --s_locks; if (s_safety) {
if (locks < 0) { int locks = --s_locks;
// this is very very bad - abort right now if (locks < 0) {
abortOnBug(true); // this is very very bad - abort right now
s_locks = 0; abortOnBug(true);
Debug(DebugFail,"MutexPrivate::locks() is %d [%p]",locks,this); s_locks = 0;
Debug(DebugFail,"MutexPrivate::locks() is %d [%p]",locks,this);
}
} }
if (!s_unsafe) if (!s_unsafe)
#ifdef _WINDOWS #ifdef _WINDOWS
@ -352,7 +364,8 @@ bool MutexPrivate::unlock()
} }
else else
Debug(DebugFail,"MutexPrivate::unlock called on unlocked '%s' [%p]",m_name,this); Debug(DebugFail,"MutexPrivate::unlock called on unlocked '%s' [%p]",m_name,this);
GlobalMutex::unlock(); if (s_safety)
GlobalMutex::unlock();
return ok; return ok;
} }
@ -395,14 +408,17 @@ bool SemaphorePrivate::lock(long maxwait)
maxwait = (long)s_maxwait; maxwait = (long)s_maxwait;
warn = true; warn = true;
} }
GlobalMutex::lock(); if (s_safety)
GlobalMutex::lock();
ref(); ref();
s_locks++;
m_waiting++;
Thread* thr = Thread::current(); Thread* thr = Thread::current();
if (thr) if (thr)
thr->m_locking = true; thr->m_locking = true;
GlobalMutex::unlock(); if (s_safety) {
s_locks++;
m_waiting++;
GlobalMutex::unlock();
}
#ifdef _WINDOWS #ifdef _WINDOWS
DWORD ms = 0; DWORD ms = 0;
if (maxwait < 0) if (maxwait < 0)
@ -443,19 +459,22 @@ bool SemaphorePrivate::lock(long maxwait)
#endif // HAVE_TIMEDWAIT #endif // HAVE_TIMEDWAIT
} }
#endif // _WINDOWS #endif // _WINDOWS
GlobalMutex::lock(); if (s_safety) {
m_waiting--; GlobalMutex::lock();
int locks = --s_locks; int locks = --s_locks;
if (locks < 0) { if (locks < 0) {
// this is very very bad - abort right now // this is very very bad - abort right now
abortOnBug(true); abortOnBug(true);
s_locks = 0; s_locks = 0;
Debug(DebugFail,"SemaphorePrivate::locks() is %d [%p]",locks,this); Debug(DebugFail,"SemaphorePrivate::locks() is %d [%p]",locks,this);
}
m_waiting--;
} }
if (thr) if (thr)
thr->m_locking = false; thr->m_locking = false;
deref(); deref();
GlobalMutex::unlock(); if (s_safety)
GlobalMutex::unlock();
if (warn && !rval) if (warn && !rval)
Debug(DebugFail,"Thread '%s' could not lock semaphore '%s' waited by %u others for %lu usec!", Debug(DebugFail,"Thread '%s' could not lock semaphore '%s' waited by %u others for %lu usec!",
Thread::currentName(),m_name,m_waiting,maxwait); Thread::currentName(),m_name,m_waiting,maxwait);
@ -464,7 +483,8 @@ bool SemaphorePrivate::lock(long maxwait)
bool SemaphorePrivate::unlock() bool SemaphorePrivate::unlock()
{ {
GlobalMutex::lock(); if (s_safety)
GlobalMutex::lock();
ref(); ref();
if (!s_unsafe) { if (!s_unsafe) {
#ifdef _WINDOWS #ifdef _WINDOWS
@ -476,7 +496,8 @@ bool SemaphorePrivate::unlock()
#endif #endif
} }
deref(); deref();
GlobalMutex::unlock(); if (s_safety)
GlobalMutex::unlock();
return true; return true;
} }
@ -508,6 +529,11 @@ void Lockable::startUsingNow()
s_unsafe = false; s_unsafe = false;
} }
void Lockable::disableSafety()
{
s_safety = false;
}
void Lockable::wait(unsigned long maxwait) void Lockable::wait(unsigned long maxwait)
{ {
s_maxwait = maxwait; s_maxwait = maxwait;

View File

@ -4259,6 +4259,13 @@ public:
* before creating any threads and without holding any object locked. * before creating any threads and without holding any object locked.
*/ */
static void startUsingNow(); static void startUsingNow();
/**
* Disable some safety and sanity check features.
* This provides a performance improvement but makes the code less safe and
* more difficult to debug locking issues.
*/
static void disableSafety();
}; };
/** /**