diff options
author | Vincent Richard <[email protected]> | 2007-05-22 19:25:59 +0000 |
---|---|---|
committer | Vincent Richard <[email protected]> | 2007-05-22 19:25:59 +0000 |
commit | 8c6ba0e0587b4b28044385da90af408d72a0da01 (patch) | |
tree | 9a5ff41766dc96c9808bccc1777b305ed4d78022 /src | |
parent | Fail if GNU TLS or GNU SASL dev packages are required but not installed. (diff) | |
download | vmime-8c6ba0e0587b4b28044385da90af408d72a0da01.tar.gz vmime-8c6ba0e0587b4b28044385da90af408d72a0da01.zip |
Fixed bug #1721186: thread-safe reference counting.
Diffstat (limited to 'src')
-rw-r--r-- | src/object.cpp | 4 | ||||
-rw-r--r-- | src/utility/smartPtr.cpp | 131 | ||||
-rw-r--r-- | src/utility/smartPtrInt.cpp | 301 |
3 files changed, 306 insertions, 130 deletions
diff --git a/src/object.cpp b/src/object.cpp index 651aa1e1..c03653e9 100644 --- a/src/object.cpp +++ b/src/object.cpp @@ -33,13 +33,13 @@ namespace vmime object::object() - : m_refMgr(new utility::refManager(this)) + : m_refMgr(utility::refManager::create(this)) { } object::object(const object&) - : m_refMgr(new utility::refManager(this)) + : m_refMgr(utility::refManager::create(this)) { } diff --git a/src/utility/smartPtr.cpp b/src/utility/smartPtr.cpp index 16249df8..08a8f57c 100644 --- a/src/utility/smartPtr.cpp +++ b/src/utility/smartPtr.cpp @@ -29,135 +29,10 @@ namespace vmime { namespace utility { -// refManager - -refManager::refManager(object* obj) - : m_object(obj), m_strongCount(1), m_weakCount(1) -{ -} - - -refManager::~refManager() -{ -} - - -const bool refManager::addStrong() -{ - if (m_strongCount <= 0) - return false; - - m_strongCount.increment(); - m_weakCount.increment(); - - return true; -} - - -void refManager::releaseStrong() -{ - m_strongCount.decrement(); - - if (m_strongCount.compareExchange(0, -424242) == 0) // prevent from adding strong refs later - deleteObject(); - - releaseWeak(); -} - - -void refManager::addWeak() -{ - m_weakCount.increment(); -} - - -void refManager::releaseWeak() -{ - if (m_weakCount.decrement() == 0) - deleteManager(); -} - - -object* refManager::getObject() -{ - return m_object; -} - - -void refManager::deleteManager() -{ - delete this; -} - - -void refManager::deleteObject() -{ - try - { - m_object->setRefManager(0); - delete m_object; - } - catch (...) - { - // Exception in destructor - } - - m_object = 0; -} - - -const long refManager::getStrongRefCount() const -{ - return m_strongCount; -} - - -const long refManager::getWeakRefCount() const -{ - return m_weakCount; -} - - - -// refCounter - -refCounter::refCounter(const long initialValue) - : m_value(initialValue) -{ -} - - -refCounter::~refCounter() -{ -} - - -const long refCounter::increment() -{ - return ++m_value; -} - - -const long refCounter::decrement() -{ - return --m_value; -} - - -const long refCounter::compareExchange(const long compare, const long exchangeWith) -{ - const int prev = m_value; - - if (m_value == compare) - m_value = exchangeWith; - - return prev; -} - - -refCounter::operator long() const +void refManager::deleteObjectImpl(object* obj) { - return m_value; + obj->setRefManager(0); + delete obj; } diff --git a/src/utility/smartPtrInt.cpp b/src/utility/smartPtrInt.cpp new file mode 100644 index 00000000..a3036310 --- /dev/null +++ b/src/utility/smartPtrInt.cpp @@ -0,0 +1,301 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2007 Vincent Richard <[email protected]> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/utility/smartPtrInt.hpp" +#include "vmime/object.hpp" + +#if defined(_WIN32) +# include <windows.h> +#elif defined(VMIME_HAVE_PTHREAD) +# include <pthread.h> +#endif + + +namespace vmime { +namespace utility { + + +// static +refManager* refManager::create(object* obj) +{ + return new refManagerImpl(obj); +} + + +// +// refManager +// + +refManagerImpl::refManagerImpl(object* obj) + : m_object(obj), m_strongCount(1), m_weakCount(1) +{ +} + + +refManagerImpl::~refManagerImpl() +{ +} + + +const bool refManagerImpl::addStrong() +{ + if (m_strongCount <= 0) + return false; + + m_strongCount.increment(); + m_weakCount.increment(); + + return true; +} + + +void refManagerImpl::releaseStrong() +{ + if (m_strongCount.decrement() <= 0) + deleteObject(); + + releaseWeak(); +} + + +void refManagerImpl::addWeak() +{ + m_weakCount.increment(); +} + + +void refManagerImpl::releaseWeak() +{ + if (m_weakCount.decrement() <= 0) + deleteManager(); +} + + +object* refManagerImpl::getObject() +{ + return m_object; +} + + +void refManagerImpl::deleteManager() +{ + delete this; +} + + +void refManagerImpl::deleteObject() +{ + try + { + deleteObjectImpl(m_object); + } + catch (...) + { + // Exception in destructor + } + + m_object = 0; +} + + +const long refManagerImpl::getStrongRefCount() const +{ + return m_strongCount; +} + + +const long refManagerImpl::getWeakRefCount() const +{ + return m_weakCount; +} + + + +// +// refCounter +// + +#ifdef _WIN32 + + +refCounter::refCounter(const long initialValue) + : m_value(initialValue) +{ +} + + +refCounter::~refCounter() +{ +} + + +const long refCounter::increment() +{ + return InterlockedIncrement(&m_value); +} + + +const long refCounter::decrement() +{ + return InterlockedDecrement(&m_value); +} + + +refCounter::operator long() const +{ + return m_value; +} + + +#elif defined(__GNUC__) && defined(__GLIBCPP__) + + +refCounter::refCounter(const long initialValue) + : m_value(static_cast <int>(initialValue)) +{ +} + + +refCounter::~refCounter() +{ +} + + +const long refCounter::increment() +{ +#if __GNUC_MINOR__ < 4 && __GNUC__ < 4 + return __exchange_and_add(&m_value, 1) + 1; +#else + return __gnu_cxx::__exchange_and_add(&m_value, 1) + 1; +#endif +} + + +const long refCounter::decrement() +{ +#if __GNUC_MINOR__ < 4 && __GNUC__ < 4 + return __exchange_and_add(&m_value, -1) - 1; +#else + return __gnu_cxx::__exchange_and_add(&m_value, -1) - 1; +#endif +} + + +refCounter::operator long() const +{ +#if __GNUC_MINOR__ < 4 && __GNUC__ < 4 + return static_cast <long>(__exchange_and_add(&m_value, 0)); +#else + return static_cast <long>(__gnu_cxx::__exchange_and_add(&m_value, 0)); +#endif +} + + +#elif defined(VMIME_HAVE_PTHREAD) + + +refCounter::refCounter(const long initialValue) + : m_value(initialValue) +{ + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); + pthread_mutex_init(&m_mutex, &attr); + pthread_mutexattr_destroy(&attr); +} + + +refCounter::~refCounter() +{ + pthread_mutex_destroy(&m_mutex); +} + + +const long refCounter::increment() +{ + long value; + + pthread_mutex_lock(&m_mutex); + value = ++m_value; + pthread_mutex_unlock(&m_mutex); + + return value; +} + + +const long refCounter::decrement() +{ + long value; + + pthread_mutex_lock(&m_mutex); + value = --m_value; + pthread_mutex_unlock(&m_mutex); + + return value; +} + + +refCounter::operator long() const +{ + return m_value; +} + + +#else // not thread-safe implementation + + +refCounter::refCounter(const long initialValue) + : m_value(initialValue) +{ +} + + +refCounter::~refCounter() +{ +} + + +const long refCounter::increment() +{ + return ++m_value; +} + + +const long refCounter::decrement() +{ + return --m_value; +} + + +refCounter::operator long() const +{ + return m_value; +} + + +#endif + + +} // utility +} // vmime + |