version 1.1.2.1, 2006/07/27 23:11:52
|
version 1.1.2.11, 2006/07/29 01:18:27
|
|
|
#include "ReadWriteSem.h" | #include "ReadWriteSem.h" |
#include "Time.h" | #include "Time.h" |
#include "PegasusAssert.h" | #include "PegasusAssert.h" |
|
#include "Threads.h" |
| |
PEGASUS_NAMESPACE_BEGIN | PEGASUS_NAMESPACE_BEGIN |
| |
|
|
ReadWriteSem::ReadWriteSem() : _readers(0), _writers(0) | ReadWriteSem::ReadWriteSem() : _readers(0), _writers(0) |
{ | { |
pthread_rwlock_init(&_rwlock.rwlock, NULL); | pthread_rwlock_init(&_rwlock.rwlock, NULL); |
_rwlock.owner = 0; |
Threads::clear(_rwlock.owner); |
} | } |
| |
ReadWriteSem::~ReadWriteSem() | ReadWriteSem::~ReadWriteSem() |
|
|
| |
// timedrdlock and timedwrlock are not supported on HPUX | // timedrdlock and timedwrlock are not supported on HPUX |
// mdday Sun Aug 5 14:21:00 2001 | // mdday Sun Aug 5 14:21:00 2001 |
void ReadWriteSem::timed_wait( |
void ReadWriteSem::timed_wait(Uint32 mode, |
Uint32 mode, |
ThreadType caller, int milliseconds) |
ThreadType caller, |
|
int milliseconds) |
|
{ | { |
int errorcode = 0, timeout; |
int errorcode = 0, timeout = 0; |
struct timeval now, finish, remaining; | struct timeval now, finish, remaining; |
Uint32 usec; | Uint32 usec; |
| |
|
|
gettimeofday(&now, NULL); | gettimeofday(&now, NULL); |
} | } |
while (errorcode == EBUSY && | while (errorcode == EBUSY && |
(0 == |
(0 == (timeout = Time::subtract(&remaining, &finish, &now)))); |
(timeout = Time::subtract(&remaining, &finish, &now)))); |
|
if (0 == errorcode) | if (0 == errorcode) |
{ | { |
_readers++; | _readers++; |
|
|
gettimeofday(&now, NULL); | gettimeofday(&now, NULL); |
} | } |
while (errorcode == EBUSY && | while (errorcode == EBUSY && |
(0 == |
(0 == (timeout = Time::subtract(&remaining, &finish, &now)))); |
(timeout = Time::subtract(&remaining, &finish, &now)))); |
|
| |
if (0 == errorcode) | if (0 == errorcode) |
{ | { |
|
|
if (mode == PEG_SEM_WRITE) | if (mode == PEG_SEM_WRITE) |
{ | { |
owner = _rwlock.owner; | owner = _rwlock.owner; |
_rwlock.owner = 0; |
Threads::clear(_rwlock.owner); |
} | } |
if (0 != pthread_rwlock_unlock(&_rwlock.rwlock)) | if (0 != pthread_rwlock_unlock(&_rwlock.rwlock)) |
{ | { |
|
|
| |
int ReadWriteSem::read_count() const | int ReadWriteSem::read_count() const |
{ | { |
#if defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU) |
|
PEGASUS_ASSERT(_readers.get() == _rwlock.rwlock.__rw_readers); |
|
#endif |
|
return (_readers.get()); | return (_readers.get()); |
} | } |
| |
int ReadWriteSem::write_count() const | int ReadWriteSem::write_count() const |
{ | { |
#if defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU) |
|
if (_rwlock.rwlock.__rw_writer != NULL) |
|
{ |
|
PEGASUS_ASSERT(_writers.get() == 1); |
|
} |
|
#endif |
|
return (_writers.get()); | return (_writers.get()); |
} | } |
| |
|
|
// 2) I do not hold the write lock | // 2) I do not hold the write lock |
// 3) I am not using a reader slot | // 3) I am not using a reader slot |
| |
|
#if 0 |
void extricate_read_write(void *parm) | void extricate_read_write(void *parm) |
{ | { |
ReadWriteSem *rws = (ReadWriteSem *)parm; | ReadWriteSem *rws = (ReadWriteSem *)parm; |
ThreadType myself = Threads::self(); | ThreadType myself = Threads::self(); |
| |
if(rws->_rwlock._wlock.get_owner() == myself) |
if (Threads::equal(rws->_rwlock._wlock.get_owner(), myself)) |
rws->_rwlock._wlock.unlock(); | rws->_rwlock._wlock.unlock(); |
else |
else if (rws->_readers.get() > 0) |
if(rws->_readers.get() > 0) |
|
rws->_rwlock._rlock.signal(); | rws->_rwlock._rlock.signal(); |
if (rws->_rwlock._internal_lock.get_owner() == myself) |
|
|
if (Threads::equal(rws->_rwlock._internal_lock.get_owner(), myself)) |
rws->_rwlock._internal_lock.unlock(); | rws->_rwlock._internal_lock.unlock(); |
} | } |
|
#endif |
| |
| |
ReadWriteSem::ReadWriteSem() : _readers(0), _writers(0), _rwlock() | ReadWriteSem::ReadWriteSem() : _readers(0), _writers(0), _rwlock() |
|
|
// lock everyone out of this object | // lock everyone out of this object |
try | try |
{ | { |
_rwlock._internal_lock.lock(Threads::self()); |
_rwlock._internal_lock.lock(); |
} | } |
catch(Deadlock& d) | catch(Deadlock& d) |
{ | { |
d = d; // no problem - we own the lock, which is what we want |
d = d; // no problem - we own the lock, which is |
|
// what we want |
} | } |
catch(IPCException& ) | catch(IPCException& ) |
{ | { |
|
|
// if milliseconds == -1, wait indefinately | // if milliseconds == -1, wait indefinately |
// if milliseconds == 0, fast wait | // if milliseconds == 0, fast wait |
//----------------------------------------------------------------- | //----------------------------------------------------------------- |
void ReadWriteSem::timed_wait(Uint32 mode, ThreadType caller, int milliseconds) |
void ReadWriteSem::timed_wait(Uint32 mode, ThreadType caller, |
|
int milliseconds) |
{ | { |
|
|
//----------------------------------------------------------------- | //----------------------------------------------------------------- |
// Lock this object to maintain integrity while we decide | // Lock this object to maintain integrity while we decide |
// exactly what to do next. | // exactly what to do next. |
|
|
//TooManyReaders caughtTooManyReaders((ThreadType)0); | //TooManyReaders caughtTooManyReaders((ThreadType)0); |
| |
ThreadType zero; | ThreadType zero; |
zero = 0; |
|
IPCException caught(zero); | IPCException caught(zero); |
WaitFailed caughtWaitFailed(zero); | WaitFailed caughtWaitFailed(zero); |
TimeOut caughtTimeOut(zero); | TimeOut caughtTimeOut(zero); |
TooManyReaders caughtTooManyReaders(zero); | TooManyReaders caughtTooManyReaders(zero); |
| |
{ // cleanup stack frame |
// cleanup stack frame |
|
{ |
Threads::cleanup_push(extricate_read_write, this); |
// Threads::cleanup_push(extricate_read_write, this); |
| |
try | try |
{ | { |
if(milliseconds == 0) | if(milliseconds == 0) |
_rwlock._internal_lock.try_lock(Threads::self()); |
_rwlock._internal_lock.try_lock(); |
else if(milliseconds == -1) | else if(milliseconds == -1) |
_rwlock._internal_lock.lock(Threads::self()); |
_rwlock._internal_lock.lock(); |
else | else |
_rwlock._internal_lock.timed_lock(milliseconds, Threads::self()); |
_rwlock._internal_lock.timed_lock(milliseconds); |
} | } |
catch(const IPCException& e) | catch(const IPCException& e) |
{ | { |
|
|
else // timed wait | else // timed wait |
{ | { |
struct timeval start, now; | struct timeval start, now; |
gettimeofday(&start, NULL); |
Time::gettimeofday(&start); |
start.tv_usec += (1000 * milliseconds); | start.tv_usec += (1000 * milliseconds); |
while(_readers.get() > 0) | while(_readers.get() > 0) |
{ | { |
gettimeofday(&now, NULL); |
Time::gettimeofday(&now); |
if((now.tv_usec > start.tv_usec) || now.tv_sec > start.tv_sec ) |
if ((now.tv_usec > start.tv_usec) || |
|
now.tv_sec > start.tv_sec) |
{ | { |
_rwlock._internal_lock.unlock(); | _rwlock._internal_lock.unlock(); |
//caught.reset(new TimeOut(Threads::self())); | //caught.reset(new TimeOut(Threads::self())); |
|
|
{ | { |
try | try |
{ | { |
_rwlock._wlock.try_lock(Threads::self()); |
_rwlock._wlock.try_lock(); |
} | } |
catch(IPCException& e) | catch(IPCException& e) |
{ | { |
|
|
{ | { |
try | try |
{ | { |
_rwlock._wlock.lock(Threads::self()); |
_rwlock._wlock.lock(); |
} | } |
catch (const IPCException& e) | catch (const IPCException& e) |
{ | { |
|
|
{ | { |
try | try |
{ | { |
_rwlock._wlock.timed_lock(milliseconds, Threads::self()); |
_rwlock._wlock.timed_lock(milliseconds); |
} | } |
catch(const IPCException& e) | catch(const IPCException& e) |
{ | { |
|
|
while(_writers.get() > 0) | while(_writers.get() > 0) |
{ | { |
Time::gettimeofday(&now); | Time::gettimeofday(&now); |
if((now.tv_usec > start.tv_usec) || (now.tv_sec > start.tv_sec)) |
if ((now.tv_usec > start.tv_usec) || |
|
(now.tv_sec > start.tv_sec)) |
{ | { |
_rwlock._internal_lock.unlock(); | _rwlock._internal_lock.unlock(); |
//caught.reset(new TimeOut(Threads::self())); | //caught.reset(new TimeOut(Threads::self())); |
|
|
} | } |
catch(const IPCException&) | catch(const IPCException&) |
{ | { |
// the wait failed, there must be too many readers already. |
// the wait failed, there must be too many readers |
|
// already. |
// unlock the object | // unlock the object |
caughtTooManyReaders = TooManyReaders(Threads::self()); | caughtTooManyReaders = TooManyReaders(Threads::self()); |
_rwlock._internal_lock.unlock(); | _rwlock._internal_lock.unlock(); |
|
|
throw_from_here: | throw_from_here: |
// ATTN: | // ATTN: |
Threads::cleanup_pop(0); | Threads::cleanup_pop(0); |
} // cleanup stack frame |
} |
| |
if (caught.get_owner() != 0) |
if (Threads::id(caught.get_owner()) != 0) |
throw caught; | throw caught; |
if (caughtWaitFailed.get_owner() != 0) |
if (Threads::id(caughtWaitFailed.get_owner()) != 0) |
throw caughtWaitFailed; | throw caughtWaitFailed; |
if (caughtTimeOut.get_owner() != 0) |
if (Threads::id(caughtTimeOut.get_owner()) != 0) |
throw caughtTimeOut; | throw caughtTimeOut; |
if (caughtTooManyReaders.get_owner() != 0) |
if (Threads::id(caughtTooManyReaders.get_owner()) != 0) |
throw caughtTooManyReaders; | throw caughtTooManyReaders; |
return; | return; |
} | } |
|
|
} | } |
| |
int ReadWriteSem::read_count() const | int ReadWriteSem::read_count() const |
|
|
{ | { |
return( _readers.get() ); | return( _readers.get() ); |
} | } |