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
Attempt to debug mutex deadlocks by setting a maximum 10s limit, if repeated halves the limit
.TP
.B \-Dd
Disable some locking debugging and safety features, improves performance instead
.TP
.B \-Dl
Attempt to load modules without having their symbols globally visible
.TP

View File

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

View File

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

View File

@ -4259,6 +4259,13 @@ public:
* before creating any threads and without holding any object locked.
*/
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();
};
/**