From ba59abba3ee3d9b6b9cc513aeb9659ddc9c3b079 Mon Sep 17 00:00:00 2001
From: Paul Wisbey
Date: Mon, 17 Feb 2020 16:28:52 +0000
Subject: [PATCH] Moved SingletonService into dali-core
Change-Id: I72649695560fa6acafbdeb5f48df61c7d4c75509
---
automated-tests/src/dali/CMakeLists.txt | 1 +
.../src/dali/utc-Dali-SingletonService.cpp | 84 +++++++++++++++++
dali/devel-api/common/singleton-service.cpp | 60 ++++++++++++
dali/devel-api/common/singleton-service.h | 104 +++++++++++++++++++++
dali/devel-api/file.list | 2 +
dali/internal/common/core-impl.cpp | 5 +-
.../internal/event/common/thread-local-storage.cpp | 64 +++++++++++++
dali/internal/event/common/thread-local-storage.h | 70 ++++++++++++--
8 files changed, 382 insertions(+), 8 deletions(-)
create mode 100644 automated-tests/src/dali/utc-Dali-SingletonService.cpp
create mode 100644 dali/devel-api/common/singleton-service.cpp
create mode 100755 dali/devel-api/common/singleton-service.h
diff --git a/automated-tests/src/dali/CMakeLists.txt b/automated-tests/src/dali/CMakeLists.txt
index 169f2d1..6db6c25 100644
--- a/automated-tests/src/dali/CMakeLists.txt
+++ b/automated-tests/src/dali/CMakeLists.txt
@@ -89,6 +89,7 @@ SET(TC_SOURCES
utc-Dali-SignalDelegate.cpp
utc-Dali-SignalTemplatesFunctors.cpp
utc-Dali-SignalTemplates.cpp
+ utc-Dali-SingletonService.cpp
utc-Dali-Stage.cpp
utc-Dali-TapGesture.cpp
utc-Dali-TapGestureDetector.cpp
diff --git a/automated-tests/src/dali/utc-Dali-SingletonService.cpp b/automated-tests/src/dali/utc-Dali-SingletonService.cpp
new file mode 100644
index 0000000..21087cd
--- /dev/null
+++ b/automated-tests/src/dali/utc-Dali-SingletonService.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include
+#include
+#include
+#include
+#include
+
+using namespace Dali;
+
+namespace
+{
+
+class TestHandle : public BaseHandle
+{
+public:
+ TestHandle() {}
+ TestHandle( BaseObject* object ) : BaseHandle( object ) {}
+};
+
+class TestObject : public BaseObject
+{
+};
+
+} // unnamed namespace
+
+void utc_dali_singleton_service_startup(void)
+{
+ test_return_value = TET_UNDEF;
+}
+
+void utc_dali_singleton_service_cleanup(void)
+{
+ test_return_value = TET_PASS;
+}
+
+int UtcDaliSingletonServiceGet(void)
+{
+ // Attempt to retrieve SingletonService before creating application
+ SingletonService singletonService;
+ singletonService = SingletonService::Get();
+ DALI_TEST_CHECK( !singletonService );
+
+ // Create Application class, should be able to retrieve SingletonService now
+ TestApplication application;
+ singletonService = SingletonService::Get();
+ DALI_TEST_CHECK( singletonService );
+
+ END_TEST;
+}
+
+int UtcDaliSingletonServiceRegisterAndGetSingleton(void)
+{
+ TestApplication application;
+ SingletonService singletonService( SingletonService::Get() );
+
+ // Attempt to register an empty handle
+ TestHandle handle;
+ singletonService.Register( typeid( handle ), handle );
+ DALI_TEST_CHECK( !singletonService.GetSingleton( typeid( handle ) ) );
+
+ // Create an actor instance and retrieve, should be valid this time
+ handle = TestHandle( new TestObject );
+ singletonService.Register( typeid( handle ), handle );
+ DALI_TEST_CHECK( singletonService.GetSingleton( typeid( handle ) ) );
+
+ END_TEST;
+}
diff --git a/dali/devel-api/common/singleton-service.cpp b/dali/devel-api/common/singleton-service.cpp
new file mode 100644
index 0000000..715e3ed
--- /dev/null
+++ b/dali/devel-api/common/singleton-service.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include
+
+// INTERNAL INCLUDES
+#include
+
+namespace Dali
+{
+
+SingletonService::SingletonService()
+{
+}
+
+SingletonService SingletonService::Get()
+{
+ return Internal::ThreadLocalStorage::GetSingletonService();
+}
+
+SingletonService::~SingletonService()
+{
+}
+
+void SingletonService::Register( const std::type_info& info, BaseHandle singleton )
+{
+ GetImplementation( *this ).Register( info, singleton );
+}
+
+void SingletonService::UnregisterAll()
+{
+ GetImplementation( *this ).UnregisterAll();
+}
+
+BaseHandle SingletonService::GetSingleton( const std::type_info& info ) const
+{
+ return GetImplementation( *this ).GetSingleton( info );
+}
+
+SingletonService::SingletonService( Internal::ThreadLocalStorage* tls )
+: BaseHandle( tls )
+{
+}
+
+} // namespace Dali
diff --git a/dali/devel-api/common/singleton-service.h b/dali/devel-api/common/singleton-service.h
new file mode 100755
index 0000000..7677487
--- /dev/null
+++ b/dali/devel-api/common/singleton-service.h
@@ -0,0 +1,104 @@
+#ifndef DALI_SINGELTON_SERVICE_H
+#define DALI_SINGELTON_SERVICE_H
+
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include
+#include
+
+namespace Dali
+{
+
+namespace Internal DALI_INTERNAL
+{
+class ThreadLocalStorage;
+}
+
+/**
+ * @brief Allows the registration of a class as a singleton
+ *
+ * @note This class is created by the Application class and is destroyed when the Application class is destroyed.
+ *
+ * @see Application
+ */
+class DALI_CORE_API SingletonService : public BaseHandle
+{
+public:
+
+ /**
+ * @brief Create an uninitialized handle.
+ *
+ * This can be initialized by calling SingletonService::Get().
+ */
+ SingletonService();
+
+ /**
+ * @brief Retrieves a handle to the SingletonService.
+ *
+ * @return A handle to the SingletonService if it is available. This will be an empty handle if
+ * the service is not available.
+ */
+ static SingletonService Get();
+
+ /**
+ * @brief Destructor
+ *
+ * This is non-virtual since derived Handle types must not contain data or virtual methods.
+ */
+ ~SingletonService();
+
+ /**
+ * @brief Registers the singleton of Dali handle with its type info.
+ *
+ * The singleton will be kept alive for the lifetime of the service.
+ *
+ * @note This is not intended for application developers.
+ * @param[in] info The type info of the Dali handle generated by the compiler.
+ * @param[in] singleton The Dali handle to be registered
+ */
+ void Register( const std::type_info& info, BaseHandle singleton );
+
+ /**
+ * @brief Unregisters all singletons.
+ *
+ * @note This is not intended for application developers.
+ */
+ void UnregisterAll();
+
+ /**
+ * @brief Gets the singleton for the given type.
+ *
+ * @note This is not intended for application developers.
+ * @param[in] info The type info of the given type.
+ * @return the Dali handle if it is registered as a singleton or an uninitialized handle.
+ */
+ BaseHandle GetSingleton( const std::type_info& info ) const;
+
+public: // Not intended for application developers
+
+ /**
+ * @brief This constructor is used by SingletonService::Get().
+ * @param[in] singletonService A pointer to the internal singleton-service object.
+ */
+ explicit DALI_INTERNAL SingletonService( Internal::ThreadLocalStorage* singletonService );
+};
+
+} // namespace Dali
+
+#endif // DALI_SINGELTON_SERVICE_H
diff --git a/dali/devel-api/file.list b/dali/devel-api/file.list
index 78f1aab..5ac372f 100644
--- a/dali/devel-api/file.list
+++ b/dali/devel-api/file.list
@@ -9,6 +9,7 @@ SET( devel_api_src_files
${devel_api_src_dir}/animation/animation-devel.cpp
${devel_api_src_dir}/animation/path-constrainer.cpp
${devel_api_src_dir}/common/hash.cpp
+ ${devel_api_src_dir}/common/singleton-service.cpp
${devel_api_src_dir}/common/stage-devel.cpp
${devel_api_src_dir}/events/hit-test-algorithm.cpp
${devel_api_src_dir}/events/long-press-gesture-detector-devel.cpp
@@ -52,6 +53,7 @@ SET( devel_api_core_common_header_files
${devel_api_src_dir}/common/bitwise-enum.h
${devel_api_src_dir}/common/circular-queue.h
${devel_api_src_dir}/common/hash.h
+ ${devel_api_src_dir}/common/singleton-service.h
${devel_api_src_dir}/common/map-wrapper.h
${devel_api_src_dir}/common/owner-container.h
${devel_api_src_dir}/common/ref-counted-dali-vector.h
diff --git a/dali/internal/common/core-impl.cpp b/dali/internal/common/core-impl.cpp
index ac0c500..43f2a2a 100644
--- a/dali/internal/common/core-impl.cpp
+++ b/dali/internal/common/core-impl.cpp
@@ -153,7 +153,7 @@ Core::~Core()
if( tls )
{
tls->Remove();
- delete tls;
+ tls->Unreference();
}
mObjectRegistry.Reset();
@@ -432,7 +432,8 @@ void Core::CreateThreadLocalStorage()
{
// a pointer to the ThreadLocalStorage object will be stored in TLS
// The ThreadLocalStorage object should be deleted by the Core destructor
- new ThreadLocalStorage(this);
+ ThreadLocalStorage* tls = new ThreadLocalStorage(this);
+ tls->Reference();
}
void Core::RegisterObject( Dali::BaseObject* object )
diff --git a/dali/internal/event/common/thread-local-storage.cpp b/dali/internal/event/common/thread-local-storage.cpp
index 8ce6c11..2424d41 100644
--- a/dali/internal/event/common/thread-local-storage.cpp
+++ b/dali/internal/event/common/thread-local-storage.cpp
@@ -22,6 +22,23 @@
#include
#include
#include
+#include
+
+#if defined(DEBUG_ENABLED)
+#include
+Debug::Filter* gSingletonServiceLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_SINGLETON_SERVICE" );
+
+// Need to define own macro as the log function is not installed when this object is created so no logging is shown with DALI_LOG_INFO at construction and destruction
+#define DALI_LOG_SINGLETON_SERVICE_DIRECT(level, message) \
+ if(gSingletonServiceLogFilter && gSingletonServiceLogFilter->IsEnabledFor(level)) { std::string string(message); Dali::TizenPlatform::LogMessage( Debug::DebugInfo, string ); }
+
+#define DALI_LOG_SINGLETON_SERVICE(level, format, ...) DALI_LOG_INFO(gSingletonServiceLogFilter, level, format, ## __VA_ARGS__ )
+#else
+
+#define DALI_LOG_SINGLETON_SERVICE_DIRECT(level, message)
+#define DALI_LOG_SINGLETON_SERVICE(level, format, ...)
+
+#endif
namespace Dali
{
@@ -58,6 +75,16 @@ ThreadLocalStorage& ThreadLocalStorage::Get()
return *threadLocal;
}
+Dali::SingletonService ThreadLocalStorage::GetSingletonService()
+{
+ Dali::SingletonService singletonService;
+ if ( threadLocal )
+ {
+ singletonService = Dali::SingletonService( threadLocal );
+ }
+ return singletonService;
+}
+
bool ThreadLocalStorage::Created()
{
// see if the TLS has been set yet
@@ -134,6 +161,43 @@ void ThreadLocalStorage::RemoveScene( Scene* scene )
mCore->RemoveScene( scene );
}
+void ThreadLocalStorage::Register( const std::type_info& info, BaseHandle singleton )
+{
+ if( singleton )
+ {
+ DALI_LOG_SINGLETON_SERVICE( Debug::General, "Singleton Added: %s\n", info.name() );
+ mSingletonContainer.push_back( SingletonPair( info.name(), singleton ) );
+
+ Integration::Processor* processor = dynamic_cast( &singleton.GetBaseObject() );
+ if( processor )
+ {
+ mCore->RegisterProcessor( *processor );
+ }
+ }
+}
+
+void ThreadLocalStorage::UnregisterAll( )
+{
+ mSingletonContainer.clear();
+}
+
+BaseHandle ThreadLocalStorage::GetSingleton( const std::type_info& info ) const
+{
+ BaseHandle object;
+
+ const SingletonContainer::const_iterator end = mSingletonContainer.end();
+ for( SingletonContainer::const_iterator iter = mSingletonContainer.begin(); iter != end; ++iter )
+ {
+ // comparing the addresses as these are allocated statically per library
+ if( ( *iter ).first == info.name() )
+ {
+ object = ( *iter ).second;
+ }
+ }
+
+ return object;
+}
+
} // namespace Internal
} // namespace Dali
diff --git a/dali/internal/event/common/thread-local-storage.h b/dali/internal/event/common/thread-local-storage.h
index 448a61f..0335955 100644
--- a/dali/internal/event/common/thread-local-storage.h
+++ b/dali/internal/event/common/thread-local-storage.h
@@ -18,7 +18,11 @@
*
*/
+// EXTERNAL INCLUDES
+#include
+
// INTERNAL INCLUDES
+#include
#include
#include
@@ -52,7 +56,7 @@ class UpdateManager;
* Class to store a pointer to core in thread local storage.
*
*/
-class ThreadLocalStorage
+class ThreadLocalStorage : public Dali::BaseObject
{
public:
@@ -64,11 +68,6 @@ public:
ThreadLocalStorage(Core* core);
/**
- * Destructor.
- */
- ~ThreadLocalStorage();
-
- /**
* Remove core pointer.
* Prevents the core pointer being automatically deleted when the thread exits.
*/
@@ -81,6 +80,11 @@ public:
static ThreadLocalStorage& Get();
/**
+ * @copydoc Dali::SingletonService::Get()
+ */
+ static Dali::SingletonService GetSingletonService();
+
+ /**
* Checks if the TLS has been created
* @return if the TLS has been created
*/
@@ -172,14 +176,68 @@ public:
*/
void RemoveScene( Scene* scene );
+ /**
+ * @copydoc Dali::SingletonService::Register()
+ */
+ void Register( const std::type_info& info, BaseHandle singleton );
+
+ /**
+ * @copydoc Dali::SingletonService::UnregisterAll()
+ */
+ void UnregisterAll();
+
+ /**
+ * @copydoc Dali::SingletonService::GetSingleton()
+ */
+ BaseHandle GetSingleton( const std::type_info& info ) const;
+
+private:
+
+ /**
+ * Virtual Destructor
+ */
+ virtual ~ThreadLocalStorage();
+
+ // Undefined
+ ThreadLocalStorage( const ThreadLocalStorage& );
+ ThreadLocalStorage& operator=( ThreadLocalStorage& );
+
private:
Core* mCore; ///< reference to core
+ // using the address of the type name string as compiler will allocate these once per library
+ // and we don't support un/re-loading of dali libraries while singleton service is alive
+ typedef std::pair< const char*, BaseHandle> SingletonPair;
+ typedef std::vector< SingletonPair > SingletonContainer;
+ typedef SingletonContainer::const_iterator SingletonConstIter;
+
+ SingletonContainer mSingletonContainer; ///< The container to look up singleton by its type name
+
};
} // namespace Internal
+// Helpers for public-api forwarding methods
+
+inline Internal::ThreadLocalStorage& GetImplementation(Dali::SingletonService& service)
+{
+ DALI_ASSERT_ALWAYS( service && "SingletonService handle is empty" );
+
+ BaseObject& handle = service.GetBaseObject();
+
+ return static_cast(handle);
+}
+
+inline const Internal::ThreadLocalStorage& GetImplementation(const Dali::SingletonService& service)
+{
+ DALI_ASSERT_ALWAYS( service && "SingletonService handle is empty" );
+
+ const BaseObject& handle = service.GetBaseObject();
+
+ return static_cast(handle);
+}
+
} // namespace Dali
#endif // DALI_INTERNAL_THREAD_LOCAL_STORAGE_H
--
2.7.4