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>
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)
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
%{_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
GOBJECT_2_DEPS
PKGMGR_INFO_DEPS
TIZEN_EXTENSION_CLIENT_DEPS
+ TIZEN_SHARED_QUEUE_DEPS
TTRACE_DEPS
WAYLAND_CLIENT_DEPS
)
#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"
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)
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)
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;
}
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;
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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_
PKGMGR_INFO_DEPS
SENSOR_DEPS
TIZEN_EXTENSION_CLIENT_DEPS
+ TIZEN_SHARED_QUEUE_DEPS
TTRACE_DEPS
VCONF_DEPS
WAYLAND_CLIENT_DEPS