Remove boost atomic dependency from ResourceObject
authorcoderhyme <jhyo.kim@samsung.com>
Fri, 14 Aug 2015 08:06:32 +0000 (17:06 +0900)
committerMadan Lanka <lanka.madan@samsung.com>
Tue, 18 Aug 2015 01:53:50 +0000 (01:53 +0000)
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 <jhyo.kim@samsung.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/2209
Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
Reviewed-by: Hun-je Yeon <hunje.yeon@samsung.com>
Reviewed-by: Madan Lanka <lanka.madan@samsung.com>
service/resource-encapsulation/include/RCSResourceObject.h
service/resource-encapsulation/src/common/utils/include/AtomicHelper.h [new file with mode: 0644]
service/resource-encapsulation/src/serverBuilder/SConscript
service/resource-encapsulation/src/serverBuilder/src/RCSResourceObject.cpp
service/resource-encapsulation/src/serverBuilder/unittests/RCSResourceObjectTest.cpp

index 7c0c636..85c7848 100644 (file)
@@ -31,8 +31,6 @@
 #include <mutex>
 #include <thread>
 
-#include <boost/atomic.hpp>
-
 #include <RCSResourceAttributes.h>
 #include <RCSResponse.h>
 #include <RCSRequest.h>
@@ -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 (file)
index 0000000..9a48d37
--- /dev/null
@@ -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 <atomic>
+#include <boost/version.hpp>
+
+#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 <boost/atomic.hpp>
+#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
index 98e0cb7..c0aa20a 100644 (file)
@@ -42,6 +42,7 @@ release = env.get('RELEASE')
 ######################################################################
 server_builder_env.AppendUnique(CPPPATH = [
     '../common/primitiveResource/include',
+    '../common/utils/include',
     '../../include',
     ])
 
index 097ecac..ffbf522 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <RequestHandler.h>
 #include <AssertUtils.h>
+#include <AtomicHelper.h>
 #include <ResourceAttributesConverter.h>
 
 #include <logger.h>
@@ -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;
         }
+
     }
 }
index 33cfaa6..435859d 100644 (file)
@@ -287,7 +287,8 @@ public:
     {
         auto request = make_shared<OCResourceRequest>();
 
-        OCEntityHandlerRequest ocEntityHandlerRequest { 0 };
+        OCEntityHandlerRequest ocEntityHandlerRequest;
+        memset(&ocEntityHandlerRequest, 0, sizeof(OCEntityHandlerRequest));
         OC::MessageContainer mc;
 
         mc.addRepresentation(ocRep);