Added Semaphore class, made Mutex derive from (new class) Lockable, made Lock able to get a lock on any Lockable - Mutex or Semaphore.
Use pthread_mutex_timedlock and sem_timedwait if available on platform. Fixed a bug in the IAX channel exposed by Mutex having virtual methods. git-svn-id: http://voip.null.ro/svn/yate@2761 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
parent
25450eaaff
commit
09b07f4b00
43
configure.in
43
configure.in
|
@ -82,7 +82,7 @@ AC_MSG_RESULT([$ld_unresolved_symbols])
|
|||
# Checks for header files.
|
||||
AC_HEADER_DIRENT
|
||||
AC_HEADER_STDC
|
||||
AC_CHECK_HEADERS([fcntl.h arpa/inet.h netdb.h netinet/in.h sys/ioctl.h sys/socket.h sys/time.h], , [AC_MSG_ERROR([This header file is required.])])
|
||||
AC_CHECK_HEADERS([fcntl.h semaphore.h arpa/inet.h netdb.h netinet/in.h sys/ioctl.h sys/socket.h sys/time.h], , [AC_MSG_ERROR([This header file is required.])])
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_CONST
|
||||
|
@ -133,11 +133,12 @@ AC_SUBST(DLOPEN_LIB)
|
|||
LIBS="$SAVE_LIBS"
|
||||
|
||||
MUTEX_HACK=""
|
||||
AC_MSG_CHECKING([for pthread_mutexattr_settype declaration])
|
||||
AC_LANG_SAVE
|
||||
AC_LANG_C
|
||||
SAVE_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS -Wall -Werror"
|
||||
|
||||
AC_MSG_CHECKING([for pthread_mutexattr_settype declaration])
|
||||
AC_TRY_COMPILE([
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
@ -148,12 +149,46 @@ pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE_NP);
|
|||
have_mutex_settype="yes",
|
||||
have_mutex_settype="no"
|
||||
)
|
||||
CFLAGS="$SAVE_CFLAGS"
|
||||
AC_LANG_RESTORE
|
||||
if [[ "$have_mutex_settype" = "no" ]]; then
|
||||
MUTEX_HACK="-DMUTEX_HACK"
|
||||
fi
|
||||
AC_MSG_RESULT([$have_mutex_settype])
|
||||
|
||||
AC_MSG_CHECKING([for pthread_mutex_timedlock declaration])
|
||||
AC_TRY_COMPILE([
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
],[
|
||||
pthread_mutex_t mutex;
|
||||
struct timespec tout;
|
||||
pthread_mutex_timedlock(&mutex,&tout);
|
||||
],
|
||||
have_mutex_timedlock="yes",
|
||||
have_mutex_timedlock="no"
|
||||
)
|
||||
if [[ "$have_mutex_timedlock" = "yes" ]]; then
|
||||
MUTEX_HACK="$MUTEX_HACK -DHAVE_TIMEDLOCK"
|
||||
fi
|
||||
AC_MSG_RESULT([$have_mutex_timedlock])
|
||||
|
||||
AC_MSG_CHECKING([for sem_timedwait declaration])
|
||||
AC_TRY_COMPILE([
|
||||
#include <semaphore.h>
|
||||
],[
|
||||
sem_t sem;
|
||||
struct timespec tout;
|
||||
sem_timedwait(&sem,&tout);
|
||||
],
|
||||
have_sem_timedwait="yes",
|
||||
have_sem_timedwait="no"
|
||||
)
|
||||
if [[ "$have_sem_timedwait" = "yes" ]]; then
|
||||
MUTEX_HACK="$MUTEX_HACK -DHAVE_TIMEDWAIT"
|
||||
fi
|
||||
AC_MSG_RESULT([$have_sem_timedwait])
|
||||
|
||||
CFLAGS="$SAVE_CFLAGS"
|
||||
AC_LANG_RESTORE
|
||||
AC_SUBST(MUTEX_HACK)
|
||||
|
||||
THREAD_KILL=""
|
||||
|
|
|
@ -161,7 +161,7 @@ bool CallEndpoint::disconnect(bool final, const char* reason, bool notify, const
|
|||
DDebug(DebugAll,"CallEndpoint '%s' disconnecting peer %p from [%p]",m_id.c_str(),m_peer,this);
|
||||
|
||||
Lock lock(s_mutex,5000000);
|
||||
if (!lock.mutex()) {
|
||||
if (!lock.locked()) {
|
||||
Debug(DebugFail,"Call disconnect failed - deadlock on call endpoint mutex!");
|
||||
Engine::restart(0);
|
||||
return false;
|
||||
|
|
|
@ -515,7 +515,7 @@ unsigned long DataSource::Forward(const DataBlock& data, unsigned long tStamp, u
|
|||
{
|
||||
Lock mylock(this,100000);
|
||||
// we DON'T refcount here, we rely on the mutex to keep us safe
|
||||
if (!(mylock.mutex() && alive())) {
|
||||
if (!(mylock.locked() && alive())) {
|
||||
DDebug(DebugInfo,"Forwarding on a dead DataSource! [%p]",this);
|
||||
return 0;
|
||||
}
|
||||
|
@ -627,7 +627,7 @@ void DataSource::clear()
|
|||
void DataSource::synchronize(unsigned long tStamp)
|
||||
{
|
||||
Lock mylock(this,100000);
|
||||
if (!(mylock.mutex() && alive())) {
|
||||
if (!(mylock.locked() && alive())) {
|
||||
DDebug(DebugInfo,"Synchronizing on a dead DataSource! [%p]",this);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -302,6 +302,8 @@ bool EngineStatusHandler::received(Message &msg)
|
|||
msg.retValue() << ",workers=" << EnginePrivate::count;
|
||||
msg.retValue() << ",mutexes=" << Mutex::count();
|
||||
msg.retValue() << ",locks=" << Mutex::locks();
|
||||
msg.retValue() << ",semaphores=" << Semaphore::count();
|
||||
msg.retValue() << ",waiting=" << Semaphore::locks();
|
||||
msg.retValue() << "\r\n";
|
||||
return false;
|
||||
}
|
||||
|
@ -1500,7 +1502,7 @@ int Engine::main(int argc, const char** argv, const char** env, RunMode mode, bo
|
|||
const char* usrpath = 0;
|
||||
int debug_level = debugLevel();
|
||||
|
||||
Mutex::startUsingNow();
|
||||
Lockable::startUsingNow();
|
||||
|
||||
const char* cfgfile = ::strrchr(argv[0],'/');
|
||||
if (!cfgfile)
|
||||
|
@ -1680,7 +1682,7 @@ int Engine::main(int argc, const char** argv, const char** env, RunMode mode, bo
|
|||
s_lateabrt = true;
|
||||
break;
|
||||
case 'm':
|
||||
Mutex::wait(10000000);
|
||||
Lockable::wait(10000000);
|
||||
break;
|
||||
#ifdef RTLD_GLOBAL
|
||||
case 'l':
|
||||
|
|
310
engine/Mutex.cpp
310
engine/Mutex.cpp
|
@ -25,10 +25,12 @@
|
|||
#ifdef _WINDOWS
|
||||
|
||||
typedef HANDLE HMUTEX;
|
||||
typedef HANDLE HSEMAPHORE;
|
||||
|
||||
#else
|
||||
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
#ifdef MUTEX_HACK
|
||||
extern "C" {
|
||||
|
@ -42,6 +44,7 @@ extern int pthread_mutexattr_settype(pthread_mutexattr_t *__attr, int __kind) __
|
|||
#endif
|
||||
|
||||
typedef pthread_mutex_t HMUTEX;
|
||||
typedef sem_t HSEMAPHORE;
|
||||
|
||||
#endif /* ! _WINDOWS */
|
||||
|
||||
|
@ -69,7 +72,7 @@ public:
|
|||
bool locked() const
|
||||
{ return (m_locked > 0); }
|
||||
bool lock(long maxwait);
|
||||
void unlock();
|
||||
bool unlock();
|
||||
static volatile int s_count;
|
||||
static volatile int s_locks;
|
||||
private:
|
||||
|
@ -81,6 +84,30 @@ private:
|
|||
const char* m_owner;
|
||||
};
|
||||
|
||||
class SemaphorePrivate {
|
||||
public:
|
||||
SemaphorePrivate(unsigned int maxcount, const char* name);
|
||||
~SemaphorePrivate();
|
||||
inline void ref()
|
||||
{ ++m_refcount; }
|
||||
inline void deref()
|
||||
{ if (!--m_refcount) delete this; }
|
||||
inline const char* name() const
|
||||
{ return m_name; }
|
||||
bool locked() const
|
||||
{ return (m_waiting > 0); }
|
||||
bool lock(long maxwait);
|
||||
bool unlock();
|
||||
static volatile int s_count;
|
||||
static volatile int s_locks;
|
||||
private:
|
||||
HSEMAPHORE m_semaphore;
|
||||
int m_refcount;
|
||||
volatile unsigned int m_waiting;
|
||||
unsigned int m_maxcount;
|
||||
const char* m_name;
|
||||
};
|
||||
|
||||
class GlobalMutex {
|
||||
public:
|
||||
GlobalMutex();
|
||||
|
@ -103,6 +130,8 @@ static bool s_unsafe = MUTEX_STATIC_UNSAFE;
|
|||
|
||||
volatile int MutexPrivate::s_count = 0;
|
||||
volatile int MutexPrivate::s_locks = 0;
|
||||
volatile int SemaphorePrivate::s_count = 0;
|
||||
volatile int SemaphorePrivate::s_locks = 0;
|
||||
bool GlobalMutex::s_init = true;
|
||||
|
||||
// WARNING!!!
|
||||
|
@ -211,7 +240,6 @@ bool MutexPrivate::lock(long maxwait)
|
|||
{
|
||||
bool rval = false;
|
||||
bool warn = false;
|
||||
bool dead = false;
|
||||
if (s_maxwait && (maxwait < 0)) {
|
||||
maxwait = (long)s_maxwait;
|
||||
warn = true;
|
||||
|
@ -226,9 +254,8 @@ bool MutexPrivate::lock(long maxwait)
|
|||
DWORD ms = 0;
|
||||
if (maxwait < 0)
|
||||
ms = INFINITE;
|
||||
else if (maxwait > 0) {
|
||||
else if (maxwait > 0)
|
||||
ms = (DWORD)(maxwait / 1000);
|
||||
}
|
||||
rval = s_unsafe || (::WaitForSingleObject(m_mutex,ms) == WAIT_OBJECT_0);
|
||||
#else
|
||||
if (s_unsafe)
|
||||
|
@ -239,6 +266,15 @@ bool MutexPrivate::lock(long maxwait)
|
|||
rval = !::pthread_mutex_trylock(&m_mutex);
|
||||
else {
|
||||
u_int64_t t = Time::now() + maxwait;
|
||||
#ifdef HAVE_TIMEDLOCK
|
||||
struct timeval tv;
|
||||
struct timespec ts;
|
||||
Time::toTimeval(&tv,t);
|
||||
ts.tv_sec = tv.tv_sec;
|
||||
ts.tv_nsec = 1000 * tv.tv_usec;
|
||||
rval = !::pthread_mutex_timedlock(&m_mutex,&ts);
|
||||
#else
|
||||
bool dead = false;
|
||||
do {
|
||||
if (!dead) {
|
||||
dead = Thread::check(false);
|
||||
|
@ -251,8 +287,9 @@ bool MutexPrivate::lock(long maxwait)
|
|||
break;
|
||||
Thread::yield();
|
||||
} while (t > Time::now());
|
||||
#endif // HAVE_TIMEDLOCK
|
||||
}
|
||||
#endif
|
||||
#endif // _WINDOWS
|
||||
GlobalMutex::lock();
|
||||
if (thr)
|
||||
thr->m_locking = false;
|
||||
|
@ -275,8 +312,9 @@ bool MutexPrivate::lock(long maxwait)
|
|||
return rval;
|
||||
}
|
||||
|
||||
void MutexPrivate::unlock()
|
||||
bool MutexPrivate::unlock()
|
||||
{
|
||||
bool ok = false;
|
||||
// Hope we don't hit a bug related to the debug mutex!
|
||||
GlobalMutex::lock();
|
||||
if (m_locked) {
|
||||
|
@ -304,10 +342,169 @@ void MutexPrivate::unlock()
|
|||
::pthread_mutex_unlock(&m_mutex);
|
||||
#endif
|
||||
deref();
|
||||
ok = true;
|
||||
}
|
||||
else
|
||||
Debug(DebugFail,"MutexPrivate::unlock called on unlocked '%s' [%p]",m_name,this);
|
||||
GlobalMutex::unlock();
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
SemaphorePrivate::SemaphorePrivate(unsigned int maxcount, const char* name)
|
||||
: m_refcount(1), m_waiting(0), m_maxcount(maxcount),
|
||||
m_name(name)
|
||||
{
|
||||
GlobalMutex::lock();
|
||||
s_count++;
|
||||
#ifdef _WINDOWS
|
||||
m_semaphore = ::CreateSemaphore(NULL,1,maxcount,NULL);
|
||||
#else
|
||||
::sem_init(&m_semaphore,0,1);
|
||||
#endif
|
||||
GlobalMutex::unlock();
|
||||
}
|
||||
|
||||
SemaphorePrivate::~SemaphorePrivate()
|
||||
{
|
||||
GlobalMutex::lock();
|
||||
s_count--;
|
||||
#ifdef _WINDOWS
|
||||
::CloseHandle(m_semaphore);
|
||||
m_semaphore = 0;
|
||||
#else
|
||||
::sem_destroy(&m_semaphore);
|
||||
#endif
|
||||
GlobalMutex::unlock();
|
||||
if (m_waiting)
|
||||
Debug(DebugFail,"SemaphorePrivate '%s' destroyed with %u locks [%p]",
|
||||
m_name,m_waiting,this);
|
||||
}
|
||||
|
||||
bool SemaphorePrivate::lock(long maxwait)
|
||||
{
|
||||
bool rval = false;
|
||||
bool warn = false;
|
||||
if (s_maxwait && (maxwait < 0)) {
|
||||
maxwait = (long)s_maxwait;
|
||||
warn = true;
|
||||
}
|
||||
GlobalMutex::lock();
|
||||
ref();
|
||||
s_locks++;
|
||||
m_waiting++;
|
||||
Thread* thr = Thread::current();
|
||||
if (thr)
|
||||
thr->m_locking = true;
|
||||
GlobalMutex::unlock();
|
||||
#ifdef _WINDOWS
|
||||
DWORD ms = 0;
|
||||
if (maxwait < 0)
|
||||
ms = INFINITE;
|
||||
else if (maxwait > 0)
|
||||
ms = (DWORD)(maxwait / 1000);
|
||||
rval = s_unsafe || (::WaitForSingleObject(m_semaphore,ms) == WAIT_OBJECT_0);
|
||||
#else
|
||||
if (s_unsafe)
|
||||
rval = true;
|
||||
else if (maxwait < 0)
|
||||
rval = !::sem_wait(&m_semaphore);
|
||||
else if (!maxwait)
|
||||
rval = !::sem_trywait(&m_semaphore);
|
||||
else {
|
||||
u_int64_t t = Time::now() + maxwait;
|
||||
#ifdef HAVE_TIMEDWAIT
|
||||
struct timeval tv;
|
||||
struct timespec ts;
|
||||
Time::toTimeval(&tv,t);
|
||||
ts.tv_sec = tv.tv_sec;
|
||||
ts.tv_nsec = 1000 * tv.tv_usec;
|
||||
rval = !::sem_timedwait(&m_semaphore,&ts);
|
||||
#else
|
||||
bool dead = false;
|
||||
do {
|
||||
if (!dead) {
|
||||
dead = Thread::check(false);
|
||||
// give up only if caller asked for a limited wait
|
||||
if (dead && !warn)
|
||||
break;
|
||||
}
|
||||
rval = !::sem_trywait(&m_semaphore);
|
||||
if (rval)
|
||||
break;
|
||||
Thread::yield();
|
||||
} while (t > Time::now());
|
||||
#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 (thr)
|
||||
thr->m_locking = false;
|
||||
if (!rval)
|
||||
deref();
|
||||
GlobalMutex::unlock();
|
||||
if (warn && !rval)
|
||||
Debug(DebugFail,"Thread '%s' could not lock semaphore '%s' for %lu usec!",
|
||||
Thread::currentName(),m_name,maxwait);
|
||||
return rval;
|
||||
}
|
||||
|
||||
bool SemaphorePrivate::unlock()
|
||||
{
|
||||
if (!s_unsafe) {
|
||||
#ifdef _WINDOWS
|
||||
::ReleaseSemaphore(m_semaphore,1,NULL);
|
||||
#else
|
||||
int val = 0;
|
||||
if (!::sem_getvalue(&m_semaphore,&val) && (val < (int)m_maxcount))
|
||||
::sem_post(&m_semaphore);
|
||||
#endif
|
||||
}
|
||||
GlobalMutex::lock();
|
||||
deref();
|
||||
GlobalMutex::unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Lockable::~Lockable()
|
||||
{
|
||||
}
|
||||
|
||||
bool Lockable::check(long maxwait)
|
||||
{
|
||||
bool ret = lock(maxwait);
|
||||
if (ret)
|
||||
unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Lockable::unlockAll()
|
||||
{
|
||||
while (locked()) {
|
||||
if (!unlock())
|
||||
return false;
|
||||
Thread::yield();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Lockable::startUsingNow()
|
||||
{
|
||||
s_unsafe = false;
|
||||
}
|
||||
|
||||
void Lockable::wait(unsigned long maxwait)
|
||||
{
|
||||
s_maxwait = maxwait;
|
||||
}
|
||||
|
||||
|
||||
|
@ -326,7 +523,7 @@ Mutex::Mutex(const Mutex &original)
|
|||
|
||||
Mutex::~Mutex()
|
||||
{
|
||||
MutexPrivate *priv = m_private;
|
||||
MutexPrivate* priv = m_private;
|
||||
m_private = 0;
|
||||
if (priv)
|
||||
priv->deref();
|
||||
|
@ -334,14 +531,14 @@ Mutex::~Mutex()
|
|||
|
||||
Mutex& Mutex::operator=(const Mutex& original)
|
||||
{
|
||||
MutexPrivate *priv = m_private;
|
||||
MutexPrivate* priv = m_private;
|
||||
m_private = original.privDataCopy();
|
||||
if (priv)
|
||||
priv->deref();
|
||||
return *this;
|
||||
}
|
||||
|
||||
MutexPrivate *Mutex::privDataCopy() const
|
||||
MutexPrivate* Mutex::privDataCopy() const
|
||||
{
|
||||
if (m_private)
|
||||
m_private->ref();
|
||||
|
@ -350,21 +547,12 @@ MutexPrivate *Mutex::privDataCopy() const
|
|||
|
||||
bool Mutex::lock(long maxwait)
|
||||
{
|
||||
return m_private ? m_private->lock(maxwait) : false;
|
||||
return m_private && m_private->lock(maxwait);
|
||||
}
|
||||
|
||||
void Mutex::unlock()
|
||||
bool Mutex::unlock()
|
||||
{
|
||||
if (m_private)
|
||||
m_private->unlock();
|
||||
}
|
||||
|
||||
bool Mutex::check(long maxwait)
|
||||
{
|
||||
bool ret = lock(maxwait);
|
||||
if (ret)
|
||||
unlock();
|
||||
return ret;
|
||||
return m_private && m_private->unlock();
|
||||
}
|
||||
|
||||
bool Mutex::recursive() const
|
||||
|
@ -387,14 +575,86 @@ int Mutex::locks()
|
|||
return MutexPrivate::s_locks;
|
||||
}
|
||||
|
||||
void Mutex::startUsingNow()
|
||||
bool Mutex::efficientTimedLock()
|
||||
{
|
||||
s_unsafe = false;
|
||||
#if defined(_WINDOWS) || defined(HAVE_TIMEDLOCK)
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Mutex::wait(unsigned long maxwait)
|
||||
|
||||
Semaphore::Semaphore(unsigned int maxcount, const char* name)
|
||||
: m_private(0)
|
||||
{
|
||||
s_maxwait = maxwait;
|
||||
if (!name)
|
||||
name = "?";
|
||||
if (maxcount)
|
||||
m_private = new SemaphorePrivate(maxcount,name);
|
||||
}
|
||||
|
||||
Semaphore::Semaphore(const Semaphore &original)
|
||||
: m_private(original.privDataCopy())
|
||||
{
|
||||
}
|
||||
|
||||
Semaphore::~Semaphore()
|
||||
{
|
||||
SemaphorePrivate* priv = m_private;
|
||||
m_private = 0;
|
||||
if (priv)
|
||||
priv->deref();
|
||||
}
|
||||
|
||||
Semaphore& Semaphore::operator=(const Semaphore& original)
|
||||
{
|
||||
SemaphorePrivate* priv = m_private;
|
||||
m_private = original.privDataCopy();
|
||||
if (priv)
|
||||
priv->deref();
|
||||
return *this;
|
||||
}
|
||||
|
||||
SemaphorePrivate* Semaphore::privDataCopy() const
|
||||
{
|
||||
if (m_private)
|
||||
m_private->ref();
|
||||
return m_private;
|
||||
}
|
||||
|
||||
bool Semaphore::lock(long maxwait)
|
||||
{
|
||||
return m_private && m_private->lock(maxwait);
|
||||
}
|
||||
|
||||
bool Semaphore::unlock()
|
||||
{
|
||||
return m_private && m_private->unlock();
|
||||
}
|
||||
|
||||
bool Semaphore::locked() const
|
||||
{
|
||||
return m_private && m_private->locked();
|
||||
}
|
||||
|
||||
int Semaphore::count()
|
||||
{
|
||||
return SemaphorePrivate::s_count;
|
||||
}
|
||||
|
||||
int Semaphore::locks()
|
||||
{
|
||||
return SemaphorePrivate::s_locks;
|
||||
}
|
||||
|
||||
bool Semaphore::efficientTimedLock()
|
||||
{
|
||||
#if defined(_WINDOWS) || defined(HAVE_TIMEDWAIT)
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -485,7 +485,7 @@ void ForkModule::initialize()
|
|||
bool ForkModule::unload()
|
||||
{
|
||||
Lock lock(s_mutex,500000);
|
||||
if (!lock.mutex())
|
||||
if (!lock.locked())
|
||||
return false;
|
||||
if (s_calls.count())
|
||||
return false;
|
||||
|
|
|
@ -980,7 +980,7 @@ bool ConferenceDriver::checkRoom(String& room, bool existing, bool counted)
|
|||
bool ConferenceDriver::unload()
|
||||
{
|
||||
Lock lock(this,500000);
|
||||
if (!lock.mutex())
|
||||
if (!lock.locked())
|
||||
return false;
|
||||
if (isBusy() || s_rooms.count())
|
||||
return false;
|
||||
|
|
|
@ -360,7 +360,7 @@ void MuxSource::consume(MuxConsumer& consumer, const DataBlock& data, unsigned l
|
|||
if (!data.length() || consumer.m_owner != this)
|
||||
return;
|
||||
Lock lock(m_lock,100000);
|
||||
if (!(lock.mutex() && alive())) {
|
||||
if (!(lock.locked() && alive())) {
|
||||
Debug(this,DebugMild,"Locking failed, dropping %u bytes [%p]",data.length(),this);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -524,9 +524,9 @@ private:
|
|||
* Local data
|
||||
*/
|
||||
static Configuration s_cfg; // Configuration file
|
||||
static YIAXDriver iplugin; // Init the driver
|
||||
static YIAXLineContainer s_lines; // Lines
|
||||
static Thread::Priority s_priority = Thread::Normal; // Threads priority
|
||||
static YIAXDriver iplugin; // Init the driver
|
||||
|
||||
|
||||
/*
|
||||
|
|
215
yateclass.h
215
yateclass.h
|
@ -3563,13 +3563,77 @@ protected:
|
|||
};
|
||||
|
||||
class MutexPrivate;
|
||||
class SemaphorePrivate;
|
||||
class ThreadPrivate;
|
||||
|
||||
/**
|
||||
* An abstract base class for implementing lockable objects
|
||||
* @short Abstract interface for lockable objects
|
||||
*/
|
||||
class YATE_API Lockable
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~Lockable();
|
||||
|
||||
/**
|
||||
* Attempt to lock the object and eventually wait for it
|
||||
* @param maxwait Time in microseconds to wait, -1 wait forever
|
||||
* @return True if successfully locked, false on failure
|
||||
*/
|
||||
virtual bool lock(long maxwait = -1) = 0;
|
||||
|
||||
/**
|
||||
* Unlock the object, does never wait
|
||||
* @return True if successfully unlocked the object
|
||||
*/
|
||||
virtual bool unlock() = 0;
|
||||
|
||||
/**
|
||||
* Check if the object is currently locked - as it's asynchronous it
|
||||
* guarantees nothing if other thread changes the status
|
||||
* @return True if the object was locked when the function was called
|
||||
*/
|
||||
virtual bool locked() const = 0;
|
||||
|
||||
/**
|
||||
* Check if the object is unlocked (try to lock and unlock it)
|
||||
* @param maxwait Time in microseconds to wait, -1 to wait forever
|
||||
* @return True if successfully locked and unlocked, false on failure
|
||||
*/
|
||||
virtual bool check(long maxwait = -1);
|
||||
|
||||
/**
|
||||
* Fully unlock the object, even if it was previously multiple locked.
|
||||
* There is no guarantee about the object status after the function returns.
|
||||
* This function should be used only if you understand it very well
|
||||
* @return True if the object was fully unlocked
|
||||
*/
|
||||
virtual bool unlockAll();
|
||||
|
||||
/**
|
||||
* Set a maximum wait time for debugging purposes
|
||||
* @param maxwait Maximum time in microseconds to wait for any lockable
|
||||
* object when no time limit was requested, zero to disable limit
|
||||
*/
|
||||
static void wait(unsigned long maxwait);
|
||||
|
||||
/**
|
||||
* Start actually using lockables, for platforms where these objects are not
|
||||
* usable in global object constructors.
|
||||
* This method must be called at least once somewhere from main() but
|
||||
* before creating any threads and without holding any object locked.
|
||||
*/
|
||||
static void startUsingNow();
|
||||
};
|
||||
|
||||
/**
|
||||
* A simple mutual exclusion for locking access between threads
|
||||
* @short Mutex support
|
||||
*/
|
||||
class YATE_API Mutex
|
||||
class YATE_API Mutex : public Lockable
|
||||
{
|
||||
friend class MutexPrivate;
|
||||
public:
|
||||
|
@ -3582,7 +3646,7 @@ public:
|
|||
Mutex(bool recursive = false, const char* name = 0);
|
||||
|
||||
/**
|
||||
* Copy constructor creates a shared mutex
|
||||
* Copy constructor, creates a shared mutex
|
||||
* @param original Reference of the mutex to share
|
||||
*/
|
||||
Mutex(const Mutex& original);
|
||||
|
@ -3603,26 +3667,20 @@ public:
|
|||
* @param maxwait Time in microseconds to wait for the mutex, -1 wait forever
|
||||
* @return True if successfully locked, false on failure
|
||||
*/
|
||||
bool lock(long maxwait = -1);
|
||||
virtual bool lock(long maxwait = -1);
|
||||
|
||||
/**
|
||||
* Unlock the mutex, does never wait
|
||||
* @return True if successfully unlocked the mutex
|
||||
*/
|
||||
void unlock();
|
||||
virtual bool unlock();
|
||||
|
||||
/**
|
||||
* Check if the mutex is currently locked - as it's asynchronous it
|
||||
* guarantees nothing if other thread changes the mutex's status
|
||||
* @return True if the mutex was locked when the function was called
|
||||
*/
|
||||
bool locked() const;
|
||||
|
||||
/**
|
||||
* Check if the mutex is unlocked (try to lock and unlock the mutex)
|
||||
* @param maxwait Time in microseconds to wait for the mutex, -1 wait forever
|
||||
* @return True if successfully locked and unlocked, false on failure
|
||||
*/
|
||||
bool check(long maxwait = -1);
|
||||
virtual bool locked() const;
|
||||
|
||||
/**
|
||||
* Check if this mutex is recursive or not
|
||||
|
@ -3643,19 +3701,10 @@ public:
|
|||
static int locks();
|
||||
|
||||
/**
|
||||
* Set a maximum mutex wait time for debugging purposes
|
||||
* @param maxwait Maximum time in microseconds to wait for any mutex
|
||||
* when no time limit was requested, zero to disable limit
|
||||
* Check if a timed lock() is efficient on this platform
|
||||
* @return True if a lock with a maxwait parameter is efficiently implemented
|
||||
*/
|
||||
static void wait(unsigned long maxwait);
|
||||
|
||||
/**
|
||||
* Start actually using mutexes, for platforms where mutexes are not
|
||||
* usable in global object constructors.
|
||||
* This method must be called at least once somewhere from main() but
|
||||
* before creating any threads and without holding any mutex locked.
|
||||
*/
|
||||
static void startUsingNow();
|
||||
static bool efficientTimedLock();
|
||||
|
||||
private:
|
||||
MutexPrivate* privDataCopy() const;
|
||||
|
@ -3663,50 +3712,125 @@ private:
|
|||
};
|
||||
|
||||
/**
|
||||
* A lock is a stack allocated (automatic) object that locks a mutex on
|
||||
* creation and unlocks it on destruction - typically when exiting a block
|
||||
* @short Ephemeral mutex locking object
|
||||
* A semaphore object for synchronizing threads, can also be used as a token bucket
|
||||
* @short Semaphore implementation
|
||||
*/
|
||||
class YATE_API Semaphore : public Lockable
|
||||
{
|
||||
friend class SemaphorePrivate;
|
||||
public:
|
||||
/**
|
||||
* Construct a new unlocked semaphore
|
||||
* @param maxcount Maximum unlock count, must be strictly positive
|
||||
* @param name Static name of the semaphore (for debugging purpose only)
|
||||
*/
|
||||
Semaphore(unsigned int maxcount = 1, const char* name = 0);
|
||||
|
||||
/**
|
||||
* Copy constructor, creates a shared semaphore
|
||||
* @param original Reference of the semaphore to share
|
||||
*/
|
||||
Semaphore(const Semaphore& original);
|
||||
|
||||
/**
|
||||
* Destroy the semaphore
|
||||
*/
|
||||
~Semaphore();
|
||||
|
||||
/**
|
||||
* Assignment operator makes the semaphore shared with the original
|
||||
* @param original Reference of the semaphore to share
|
||||
*/
|
||||
Semaphore& operator=(const Semaphore& original);
|
||||
|
||||
/**
|
||||
* Attempt to get a lock on the semaphore and eventually wait for it
|
||||
* @param maxwait Time in microseconds to wait, -1 wait forever
|
||||
* @return True if successfully locked, false on failure
|
||||
*/
|
||||
virtual bool lock(long maxwait = -1);
|
||||
|
||||
/**
|
||||
* Unlock the semaphore, does never wait nor get over counter maximum
|
||||
* @return True if successfully unlocked
|
||||
*/
|
||||
virtual bool unlock();
|
||||
|
||||
/**
|
||||
* Check if the semaphore is currently locked (waiting) - as it's
|
||||
* asynchronous it guarantees nothing if other thread changes status
|
||||
* @return True if the semaphore was locked when the function was called
|
||||
*/
|
||||
virtual bool locked() const;
|
||||
|
||||
/**
|
||||
* Get the number of semaphores counting the shared ones only once
|
||||
* @return Count of individual semaphores
|
||||
*/
|
||||
static int count();
|
||||
|
||||
/**
|
||||
* Get the number of currently locked (waiting) semaphores
|
||||
* @return Count of locked semaphores, should be zero at program exit
|
||||
*/
|
||||
static int locks();
|
||||
|
||||
/**
|
||||
* Check if a timed lock() is efficient on this platform
|
||||
* @return True if a lock with a maxwait parameter is efficiently implemented
|
||||
*/
|
||||
static bool efficientTimedLock();
|
||||
|
||||
private:
|
||||
SemaphorePrivate* privDataCopy() const;
|
||||
SemaphorePrivate* m_private;
|
||||
};
|
||||
|
||||
/**
|
||||
* A lock is a stack allocated (automatic) object that locks a lockable object
|
||||
* on creation and unlocks it on destruction - typically when exiting a block
|
||||
* @short Ephemeral mutex or semaphore locking object
|
||||
*/
|
||||
class YATE_API Lock
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Create the lock, try to lock the mutex
|
||||
* @param mutex Reference to the mutex to lock
|
||||
* @param maxwait Time in microseconds to wait for the mutex, -1 wait forever
|
||||
* Create the lock, try to lock the object
|
||||
* @param lck Reference to the object to lock
|
||||
* @param maxwait Time in microseconds to wait, -1 wait forever
|
||||
*/
|
||||
inline Lock(Mutex& mutex, long maxwait = -1)
|
||||
{ m_mutex = mutex.lock(maxwait) ? &mutex : 0; }
|
||||
inline Lock(Lockable& lck, long maxwait = -1)
|
||||
{ m_lock = lck.lock(maxwait) ? &lck : 0; }
|
||||
|
||||
/**
|
||||
* Create the lock, try to lock the mutex
|
||||
* @param mutex Pointer to the mutex to lock
|
||||
* @param maxwait Time in microseconds to wait for the mutex, -1 wait forever
|
||||
* Create the lock, try to lock the object
|
||||
* @param lck Pointer to the object to lock
|
||||
* @param maxwait Time in microseconds to wait, -1 wait forever
|
||||
*/
|
||||
inline Lock(Mutex* mutex, long maxwait = -1)
|
||||
{ m_mutex = (mutex && mutex->lock(maxwait)) ? mutex : 0; }
|
||||
inline Lock(Lockable* lck, long maxwait = -1)
|
||||
{ m_lock = (lck && lck->lock(maxwait)) ? lck : 0; }
|
||||
|
||||
/**
|
||||
* Destroy the lock, unlock the mutex if it was locked
|
||||
*/
|
||||
inline ~Lock()
|
||||
{ if (m_mutex) m_mutex->unlock(); }
|
||||
{ if (m_lock) m_lock->unlock(); }
|
||||
|
||||
/**
|
||||
* Return a pointer to the mutex this lock holds
|
||||
* @return A mutex pointer or NULL if locking failed
|
||||
* Return a pointer to the lockable object this lock holds
|
||||
* @return A pointer to a Lockable or NULL if locking failed
|
||||
*/
|
||||
inline Mutex* mutex() const
|
||||
{ return m_mutex; }
|
||||
inline Lockable* locked() const
|
||||
{ return m_lock; }
|
||||
|
||||
/**
|
||||
* Unlock the mutex if it was locked and drop the reference to it
|
||||
* Unlock the object if it was locked and drop the reference to it
|
||||
*/
|
||||
inline void drop()
|
||||
{ if (m_mutex) m_mutex->unlock(); m_mutex = 0; }
|
||||
{ if (m_lock) m_lock->unlock(); m_lock = 0; }
|
||||
|
||||
private:
|
||||
Mutex* m_mutex;
|
||||
Lockable* m_lock;
|
||||
|
||||
/** Make sure no Lock is ever created on heap */
|
||||
inline void* operator new(size_t);
|
||||
|
@ -3828,6 +3952,7 @@ class YATE_API Thread : public Runnable
|
|||
{
|
||||
friend class ThreadPrivate;
|
||||
friend class MutexPrivate;
|
||||
friend class SemaphorePrivate;
|
||||
public:
|
||||
/**
|
||||
* Running priorities, their mapping is operating system dependent
|
||||
|
|
Loading…
Reference in New Issue