Send state changed event to threads
authorChanggyu Choi <changyu.choi@samsung.com>
Mon, 24 Mar 2025 02:16:37 +0000 (11:16 +0900)
committerChanggyu Choi <changyu.choi@samsung.com>
Mon, 24 Mar 2025 02:18:44 +0000 (11:18 +0900)
OnServiceStateChanged() event handler should be invoked from the thread
that registered the event handler.

Signed-off-by: Changgyu Choi <changyu.choi@samsung.com>
src/service_manager.cc
src/service_manager.hh
src/stub_service.cc

index 7cbb6c14c2838a7591a292d72f1399946bf38b1f..b2cf7c55592eecf1faf794ed14967ebaa2429b51 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "service_manager.hh"
 
+#include <algorithm>
 #include <stdexcept>
 #include <utility>
 
@@ -53,25 +54,82 @@ bool ServiceManager::Contains(const std::string& name) const {
   return services_.find(name) != services_.end();
 }
 
-void ServiceManager::Remove(const std::string& name) { services_.erase(name); }
+void ServiceManager::Remove(const std::string& name) {
+  auto it = services_.find(name);
+  if (it == services_.end())
+    return;
 
-void ServiceManager::AddEventListener(ServiceManager::IEvent* listener) {
-  listeners_.push_back(listener);
+  auto service = it->second;
+  listeners_.erase(service);
+  services_.erase(it);
 }
 
-void ServiceManager::RemoveEventListener(ServiceManager::IEvent* listener) {
-  auto found = std::find(listeners_.begin(), listeners_.end(), listener);
-  if (found == listeners_.end()) return;
+void ServiceManager::AddEventListener(const std::shared_ptr<Service>& service,
+                                      IEvent* listener) {
+  listeners_[service].push_back(listener);
+}
 
-  listeners_.erase(found);
+void ServiceManager::RemoveEventListener(
+    const std::shared_ptr<Service>& service,
+    IEvent* listener) {
+  auto found = listeners_.find(service);
+  if (found == listeners_.end())
+    return;
+
+  auto& core_listeners = found->second;
+  auto it = std::find(core_listeners.begin(), core_listeners.end(), listener);
+  if (it != core_listeners.end())
+    core_listeners.erase(it);
 }
 
-void ServiceManager::NotifyServiceStateChanged(const Service* service) {
-  for (auto* listener : listeners_) listener->OnServiceStateChanged(service);
+void ServiceManager::NotifyServiceStateChanged(Service* service) {
+  for (auto [svc, listeners] : listeners_) {
+    for (auto listener : listeners) {
+      auto* cb_info = new std::tuple<IEvent*, Service*, Service::State>(
+          listener, service, service->GetState());
+      tizen_core_source_h source = nullptr;
+      tizen_core_add_idle_job(
+          svc->GetCore(),
+          [](void* user_data) -> bool {
+            auto* cb_info =
+                static_cast<std::tuple<IEvent*, Service*, Service::State>*>(
+                    user_data);
+            auto [listener, service, state] = *cb_info;
+            delete cb_info;
+            listener->OnServiceStateChanged(service, state);
+            return false;
+          },
+          cb_info, &source);
+      if (source == nullptr) {
+        _E("Failed to create idle job");
+        delete cb_info;
+      }
+    }
+  }
+}
+
+std::shared_ptr<Service> ServiceManager::FindFromThisThread() {
+  tizen_core_h core = nullptr;
+  tizen_core_find_from_this_thread(&core);
+  if (core == nullptr)
+    return nullptr;
+
+  auto it = std::find_if(
+      services_.begin(), services_.end(),
+      [&](const std::pair<std::string, std::shared_ptr<Service>>& element)
+          -> bool {
+        auto& [name, service] = element;
+        return service->GetCore() == core;
+      });
+
+  if (it == services_.end())
+    return nullptr;
+
+  return it->second;
 }
 
 ServiceManager::ServiceManager() {}
 
 ServiceManager::~ServiceManager() {}
 
-} // namespace tizen_base
+}  // namespace tizen_base
index 199655d029c341e0463b712ae73cd5f35affaf9b..286491f747a0542ba3f18b0e0232193c802d1c70 100644 (file)
@@ -31,7 +31,8 @@ class ServiceManager {
   class IEvent {
    public:
     virtual ~IEvent() = default;
-    virtual void OnServiceStateChanged(const Service* service) = 0;
+    virtual void OnServiceStateChanged(Service* service,
+                                       Service::State state) = 0;
   };
 
   static ServiceManager& GetInst();
@@ -40,9 +41,13 @@ class ServiceManager {
   std::shared_ptr<Service> Get(const std::string& name) const;
   bool Contains(const std::string& name) const;
   void Remove(const std::string& name);
-  void AddEventListener(IEvent* listener);
-  void RemoveEventListener(IEvent* listener);
-  void NotifyServiceStateChanged(const Service* service);
+  void AddEventListener(const std::shared_ptr<Service>& service,
+                        IEvent* listener);
+  void RemoveEventListener(const std::shared_ptr<Service>& service,
+                           IEvent* listener);
+  void NotifyServiceStateChanged(Service* service);
+
+  std::shared_ptr<Service> FindFromThisThread();
 
  private:
   ServiceManager();
@@ -50,9 +55,9 @@ class ServiceManager {
 
  private:
   std::unordered_map<std::string, std::shared_ptr<Service>> services_;
-  std::vector<IEvent*> listeners_;
+  std::unordered_map<std::shared_ptr<Service>, std::vector<IEvent*>> listeners_;
 };
 
-} // namespace tizen_base
+}  // namespace tizen_base
 
 #endif  // SERVICE_MANAGER_HH_
index 127f036fa3b2744153de12b64f2969de0f91c5c6..d066f5518d84b73aeb2e510564b2022507126c80 100644 (file)
  * limitations under the License.
  */
 
-#include "service_manager.h"
 #include "service.h"
+#include "service_manager.h"
 
+#include <algorithm>
 #include <new>
 #include <stdexcept>
 #include <utility>
@@ -39,7 +40,7 @@ class ServiceExt : public tizen_base::Service {
 
   virtual ~ServiceExt() {}
 
-  void SetCallback(service_lifecycle_callback_s *callback, void* user_data) {
+  void SetCallback(service_lifecycle_callback_scallback, void* user_data) {
     callback_ = *callback;
     user_data_ = user_data;
   }
@@ -75,13 +76,12 @@ class EventHandler : public tizen_base::ServiceManager::IEvent {
 
   virtual ~EventHandler() {}
 
-  void OnServiceStateChanged(const tizen_base::Service* service) override {
+  void OnServiceStateChanged(tizen_base::Service* service,
+                             tizen_base::Service::State state) override {
     if (callback_) {
-      callback_(
-          reinterpret_cast<service_h>(
-              const_cast<tizen_base::Service*>(service)),
-          static_cast<service_state_e>(service->GetState()),
-          user_data_);
+      callback_(reinterpret_cast<service_h>(
+                    const_cast<tizen_base::Service*>(service)),
+                static_cast<service_state_e>(state), user_data_);
     }
   }
 
@@ -146,7 +146,7 @@ API int service_quit(service_h service) {
   return SERVICE_ERROR_NONE;
 }
 
-API int service_send_message(service_h service, bundle *envelope) {
+API int service_send_message(service_h service, bundleenvelope) {
   if (!service || !envelope) {
     _E("Invalid parameter");
     return SERVICE_ERROR_INVALID_PARAMETER;
@@ -174,7 +174,6 @@ API int service_destroy(service_h service) {
   return SERVICE_ERROR_NONE;
 }
 
-
 API int service_get_name(service_h service, char** name) {
   if (!service || !name) {
     _E("Invalid parameter");
@@ -239,7 +238,14 @@ API int service_manager_add_event_handler(service_state_changed_cb callback,
     return SERVICE_MANAGER_ERROR_OUT_OF_MEMORY;
   }
 
-  tizen_base::ServiceManager::GetInst().AddEventListener(handle);
+  auto& inst = tizen_base::ServiceManager::GetInst();
+  auto service = inst.FindFromThisThread();
+  if (service == nullptr) {
+    _E("Failed to find service from this thread");
+    return SERVICE_ERROR_INVALID_CONTEXT;
+  }
+
+  tizen_base::ServiceManager::GetInst().AddEventListener(service, handle);
   *event_handler = reinterpret_cast<service_manager_event_h>(handle);
   return SERVICE_MANAGER_ERROR_NONE;
 }
@@ -252,7 +258,15 @@ API int service_manager_remove_event_handler(
   }
 
   auto* handle = reinterpret_cast<EventHandler*>(event_handler);
-  tizen_base::ServiceManager::GetInst().RemoveEventListener(handle);
+  auto& inst = tizen_base::ServiceManager::GetInst();
+
+  auto service = inst.FindFromThisThread();
+  if (service == nullptr) {
+    _E("Failed to find service from this thread");
+    return SERVICE_ERROR_INVALID_CONTEXT;
+  }
+
+  inst.RemoveEventListener(service, handle);
   delete handle;
   return SERVICE_MANAGER_ERROR_NONE;
 }