From 226d1f85da76a8a186fd74380ce374fc7b30f890 Mon Sep 17 00:00:00 2001 From: coderhyme Date: Fri, 14 Aug 2015 17:06:32 +0900 Subject: [PATCH] Remove boost atomic dependency from ResourceObject It uses one of std and boost if possible. When they are not fittable which means the boost version is lower than 1.53.0 and the template parameter is not an integral type, then it selects handmade atomic class. Change-Id: I556a936f933d524bb4c78224202da4d742c6e9d5 Signed-off-by: coderhyme Reviewed-on: https://gerrit.iotivity.org/gerrit/2209 Tested-by: jenkins-iotivity Reviewed-by: Hun-je Yeon Reviewed-by: Madan Lanka --- .../include/RCSResourceObject.h | 15 +- .../src/common/utils/include/AtomicHelper.h | 306 +++++++++++++++++++++ .../src/serverBuilder/SConscript | 1 + .../src/serverBuilder/src/RCSResourceObject.cpp | 31 ++- .../unittests/RCSResourceObjectTest.cpp | 3 +- 5 files changed, 342 insertions(+), 14 deletions(-) create mode 100644 service/resource-encapsulation/src/common/utils/include/AtomicHelper.h diff --git a/service/resource-encapsulation/include/RCSResourceObject.h b/service/resource-encapsulation/include/RCSResourceObject.h index 7c0c636..85c7848 100644 --- a/service/resource-encapsulation/include/RCSResourceObject.h +++ b/service/resource-encapsulation/include/RCSResourceObject.h @@ -31,8 +31,6 @@ #include #include -#include - #include #include #include @@ -59,6 +57,11 @@ namespace OIC NoLockException(std::string &&what) : RCSException { std::move(what) } {} }; + //! @cond + template < typename T > + class AtomicWrapper; + //! @endcond + /** * @brief RCSResourceObject represents a resource. It handles any requests from * clients automatically with attributes. @@ -76,6 +79,8 @@ namespace OIC private: class WeakGuard; + typedef AtomicWrapper< std::thread::id > AtomicThreadId; + public: /** * @brief represents the policy of AutoNotify function. @@ -433,6 +438,10 @@ namespace OIC void expectOwnLock() const; + std::thread::id getLockOwner() const noexcept; + + void setLockOwner(std::thread::id&&) const noexcept; + void autoNotify(bool, AutoNotifyPolicy) const; void autoNotify(bool) const; @@ -455,7 +464,7 @@ namespace OIC std::unordered_map< std::string, AttributeUpdatedListener > m_keyAttributesUpdatedListeners; - mutable boost::atomic< std::thread::id > m_lockOwner; + mutable std::unique_ptr< AtomicThreadId > m_lockOwner; mutable std::mutex m_mutex; std::mutex m_mutexKeyAttributeUpdate; diff --git a/service/resource-encapsulation/src/common/utils/include/AtomicHelper.h b/service/resource-encapsulation/src/common/utils/include/AtomicHelper.h new file mode 100644 index 0000000..9a48d37 --- /dev/null +++ b/service/resource-encapsulation/src/common/utils/include/AtomicHelper.h @@ -0,0 +1,306 @@ +//****************************************************************** +// +// Copyright 2015 Samsung Electronics All Rights Reserved. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +#ifndef COMMON_UTILS_ATOMICHELPER_H +#define COMMON_UTILS_ATOMICHELPER_H + +#include +#include + +#ifdef __GNUC__ +#define RCS_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#endif + +#if defined(RCS_GCC_VERSION) && RCS_GCC_VERSION >= 40700 +#define RCS_USE_STD_ATOMIC +#elif BOOST_VERSION >= 105300 +#include +#define RCS_USE_BOOST_ATOMIC +#else +#define RCS_USE_CUSTOM_ATOMIC +#endif + +namespace OIC +{ + namespace Service + { + namespace Detail + { + + class ScopedLock + { + public: + explicit ScopedLock(std::atomic_flag& flag) noexcept : + m_flag(flag) + { + while (m_flag.test_and_set(std::memory_order_acquire)); + } + + ~ScopedLock() noexcept + { + m_flag.clear(std::memory_order_release); + } + + ScopedLock(const ScopedLock&) = delete; + ScopedLock& operator=(const ScopedLock&) = delete; + + private: + std::atomic_flag& m_flag; + }; + + template< typename T > + class CustomAtomic + { + public: + CustomAtomic() noexcept : + m_value { }, + m_flag { ATOMIC_FLAG_INIT } + { + + } + ~CustomAtomic() = default; + + CustomAtomic(const CustomAtomic&) = delete; + + CustomAtomic& operator=(const CustomAtomic&) = delete; + CustomAtomic& operator=(const CustomAtomic&) volatile = delete; + + explicit CustomAtomic(T v) noexcept : + m_value{ v }, + m_flag { ATOMIC_FLAG_INIT } + { + } + + operator T() const noexcept + { + return load(); + } + + operator T() const volatile noexcept + { + return load(); + } + + T operator=(T v) noexcept + { + store(v); + return v; + } + + T operator=(T v) volatile noexcept + { + store(v); + return v; + } + + bool is_lock_free() const noexcept + { + return false; + } + + bool is_lock_free() const volatile noexcept + { + return false; + } + + void store(T v, std::memory_order = std::memory_order_seq_cst) noexcept + { + ScopedLock guard(m_flag); + memcpy(&m_value, &v, sizeof(T)); + } + + void store(T v, std::memory_order = std::memory_order_seq_cst) volatile noexcept + { + ScopedLock guard(m_flag); + memcpy(&m_value, &v, sizeof(T)); + } + + T load(std::memory_order = std::memory_order_seq_cst) const noexcept + { + ScopedLock guard(m_flag); + + T v; + memcpy(&v, &m_value, sizeof(T)); + return v; + } + + T load(std::memory_order = std::memory_order_seq_cst) const volatile noexcept + { + ScopedLock guard(m_flag); + + T v; + memcpy(&v, &m_value, sizeof(T)); + return v; + } + + T exchange(T v, std::memory_order = std::memory_order_seq_cst) noexcept + { + ScopedLock guard(m_flag); + + T tmp; + memcpy(&tmp, &m_value, sizeof(T)); + + memcpy(&m_value, &v, sizeof(T)); + return tmp; + } + + T exchange(T v, std::memory_order = std::memory_order_seq_cst) volatile noexcept + { + ScopedLock guard(m_flag); + + T tmp; + memcpy(&tmp, &m_value, sizeof(T)); + + memcpy(&m_value, &v, sizeof(T)); + return tmp; + } + + bool compare_exchange_weak(T& expected, T desired, std::memory_order success, + std::memory_order failure) volatile noexcept + { + return compare_exchange_strong(expected, desired, success, failure); + } + + bool compare_exchange_weak(T& expected, T desired, + std::memory_order m = std::memory_order_seq_cst) volatile noexcept + { + return compare_exchange_weak(expected, desired, m, m); + } + + bool compare_exchange_strong(T& expected, T desired, std::memory_order /*success*/, + std::memory_order /*failure*/) volatile noexcept + { + ScopedLock guard(m_flag); + + if (memcmp(&m_value, &expected, sizeof(T)) == 0) { + memcpy(&m_value, &desired, sizeof(T)); + return true; + } else { + memcpy(&expected, &m_value, sizeof(T)); + return false; + } + } + + bool compare_exchange_strong(T& expected, T desired, + std::memory_order m = std::memory_order_seq_cst) volatile noexcept + { + return compare_exchange_strong(expected, desired, m, m); + } + + private: + T m_value; + mutable std::atomic_flag m_flag; + }; + +#if defined(RCS_USE_BOOST_ATOMIC) + inline boost::memory_order convertMemoryOrder(std::memory_order m) noexcept + { + switch(m) + { + case std::memory_order_relaxed: return boost::memory_order_relaxed; + case std::memory_order_consume: return boost::memory_order_consume; + case std::memory_order_acquire: return boost::memory_order_acquire; + case std::memory_order_release: return boost::memory_order_release; + case std::memory_order_acq_rel: return boost::memory_order_acq_rel; + case std::memory_order_seq_cst: return boost::memory_order_seq_cst; + } + return boost::memory_order_seq_cst; + } +#else + inline std::memory_order convertMemoryOrder(std::memory_order m) noexcept + { + return m; + } +#endif + + } // namespace detail + + template < typename T > + struct AtomicBase + { +#if defined(RCS_USE_STD_ATOMIC) + typedef std::atomic< T > type; +#elif defined(RCS_USE_BOOST_ATOMIC) + typedef boost::atomic< T > type; +#else + typedef typename std::conditional< std::is_integral< T >::value, std::atomic< T >, + Detail::CustomAtomic< T > >::type type; +#endif + }; + + template< typename T > + class AtomicWrapper + { + public: + AtomicWrapper() = default; + + AtomicWrapper(T v) : + m_base{ v } + { + } + + AtomicWrapper(const AtomicWrapper&) = delete; + AtomicWrapper& operator=(const AtomicWrapper&) = delete; + + operator T() const noexcept + { + return load(); + } + + operator T() const volatile noexcept + { + return load(); + } + + T operator=(T v) noexcept + { + store(v); + return v; + } + + T operator=(T v) volatile noexcept + { + store(v); + return v; + } + + T load(std::memory_order order = std::memory_order_seq_cst) const noexcept + { + return m_base.load(Detail::convertMemoryOrder(order)); + } + + T load(std::memory_order order = std::memory_order_seq_cst) const volatile noexcept + { + return m_base.load(Detail::convertMemoryOrder(order)); + } + + void store(T v, std::memory_order order = std::memory_order_seq_cst) noexcept + { + m_base.store(v, Detail::convertMemoryOrder(order)); + } + + private: + typename AtomicBase< T >::type m_base; + }; + + } +} + +#endif // COMMON_UTILS_ATOMICHELPER_H diff --git a/service/resource-encapsulation/src/serverBuilder/SConscript b/service/resource-encapsulation/src/serverBuilder/SConscript index 98e0cb7..c0aa20a 100644 --- a/service/resource-encapsulation/src/serverBuilder/SConscript +++ b/service/resource-encapsulation/src/serverBuilder/SConscript @@ -42,6 +42,7 @@ release = env.get('RELEASE') ###################################################################### server_builder_env.AppendUnique(CPPPATH = [ '../common/primitiveResource/include', + '../common/utils/include', '../../include', ]) diff --git a/service/resource-encapsulation/src/serverBuilder/src/RCSResourceObject.cpp b/service/resource-encapsulation/src/serverBuilder/src/RCSResourceObject.cpp index 097ecac..ffbf522 100644 --- a/service/resource-encapsulation/src/serverBuilder/src/RCSResourceObject.cpp +++ b/service/resource-encapsulation/src/serverBuilder/src/RCSResourceObject.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -199,6 +200,7 @@ namespace OIC m_mutex{ }, m_mutexKeyAttributeUpdate{ } { + m_lockOwner.reset(new AtomicThreadId); } RCSResourceObject::~RCSResourceObject() @@ -306,12 +308,22 @@ namespace OIC void RCSResourceObject::expectOwnLock() const { - if (m_lockOwner != std::this_thread::get_id()) + if (getLockOwner() != std::this_thread::get_id()) { throw NoLockException{ "Must acquire the lock first using LockGuard." }; } } + std::thread::id RCSResourceObject::getLockOwner() const noexcept + { + return *m_lockOwner; + } + + void RCSResourceObject::setLockOwner(std::thread::id&& id) const noexcept + { + m_lockOwner->store(std::move(id)); + } + bool RCSResourceObject::isObservable() const { return ::hasProperty(m_properties, OC_OBSERVABLE); @@ -496,10 +508,8 @@ namespace OIC } OCEntityHandlerResult RCSResourceObject::handleObserve( - std::shared_ptr< OC::OCResourceRequest > request) + std::shared_ptr< OC::OCResourceRequest >) { - assert(request != nullptr); - if (!isObservable()) { return OC_EH_ERROR; @@ -549,17 +559,17 @@ namespace OIC if (m_isOwningLock) { - m_resourceObject.m_lockOwner = std::thread::id{ }; + m_resourceObject.setLockOwner(std::thread::id{ }); m_resourceObject.m_mutex.unlock(); } } void RCSResourceObject::LockGuard::init() { - if (m_resourceObject.m_lockOwner != std::this_thread::get_id()) + if (m_resourceObject.getLockOwner() != std::this_thread::get_id()) { m_resourceObject.m_mutex.lock(); - m_resourceObject.m_lockOwner = std::this_thread::get_id(); + m_resourceObject.setLockOwner(std::this_thread::get_id()); m_isOwningLock = true; } m_autoNotifyFunc = ::createAutoNotifyInvoker(&RCSResourceObject::autoNotify, @@ -571,10 +581,10 @@ namespace OIC m_isOwningLock{ false }, m_resourceObject(resourceObject) { - if (resourceObject.m_lockOwner != std::this_thread::get_id()) + if (m_resourceObject.getLockOwner() != std::this_thread::get_id()) { m_resourceObject.m_mutex.lock(); - m_resourceObject.m_lockOwner = std::this_thread::get_id(); + m_resourceObject.setLockOwner(std::this_thread::get_id()); m_isOwningLock = true; } } @@ -583,7 +593,7 @@ namespace OIC { if (m_isOwningLock) { - m_resourceObject.m_lockOwner = std::thread::id{ }; + m_resourceObject.setLockOwner(std::thread::id{ }); m_resourceObject.m_mutex.unlock(); } } @@ -592,5 +602,6 @@ namespace OIC { return m_isOwningLock; } + } } diff --git a/service/resource-encapsulation/src/serverBuilder/unittests/RCSResourceObjectTest.cpp b/service/resource-encapsulation/src/serverBuilder/unittests/RCSResourceObjectTest.cpp index 33cfaa6..435859d 100644 --- a/service/resource-encapsulation/src/serverBuilder/unittests/RCSResourceObjectTest.cpp +++ b/service/resource-encapsulation/src/serverBuilder/unittests/RCSResourceObjectTest.cpp @@ -287,7 +287,8 @@ public: { auto request = make_shared(); - OCEntityHandlerRequest ocEntityHandlerRequest { 0 }; + OCEntityHandlerRequest ocEntityHandlerRequest; + memset(&ocEntityHandlerRequest, 0, sizeof(OCEntityHandlerRequest)); OC::MessageContainer mc; mc.addRepresentation(ocRep); -- 2.7.4