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:
parent
242ae2be8d
commit
0883e02e29
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue