Add AppCoreUiThreadBase class 76/294076/5
authorHwankyu Jhun <h.jhun@samsung.com>
Tue, 13 Jun 2023 00:16:01 +0000 (00:16 +0000)
committerHwankyu Jhun <h.jhun@samsung.com>
Tue, 13 Jun 2023 02:31:18 +0000 (02:31 +0000)
To support preloading ui thread in the candidate process, the class is added.
The AppCoreUiBase class uses the AppCoreUiThreadBase class to create & run
the ui thread.

Change-Id: Ibb290befd3fb58bbb465873d2ef9bff2ba4863a5
Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
CMakeLists.txt
packaging/app-core.spec
tizen-cpp/app-core-ui-cpp/CMakeLists.txt
tizen-cpp/app-core-ui-cpp/app_core_ui_base.cc
tizen-cpp/app-core-ui-cpp/app_core_ui_thread_base.cc [new file with mode: 0644]
tizen-cpp/app-core-ui-cpp/app_core_ui_thread_base.hh [new file with mode: 0644]
unittests/CMakeLists.txt

index 2f9fe37..a24831a 100644 (file)
@@ -45,6 +45,7 @@ PKG_CHECK_MODULES(GOBJECT_2_DEPS REQUIRED gobject-2.0)
 PKG_CHECK_MODULES(PKGMGR_INFO_DEPS REQUIRED pkgmgr-info)
 PKG_CHECK_MODULES(SENSOR_DEPS REQUIRED sensor)
 PKG_CHECK_MODULES(TIZEN_EXTENSION_CLIENT_DEPS REQUIRED tizen-extension-client)
+PKG_CHECK_MODULES(TIZEN_SHARED_QUEUE_DEPS REQUIRED tizen-shared-queue)
 PKG_CHECK_MODULES(TTRACE_DEPS REQUIRED ttrace)
 PKG_CHECK_MODULES(VCONF_DEPS REQUIRED vconf)
 PKG_CHECK_MODULES(WAYLAND_CLIENT_DEPS REQUIRED wayland-client)
index 66abd88..39b7e7b 100644 (file)
@@ -5,26 +5,28 @@ Release:        0
 Group:          Application Framework/Libraries
 License:        Apache-2.0
 Source0:        app-core-%{version}.tar.gz
-BuildRequires:  pkgconfig(ecore-wl2)
-BuildRequires:  pkgconfig(wayland-client)
-BuildRequires:  pkgconfig(tizen-extension-client)
-BuildRequires:  pkgconfig(wayland-tbm-client)
 Source1001:     app-core.manifest
-BuildRequires:  pkgconfig(gio-2.0)
-BuildRequires:  pkgconfig(sensor)
-BuildRequires:  pkgconfig(vconf)
+
+BuildRequires:  cmake
 BuildRequires:  pkgconfig(aul)
 BuildRequires:  pkgconfig(bundle)
+BuildRequires:  pkgconfig(capi-system-info)
 BuildRequires:  pkgconfig(dlog)
-BuildRequires:  pkgconfig(elementary)
 BuildRequires:  pkgconfig(ecore)
-BuildRequires:  pkgconfig(gobject-2.0)
+BuildRequires:  pkgconfig(ecore-wl2)
+BuildRequires:  pkgconfig(elementary)
+BuildRequires:  pkgconfig(gio-2.0)
 BuildRequires:  pkgconfig(glib-2.0)
+BuildRequires:  pkgconfig(gmock)
+BuildRequires:  pkgconfig(gobject-2.0)
 BuildRequires:  pkgconfig(pkgmgr-info)
+BuildRequires:  pkgconfig(sensor)
+BuildRequires:  pkgconfig(tizen-extension-client)
+BuildRequires:  pkgconfig(tizen-shared-queue)
 BuildRequires:  pkgconfig(ttrace)
-BuildRequires:  pkgconfig(gmock)
-BuildRequires:  cmake
-BuildRequires:  pkgconfig(capi-system-info)
+BuildRequires:  pkgconfig(vconf)
+BuildRequires:  pkgconfig(wayland-client)
+BuildRequires:  pkgconfig(wayland-tbm-client)
 
 %if 0%{?gcov:1}
 BuildRequires:  lcov
@@ -295,6 +297,7 @@ install -m 0644 %{name}.zip %{buildroot}%{_datadir}/gcov/
 
 %{_includedir}/appcore_cpp/app_core_task_base.hh
 %{_includedir}/appcore_cpp/app_core_ui_base.hh
+%{_includedir}/appcore_cpp/app_core_ui_thread_base.hh
 %{_includedir}/appcore_cpp/api/app_core_ui_base.h
 %{_libdir}/libapp-core-ui-cpp.so
 %{_libdir}/pkgconfig/app-core-ui-cpp.pc
index b722e69..6c52af8 100644 (file)
@@ -31,6 +31,7 @@ APPLY_PKG_CONFIG(${TARGET_APP_CORE_UI_CPP} PUBLIC
   GOBJECT_2_DEPS
   PKGMGR_INFO_DEPS
   TIZEN_EXTENSION_CLIENT_DEPS
+  TIZEN_SHARED_QUEUE_DEPS
   TTRACE_DEPS
   WAYLAND_CLIENT_DEPS
 )
index e7f8c0e..9b1c99f 100644 (file)
@@ -39,6 +39,7 @@
 #include "app-core-ui-cpp/app_core_task_base.hh"
 #include "app-core-ui-cpp/app_core_ui_delegator_private.hh"
 #include "app-core-ui-cpp/app_core_ui_plugin_private.hh"
+#include "app-core-ui-cpp/app_core_ui_thread_base.hh"
 #include "app-core-ui-cpp/wayland_handler_private.hh"
 #include "app-core-ui-cpp/window_position_private.hh"
 #include "common/ecore_handler.hh"
@@ -51,22 +52,6 @@ constexpr const char K_SERVICE_THREAD[] = "__K_SERVICE_THREAD";
 constexpr const char K_HINT_RECENT_SCREEN_POSITION[] =
     "__K_HINT_RECENT_SCREEN_POSITION";
 
-void SetComm(const std::string& name) {
-  pid_t tid = syscall(__NR_gettid);
-  std::string path = "/proc/" + std::to_string(tid) + "/comm";
-  int fd = open(path.c_str(), O_WRONLY);
-  if (fd < 0) {
-    _E("open(%s) is failed. errno(%d)", path.c_str(), errno);
-    return;
-  }
-
-  ssize_t bytes_written = write(fd, name.c_str(), name.length() + 1);
-  if (bytes_written < 0)
-    _E("write(%d) is failed. errno(%d)", fd, errno);
-
-  close(fd);
-}
-
 class AppCoreUiBase::Impl {
  public:
   Impl(AppCoreUiBase* parent, unsigned int hint)
@@ -151,11 +136,10 @@ class AppCoreUiBase::Impl {
   std::unique_ptr<AppCoreUiDelegator> plugin_delegator_;
   std::unique_ptr<AppCoreUiPlugin> plugin_;
   std::unique_ptr<AppCoreTaskBase> service_;
-  GMainContext* context_ = nullptr;
-  std::thread thread_;
   std::unique_ptr<WindowPosition> position_;
   Ecore_Wl2_Window* window_ = nullptr;
   std::unique_ptr<WindowPositionManager> wp_manager_;
+  std::unique_ptr<AppCoreUiThreadBase> thread_;
 };
 
 AppCoreUiBase::AppCoreUiBase(unsigned int hint)
@@ -526,28 +510,16 @@ void AppCoreUiBase::DoExit() {
 
 void AppCoreUiBase::Impl::Run(int argc, char** argv) {
   if (hint_ & HINT_DUAL_THREAD) {
-    // For the loader case
-    while (ecore_shutdown() != 0) {}
-
     service_ = parent_->CreateTask();
-    context_ = g_main_context_new();
-    std::string env = std::to_string(
-        reinterpret_cast<unsigned long int>(context_));
-    setenv("TIZEN_GLIB_CONTEXT", env.c_str(), 1);
-
-    thread_ = std::thread([&] {
-          SetComm("UIThread+");
-          parent_->DoRun(argc, argv);
-        });
+    auto* thread_context = AppCoreUiThreadBase::GetContext();
+    if (thread_context == nullptr) {
+      thread_.reset(new AppCoreUiThreadBase());
+      thread_->Run(argc, argv);
+      thread_context = AppCoreUiThreadBase::GetContext();
+    }
 
+    thread_context->Post([&]() { parent_->DoRun(argc, argv); });
     service_->Run(argc, argv);
-
-    if (thread_.joinable())
-      thread_.join();
-
-    setenv("TIZEN_GLIB_CONTEXT", "0", 1);
-    g_main_context_unref(context_);
-    context_ = nullptr;
     return;
   }
 
@@ -556,11 +528,11 @@ void AppCoreUiBase::Impl::Run(int argc, char** argv) {
 
 void AppCoreUiBase::Impl::Exit() {
   if (hint_ & HINT_DUAL_THREAD) {
-    GLib::IdleAdd(context_, [](gpointer user_data) {
-          auto* impl = static_cast<AppCoreUiBase::Impl*>(user_data);
-          impl->parent_->DoExit();
-          return G_SOURCE_REMOVE;
-        }, this);
+    auto* thread_context = AppCoreUiThreadBase::GetContext();
+    if (thread_context != nullptr) {
+      thread_context->Post([&]() { parent_->DoExit(); });
+      thread_context->Exit();
+    }
 
     service_->Exit();
     return;
diff --git a/tizen-cpp/app-core-ui-cpp/app_core_ui_thread_base.cc b/tizen-cpp/app-core-ui-cpp/app_core_ui_thread_base.cc
new file mode 100644 (file)
index 0000000..2b3fe35
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#include "app-core-ui-cpp/app_core_ui_thread_base.hh"
+
+#include <Ecore.h>
+#include <glib.h>
+#include <pthread.h>
+#include <stdlib.h>
+
+#include <thread>
+#include <string>
+
+#include <shared-queue.hpp>
+
+#include "common/glib_private.hh"
+#include "common/log_private.hh"
+
+namespace tizen_cpp {
+namespace {
+
+AppCoreUiThreadBase* context = nullptr;
+
+}  // namespace
+
+class AppCoreUiThreadBase::Impl {
+ public:
+  Impl(AppCoreUiThreadBase* parent) : parent_(parent) {}
+
+  ~Impl() {
+    if (thread_.joinable())
+      thread_.join();
+  }
+
+  void Run(int argc, char** argv) {
+    if (context_ != nullptr) {
+      _E("Already running");
+      return;
+    }
+
+    context_ = g_main_context_new();
+    std::string context_str = std::to_string(
+        reinterpret_cast<unsigned long int>(context_));
+    setenv("TIZEN_GLIB_CONTEXT", context_str.c_str(), 1);
+
+    thread_ = std::thread([&] {
+          pthread_setname_np(pthread_self(), "UIThread+");
+          parent_->OnLoopInit(argc, argv);
+          parent_->OnLoopRun();
+          parent_->OnLoopFinish();
+        });
+  }
+
+  void Exit() {
+    parent_->OnLoopExit();
+  }
+
+  void Post(Runner runner) {
+    queue_.Push(std::move(runner));
+
+    guint source = GLib::IdleAdd(context_,
+        [](gpointer user_data) {
+          auto* impl = static_cast<AppCoreUiThreadBase::Impl*>(user_data);
+          auto action = std::move(impl->queue_.WaitAndPop());
+          action();
+          return G_SOURCE_REMOVE;
+        }, this);
+    if (source == 0)
+      _E("Failed to add idle source");
+  }
+
+ private:
+  friend class AppCoreUiThreadBase;
+  AppCoreUiThreadBase* parent_;
+
+ private:
+  std::thread thread_;
+  GMainContext* context_ = nullptr;
+  tizen_base::SharedQueue<Runner> queue_;
+};
+
+AppCoreUiThreadBase::AppCoreUiThreadBase() : impl_(new Impl(this)) {
+  if (context != nullptr)
+    _E("Already exists");
+
+  context = this;
+}
+
+AppCoreUiThreadBase::~AppCoreUiThreadBase() {
+  context = nullptr;
+}
+
+void AppCoreUiThreadBase::Run(int argc, char** argv) {
+  impl_->Run(argc, argv);
+}
+
+void AppCoreUiThreadBase::Exit() {
+  impl_->Exit();
+}
+
+void AppCoreUiThreadBase::Post(Runner runner) {
+  impl_->Post(std::move(runner));
+}
+
+void AppCoreUiThreadBase::OnLoopInit(int argc, char** argv) {
+  _W("Loop init");
+  ecore_init();
+}
+
+void AppCoreUiThreadBase::OnLoopRun() {
+  _W("Loop run");
+  ecore_main_loop_begin();
+}
+
+void AppCoreUiThreadBase::OnLoopExit() {
+  _W("Loop quit");
+  ecore_main_loop_thread_safe_call_sync([](void* data) -> void* {
+        ecore_main_loop_quit();
+        return nullptr;
+      }, nullptr);
+}
+
+void AppCoreUiThreadBase::OnLoopFinish() {
+  _W("Loop finish");
+  ecore_shutdown();
+}
+
+AppCoreUiThreadBase* AppCoreUiThreadBase::GetContext() {
+  return context;
+}
+
+}  // namespace tizen_cpp
diff --git a/tizen-cpp/app-core-ui-cpp/app_core_ui_thread_base.hh b/tizen-cpp/app-core-ui-cpp/app_core_ui_thread_base.hh
new file mode 100644 (file)
index 0000000..b13254d
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef TIZEN_CPP_APP_CORE_UI_CPP_APP_CORE_UI_THREAD_BASE_HH_
+#define TIZEN_CPP_APP_CORE_UI_CPP_APP_CORE_UI_THREAD_BASE_HH_
+
+#include <functional>
+#include <memory>
+
+#include <interface_main_loop.hh>
+
+#undef EXPORT_API
+#define EXPORT_API __attribute__((visibility("default")))
+
+namespace tizen_cpp {
+
+class EXPORT_API AppCoreUiThreadBase : public IMainLoop {
+ public:
+  using Runner = std::function<void()>;
+
+  AppCoreUiThreadBase();
+  virtual ~AppCoreUiThreadBase();
+
+  void Run(int argc, char** argv);
+  void Exit();
+  void Post(Runner runner);
+
+  void OnLoopInit(int argc, char** argv) override;
+  void OnLoopRun() override;
+  void OnLoopExit() override;
+  void OnLoopFinish() override;
+
+  static AppCoreUiThreadBase* GetContext();
+
+ private:
+  class Impl;
+  std::unique_ptr<Impl> impl_;
+};
+
+}  // namespace tizen_cpp
+
+#endif  // TIZEN_CPP_APP_CORE_UI_CPP_APP_CORE_UI_THREAD_BASE_HH_
index 23aeff3..b7a6671 100644 (file)
@@ -48,6 +48,7 @@ APPLY_PKG_CONFIG(${TARGET_UNIT_TEST} PUBLIC
   PKGMGR_INFO_DEPS
   SENSOR_DEPS
   TIZEN_EXTENSION_CLIENT_DEPS
+  TIZEN_SHARED_QUEUE_DEPS
   TTRACE_DEPS
   VCONF_DEPS
   WAYLAND_CLIENT_DEPS