|
@@ -12,6 +12,8 @@
|
|
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
// PERFORMANCE OF THIS SOFTWARE.
|
|
// PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
|
|
|
|
+#include "config.h"
|
|
|
|
+
|
|
#include "sync.h"
|
|
#include "sync.h"
|
|
|
|
|
|
#include <exceptions/exceptions.h>
|
|
#include <exceptions/exceptions.h>
|
|
@@ -31,12 +33,16 @@ namespace thread {
|
|
|
|
|
|
class Mutex::Impl {
|
|
class Mutex::Impl {
|
|
public:
|
|
public:
|
|
- Impl() :
|
|
|
|
- locked_count(0)
|
|
|
|
|
|
+ Impl()
|
|
|
|
+#ifdef ENABLE_DEBUG
|
|
|
|
+ : locked_count(0)
|
|
|
|
+#endif // ENABLE_DEBUG
|
|
{}
|
|
{}
|
|
|
|
+
|
|
pthread_mutex_t mutex;
|
|
pthread_mutex_t mutex;
|
|
- // Only in debug mode
|
|
|
|
|
|
+#ifdef ENABLE_DEBUG
|
|
size_t locked_count;
|
|
size_t locked_count;
|
|
|
|
+#endif // ENABLE_DEBUG
|
|
};
|
|
};
|
|
|
|
|
|
namespace {
|
|
namespace {
|
|
@@ -70,12 +76,20 @@ Mutex::Mutex() :
|
|
isc_throw(isc::InvalidOperation, std::strerror(result));
|
|
isc_throw(isc::InvalidOperation, std::strerror(result));
|
|
}
|
|
}
|
|
Deinitializer deinitializer(attributes);
|
|
Deinitializer deinitializer(attributes);
|
|
- // TODO: Distinguish if debug mode is enabled in compilation.
|
|
|
|
- // If so, it should be PTHREAD_MUTEX_NORMAL or NULL
|
|
|
|
|
|
+
|
|
|
|
+ // If debug mode is enabled in compilation, use the slower
|
|
|
|
+ // error-checking mutexes that detect deadlocks. Otherwise, use fast
|
|
|
|
+ // mutexes which don't. See the pthread_mutexattr_settype() POSIX
|
|
|
|
+ // documentation which describes these type attributes.
|
|
|
|
+#ifdef ENABLE_DEBUG
|
|
result = pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_ERRORCHECK);
|
|
result = pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_ERRORCHECK);
|
|
|
|
+#else
|
|
|
|
+ result = pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_NORMAL);
|
|
|
|
+#endif // ENABLE_DEBUG
|
|
if (result != 0) {
|
|
if (result != 0) {
|
|
isc_throw(isc::InvalidOperation, std::strerror(result));
|
|
isc_throw(isc::InvalidOperation, std::strerror(result));
|
|
}
|
|
}
|
|
|
|
+
|
|
auto_ptr<Impl> impl(new Impl);
|
|
auto_ptr<Impl> impl(new Impl);
|
|
result = pthread_mutex_init(&impl->mutex, &attributes);
|
|
result = pthread_mutex_init(&impl->mutex, &attributes);
|
|
switch (result) {
|
|
switch (result) {
|
|
@@ -93,12 +107,17 @@ Mutex::Mutex() :
|
|
Mutex::~Mutex() {
|
|
Mutex::~Mutex() {
|
|
if (impl_ != NULL) {
|
|
if (impl_ != NULL) {
|
|
const int result = pthread_mutex_destroy(&impl_->mutex);
|
|
const int result = pthread_mutex_destroy(&impl_->mutex);
|
|
|
|
+
|
|
|
|
+#ifdef ENABLE_DEBUG
|
|
const bool locked = impl_->locked_count != 0;
|
|
const bool locked = impl_->locked_count != 0;
|
|
|
|
+#endif // ENABLE_DEBUG
|
|
|
|
+
|
|
delete impl_;
|
|
delete impl_;
|
|
// We don't want to throw from the destructor. Also, if this ever
|
|
// We don't want to throw from the destructor. Also, if this ever
|
|
// fails, something is really screwed up a lot.
|
|
// fails, something is really screwed up a lot.
|
|
assert(result == 0);
|
|
assert(result == 0);
|
|
|
|
|
|
|
|
+#ifdef ENABLE_DEBUG
|
|
// We should not try to destroy a locked mutex, bad threaded monsters
|
|
// We should not try to destroy a locked mutex, bad threaded monsters
|
|
// could get loose if we ever do and it is also forbidden by pthreads.
|
|
// could get loose if we ever do and it is also forbidden by pthreads.
|
|
|
|
|
|
@@ -106,29 +125,19 @@ Mutex::~Mutex() {
|
|
// pthread_mutex_destroy should check for it already. But it seems
|
|
// pthread_mutex_destroy should check for it already. But it seems
|
|
// there are systems that don't check it.
|
|
// there are systems that don't check it.
|
|
assert(!locked);
|
|
assert(!locked);
|
|
|
|
+#endif // ENABLE_DEBUG
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+#ifdef ENABLE_DEBUG
|
|
|
|
+
|
|
void
|
|
void
|
|
Mutex::postLockAction() {
|
|
Mutex::postLockAction() {
|
|
- // This assertion would fail only in non-debugging mode, in which case
|
|
|
|
- // this method wouldn't be called either, so we simply assert the
|
|
|
|
- // condition.
|
|
|
|
assert(impl_->locked_count == 0);
|
|
assert(impl_->locked_count == 0);
|
|
++impl_->locked_count;
|
|
++impl_->locked_count;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
void
|
|
-Mutex::lock() {
|
|
|
|
- assert(impl_ != NULL);
|
|
|
|
- const int result = pthread_mutex_lock(&impl_->mutex);
|
|
|
|
- if (result != 0) {
|
|
|
|
- isc_throw(isc::InvalidOperation, std::strerror(result));
|
|
|
|
- }
|
|
|
|
- postLockAction(); // Only in debug mode
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-void
|
|
|
|
Mutex::preUnlockAction(bool throw_ok) {
|
|
Mutex::preUnlockAction(bool throw_ok) {
|
|
if (impl_->locked_count == 0) {
|
|
if (impl_->locked_count == 0) {
|
|
if (throw_ok) {
|
|
if (throw_ok) {
|
|
@@ -141,20 +150,35 @@ Mutex::preUnlockAction(bool throw_ok) {
|
|
--impl_->locked_count;
|
|
--impl_->locked_count;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+bool
|
|
|
|
+Mutex::locked() const {
|
|
|
|
+ return (impl_->locked_count != 0);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#endif // ENABLE_DEBUG
|
|
|
|
+
|
|
|
|
+void
|
|
|
|
+Mutex::lock() {
|
|
|
|
+ assert(impl_ != NULL);
|
|
|
|
+ const int result = pthread_mutex_lock(&impl_->mutex);
|
|
|
|
+ if (result != 0) {
|
|
|
|
+ isc_throw(isc::InvalidOperation, std::strerror(result));
|
|
|
|
+ }
|
|
|
|
+#ifdef ENABLE_DEBUG
|
|
|
|
+ postLockAction(); // Only in debug mode
|
|
|
|
+#endif // ENABLE_DEBUG
|
|
|
|
+}
|
|
|
|
+
|
|
void
|
|
void
|
|
Mutex::unlock() {
|
|
Mutex::unlock() {
|
|
assert(impl_ != NULL);
|
|
assert(impl_ != NULL);
|
|
|
|
+#ifdef ENABLE_DEBUG
|
|
preUnlockAction(false); // Only in debug mode. Ensure no throw.
|
|
preUnlockAction(false); // Only in debug mode. Ensure no throw.
|
|
|
|
+#endif // ENABLE_DEBUG
|
|
const int result = pthread_mutex_unlock(&impl_->mutex);
|
|
const int result = pthread_mutex_unlock(&impl_->mutex);
|
|
assert(result == 0); // This should never be possible
|
|
assert(result == 0); // This should never be possible
|
|
}
|
|
}
|
|
|
|
|
|
-// TODO: Disable in non-debug build
|
|
|
|
-bool
|
|
|
|
-Mutex::locked() const {
|
|
|
|
- return (impl_->locked_count != 0);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
class CondVar::Impl {
|
|
class CondVar::Impl {
|
|
public:
|
|
public:
|
|
Impl() {
|
|
Impl() {
|
|
@@ -187,10 +211,13 @@ CondVar::~CondVar() {
|
|
|
|
|
|
void
|
|
void
|
|
CondVar::wait(Mutex& mutex) {
|
|
CondVar::wait(Mutex& mutex) {
|
|
|
|
+#ifdef ENABLE_DEBUG
|
|
mutex.preUnlockAction(true); // Only in debug mode
|
|
mutex.preUnlockAction(true); // Only in debug mode
|
|
const int result = pthread_cond_wait(&impl_->cond_, &mutex.impl_->mutex);
|
|
const int result = pthread_cond_wait(&impl_->cond_, &mutex.impl_->mutex);
|
|
mutex.postLockAction(); // Only in debug mode
|
|
mutex.postLockAction(); // Only in debug mode
|
|
-
|
|
|
|
|
|
+#else
|
|
|
|
+ const int result = pthread_cond_wait(&impl_->cond_, &mutex.impl_->mutex);
|
|
|
|
+#endif
|
|
// pthread_cond_wait should normally succeed unless mutex is completely
|
|
// pthread_cond_wait should normally succeed unless mutex is completely
|
|
// broken.
|
|
// broken.
|
|
if (result != 0) {
|
|
if (result != 0) {
|