version 1.3.14.8, 2006/07/30 23:11:55
|
version 1.9.16.3, 2007/09/12 03:24:32
|
|
|
// | // |
//============================================================================== | //============================================================================== |
// | // |
// Author: Mike Brasher (m.brasher@inovadevelopment.com) |
|
// |
|
//%///////////////////////////////////////////////////////////////////////////// | //%///////////////////////////////////////////////////////////////////////////// |
| |
#include "Mutex.h" | #include "Mutex.h" |
|
|
| |
//============================================================================== | //============================================================================== |
// | // |
// PEGASUS_HAVE_PTHREADS |
// Mutex implementation with PTHREAD_MUTEX_RECURSIVE feature. |
// | // |
//============================================================================== | //============================================================================== |
| |
#if defined(PEGASUS_HAVE_PTHREADS) |
#if defined(PEGASUS_HAVE_PTHREADS) && defined(PEGASUS_HAVE_RECURSIVE_MUTEXES) |
| |
static Once _once = PEGASUS_ONCE_INITIALIZER; | static Once _once = PEGASUS_ONCE_INITIALIZER; |
static pthread_mutexattr_t _attr; | static pthread_mutexattr_t _attr; |
|
|
{ | { |
once(&_once, _init_attr); | once(&_once, _init_attr); |
pthread_mutex_init(&_rep.mutex, &_attr); | pthread_mutex_init(&_rep.mutex, &_attr); |
|
#if defined(PEGASUS_DEBUG) |
|
_rep.count = 0; |
|
#endif |
|
} |
|
|
|
Mutex::Mutex(RecursiveTag) |
|
{ |
|
once(&_once, _init_attr); |
|
pthread_mutex_init(&_rep.mutex, &_attr); |
|
#if defined(PEGASUS_DEBUG) |
|
_rep.count = 0; |
|
#endif |
|
} |
|
|
|
Mutex::Mutex(NonRecursiveTag) |
|
{ |
|
pthread_mutex_init(&_rep.mutex, NULL); |
|
#if defined(PEGASUS_DEBUG) |
|
_rep.count = 0; |
|
#endif |
} | } |
| |
Mutex::~Mutex() | Mutex::~Mutex() |
|
|
switch (pthread_mutex_lock(&_rep.mutex)) | switch (pthread_mutex_lock(&_rep.mutex)) |
{ | { |
case 0: | case 0: |
|
#if defined(PEGASUS_DEBUG) |
|
_rep.count++; |
|
#endif |
break; | break; |
| |
case EDEADLK: |
|
throw Deadlock(ThreadType()); |
|
|
|
default: | default: |
throw WaitFailed(ThreadType()); |
throw WaitFailed(Threads::self()); |
} | } |
} | } |
| |
|
|
{ | { |
PEGASUS_DEBUG_ASSERT(_magic); | PEGASUS_DEBUG_ASSERT(_magic); |
| |
switch (pthread_mutex_trylock(&_rep.mutex)) |
int r = pthread_mutex_trylock(&_rep.mutex); |
|
if (r == -1) |
|
r=errno; |
|
switch (r) |
{ | { |
case 0: | case 0: |
|
#if defined(PEGASUS_DEBUG) |
|
_rep.count++; |
|
#endif |
break; | break; |
| |
case EBUSY: | case EBUSY: |
throw AlreadyLocked(ThreadType()); |
throw AlreadyLocked(Threads::self()); |
|
|
case EDEADLK: |
|
throw Deadlock(ThreadType()); |
|
| |
default: | default: |
throw WaitFailed(ThreadType()); |
throw WaitFailed(Threads::self()); |
} | } |
} | } |
| |
|
|
| |
for (;;) | for (;;) |
{ | { |
switch (pthread_mutex_trylock(&_rep.mutex)) |
int r=pthread_mutex_trylock(&_rep.mutex); |
|
if (r == -1) |
|
r = errno; |
|
switch (r) |
{ | { |
case 0: | case 0: |
|
#if defined(PEGASUS_DEBUG) |
|
_rep.count++; |
|
#endif |
return; | return; |
| |
case EBUSY: | case EBUSY: |
|
|
break; | break; |
} | } |
| |
case EDEADLK: |
default: |
throw Deadlock(Threads::self()); |
throw WaitFailed(Threads::self()); |
|
} |
|
} |
|
} |
|
|
|
void Mutex::unlock() |
|
{ |
|
PEGASUS_DEBUG_ASSERT(_magic); |
|
PEGASUS_DEBUG_ASSERT(_rep.count > 0); |
|
|
|
#if defined(PEGASUS_DEBUG) |
|
_rep.count--; |
|
#endif |
|
|
|
if (pthread_mutex_unlock(&_rep.mutex) != 0) |
|
throw Permission(Threads::self()); |
|
} |
|
|
|
#if defined(PEGASUS_OS_LINUX) |
|
void Mutex::reinitialize() |
|
{ |
|
pthread_mutex_init(&_rep.mutex, &_attr); |
|
#if defined(PEGASUS_DEBUG) |
|
_rep.count = 0; |
|
#endif |
|
} |
|
#endif |
|
|
|
#endif /* PEGASUS_HAVE_PTHREADS && PEGASUS_HAVE_RECURSIVE_MUTEXES */ |
|
|
|
//============================================================================== |
|
// |
|
// Mutex implementation without PTHREAD_MUTEX_RECURSIVE feature. |
|
// |
|
//============================================================================== |
|
|
|
#if defined(PEGASUS_HAVE_PTHREADS) && !defined(PEGASUS_HAVE_RECURSIVE_MUTEXES) |
|
|
|
Mutex::Mutex() |
|
{ |
|
memset(&_rep, 0, sizeof(_rep)); |
|
_rep.recursive = 1; |
|
pthread_mutex_init(&_rep.mutex, NULL); |
|
pthread_cond_init(&_rep.cond, NULL); |
|
_rep.owner = 0; |
|
_rep.count = 0; |
|
} |
|
|
|
Mutex::Mutex(RecursiveTag) |
|
{ |
|
memset(&_rep, 0, sizeof(_rep)); |
|
_rep.recursive = 1; |
|
pthread_mutex_init(&_rep.mutex, NULL); |
|
pthread_cond_init(&_rep.cond, NULL); |
|
_rep.owner = 0; |
|
_rep.count = 0; |
|
} |
|
|
|
Mutex::Mutex(NonRecursiveTag) |
|
{ |
|
memset(&_rep, 0, sizeof(_rep)); |
|
_rep.recursive = 0; |
|
pthread_mutex_init(&_rep.mutex, NULL); |
|
} |
|
|
|
Mutex::~Mutex() |
|
{ |
|
PEGASUS_DEBUG_ASSERT(_magic); |
|
pthread_mutex_destroy(&_rep.mutex); |
|
|
|
if (_rep.recursive) |
|
pthread_cond_destroy(&_rep.cond); |
|
} |
|
|
|
void Mutex::lock() |
|
{ |
|
PEGASUS_DEBUG_ASSERT(_magic); |
|
|
|
if (_rep.recursive) |
|
{ |
|
pthread_t self = pthread_self(); |
|
|
|
pthread_mutex_lock(&_rep.mutex); |
|
{ |
|
if (_rep.count == 0) |
|
{ |
|
_rep.owner = self; |
|
} |
|
else if (!pthread_equal(_rep.owner, self)) |
|
{ |
|
while (_rep.count > 0) |
|
pthread_cond_wait(&_rep.cond, &_rep.mutex); |
|
|
|
_rep.owner = self; |
|
} |
|
|
|
_rep.count++; |
|
} |
|
pthread_mutex_unlock(&_rep.mutex); |
|
} |
|
else |
|
{ |
|
if (pthread_mutex_lock(&_rep.mutex) != 0) |
|
{ |
|
throw WaitFailed(Threads::self()); |
|
} |
|
} |
|
} |
|
|
|
void Mutex::try_lock() |
|
{ |
|
PEGASUS_DEBUG_ASSERT(_magic); |
|
|
|
if (_rep.recursive) |
|
{ |
|
pthread_t self = pthread_self(); |
|
|
|
pthread_mutex_lock(&_rep.mutex); |
|
{ |
|
if (_rep.count == 0) |
|
{ |
|
_rep.owner = self; |
|
_rep.count = 1; |
|
} |
|
else if (pthread_equal(_rep.owner, self)) |
|
{ |
|
_rep.count++; |
|
} |
|
else |
|
{ |
|
pthread_mutex_unlock(&_rep.mutex); |
|
throw AlreadyLocked(Threads::self()); |
|
} |
|
} |
|
pthread_mutex_unlock(&_rep.mutex); |
|
} |
|
else |
|
{ |
|
int r = pthread_mutex_trylock(&_rep.mutex); |
|
|
|
if (r == -1) |
|
r = errno; |
|
|
|
switch (r) |
|
{ |
|
case 0: |
|
break; |
|
|
|
case EBUSY: |
|
throw AlreadyLocked(Threads::self()); |
|
|
|
default: |
|
throw WaitFailed(Threads::self()); |
|
} |
|
} |
|
} |
|
|
|
void Mutex::timed_lock(Uint32 milliseconds) |
|
{ |
|
PEGASUS_DEBUG_ASSERT(_magic); |
|
|
|
if (_rep.recursive) |
|
{ |
|
pthread_t self = pthread_self(); |
|
|
|
pthread_mutex_lock(&_rep.mutex); |
|
{ |
|
if (_rep.count == 0) |
|
{ |
|
_rep.owner = self; |
|
} |
|
else if (!pthread_equal(_rep.owner, self)) |
|
{ |
|
timespec ts; |
|
clock_gettime(CLOCK_REALTIME, &ts); |
|
|
|
ts.tv_sec += milliseconds / 1000; |
|
ts.tv_nsec += (milliseconds % 1000) * 1000000; |
|
|
|
while (_rep.count > 0) |
|
{ |
|
if (pthread_cond_timedwait( |
|
&_rep.cond, &_rep.mutex, &ts) != 0) |
|
{ |
|
pthread_mutex_unlock(&_rep.mutex); |
|
throw TimeOut(Threads::self()); |
|
} |
|
} |
|
|
|
_rep.owner = self; |
|
} |
|
|
|
_rep.count++; |
|
} |
|
pthread_mutex_unlock(&_rep.mutex); |
|
} |
|
else |
|
{ |
|
struct timeval now; |
|
struct timeval finish; |
|
struct timeval remaining; |
|
{ |
|
Uint32 usec; |
|
gettimeofday(&finish, NULL); |
|
finish.tv_sec += (milliseconds / 1000 ); |
|
milliseconds %= 1000; |
|
usec = finish.tv_usec + ( milliseconds * 1000 ); |
|
finish.tv_sec += (usec / 1000000); |
|
finish.tv_usec = usec % 1000000; |
|
} |
|
|
|
for (;;) |
|
{ |
|
int r = pthread_mutex_trylock(&_rep.mutex); |
|
|
|
if (r == -1) |
|
r = errno; |
|
|
|
switch (r) |
|
{ |
|
case 0: |
|
return; |
|
|
|
case EBUSY: |
|
{ |
|
gettimeofday(&now, NULL); |
|
|
|
if (Time::subtract(&remaining, &finish, &now)) |
|
throw TimeOut(Threads::self()); |
|
|
|
Threads::yield(); |
|
break; |
|
} |
| |
default: | default: |
throw WaitFailed(Threads::self()); | throw WaitFailed(Threads::self()); |
} | } |
} | } |
} | } |
|
} |
| |
void Mutex::unlock() | void Mutex::unlock() |
{ | { |
PEGASUS_DEBUG_ASSERT(_magic); | PEGASUS_DEBUG_ASSERT(_magic); |
| |
|
if (_rep.recursive) |
|
{ |
|
pthread_t self = pthread_self(); |
|
|
|
pthread_mutex_lock(&_rep.mutex); |
|
{ |
|
// If not locked or if calling thread is not the locker. |
|
|
|
if (_rep.count == 0 || !pthread_equal(_rep.owner, self)) |
|
PEGASUS_DEBUG_ASSERT(0); |
|
|
|
_rep.count--; |
|
_rep.owner = 0; |
|
|
|
pthread_cond_signal(&_rep.cond); |
|
} |
|
pthread_mutex_unlock(&_rep.mutex); |
|
} |
|
else |
|
{ |
if (pthread_mutex_unlock(&_rep.mutex) != 0) | if (pthread_mutex_unlock(&_rep.mutex) != 0) |
throw Permission(ThreadType()); |
throw Permission(Threads::self()); |
|
} |
} | } |
| |
#endif /* PEGASUS_HAVE_PTHREADS */ |
#endif /* PEGASUS_HAVE_PTHREADS && !PEGASUS_HAVE_RECURSIVE_MUTEXES */ |
| |
//============================================================================== | //============================================================================== |
// | // |
|
|
| |
#if defined(PEGASUS_HAVE_WINDOWS_THREADS) | #if defined(PEGASUS_HAVE_WINDOWS_THREADS) |
| |
|
static inline void _initialize(MutexRep& rep) |
|
{ |
|
rep.handle = CreateMutex(NULL, FALSE, NULL); |
|
rep.count = 0; |
|
} |
|
|
Mutex::Mutex() | Mutex::Mutex() |
{ | { |
_rep.handle = CreateMutex(NULL, FALSE, NULL); |
_initialize(_rep); |
Threads::clear(ThreadType()); |
} |
_rep.count = 0; |
|
|
Mutex::Mutex(RecursiveTag) |
|
{ |
|
_initialize(_rep); |
|
} |
|
|
|
Mutex::Mutex(NonRecursiveTag) |
|
{ |
|
_initialize(_rep); |
} | } |
| |
Mutex::~Mutex() | Mutex::~Mutex() |
|
|
DWORD rc = WaitForSingleObject(_rep.handle, INFINITE); | DWORD rc = WaitForSingleObject(_rep.handle, INFINITE); |
| |
if (rc == WAIT_FAILED) | if (rc == WAIT_FAILED) |
throw WaitFailed(ThreadType()); |
throw WaitFailed(Threads::self()); |
| |
_rep.count++; | _rep.count++; |
} | } |
|
|
DWORD rc = WaitForSingleObject(_rep.handle, 0); | DWORD rc = WaitForSingleObject(_rep.handle, 0); |
| |
if (rc == WAIT_TIMEOUT) | if (rc == WAIT_TIMEOUT) |
throw AlreadyLocked(ThreadType()); |
throw AlreadyLocked(Threads::self()); |
| |
if (rc == WAIT_FAILED) | if (rc == WAIT_FAILED) |
throw WaitFailed(ThreadType()); |
throw WaitFailed(Threads::self()); |
| |
_rep.count++; | _rep.count++; |
} | } |
|
|
DWORD rc = WaitForSingleObject(_rep.handle, milliseconds); | DWORD rc = WaitForSingleObject(_rep.handle, milliseconds); |
| |
if (rc == WAIT_TIMEOUT) | if (rc == WAIT_TIMEOUT) |
throw TimeOut(ThreadType()); |
throw TimeOut(Threads::self()); |
| |
if (rc == WAIT_FAILED) | if (rc == WAIT_FAILED) |
throw WaitFailed(ThreadType()); |
throw WaitFailed(Threads::self()); |
| |
_rep.count++; | _rep.count++; |
} | } |
|
|
void Mutex::unlock() | void Mutex::unlock() |
{ | { |
PEGASUS_DEBUG_ASSERT(_magic); | PEGASUS_DEBUG_ASSERT(_magic); |
|
PEGASUS_DEBUG_ASSERT(_rep.count > 0); |
| |
Threads::clear(ThreadType()); |
|
_rep.count--; | _rep.count--; |
ReleaseMutex(_rep.handle); | ReleaseMutex(_rep.handle); |
} | } |