Implement FdMonitor
authorChanggyu Choi <changyu.choi@samsung.com>
Wed, 9 Apr 2025 01:41:20 +0000 (10:41 +0900)
committerChanggyu Choi <changyu.choi@samsung.com>
Wed, 14 May 2025 09:02:19 +0000 (18:02 +0900)
Signed-off-by: Changgyu Choi <changyu.choi@samsung.com>
src/activation_method/fd_monitor.cc
src/activation_method/fd_monitor.hh
src/service.cc
src/service.hh
src/service_context.cc [deleted file]
src/service_loader.cc

index e93b1923c936504a6a0712ccc44f63370f55e9e9..84398696705f09514efd3dbf9d569ebbd526d286 100644 (file)
@@ -1,16 +1,67 @@
 #include "fd_monitor.hh"
 
-tizen_base::FdMonitor::FdMonitor(std::string,
-                                 int fd,
-                                 IEventListener* listener) {}
-
-tizen_base::FdMonitor::FdMonitor(std::string name,
-                                 std::string path,
-                                 IEventListener* listener) {}
-
-gboolean tizen_base::FdMonitor::UnixFdSourceFunc(gint fd,
-                                                 GIOCondition cond,
-                                                 gpointer data) {
-  // TODO
-  return FALSE;
+#include <systemd/sd-daemon.h>
+
+#include <gio/gio.h>
+#include <glib-unix.h>
+#include <glib.h>
+
+#include <stdexcept>
+#include <utility>
+
+#include "../event_listener.hh"
+#include "../log_private.hh"
+namespace tizen_base {
+
+FdMonitor::FdMonitor(std::string name, int fd, IEventListener* listener)
+    : name_(std::move(name)), listener_(listener) {}
+
+FdMonitor::FdMonitor(std::string name,
+                     std::string path,
+                     IEventListener* listener)
+    : name_(std::move(name)), listener_(listener) {
+  int n = sd_listen_fds(0);
+  if (n < 0) {
+    throw std::runtime_error("std_listen_fds failed.");
+  }
+
+  int fd = -1;
+  for (int i = SD_LISTEN_FDS_START; i < SD_LISTEN_FDS_START + n; i++) {
+    int r = sd_is_socket_unix(i, SOCK_STREAM, -1, path.c_str(), 0);
+    if (r > 0) {
+      fd = i;
+      break;
+    }
+  }
+
+  if (fd == -1)
+    throw std::runtime_error("Can not find socket file descriptor(" + path +
+                             ")");
+
+  unix_fd_source_id_ = g_unix_fd_add(fd, G_IO_IN, UnixFdSourceFunc, this);
+  if (unix_fd_source_id_ == 0)
+    throw std::runtime_error("g_unix_fd_add failed.");
+}
+
+FdMonitor::~FdMonitor() {
+  if (unix_fd_source_id_)
+    g_source_remove(unix_fd_source_id_);
 }
+
+gboolean FdMonitor::UnixFdSourceFunc(gint fd,
+                                     GIOCondition cond,
+                                     gpointer data) {
+  FdMonitor* self = static_cast<FdMonitor*>(data);
+  if (!(cond & G_IO_IN)) {
+    _E("G_IO_IN condition is not set. cond: %d", static_cast<int>(cond));
+    self->unix_fd_source_id_ = 0;
+    return G_SOURCE_REMOVE;
+  }
+
+  _I("Receive event from fd(%d) name(%s)", fd, self->name_.c_str());
+  self->listener_->OnEvent(self->name_);
+  self->unix_fd_source_id_ = 0;
+  return G_SOURCE_REMOVE;
+}
+
+}  // namespace tizen_base
index 78da3631fc979832fa6caf76973b015f03fe70da..59c6e1c70282791de91d93c00438a4784313f7ee 100644 (file)
@@ -30,8 +30,13 @@ class FdMonitor {
  public:
   FdMonitor(std::string, int fd, IEventListener* listener);
   FdMonitor(std::string name, std::string path, IEventListener* listener);
-
+  ~FdMonitor();
   static gboolean UnixFdSourceFunc(gint fd, GIOCondition cond, gpointer data);
+
+ private:
+  guint unix_fd_source_id_ = 0;
+  std::string name_;
+  IEventListener* listener_ = nullptr;
 };
 
 };
index a7e346f9f2785d2b2d3f8a8fdc79f3ba42967541..6eea04e994db714a2d09605b851ee3f943e79189 100644 (file)
@@ -233,7 +233,16 @@ void Service::SetStateChangedCb(StateChangedCb cb) {
   state_changed_cb_ = std::move(cb);
 }
 
-void Service::Listen(IEventListener* listener) {
+bool Service::IsMonitoring() const {
+  return monitoring_;
+}
+
+void Service::StartMonitoring(IEventListener* listener) {
+  if (monitoring_) {
+    _W("Already monitoring");
+    return;
+  }
+
   auto type = info_->GetType();
   if (type == "socket") {
     const auto& socket_info = info_->GetSocketInfo();
@@ -245,6 +254,15 @@ void Service::Listen(IEventListener* listener) {
     const auto& dbus_info = info_->GetDbusInfo();
     dbus_monitor_.reset(new DBusMonitor(info_->GetName(), dbus_info->GetBusName(), listener));
   }
+
+  monitoring_ = true;
+}
+
+void Service::StopMonitoring() {
+  fd_monitor_.reset();
+  file_monitor_.reset();
+  dbus_monitor_.reset();
+  monitoring_ = false;
 }
 
 void Service::NotifyStateChanged() {
index 037021544f12caf2f50069016553649b5b53900c..5620613b0fb01555d89c8ff75f0b43bc2b36ad0d 100644 (file)
@@ -71,7 +71,10 @@ class Service : public std::enable_shared_from_this<Service> {
   tizen_core_channel_sender_h GetChannelSender() const;
   void SendMessage(const tizen_base::Bundle& envelope);
   void SetStateChangedCb(StateChangedCb cb);
-  void Listen(IEventListener* listener);
+
+  bool IsMonitoring() const;
+  void StartMonitoring(IEventListener* listener);
+  void StopMonitoring();
 
  private:
   void OnBaseCreate();
@@ -96,6 +99,7 @@ class Service : public std::enable_shared_from_this<Service> {
   tizen_core_channel_receiver_h receiver_ = nullptr;
   tizen_core_source_h source_ = nullptr;
   std::atomic<bool> running_{false};
+  std::atomic<bool> monitoring_{false};
   pid_t tid_ = -1;
   StateChangedCb state_changed_cb_ = nullptr;
 
diff --git a/src/service_context.cc b/src/service_context.cc
deleted file mode 100644 (file)
index b8dba0e..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (c) 2025 Samsung Electronics Co., Ltd 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.
- */
-
-#include "service_context.hh"
-
-#include <dlfcn.h>
-
-#include <string>
-#include <utility>
-
-#include "log_private.hh"
-
-namespace {
-
-constexpr const char kUnitedServiceInit[] = "UNITED_SERVICE_INIT";
-constexpr const char kUnitedServiceShutdown[] = "UNITED_SERVICE_SHUTDOWN";
-
-}  // namespace
-
-namespace tizen_base {
-
-ServiceContext::ServiceContext(std::shared_ptr<ServiceInfo> info)
-    : info_(std::move(info)) {}
-
-ServiceContext::~ServiceContext() { Shutdown(); }
-
-bool ServiceContext::Init() {
-  if (!Load()) return false;
-
-  auto* init_func = reinterpret_cast<void* (*)(const char*)>(
-      dlsym(handle_, kUnitedServiceInit));
-  if (init_func == nullptr) {
-    _E("dlsym() is failed. error=%s", dlerror());
-    Unload();
-    return false;
-  }
-
-  auto* handle = init_func(info_->GetName().c_str());
-  if (handle == nullptr) {
-    _E("Failed to initialize united service");
-    Unload();
-    return false;
-  }
-
-  auto* service = static_cast<Service*>(handle);
-  service_ = service->shared_from_this();
-  return true;
-}
-
-void ServiceContext::Shutdown() {
-  if (!handle_) return;
-
-  if (service_) service_->Quit();
-
-  auto* shutdown_func =
-      reinterpret_cast<void (*)(void)>(dlsym(handle_, kUnitedServiceShutdown));
-  if (shutdown_func == nullptr) {
-    _E("dlsym() is failed. error=%s", dlerror());
-  } else {
-    shutdown_func();
-  }
-
-  Unload();
-}
-
-void ServiceContext::Listen(IEventListener* listener) {
-  auto type = info_->GetType();
-  if (type == "socket") {
-    const auto& socket_info = info_->GetSocketInfo();
-    fd_monitor_.reset(new FdMonitor(info_->GetName(), socket_info->GetPath(), listener));
-  } else if (type == "file") {
-    const auto& file_info = info_->GetFileInfo();
-    file_monitor_.reset(new FileMonitor(info_->GetName(), file_info->GetPath(), listener));
-  } else if (type == "dbus") {
-    const auto& dbus_info = info_->GetDbusInfo();
-    dbus_monitor_.reset(new DBusMonitor(info_->GetName(), dbus_info->GetBusName(), listener));
-  }
-}
-
-std::shared_ptr<Service> ServiceContext::GetService() const { return service_; }
-
-std::shared_ptr<ServiceInfo> ServiceContext::GetServiceInfo() const {
-  return info_;
-}
-
-const std::string& ServiceContext::GetName() const { return info_->GetName(); }
-
-bool ServiceContext::Load() {
-  if (handle_) return true;
-
-  _D("Load(): %s", info_->GetPath().c_str());
-  handle_ = dlopen(info_->GetPath().c_str(), RTLD_LAZY | RTLD_GLOBAL);
-  if (handle_ == nullptr) {
-    _E("dlopen() is failed. path=%s, error=%s", info_->GetPath().c_str(),
-       dlerror());
-    return false;
-  }
-
-  return true;
-}
-
-void ServiceContext::Unload() {
-  if (!handle_) return;
-
-  _D("Unload(): %s", info_->GetPath().c_str());
-  dlclose(handle_);
-  handle_ = nullptr;
-}
-
-}  // namespace tizen_base
-
index 2b56b710bff3adc6b875a6ebbe10a1406e69958d..7814c44bdc3c0eeae2f4978ccae3596e1e75b17c 100755 (executable)
@@ -179,9 +179,8 @@ void ServiceLoader::LoadServices() {
         assembly->ModuleInit(info->GetName());
       }
 
-      if (info->GetMode() == "on-demand") {
-
-      }
+      if (info->GetMode() == "on-demand")
+        ListenService(name);
     } catch (const Exception& e) {
       _E("Error=%s", e.what());
       THROW(e.GetErrorCode());
@@ -243,7 +242,12 @@ void ServiceLoader::RunService(const std::string& name) {
     THROW(SERVICE_ERROR_INVALID_CONTEXT);
   }
 
-  service = std::make_shared<Service>(std::move(info), std::move(listener));
+  if (service == nullptr)
+    service = std::make_shared<Service>(std::move(info), std::move(listener));
+
+  if (service->IsMonitoring())
+    service->StopMonitoring();
+
   if (service == nullptr) {
     _E("Out of memory. name=%s", name.c_str());
     THROW(SERVICE_ERROR_OUT_OF_MEMORY);
@@ -297,7 +301,7 @@ void ServiceLoader::QuitAllServices() {
   }
 }
 
-void ServiceLoader::ListenService(const std::string & name) {
+void ServiceLoader::ListenService(const std::string& name) {
   auto service = GetService(name);
   if (service != nullptr && service->IsRunning()) {
     _E("Already running. name=%s", name.c_str());
@@ -326,7 +330,7 @@ void ServiceLoader::ListenService(const std::string & name) {
                                        this, std::placeholders::_1,
                                        std::placeholders::_2));
   services_[name] = service;
-  service->Listen();
+  service->StartMonitoring(this);
 }
 
 void ServiceLoader::LoadService(const std::string& name) {
@@ -359,7 +363,7 @@ void ServiceLoader::UnloadService(const std::string& name) {
     THROW(SERVICE_ERROR_INVALID_CONTEXT);
 
   try {
-    assembly->ModuleShutdown(name.c_str());
+    assembly->ModuleShutdown(name);
     assembly->Unload();
   } catch (const Exception& e) {
     _E("Error=%s", e.what());
@@ -390,14 +394,12 @@ void ServiceLoader::OnServiceStateChanged(const Service* service,
                                           Service::State state) {}
 
 void ServiceLoader::OnEvent(const std::string& name) {
-  auto it = std::find_if(services_.begin(), services_.end(),
-                         [&](const std::shared_ptr<Service>& service) {
-                           return service->GetName() == name;
-                         });
+  auto it = services_.find(name);
 
   if (it != services_.end()) {
     _I("%s on-demand launch", name.c_str());
-    auto& service = *it;
+    auto& service = it->second;
+    service->StopMonitoring();
     service->Run();
   }
 }