summaryrefslogtreecommitdiff
path: root/cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp')
-rw-r--r--cpp/config/Make.rules.Linux2
-rw-r--r--cpp/include/IceUtil/Cond.h4
-rw-r--r--cpp/include/IceUtil/Config.h5
-rw-r--r--cpp/include/IceUtil/Lock.h85
-rw-r--r--cpp/include/IceUtil/Monitor.h11
-rw-r--r--cpp/include/IceUtil/Mutex.h86
-rw-r--r--cpp/include/IceUtil/RWRecMutex.h198
-rw-r--r--cpp/include/IceUtil/RecMutex.h32
-rw-r--r--cpp/include/IceUtil/ThreadException.h3
-rw-r--r--cpp/src/IceUtil/Cond.cpp18
-rw-r--r--cpp/src/IceUtil/RWRecMutex.cpp25
-rw-r--r--cpp/src/IceUtil/RecMutex.cpp71
-rw-r--r--cpp/src/IceUtil/Thread.cpp16
-rw-r--r--cpp/src/IceUtil/ThreadException.cpp15
-rw-r--r--cpp/src/IceUtil/UUID.cpp5
-rw-r--r--cpp/test/IceUtil/thread/MonitorMutexTest.cpp26
-rw-r--r--cpp/test/IceUtil/thread/MonitorRecMutexTest.cpp27
-rw-r--r--cpp/test/IceUtil/thread/MutexTest.cpp72
-rw-r--r--cpp/test/IceUtil/thread/RWRecMutexTest.cpp154
-rw-r--r--cpp/test/IceUtil/thread/RecMutexTest.cpp21
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();
+
}