diff options
Diffstat (limited to 'cpp')
-rw-r--r-- | cpp/config/Make.rules.Linux | 2 | ||||
-rw-r--r-- | cpp/include/IceUtil/Cond.h | 4 | ||||
-rw-r--r-- | cpp/include/IceUtil/Config.h | 5 | ||||
-rw-r--r-- | cpp/include/IceUtil/Lock.h | 85 | ||||
-rw-r--r-- | cpp/include/IceUtil/Monitor.h | 11 | ||||
-rw-r--r-- | cpp/include/IceUtil/Mutex.h | 86 | ||||
-rw-r--r-- | cpp/include/IceUtil/RWRecMutex.h | 198 | ||||
-rw-r--r-- | cpp/include/IceUtil/RecMutex.h | 32 | ||||
-rw-r--r-- | cpp/include/IceUtil/ThreadException.h | 3 | ||||
-rw-r--r-- | cpp/src/IceUtil/Cond.cpp | 18 | ||||
-rw-r--r-- | cpp/src/IceUtil/RWRecMutex.cpp | 25 | ||||
-rw-r--r-- | cpp/src/IceUtil/RecMutex.cpp | 71 | ||||
-rw-r--r-- | cpp/src/IceUtil/Thread.cpp | 16 | ||||
-rw-r--r-- | cpp/src/IceUtil/ThreadException.cpp | 15 | ||||
-rw-r--r-- | cpp/src/IceUtil/UUID.cpp | 5 | ||||
-rw-r--r-- | cpp/test/IceUtil/thread/MonitorMutexTest.cpp | 26 | ||||
-rw-r--r-- | cpp/test/IceUtil/thread/MonitorRecMutexTest.cpp | 27 | ||||
-rw-r--r-- | cpp/test/IceUtil/thread/MutexTest.cpp | 72 | ||||
-rw-r--r-- | cpp/test/IceUtil/thread/RWRecMutexTest.cpp | 154 | ||||
-rw-r--r-- | cpp/test/IceUtil/thread/RecMutexTest.cpp | 21 |
20 files changed, 527 insertions, 349 deletions
diff --git a/cpp/config/Make.rules.Linux b/cpp/config/Make.rules.Linux index d7204720e7f..50c8f6c737b 100644 --- a/cpp/config/Make.rules.Linux +++ b/cpp/config/Make.rules.Linux @@ -17,7 +17,7 @@ # CXX = c++ -CXXFLAGS = -ftemplate-depth-128 -fPIC -Wall +CXXFLAGS = -ftemplate-depth-128 -fPIC -Wall -D_REENTRANT ifeq ($(OPTIMIZE),yes) CXXFLAGS := -O2 -DNDEBUG $(CXXFLAGS) diff --git a/cpp/include/IceUtil/Cond.h b/cpp/include/IceUtil/Cond.h index 582d4f9bdde..37973c059c3 100644 --- a/cpp/include/IceUtil/Cond.h +++ b/cpp/include/IceUtil/Cond.h @@ -298,7 +298,7 @@ Cond::waitImpl(const M& mutex) const if(rc != 0) { - throw ThreadSyscallException(__FILE__, __LINE__); + throw ThreadSyscallException(__FILE__, __LINE__, rc); } } @@ -325,7 +325,7 @@ Cond::timedWaitImpl(const M& mutex, const Time& timeout) const // if(rc != ETIMEDOUT) { - throw ThreadSyscallException(__FILE__, __LINE__); + throw ThreadSyscallException(__FILE__, __LINE__, rc); } return false; } diff --git a/cpp/include/IceUtil/Config.h b/cpp/include/IceUtil/Config.h index 384d9b7de84..0e2a07026da 100644 --- a/cpp/include/IceUtil/Config.h +++ b/cpp/include/IceUtil/Config.h @@ -72,7 +72,7 @@ # define SIZEOF_WCHAR_T 2 -#elif (defined(__linux__) || defined(__FreeBSD__)) && defined(i386) +#elif (defined(__linux) || defined(__FreeBSD__)) && defined(__i386) # define ICE_UTIL_API /**/ # define HAVE_READLINE @@ -107,9 +107,6 @@ #include <sstream> #ifndef _WIN32 -# ifndef _REENTRANT -# define _REENTRANT 1 -# endif # include <pthread.h> # include <errno.h> #endif diff --git a/cpp/include/IceUtil/Lock.h b/cpp/include/IceUtil/Lock.h index 3446baee208..fa13340ae94 100644 --- a/cpp/include/IceUtil/Lock.h +++ b/cpp/include/IceUtil/Lock.h @@ -16,6 +16,7 @@ #define ICE_UTIL_LOCK_H #include <IceUtil/Config.h> +#include <IceUtil/ThreadException.h> namespace IceUtil { @@ -25,9 +26,15 @@ namespace IceUtil // class Cond; -// + +// LockT and TryLockT are the preferred construct to lock/trylock/unlock +// simple and recursive mutexes. You typically allocate them on the +// stack to hold a lock on a mutex. +// LockT and TryLockT are not recursive: you cannot acquire several times +// in a row a lock with the same Lock or TryLock object. +// // We must name this LockT instead of Lock, because otherwise some -// compilers (such as Sun Forte 6.2) have problems with constructs +// compilers (such as Sun C++ 5.4) have problems with constructs // such as: // // class Foo @@ -45,16 +52,71 @@ public: _mutex(mutex) { _mutex.lock(); + _acquired = true; } ~LockT() { + if (_acquired) + { + _mutex.unlock(); + } + } + + void acquire() const + { + if (_acquired) + { + throw ThreadLockedException(__FILE__, __LINE__); + } + _mutex.lock(); + _acquired = true; + } + + + bool tryAcquire() const + { + if (_acquired) + { + throw ThreadLockedException(__FILE__, __LINE__); + } + _acquired = _mutex.trylock(); + return _acquired; + } + + void release() const + { + if (!_acquired) + { + throw ThreadLockedException(__FILE__, __LINE__); + } _mutex.unlock(); + _acquired = false; + } + + bool acquired() const + { + return _acquired; + } + +protected: + + // TryLockT's contructor + LockT(const T& mutex, bool) : + _mutex(mutex) + { + _acquired = _mutex.trylock(); } private: + + // Not implemented; prevents accidental use. + // + LockT(const LockT&); + LockT& operator=(const LockT&); const T& _mutex; + mutable bool _acquired; friend class Cond; }; @@ -64,26 +126,13 @@ private: // an explanation. // template <typename T> -class TryLockT +class TryLockT : public LockT<T> { public: TryLockT(const T& mutex) : - _mutex(mutex) - { - _mutex.trylock(); - } - - ~TryLockT() - { - _mutex.unlock(); - } - -private: - - const T& _mutex; - - friend class Cond; + LockT<T>(mutex, true) + {} }; } // End namespace IceUtil diff --git a/cpp/include/IceUtil/Monitor.h b/cpp/include/IceUtil/Monitor.h index 9b06456bc2d..1c6bd53b29e 100644 --- a/cpp/include/IceUtil/Monitor.h +++ b/cpp/include/IceUtil/Monitor.h @@ -44,7 +44,7 @@ public: // void lock() const; void unlock() const; - void trylock() const; + bool trylock() const; void wait() const; bool timedWait(const Time&) const; @@ -91,7 +91,8 @@ IceUtil::Monitor<T>::~Monitor() template <class T> inline void IceUtil::Monitor<T>::lock() const { - if(_mutex.lock()) + _mutex.lock(); + if(_mutex.willUnlock()) { // // On the first mutex acquisition reset the number pending @@ -125,10 +126,11 @@ IceUtil::Monitor<T>::unlock() const */ } -template <class T> inline void +template <class T> inline bool IceUtil::Monitor<T>::trylock() const { - if(_mutex.trylock()) + bool result = _mutex.trylock(); + if(result && _mutex.willUnlock()) { // // On the first mutex acquisition reset the number pending @@ -136,6 +138,7 @@ IceUtil::Monitor<T>::trylock() const // _nnotify = 0; } + return result; } template <class T> inline void diff --git a/cpp/include/IceUtil/Mutex.h b/cpp/include/IceUtil/Mutex.h index 71cfe0f099c..592a9236c0c 100644 --- a/cpp/include/IceUtil/Mutex.h +++ b/cpp/include/IceUtil/Mutex.h @@ -54,37 +54,24 @@ public: // Note that lock/trylock & unlock in general should not be used // directly. Instead use Lock & TryLock. // + + void lock() const; // - // The boolean values are for the Monitor implementation which - // needs to know whether the Mutex has been locked for the first - // time, or unlocked for the last time (that is another thread is - // able to acquire the mutex). - // - - // - // Return true if the mutex has been locked for the first time. - // - bool lock() const; - - // - // Throw ThreadLockedException in the case that the lock call would - // block (that is the mutex is already owned by some other - // thread). Returns true if the mutex has been locked for the - // first time. + // Returns true if the lock was acquired, and false otherwise. // bool trylock() const; - // - // Returns true if the mutex has been unlocked for the last time - // (false otherwise). - // - bool unlock() const; + void unlock() const; // // Returns true if the mutex will unlock when calling unlock() // (false otherwise). For non-recursive mutexes, this will always - // return true. + // return true. + // This function is used by the Monitor implementation to know whether + // the Mutex has been locked for the first time, or unlocked for the + // last time (that is another thread is able to acquire the mutex). + // Pre-condition: the mutex must be locked. // bool willUnlock() const; @@ -139,7 +126,7 @@ Mutex::~Mutex() DeleteCriticalSection(&_mutex); } -inline bool +inline void Mutex::lock() const { EnterCriticalSection(&_mutex); @@ -148,7 +135,6 @@ Mutex::lock() const // member (like the UNIX implementation of RecMutex). // assert(_mutex.RecursionCount == 1); - return true; } inline bool @@ -156,22 +142,21 @@ Mutex::trylock() const { if(!TryEnterCriticalSection(&_mutex)) { - throw ThreadLockedException(__FILE__, __LINE__); + return false; } if(_mutex.RecursionCount > 1) { LeaveCriticalSection(&_mutex); - throw ThreadLockedException(__FILE__, __LINE__); + return false; } return true; } -inline bool +inline void Mutex::unlock() const { assert(_mutex.RecursionCount == 1); LeaveCriticalSection(&_mutex); - return true; } inline void @@ -191,10 +176,33 @@ Mutex::lock(LockState&) const inline Mutex::Mutex() { +#ifdef NDEBUG int rc = pthread_mutex_init(&_mutex, 0); +#else + + int rc; +#if defined(__linux) && !defined(__USE_UNIX98) + const pthread_mutexattr_t attr = { PTHREAD_MUTEX_ERRORCHECK_NP }; +#else + pthread_mutexattr_t attr; + rc = pthread_mutexattr_init(&attr); + assert(rc == 0); + rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); + assert(rc == 0); +#endif + rc = pthread_mutex_init(&_mutex, &attr); + +#if defined(__linux) && !defined(__USE_UNIX98) +// Nothing to do +#else + rc = pthread_mutexattr_destroy(&attr); + assert(rc == 0); +#endif +#endif + if(rc != 0) { - throw ThreadSyscallException(__FILE__, __LINE__); + throw ThreadSyscallException(__FILE__, __LINE__, rc); } } @@ -206,41 +214,35 @@ Mutex::~Mutex() assert(rc == 0); } -inline bool +inline void Mutex::lock() const { int rc = pthread_mutex_lock(&_mutex); if(rc != 0) { - throw ThreadSyscallException(__FILE__, __LINE__); + throw ThreadSyscallException(__FILE__, __LINE__, rc); } - return true; } inline bool Mutex::trylock() const { int rc = pthread_mutex_trylock(&_mutex); - if(rc != 0) + if(rc != 0 && rc != EBUSY) { - if(rc == EBUSY) - { - throw ThreadLockedException(__FILE__, __LINE__); - } - throw ThreadSyscallException(__FILE__, __LINE__); + throw ThreadSyscallException(__FILE__, __LINE__, rc); } - return true; + return (rc == 0); } -inline bool +inline void Mutex::unlock() const { int rc = pthread_mutex_unlock(&_mutex); if(rc != 0) { - throw ThreadSyscallException(__FILE__, __LINE__); + throw ThreadSyscallException(__FILE__, __LINE__, rc); } - return true; } inline void diff --git a/cpp/include/IceUtil/RWRecMutex.h b/cpp/include/IceUtil/RWRecMutex.h index 362ee2e0314..320b868fefe 100644 --- a/cpp/include/IceUtil/RWRecMutex.h +++ b/cpp/include/IceUtil/RWRecMutex.h @@ -31,115 +31,227 @@ public: _mutex(mutex) { _mutex.readlock(); + _acquired = true; } ~RLockT() { + if (_acquired) + { + _mutex.unlock(); + } + } + + void acquire() const + { + if (_acquired) + { + throw ThreadLockedException(__FILE__, __LINE__); + } + _mutex.readlock(); + _acquired = true; + } + + bool tryAcquire() const + { + if (_acquired) + { + throw ThreadLockedException(__FILE__, __LINE__); + } + _acquired = _mutex.tryReadlock(); + return _acquired; + } + + bool timedTryAcquire(const Time& timeout) const + { + if (_acquired) + { + throw ThreadLockedException(__FILE__, __LINE__); + } + _acquired = _mutex.timedTryReadlock(timeout); + return _acquired; + } + + + + void release() const + { + if (!_acquired) + { + throw ThreadLockedException(__FILE__, __LINE__); + } _mutex.unlock(); + _acquired = false; + } + + bool acquired() const + { + return _acquired; } void - upgrade() + upgrade() const { _mutex.upgrade(); } void - timedUpgrade(const Time& timeout) + timedUpgrade(const Time& timeout) const { _mutex.timedUpgrade(timeout); } +protected: + + // TryRLockT's constructors + + RLockT(const T& mutex, bool) : + _mutex(mutex) + { + _acquired = _mutex.tryReadlock(); + } + + + RLockT(const T& mutex, const Time& timeout) : + _mutex(mutex) + { + _acquired = _mutex.timedTryReadlock(timeout); + } + + private: + // Not implemented; prevents accidental use. + // + RLockT(const RLockT&); + RLockT& operator=(const RLockT&); + const T& _mutex; + mutable bool _acquired; }; template <typename T> -class TryRLockT +class TryRLockT : public RLockT<T> { public: TryRLockT(const T& mutex) : - _mutex(mutex) + RLockT<T>(mutex, true) { - _mutex.tryReadlock(); } TryRLockT(const T& mutex, const Time& timeout) : + RLockT<T>(mutex, timeout) + { + } +}; + +template <typename T> +class WLockT +{ +public: + + WLockT(const T& mutex) : _mutex(mutex) { - _mutex.timedTryReadlock(timeout); + _mutex.writelock(); + _acquired = true; } - ~TryRLockT() + ~WLockT() { - _mutex.unlock(); + if (_acquired) + { + _mutex.unlock(); + } } - void - upgrade() + void acquire() const { - _mutex.upgrade(); + if (_acquired) + { + throw ThreadLockedException(__FILE__, __LINE__); + } + _mutex.writelock(); + _acquired = true; } - void - timedUpgrade(const Time& timeout) + bool tryAcquire() const { - _mutex.timedUpgrade(timeout); + if (_acquired) + { + throw ThreadLockedException(__FILE__, __LINE__); + } + _acquired = _mutex.tryWritelock(); + return _acquired; } -private: + bool timedTryAcquire(const Time& timeout) const + { + if (_acquired) + { + throw ThreadLockedException(__FILE__, __LINE__); + } + _acquired = _mutex.timedTryWritelock(timeout); + return _acquired; + } - const T& _mutex; -}; + void release() const + { + if (!_acquired) + { + throw ThreadLockedException(__FILE__, __LINE__); + } + _mutex.unlock(); + _acquired = false; + } -template <typename T> -class WLockT -{ -public: + bool acquired() const + { + return _acquired; + } - WLockT(const T& mutex) : +protected: + + // TryWLockT's constructor + + WLockT(const T& mutex, bool) : _mutex(mutex) { - _mutex.writelock(); + _acquired = _mutex.tryWritelock(); } - ~WLockT() + WLockT(const T& mutex, const Time& timeout) : + _mutex(mutex) { - _mutex.unlock(); + _acquired = _mutex.timedTryWritelock(timeout); } private: + // Not implemented; prevents accidental use. + // + WLockT(const WLockT&); + WLockT& operator=(const WLockT&); + const T& _mutex; + mutable bool _acquired; }; template <typename T> -class TryWLockT +class TryWLockT : public WLockT<T> { public: TryWLockT(const T& mutex) : - _mutex(mutex) + WLockT<T>(mutex, true) { - _mutex.tryWritelock(); } TryWLockT(const T& mutex, const Time& timeout) : - _mutex(mutex) - { - _mutex.timedTryWritelock(timeout); - } - - ~TryWLockT() + WLockT<T>(mutex, timeout) { - _mutex.unlock(); } - -private: - - const T& _mutex; }; // @@ -180,12 +292,12 @@ public: // // Try to acquire a read lock. // - void tryReadlock() const; + bool tryReadlock() const; // // Try to acquire a read lock for upto the given timeout. // - void timedTryReadlock(const Time&) const; + bool timedTryReadlock(const Time&) const; // // Acquire a write lock. @@ -195,12 +307,12 @@ public: // // Acquire a write lock. // - void tryWritelock() const; + bool tryWritelock() const; // // Acquire a write lock for up to the given timeout. // - void timedTryWritelock(const Time&) const; + bool timedTryWritelock(const Time&) const; // // Unlock the reader/writer lock. diff --git a/cpp/include/IceUtil/RecMutex.h b/cpp/include/IceUtil/RecMutex.h index c1011634db2..12c00c368a6 100644 --- a/cpp/include/IceUtil/RecMutex.h +++ b/cpp/include/IceUtil/RecMutex.h @@ -47,37 +47,25 @@ public: // Note that lock/trylock & unlock in general should not be used // directly. Instead use Lock & TryLock. // + + void lock() const; // - // The boolean values are for the Monitor implementation which - // needs to know whether the Mutex has been locked for the first - // time, or unlocked for the last time (that is another thread is - // able to acquire the mutex). - // - - // - // Return true if the mutex has been locked for the first time. - // - bool lock() const; - - // - // Throw ThreadLockedException in the case that the lock call would - // block (that is the mutex is already owned by some other - // thread). Returns true if the mutex has been locked for the - // first time. + // Returns true if the lock was acquired, and false otherwise. // bool trylock() const; - // - // Returns true if the mutex has been unlocked for the last time - // (false otherwise). - // - bool unlock() const; + + void unlock() const; // // Returns true if the mutex will unlock when calling unlock() // (false otherwise). For non-recursive mutexes, this will always - // return true. + // return true. + // This function is used by the Monitor implementation to know whether + // the Mutex has been locked for the first time, or unlocked for the + // last time (that is another thread is able to acquire the mutex). + // Pre-condition: the mutex must be locked. // bool willUnlock() const; diff --git a/cpp/include/IceUtil/ThreadException.h b/cpp/include/IceUtil/ThreadException.h index a96f0da16c2..b834fb692f7 100644 --- a/cpp/include/IceUtil/ThreadException.h +++ b/cpp/include/IceUtil/ThreadException.h @@ -24,12 +24,13 @@ class ICE_UTIL_API ThreadSyscallException : public Exception { public: - ThreadSyscallException(const char*, int); + ThreadSyscallException(const char*, int, int); virtual std::string ice_name() const; virtual void ice_print(std::ostream&) const; virtual Exception* ice_clone() const; virtual void ice_throw() const; + int error() const; private: const int _error; diff --git a/cpp/src/IceUtil/Cond.cpp b/cpp/src/IceUtil/Cond.cpp index 29b76783186..a6b6a84da25 100644 --- a/cpp/src/IceUtil/Cond.cpp +++ b/cpp/src/IceUtil/Cond.cpp @@ -25,7 +25,7 @@ IceUtil::Semaphore::Semaphore(long initial) _sem = CreateSemaphore(0, initial, 0x7fffffff, 0); if(_sem == INVALID_HANDLE_VALUE) { - throw ThreadSyscallException(__FILE__, __LINE__); + throw ThreadSyscallException(__FILE__, __LINE__, GetLastError()); } } @@ -40,7 +40,7 @@ IceUtil::Semaphore::wait() const int rc = WaitForSingleObject(_sem, INFINITE); if(rc != WAIT_OBJECT_0) { - throw ThreadSyscallException(__FILE__, __LINE__); + throw ThreadSyscallException(__FILE__, __LINE__, GetLastError()); } } @@ -53,7 +53,7 @@ IceUtil::Semaphore::timedWait(const Time& timeout) const int rc = WaitForSingleObject(_sem, msec); if(rc != WAIT_TIMEOUT && rc != WAIT_OBJECT_0) { - throw ThreadSyscallException(__FILE__, __LINE__); + throw ThreadSyscallException(__FILE__, __LINE__, GetLastError()); } return rc != WAIT_TIMEOUT; } @@ -64,7 +64,7 @@ IceUtil::Semaphore::post(int count) const int rc = ReleaseSemaphore(_sem, count, 0); if(rc == 0) { - throw ThreadSyscallException(__FILE__, __LINE__); + throw ThreadSyscallException(__FILE__, __LINE__, GetLastError()); } } @@ -207,19 +207,19 @@ IceUtil::Cond::Cond() rc = pthread_condattr_init(&attr); if(rc != 0) { - throw ThreadSyscallException(__FILE__, __LINE__); + throw ThreadSyscallException(__FILE__, __LINE__, rc); } rc = pthread_cond_init(&_cond, &attr); if(rc != 0) { - throw ThreadSyscallException(__FILE__, __LINE__); + throw ThreadSyscallException(__FILE__, __LINE__, rc); } rc = pthread_condattr_destroy(&attr); if(rc != 0) { - throw ThreadSyscallException(__FILE__, __LINE__); + throw ThreadSyscallException(__FILE__, __LINE__, rc); } } @@ -236,7 +236,7 @@ IceUtil::Cond::signal() int rc = pthread_cond_signal(&_cond); if(rc != 0) { - throw ThreadSyscallException(__FILE__, __LINE__); + throw ThreadSyscallException(__FILE__, __LINE__, rc); } } @@ -246,7 +246,7 @@ IceUtil::Cond::broadcast() int rc = pthread_cond_broadcast(&_cond); if(rc != 0) { - throw ThreadSyscallException(__FILE__, __LINE__); + throw ThreadSyscallException(__FILE__, __LINE__, rc); } } diff --git a/cpp/src/IceUtil/RWRecMutex.cpp b/cpp/src/IceUtil/RWRecMutex.cpp index d5ff0a6b2db..5a98ae9036d 100644 --- a/cpp/src/IceUtil/RWRecMutex.cpp +++ b/cpp/src/IceUtil/RWRecMutex.cpp @@ -16,7 +16,6 @@ #include <IceUtil/Exception.h> #include <IceUtil/Time.h> -#include <assert.h> IceUtil::RWRecMutex::RWRecMutex() : _count(0), @@ -45,7 +44,7 @@ IceUtil::RWRecMutex::readlock() const _count++; } -void +bool IceUtil::RWRecMutex::tryReadlock() const { Mutex::Lock lock(_mutex); @@ -56,12 +55,13 @@ IceUtil::RWRecMutex::tryReadlock() const // if(_count < 0 || _waitingWriters != 0) { - throw ThreadLockedException(__FILE__, __LINE__); + return false; } _count++; + return true; } -void +bool IceUtil::RWRecMutex::timedTryReadlock(const Time& timeout) const { Mutex::Lock lock(_mutex); @@ -80,11 +80,12 @@ IceUtil::RWRecMutex::timedTryReadlock(const Time& timeout) const } else { - throw ThreadLockedException(__FILE__, __LINE__); + return false; } } _count++; + return true; } void @@ -128,7 +129,7 @@ IceUtil::RWRecMutex::writelock() const _writerId = ThreadControl().id(); } -void +bool IceUtil::RWRecMutex::tryWritelock() const { Mutex::Lock lock(_mutex); @@ -140,7 +141,7 @@ IceUtil::RWRecMutex::tryWritelock() const if(_count < 0 && _writerId == ThreadControl().id()) { --_count; - return; + return true; } // @@ -148,7 +149,7 @@ IceUtil::RWRecMutex::tryWritelock() const // if(_count != 0) { - throw ThreadLockedException(__FILE__, __LINE__); + return false; } // @@ -156,9 +157,10 @@ IceUtil::RWRecMutex::tryWritelock() const // _count = -1; _writerId = ThreadControl().id(); + return true; } -void +bool IceUtil::RWRecMutex::timedTryWritelock(const Time& timeout) const { Mutex::Lock lock(_mutex); @@ -169,7 +171,7 @@ IceUtil::RWRecMutex::timedTryWritelock(const Time& timeout) const if(_count < 0 && _writerId == ThreadControl().id()) { --_count; - return; + return true; } // @@ -196,7 +198,7 @@ IceUtil::RWRecMutex::timedTryWritelock(const Time& timeout) const } else { - throw ThreadLockedException(__FILE__, __LINE__); + return false; } } @@ -205,6 +207,7 @@ IceUtil::RWRecMutex::timedTryWritelock(const Time& timeout) const // _count = -1; _writerId = ThreadControl().id(); + return true; } void diff --git a/cpp/src/IceUtil/RecMutex.cpp b/cpp/src/IceUtil/RecMutex.cpp index a6e75363afe..44f81a0ca59 100644 --- a/cpp/src/IceUtil/RecMutex.cpp +++ b/cpp/src/IceUtil/RecMutex.cpp @@ -31,16 +31,14 @@ IceUtil::RecMutex::~RecMutex() DeleteCriticalSection(&_mutex); } -bool +void IceUtil::RecMutex::lock() const { EnterCriticalSection(&_mutex); if(++_count > 1) { LeaveCriticalSection(&_mutex); - return false; } - return true; } bool @@ -48,25 +46,22 @@ IceUtil::RecMutex::trylock() const { if(!TryEnterCriticalSection(&_mutex)) { - throw ThreadLockedException(__FILE__, __LINE__); + return false; } if(++_count > 1) { LeaveCriticalSection(&_mutex); - return false; } return true; } -bool +void IceUtil::RecMutex::unlock() const { if(--_count == 0) { LeaveCriticalSection(&_mutex); - return true; } - return false; } void @@ -90,46 +85,36 @@ IceUtil::RecMutex::RecMutex() : { int rc; -#if _POSIX_VERSION >= 199506L - +#if defined(__linux) && !defined(__USE_UNIX98) + const pthread_mutexattr_t attr = { PTHREAD_MUTEX_RECURSIVE_NP }; +#else pthread_mutexattr_t attr; - rc = pthread_mutexattr_init(&attr); if(rc != 0) { - throw ThreadSyscallException(__FILE__, __LINE__); + throw ThreadSyscallException(__FILE__, __LINE__, rc); } - rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); if(rc != 0) { - throw ThreadSyscallException(__FILE__, __LINE__); + throw ThreadSyscallException(__FILE__, __LINE__, rc); } - -#elif defined(__linux__) - - const pthread_mutexattr_t attr = { PTHREAD_MUTEX_RECURSIVE_NP }; - -#else - - const pthread_mutexattr_t attr = { PTHREAD_MUTEX_RECURSIVE }; - #endif rc = pthread_mutex_init(&_mutex, &attr); if(rc != 0) { - throw ThreadSyscallException(__FILE__, __LINE__); + throw ThreadSyscallException(__FILE__, __LINE__, rc); } -#if _POSIX_VERSION >= 199506L - +#if defined(__linux) && !defined(__USE_UNIX98) +// Nothing to do +#else rc = pthread_mutexattr_destroy(&attr); if(rc != 0) { - throw ThreadSyscallException(__FILE__, __LINE__); + throw ThreadSyscallException(__FILE__, __LINE__, rc); } - #endif } @@ -141,45 +126,45 @@ IceUtil::RecMutex::~RecMutex() assert(rc == 0); } -bool +void IceUtil::RecMutex::lock() const { int rc = pthread_mutex_lock(&_mutex); if(rc != 0) { - throw ThreadSyscallException(__FILE__, __LINE__); + throw ThreadSyscallException(__FILE__, __LINE__, rc); } if(++_count > 1) { rc = pthread_mutex_unlock(&_mutex); assert(rc == 0); - return false; } - return true; } bool IceUtil::RecMutex::trylock() const { int rc = pthread_mutex_trylock(&_mutex); - if(rc != 0) + bool result = (rc == 0); + if(!result) { - if(rc == EBUSY) + if(rc != EBUSY) { - throw ThreadLockedException(__FILE__, __LINE__); + throw ThreadSyscallException(__FILE__, __LINE__, rc); } - throw ThreadSyscallException(__FILE__, __LINE__); - } - if(++_count > 1) + } + else if(++_count > 1) { rc = pthread_mutex_unlock(&_mutex); - assert(rc == 0); - return false; + if(rc != 0) + { + throw ThreadSyscallException(__FILE__, __LINE__, rc); + } } - return true; + return result; } -bool +void IceUtil::RecMutex::unlock() const { if(--_count == 0) @@ -187,9 +172,7 @@ IceUtil::RecMutex::unlock() const int rc = 0; // Prevent warnings when NDEBUG is defined. rc = pthread_mutex_unlock(&_mutex); assert(rc == 0); - return true; } - return false; } void diff --git a/cpp/src/IceUtil/Thread.cpp b/cpp/src/IceUtil/Thread.cpp index d0f6407e12e..bb99ee54841 100644 --- a/cpp/src/IceUtil/Thread.cpp +++ b/cpp/src/IceUtil/Thread.cpp @@ -30,7 +30,7 @@ IceUtil::ThreadControl::ThreadControl() int rc = DuplicateHandle(proc, current, proc, &_handle->handle, SYNCHRONIZE, TRUE, 0); if(rc == 0) { - throw ThreadSyscallException(__FILE__, __LINE__); + throw ThreadSyscallException(__FILE__, __LINE__, GetLastError()); } } @@ -114,7 +114,7 @@ IceUtil::ThreadControl::join() int rc = WaitForSingleObject(handle->handle, INFINITE); if(rc != WAIT_OBJECT_0) { - throw ThreadSyscallException(__FILE__, __LINE__); + throw ThreadSyscallException(__FILE__, __LINE__, GetLastError()); } } @@ -236,7 +236,7 @@ IceUtil::Thread::start() if(_handle->handle == 0) { __decRef(); - throw ThreadSyscallException(__FILE__, __LINE__); + throw ThreadSyscallException(__FILE__, __LINE__, GetLastError()); } _started = true; @@ -384,7 +384,7 @@ IceUtil::ThreadControl::join() int rc = pthread_join(id, &ignore); if(rc != 0) { - throw ThreadSyscallException(__FILE__, __LINE__); + throw ThreadSyscallException(__FILE__, __LINE__, rc); } } @@ -399,7 +399,7 @@ IceUtil::ThreadControl::detach() int rc = pthread_detach(id); if(rc != 0) { - throw ThreadSyscallException(__FILE__, __LINE__); + throw ThreadSyscallException(__FILE__, __LINE__, rc); } } @@ -475,6 +475,10 @@ startHook(void* arg) cerr << "IceUtil::Thread::run(): uncaught exception: "; cerr << e << endl; } + catch(...) + { + cerr << "IceUtil::Thread::run(): uncaught exception" << endl; + } return 0; } } @@ -503,7 +507,7 @@ IceUtil::Thread::start() if(rc != 0) { __decRef(); - throw ThreadSyscallException(__FILE__, __LINE__); + throw ThreadSyscallException(__FILE__, __LINE__, rc); } _started = true; diff --git a/cpp/src/IceUtil/ThreadException.cpp b/cpp/src/IceUtil/ThreadException.cpp index 86fd1e20852..857fc962987 100644 --- a/cpp/src/IceUtil/ThreadException.cpp +++ b/cpp/src/IceUtil/ThreadException.cpp @@ -16,13 +16,9 @@ using namespace std; -IceUtil::ThreadSyscallException::ThreadSyscallException(const char* file, int line) : +IceUtil::ThreadSyscallException::ThreadSyscallException(const char* file, int line, int err ): Exception(file, line), -#ifdef _WIN32 - _error(GetLastError()) -#else - _error(errno) -#endif + _error(err) { } @@ -80,6 +76,13 @@ IceUtil::ThreadSyscallException::ice_throw() const throw *this; } +int +IceUtil::ThreadSyscallException::error() const +{ + return _error; +} + + IceUtil::ThreadLockedException::ThreadLockedException(const char* file, int line) : Exception(file, line) { diff --git a/cpp/src/IceUtil/UUID.cpp b/cpp/src/IceUtil/UUID.cpp index 2ba8a2c1709..9fe4ea8eb64 100644 --- a/cpp/src/IceUtil/UUID.cpp +++ b/cpp/src/IceUtil/UUID.cpp @@ -20,8 +20,6 @@ // (/dev/random) to generate "version 4" UUIDs, as described in // http://www.ietf.org/internet-drafts/draft-mealling-uuid-urn-00.txt -#include <assert.h> - #ifdef _WIN32 # include <rpc.h> #else @@ -59,7 +57,8 @@ inline void bytesToHex(unsigned char* bytes, int len, char*& hexBuffer) IceUtil::UUIDGenerationException::UUIDGenerationException(const char* file, int line) : Exception(file, line) -{} +{ +} string IceUtil::UUIDGenerationException::ice_name() const diff --git a/cpp/test/IceUtil/thread/MonitorMutexTest.cpp b/cpp/test/IceUtil/thread/MonitorMutexTest.cpp index e9a3df57040..7d04267abef 100644 --- a/cpp/test/IceUtil/thread/MonitorMutexTest.cpp +++ b/cpp/test/IceUtil/thread/MonitorMutexTest.cpp @@ -32,17 +32,13 @@ public: virtual void run() { - try - { - Monitor<Mutex>::TryLock lock(_monitor); - test(false); - } - catch(const ThreadLockedException&) + Monitor<Mutex>::TryLock tlock(_monitor); + test(!tlock.acquired()); + { - // Expected + Mutex::Lock lock(_trylockMutex); + _trylock = true; } - - _trylock = true; _trylockCond.signal(); Monitor<Mutex>::Lock lock(_monitor); @@ -117,16 +113,8 @@ MonitorMutexTest::run() { Monitor<Mutex>::Lock lock(monitor); - // TEST: TryLock - try - { - Monitor<Mutex>::TryLock lock(monitor); - test(false); - } - catch(const ThreadLockedException&) - { - // Expected - } + Monitor<Mutex>::TryLock tlock(monitor); + test(!tlock.acquired()); // TEST: Start thread, try to acquire the mutex. t = new MonitorMutexTestThread(monitor); diff --git a/cpp/test/IceUtil/thread/MonitorRecMutexTest.cpp b/cpp/test/IceUtil/thread/MonitorRecMutexTest.cpp index e8996fdac8c..7c64106a215 100644 --- a/cpp/test/IceUtil/thread/MonitorRecMutexTest.cpp +++ b/cpp/test/IceUtil/thread/MonitorRecMutexTest.cpp @@ -32,17 +32,14 @@ public: virtual void run() { - try - { - Monitor<RecMutex>::TryLock lock(_monitor); - test(false); - } - catch(const ThreadLockedException&) + + Monitor<RecMutex>::TryLock tlock(_monitor); + test(!tlock.acquired()); + { - // Expected + Mutex::Lock lock(_trylockMutex); + _trylock = true; } - - _trylock = true; _trylockCond.signal(); Monitor<RecMutex>::Lock lock(_monitor); @@ -119,16 +116,12 @@ MonitorRecMutexTest::run() Monitor<RecMutex>::Lock lock(monitor); Monitor<RecMutex>::TryLock lock2(monitor); + test(lock2.acquired()); // TEST: TryLock - try - { - Monitor<RecMutex>::TryLock lock(monitor); - } - catch(const ThreadLockedException&) - { - test(false); - } + + Monitor<RecMutex>::TryLock tlock(monitor); + test(tlock.acquired()); // TEST: Start thread, try to acquire the mutex. t = new MonitorRecMutexTestThread(monitor); diff --git a/cpp/test/IceUtil/thread/MutexTest.cpp b/cpp/test/IceUtil/thread/MutexTest.cpp index 77608a64c9d..4f7eb5c4b35 100644 --- a/cpp/test/IceUtil/thread/MutexTest.cpp +++ b/cpp/test/IceUtil/thread/MutexTest.cpp @@ -33,18 +33,14 @@ public: } virtual void run() - { - try - { - Mutex::TryLock lock(_mutex); - test(false); - } - catch(const ThreadLockedException&) + { + Mutex::TryLock tlock(_mutex); + test(!tlock.acquired()); + { - // Expected + Mutex::Lock lock(_trylockMutex); + _trylock = true; } - - _trylock = true; _trylockCond.signal(); Mutex::Lock lock(_mutex); @@ -87,11 +83,39 @@ MutexTest::run() { Mutex::Lock lock(mutex); - - // TEST: TryLock + + // LockT testing: + // + + test(lock.acquired()); + try { - Mutex::TryLock lock2(mutex); + lock.acquire(); + test(false); + } + catch(const ThreadLockedException&) + { + // Expected + } + + try + { + lock.tryAcquire(); + test(false); + } + catch(const ThreadLockedException&) + { + // Expected + } + + test(lock.acquired()); + lock.release(); + test(!lock.acquired()); + + try + { + lock.release(); test(false); } catch(const ThreadLockedException&) @@ -99,6 +123,28 @@ MutexTest::run() // Expected } + Mutex::TryLock lock2(mutex); + test(lock.tryAcquire() == false); + lock2.release(); + test(lock.tryAcquire() == true); + test(lock.acquired()); + + // Deadlock testing + // + +#if !defined(NDEBUG) && !defined(_WIN32) + try + { + Mutex::Lock lock2(mutex); + test(false); + } + catch(const ThreadSyscallException& e) + { + // Expected + test(e.error() == EDEADLK); + } +#endif + // TEST: Start thread, try to acquire the mutex. t = new MutexTestThread(mutex); control = t->start(); diff --git a/cpp/test/IceUtil/thread/RWRecMutexTest.cpp b/cpp/test/IceUtil/thread/RWRecMutexTest.cpp index 5fc5db11c7a..916f0fa3fa4 100644 --- a/cpp/test/IceUtil/thread/RWRecMutexTest.cpp +++ b/cpp/test/IceUtil/thread/RWRecMutexTest.cpp @@ -66,17 +66,13 @@ public: virtual void run() { - try + RWRecMutex::TryRLock tlock(_mutex); + test(tlock.acquired()); + { - RWRecMutex::TryRLock lock(_mutex); - // Expected + Mutex::Lock lock(_trylockMutex); + _trylock = true; } - catch(const ThreadLockedException&) - { - test(false); - } - - _trylock = true; _trylockCond.signal(); RWRecMutex::RLock lock(_mutex); @@ -95,17 +91,14 @@ public: virtual void run() { - try - { - RWRecMutex::TryRLock lock(_mutex); - test(false); - } - catch(const ThreadLockedException&) + + RWRecMutex::TryRLock tlock(_mutex); + test(!tlock.acquired()); + { - // Expected + Mutex::Lock lock(_trylockMutex); + _trylock = true; } - - _trylock = true; _trylockCond.signal(); RWRecMutex::RLock lock(_mutex); @@ -257,17 +250,14 @@ public: virtual void run() { - try - { - RWRecMutex::TryWLock lock(_mutex); - test(false); - } - catch(const ThreadLockedException&) + + RWRecMutex::TryWLock tlock(_mutex); + test(!tlock.acquired()); + { - // Expected + Mutex::Lock lock(_trylockMutex); + _trylock = true; } - - _trylock = true; _trylockCond.signal(); RWRecMutex::WLock lock(_mutex); @@ -290,20 +280,23 @@ RWRecMutexTest::run() // TEST: TryLock (read) { RWRecMutex::RLock rlock(mutex); - RWRecMutex::RLock rlock2(mutex); + // RLock testing + test(rlock.acquired()); + try { - RWRecMutex::TryRLock rlock2(mutex); + rlock.acquire(); + test(false); } catch(const ThreadLockedException&) { - test(false); + // Expected } try { - RWRecMutex::TryWLock wlock(mutex); + rlock.tryAcquire(); test(false); } catch(const ThreadLockedException&) @@ -311,58 +304,90 @@ RWRecMutexTest::run() // Expected } + test(rlock.acquired()); + rlock.release(); + test(!rlock.acquired()); + try { - RWRecMutex::TryWLock wlock(mutex, Time::milliSeconds(10)); + rlock.release(); test(false); } catch(const ThreadLockedException&) { // Expected } + + test(rlock.tryAcquire() == true); + test(rlock.acquired()); + + RWRecMutex::RLock rlock2(mutex); + + RWRecMutex::TryRLock trlock(mutex); + test(trlock.acquired()); + + RWRecMutex::TryWLock twlock(mutex); + test(!twlock.acquired()); + + RWRecMutex::TryWLock twlock2(mutex, Time::milliSeconds(10)); + test(!twlock2.acquired()); } // TEST: TryLock (write) { RWRecMutex::WLock wlock(mutex); + + // WLock testing + test(wlock.acquired()); - // TEST: TryLock try { - RWRecMutex::TryRLock rlock(mutex); + wlock.acquire(); test(false); } catch(const ThreadLockedException&) { // Expected } + try { - RWRecMutex::TryRLock rlock(mutex, Time::milliSeconds(10)); + wlock.tryAcquire(); test(false); } catch(const ThreadLockedException&) { // Expected } + + test(wlock.acquired()); + wlock.release(); + test(!wlock.acquired()); + try { - RWRecMutex::TryWLock wlock(mutex); - // Expected - } - catch(const ThreadLockedException&) - { + wlock.release(); test(false); } - try - { - RWRecMutex::TryWLock wlock(mutex, Time::milliSeconds(10)); - // Expected - } catch(const ThreadLockedException&) { - test(false); + // Expected } + + test(wlock.tryAcquire() == true); + test(wlock.acquired()); + + RWRecMutex::TryRLock trlock(mutex); + test(!trlock.acquired()); + + RWRecMutex::TryRLock trlock2(mutex, Time::milliSeconds(10)); + test(!trlock2.acquired()); + + RWRecMutex::TryWLock twlock(mutex); + test(twlock.acquired()); + + RWRecMutex::TryWLock twlock2(mutex, Time::milliSeconds(10)); + test(twlock2.acquired()); } // TEST: read lock @@ -417,15 +442,8 @@ RWRecMutexTest::run() // thread is actually waiting on a write lock. ThreadControl::sleep(Time::seconds(1)); - try - { - RWRecMutex::TryRLock rlock2(mutex); - test(false); - } - catch(const ThreadLockedException&) - { - // Expected - } + RWRecMutex::TryRLock trlock(mutex); + test(!trlock.acquired()); } // @@ -495,29 +513,17 @@ RWRecMutexTest::run() // // A read lock at this point should fail. // - try - { - RWRecMutex::TryRLock rlock2(mutex); - test(false); - } - catch(const ThreadLockedException&) - { - // Expected - } + RWRecMutex::TryRLock trlock(mutex); + test(!trlock.acquired()); + // // As should a write lock. // - try - { - RWRecMutex::TryWLock rlock2(mutex); - test(false); - } - catch(const ThreadLockedException&) - { - // Expected - } - + + RWRecMutex::TryWLock twlock(mutex); + test(!twlock.acquired()); + // // Once the read lock is released then the upgrade should // succeed & the thread should terminate. diff --git a/cpp/test/IceUtil/thread/RecMutexTest.cpp b/cpp/test/IceUtil/thread/RecMutexTest.cpp index 5a8a5c4a1c1..da5fab6c03c 100644 --- a/cpp/test/IceUtil/thread/RecMutexTest.cpp +++ b/cpp/test/IceUtil/thread/RecMutexTest.cpp @@ -34,17 +34,14 @@ public: virtual void run() { - try - { - RecMutex::TryLock lock(_mutex); - test(false); - } - catch(const ThreadLockedException&) + + RecMutex::TryLock tlock(_mutex); + test(!tlock.acquired()); + { - // Expected + Mutex::Lock lock(_trylockMutex); + _trylock = true; } - - _trylock = true; _trylockCond.signal(); RecMutex::Lock lock(_mutex); @@ -90,9 +87,10 @@ RecMutexTest::run() // TEST: lock twice RecMutex::Lock lock2(mutex); - + // TEST: TryLock RecMutex::TryLock lock3(mutex); + test(lock3.acquired()); // TEST: Start thread, try to acquire the mutex. t = new RecMutexTestThread(mutex); @@ -100,11 +98,14 @@ RecMutexTest::run() // TEST: Wait until the trylock has been tested. t->waitTrylock(); + } // // TEST: Once the recursive mutex has been released, the thread // should acquire the mutex and then terminate. // + control.join(); + } |