Use idler to destroy proxy handle 08/240908/2
authorHwankyu Jhun <h.jhun@samsung.com>
Wed, 12 Aug 2020 23:01:52 +0000 (08:01 +0900)
committerHwankyu Jhun <h.jhun@samsung.com>
Wed, 12 Aug 2020 23:19:06 +0000 (08:19 +0900)
Currently, the application can call rpc_port_proxy_handle() in a sub
thread when the main thread is calling the callback function.
It causes the crash issue. To prevent that, this patch uses idler to
destroy handle in the main thread.

Change-Id: Ie3a79c94bb3e69dca8b8aaf4fe91fde1cb9d1f43
Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
src/rpc-port.cc

index efae3d6..e88f699 100644 (file)
@@ -16,8 +16,9 @@
 
 #include <glib.h>
 
-#include <thread>
+#include <atomic>
 #include <mutex>
+#include <thread>
 
 #include "log-private.hh"
 #include "port-internal.h"
@@ -43,7 +44,7 @@ class Event {
 
 class ProxyExt : public Proxy, public Proxy::IEventListener {
  public:
-  explicit ProxyExt(bool mock = false) : Proxy(mock) {}
+  explicit ProxyExt(bool mock = false) : Proxy(mock), destroying_(false) {}
   virtual ~ProxyExt() = default;
 
   void AddConnectedEventListener(rpc_port_proxy_connected_event_cb cb,
@@ -71,6 +72,9 @@ class ProxyExt : public Proxy, public Proxy::IEventListener {
   }
 
   void OnConnected(const std::string& endpoint, Port* port) override {
+    if (IsDestroying())
+      return;
+
     for (auto& ev : connected_events_) {
       ev->cb_(endpoint.c_str(), GetPortName().c_str(), port,
               ev->user_data_);
@@ -78,12 +82,18 @@ class ProxyExt : public Proxy, public Proxy::IEventListener {
   }
 
   void OnDisconnected(const std::string& endpoint) override {
+    if (IsDestroying())
+      return;
+
     for (auto& ev : disconnected_events_) {
       ev->cb_(endpoint.c_str(), GetPortName().c_str(), ev->user_data_);
     }
   }
 
   void OnRejected(const std::string& endpoint, int err_code) override {
+    if (IsDestroying())
+      return;
+
     for (auto& ev : rejected_events_) {
       set_last_result(err_code);
       ev->cb_(endpoint.c_str(), GetPortName().c_str(), ev->user_data_);
@@ -91,6 +101,9 @@ class ProxyExt : public Proxy, public Proxy::IEventListener {
   }
 
   void OnReceived(const std::string& endpoint) override {
+    if (IsDestroying())
+      return;
+
     for (auto& ev : received_events_) {
       ev->cb_(endpoint.c_str(), GetPortName().c_str(), ev->user_data_);
     }
@@ -100,7 +113,16 @@ class ProxyExt : public Proxy, public Proxy::IEventListener {
     return mutex_;
   }
 
+  void SetDestroying(bool destroying) {
+    destroying_ = destroying;
+  }
+
+  bool IsDestroying() {
+    return destroying_;
+  }
+
  private:
+  std::atomic<bool> destroying_;
   std::list<std::unique_ptr<Event<rpc_port_proxy_connected_event_cb>>>
       connected_events_;
   std::list<std::unique_ptr<Event<rpc_port_proxy_disconnected_event_cb>>>
@@ -239,9 +261,16 @@ RPC_API int rpc_port_proxy_destroy(rpc_port_proxy_h h) {
   if (h == nullptr)
     return RPC_PORT_ERROR_INVALID_PARAMETER;
 
-  _W("rpc_port_proxy_destroy(%p)", h);
   auto p = static_cast<::ProxyExt*>(h);
-  delete p;
+  p->SetDestroying(true);
+
+  g_idle_add_full(G_PRIORITY_HIGH,
+      [](gpointer data) -> gboolean {
+        auto p = static_cast<::ProxyExt*>(data);
+        _W("rpc_port_proxy_destroy(%p)", p);
+        delete p;
+        return G_SOURCE_REMOVE;
+      }, h, nullptr);
   return RPC_PORT_ERROR_NONE;
 }