Support Local Execution Mode for C++ Generator 54/297654/8
authorHwankyu Jhun <h.jhun@samsung.com>
Tue, 22 Aug 2023 08:20:42 +0000 (17:20 +0900)
committerHwankyu Jhun <h.jhun@samsung.com>
Sun, 27 Aug 2023 23:29:21 +0000 (08:29 +0900)
This patch supports the local execution mode. If the stub is equal to
the proxy, the local method will be invoked.

Change-Id: I913865b82f079b95b9b5d6c4c28b12792089467e
Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
18 files changed:
idlc/gen/version2/cpp_generator_base.cc
idlc/gen/version2/cpp_generator_base.hh
idlc/gen/version2/cpp_generator_base_cb.hh
idlc/gen/version2/cpp_proxy_body_generator.cc
idlc/gen/version2/cpp_proxy_body_generator.hh
idlc/gen/version2/cpp_proxy_body_generator_cb.hh
idlc/gen/version2/cpp_proxy_header_generator.cc
idlc/gen/version2/cpp_proxy_header_generator.hh
idlc/gen/version2/cpp_proxy_header_generator_cb.hh
idlc/gen/version2/cpp_stub_body_generator.cc
idlc/gen/version2/cpp_stub_body_generator.hh
idlc/gen/version2/cpp_stub_body_generator_cb.hh
idlc/gen/version2/cpp_stub_header_generator.cc
idlc/gen/version2/cpp_stub_header_generator.hh
idlc/gen/version2/cpp_stub_header_generator_cb.hh
idlc/version2_default_generator.cc
tests/build_tests/CMakeLists.txt
tests/build_tests/prebuild.sh

index 71a2ea4..6addc1e 100644 (file)
@@ -148,6 +148,11 @@ void CppGeneratorBase::GenVersionDefinition(std::ofstream& stream) {
   stream << NLine(1);
 }
 
+void CppGeneratorBase::GenExportAPI(std::ofstream& stream) {
+  stream << CB_EXPORT_API;
+  stream << NLine(1);
+}
+
 std::string CppGeneratorBase::GenExceptions() {
   std::string code = CB_HEADER_UNIT_MAP_DEF;
   code += std::string(CB_EXCEPTIONS);
@@ -318,6 +323,17 @@ std::string CppGeneratorBase::GetParameters(const Parameters& params) {
   return code;
 }
 
+std::string CppGeneratorBase::GenParameters(const Structure& st) {
+  std::string params;
+  if (st.GetBase() != nullptr)
+    params += GenParameters(*st.GetBase());
+
+  if (!params.empty())
+    params += ", ";
+
+  return params + GenParameters(st.GetElements());
+}
+
 std::string CppGeneratorBase::GenStructuresForHeader(bool use_file) {
   std::string code(CB_HEADER_BUNDLE);
   code += NLine(1);
@@ -338,7 +354,8 @@ std::string CppGeneratorBase::GenStructuresForHeader(bool use_file) {
 
 std::string CppGeneratorBase::GenStructureForHeader(const Structure& st) {
   std::string code;
-  if (st.GetElements().Empty()) {
+  std::string params = GenParameters(st);
+  if (params.empty()) {
     if (st.GetBase() == nullptr) {
       code = ReplaceAll(CB_HEADER_STRUCTURE_BASE_EMPTY)
                  .Change("<CLS_NAME>", st.GetID())
@@ -360,11 +377,6 @@ std::string CppGeneratorBase::GenStructureForHeader(const Structure& st) {
                  .Change("<MEMBERS>\n",
                          GenStructureMembersForHeader(st.GetElements()));
     } else {
-      std::string params = GenParameters(st.GetBase()->GetElements());
-      if (!params.empty())
-        params += ", ";
-
-      params += GenParameters(st.GetElements());
       code = ReplaceAll(CB_HEADER_INHERITED_STRUCTURE_BASE)
                  .Change("<CLS_NAME>", st.GetID())
                  .Change("<BASE_CLS_NAME>", st.GetBase()->GetID())
@@ -514,8 +526,9 @@ std::string CppGeneratorBase::GenStructures(bool use_file) {
 }
 
 std::string CppGeneratorBase::GenStructure(const Structure& st) {
+  std::string params = GenParameters(st);
   std::string code;
-  if (st.GetElements().Empty()) {
+  if (params.empty()) {
     code = ReplaceAll(CB_BODY_STRUCTURE_BASE_EMPTY)
                .Change("<CLS_NAME>", st.GetID());
   } else {
@@ -523,21 +536,15 @@ std::string CppGeneratorBase::GenStructure(const Structure& st) {
       code =
           ReplaceAll(CB_BODY_STRUCTURE_BASE)
               .Change("<CLS_NAME>", st.GetID())
-              .Change("<PARAMS>", GenParameters(st.GetElements()))
+              .Change("<PARAMS>", params)
               .Change("<MEMBER_INIT>", GenStructureMemberInit(st.GetElements()))
               .Change("<GETTER_SETTER>", GenStructureGetterSetter(st));
     } else {
-      std::string params = GenParameters(st.GetBase()->GetElements());
-      if (!params.empty())
-        params += ", ";
-
-      params += GenParameters(st.GetElements());
       code =
           ReplaceAll(CB_BODY_INHERITED_STRUCTURE_BASE)
               .Change("<CLS_NAME>", st.GetID())
               .Change("<BASE_CLS_NAME>", st.GetBase()->GetID())
-              .Change("<BASE_ARGS>",
-                      GenStructureBaseArgs(st.GetBase()->GetElements()))
+              .Change("<BASE_ARGS>", GenStructureBaseArgs(*st.GetBase()))
               .Change("<PARAMS>", params)
               .Change("<MEMBER_INIT>", GenStructureMemberInit(st.GetElements()))
               .Change("<GETTER_SETTER>", GenStructureGetterSetter(st));
@@ -547,6 +554,17 @@ std::string CppGeneratorBase::GenStructure(const Structure& st) {
   return code;
 }
 
+std::string CppGeneratorBase::GenStructureBaseArgs(const Structure& st) {
+  std::string code;
+  if (st.GetBase() != nullptr)
+    code += GenStructureBaseArgs(*st.GetBase());
+
+  if (!code.empty())
+    code += ", ";
+
+  return code + GenStructureBaseArgs(st.GetElements());
+}
+
 std::string CppGeneratorBase::GenStructureBaseArgs(const Elements& elms) {
   std::string code;
   for (auto& elm : elms) {
@@ -613,10 +631,10 @@ void CppGeneratorBase::InitUnitTypes(bool use_file) {
       }
 
       for (const auto& decl : iface.GetDeclarations()) {
+        AddUnitType("delegate",
+                    BaseType(iface.GetID() + "::CallbackBase", "", true),
+                    iface.GetID());
         if (decl->GetMethodType() == Declaration::MethodType::DELEGATE) {
-          AddUnitType("delegate",
-                      BaseType(iface.GetID() + "::CallbackBase", "", true),
-                      iface.GetID());
           AddUnitType(decl->GetID(), BaseType(decl->GetID(), "", true),
                       iface.GetID());
         } else if (decl->GetMethodType() == Declaration::MethodType::SYNC) {
index d752739..4f5677a 100644 (file)
@@ -39,6 +39,7 @@ class CppGeneratorBase : public tidl::Generator {
   void GenLogTag(std::ofstream& stream, const std::string& log_tag);
   void GenLogDefinition(std::ofstream& stream);
   void GenVersionDefinition(std::ofstream& stream);
+  void GenExportAPI(std::ofstream& stream);
 
   std::string GenExceptions();
   std::string GenStructuresForHeader(bool use_file = true);
@@ -66,10 +67,12 @@ class CppGeneratorBase : public tidl::Generator {
 
  private:
   void AddTypeName(const Structure& st);
+  std::string GenParameters(const Structure& st);
   std::string GenStructureForHeader(const Structure& st);
   std::string GenStructureGetterSetterForHeader(const Elements& elms);
   std::string GenStructureMembersForHeader(const Elements& elms);
   std::string GenStructure(const Structure& st);
+  std::string GenStructureBaseArgs(const Structure& st);
   std::string GenStructureBaseArgs(const Elements& elms);
   std::string GenStructureMemberInit(const Elements& elms);
   std::string GenStructureGetterSetter(const Structure& st);
index 9cef83c..aaeda07 100644 (file)
@@ -32,14 +32,17 @@ R"__cpp_cb(
 
 constexpr const char CB_BODY_HEADER[] =
 R"__cpp_cb(
+#include <app_common.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <libgen.h>
 #include <glib.h>
 #include <dlog.h>
+#include <dlfcn.h>
 #include <rpc-port.h>
 #include <rpc-port-parcel.h>
+#include <unistd.h>
 
 #include <map>
 #include <memory>
@@ -69,6 +72,7 @@ R"__cpp_cb(
 #include <vector>
 #include <unordered_map>
 #include <unordered_set>
+#include <queue>
 )__cpp_cb";
 
 /**
@@ -1010,6 +1014,9 @@ R"__cpp_cb(
 <NAME>.Share(port_);
 )__cpp_cb";
 
+/**
+ * <NAME> The parameter name.
+ */
 constexpr const char CB_PRIVATE_SHARING_ARRAY[] =
 R"__cpp_cb(
 {
@@ -1021,6 +1028,12 @@ R"__cpp_cb(
 }
 )__cpp_cb";
 
+constexpr const char CB_EXPORT_API[] =
+R"__cpp_cb(
+#undef EXPORT_API
+#define EXPORT_API extern "C" __attribute__ ((visibility("default")))
+)__cpp_cb";
+
 }  // namespace version2
 }  // namespace tidl
 
index c8e8947..8b1e29d 100644 (file)
@@ -16,6 +16,8 @@
 
 #include "idlc/gen/version2/cpp_proxy_body_generator.hh"
 
+#include <libgen.h>
+
 #include <utility>
 
 #include "idlc/gen/version2/cpp_generator_base_cb.hh"
@@ -24,8 +26,9 @@
 namespace tidl {
 namespace version2 {
 
-CppProxyBodyGenerator::CppProxyBodyGenerator(std::shared_ptr<Document> doc)
-    : CppGeneratorBase(std::move(doc)) {}
+CppProxyBodyGenerator::CppProxyBodyGenerator(std::shared_ptr<Document> doc,
+                                             std::shared_ptr<Options> options)
+    : CppGeneratorBase(std::move(doc)), options_(std::move(options)) {}
 
 void CppProxyBodyGenerator::OnInitGen(std::ofstream& stream) {
   GenVersion(stream);
@@ -34,7 +37,10 @@ void CppProxyBodyGenerator::OnInitGen(std::ofstream& stream) {
   GenLogTag(stream, "RPC_PORT_PROXY");
   GenLogDefinition(stream);
   GenVersionDefinition(stream);
+  GenExportAPI(stream);
+  GenLemAnonymousNamespace(stream);
   GenNamespace(stream);
+  GenLemAPI(stream);
 }
 
 void CppProxyBodyGenerator::OnFiniGen(std::ofstream& stream) {}
@@ -55,13 +61,46 @@ void CppProxyBodyGenerator::GenIncludeProxyBodyHeader(std::ofstream& stream) {
 void CppProxyBodyGenerator::GenNamespace(std::ofstream& stream) {
   ReplaceAll(CB_NAMESPACE_PROXY)
       .ChangeToLower("<FILE_NAMESPACE>", GetFileNamespace())
-      .Change("<STRUCTURES>", GenStructures())
+      .Change("<STRUCTURES>", GenLemBaseWithStructures())
       .Change("<BASE_IMPL>", GenBaseImpl())
       .Change("<INTERFACES>", GenInterfaces())
       .Transform([&](std::string str) { return SmartIndent(str); })
       .Out(stream);
 }
 
+void CppProxyBodyGenerator::GenLemAnonymousNamespace(std::ofstream& stream) {
+  stream << SmartIndent(CB_LEM_ANONYMOUS_NAMESPACE);
+}
+
+void CppProxyBodyGenerator::GenLemAPI(std::ofstream& stream) {
+  std::string input = basename(const_cast<char*>(options_->GetInput().c_str()));
+  input = input.substr(0, input.find_last_of("."));
+  std::string code = NLine(1);
+  for (const auto& block : GetDocument().GetBlocks()) {
+    if (block->GetType() != Block::TYPE_INTERFACE)
+      continue;
+
+    auto& iface = static_cast<Interface&>(*block);
+    code += ReplaceAll(CB_LEM_API)
+        .Change("<CLS_NAME>", iface.GetID())
+        .ChangeToLower("<FILE_NAMESPACE>", GetFileNamespace())
+        .ChangeToLower("<INPUT_FILE>", input);
+    code += NLine(1);
+  }
+
+  stream << SmartIndent(code);
+}
+
+std::string CppProxyBodyGenerator::GenLemBaseWithStructures() {
+  std::string input = basename(const_cast<char*>(options_->GetInput().c_str()));
+  input = input.substr(0, input.find_last_of("."));
+  std::string code;
+  code += ReplaceAll(CB_LEM_BASE).ChangeToLower("<INPUT_FILE>", input);
+  code += NLine(1);
+  code += GenStructures();
+  return code;
+}
+
 std::string CppProxyBodyGenerator::GenBaseImpl() {
   std::string code = GenRemoteException();
   code += GenUnitMap();
@@ -93,16 +132,13 @@ std::string CppProxyBodyGenerator::GenInterface(const Interface& iface) {
 std::string CppProxyBodyGenerator::GenInterfaceCallbacks(
     const Interface& iface) {
   std::string code;
+  code += ReplaceAll(CB_INTERFACE_CALKBACBASE_BASE)
+              .Change("<IFACE_NAME>", iface.GetID());
+  code += NLine(1);
   for (const auto& decl : iface.GetDeclarations()) {
     if (decl->GetMethodType() != Declaration::MethodType::DELEGATE)
       continue;
 
-    if (code.empty()) {
-      code += ReplaceAll(CB_INTERFACE_CALKBACBASE_BASE)
-          .Change("<IFACE_NAME>", iface.GetID());
-      code += NLine(1);
-    }
-
     code += ReplaceAll(CB_INTERFACE_CALLBACK)
         .Change("<IFACE_NAME>", iface.GetID())
         .Change("<CLS_NAME>", decl->GetID())
index b9384bd..d4c2099 100644 (file)
 #include <string>
 
 #include "idlc/gen/version2/cpp_generator_base.hh"
+#include "idlc/options.h"
 
 namespace tidl {
 namespace version2 {
 
 class CppProxyBodyGenerator : public CppGeneratorBase {
  public:
-  explicit CppProxyBodyGenerator(std::shared_ptr<Document> doc);
+  explicit CppProxyBodyGenerator(std::shared_ptr<Document> doc,
+                                 std::shared_ptr<Options> options);
   virtual ~CppProxyBodyGenerator() = default;
 
   void OnInitGen(std::ofstream& stream) override;
@@ -36,6 +38,9 @@ class CppProxyBodyGenerator : public CppGeneratorBase {
  private:
   void GenIncludeProxyBodyHeader(std::ofstream& stream);
   void GenNamespace(std::ofstream& stream);
+  void GenLemAnonymousNamespace(std::ofstream& stream);
+  void GenLemAPI(std::ofstream& stream);
+  std::string GenLemBaseWithStructures();
   std::string GenBaseImpl();
   std::string GenInterfaces();
   std::string GenInterface(const Interface& iface);
@@ -46,6 +51,9 @@ class CppProxyBodyGenerator : public CppGeneratorBase {
       const Declaration& decl);
   std::string GenInterfaceMethodSerialize(const Declaration& decl);
   std::string GenInterfaceMethodDeserialize(const Declaration& decl);
+
+ private:
+  std::shared_ptr<Options> options_;
 };
 
 }  // namespace version2
index 55235f7..6074dbf 100644 (file)
@@ -127,6 +127,11 @@ R"__cpp_cb(
   rpc_port_proxy_add_disconnected_event_cb(proxy_, OnDisconnectedCb, this);
   rpc_port_proxy_add_rejected_event_cb(proxy_, OnRejectedCb, this);
   rpc_port_proxy_add_received_event_cb(proxy_, OnReceivedCb, this);
+
+  if (GetAppId() == target_appid_) {
+    local_execution_ = std::make_unique<LocalExecution>("<CLS_NAME>", this);
+    local_execution_->LoadSymbols();
+  }
 }
 
 <CLS_NAME>::~<CLS_NAME>() {
@@ -136,6 +141,11 @@ R"__cpp_cb(
 }
 
 void <CLS_NAME>::Connect(bool sync) {
+  if (local_execution_.get() != nullptr && local_execution_->LoadSymbols()) {
+    if (local_execution_->Connect())
+      return;
+  }
+
   int ret;
   if (sync)
     ret = rpc_port_proxy_connect_sync(proxy_, target_appid_.c_str(), "<CLS_NAME>");
@@ -159,6 +169,11 @@ void <CLS_NAME>::Connect(bool sync) {
 }
 
 void <CLS_NAME>::Disconnect() {
+  if (local_execution_.get() != nullptr && local_execution_->IsConnected()) {
+    local_execution_->Disconnect();
+    return;
+  }
+
   int ret = rpc_port_disconnect(port_);
   if (ret != RPC_PORT_ERROR_NONE) {
     _E("Failed to disconnect from <CLS_NAME>. error(%d)", ret);
@@ -180,6 +195,20 @@ void <CLS_NAME>::DisposeCallback(const std::string& tag) {
 
 <METHODS>
 
+void <CLS_NAME>::OnLocalConnected() {
+  listener_->OnConnected();
+}
+
+void <CLS_NAME>::OnLocalDisconnected() {
+  listener_->OnDisconnected();
+}
+
+void <CLS_NAME>::OnLocalReceived(rpc_port_parcel_h parcel) {
+  UnitMap map;
+  map.Deserialize(parcel);
+  ProcessReceivedEvent(map);
+}
+
 void <CLS_NAME>::ProcessReceivedEvent(const UnitMap& unit_map) {
   CallbackBase callback;
   unit_map.Read("delegate", callback);
@@ -284,7 +313,7 @@ void <CLS_NAME>::OnReceivedCb(const char* endpoint, const char* port_name, void*
 constexpr const char CB_INTERFACE_METHOD_ASYNC_BASE[] =
 R"__cpp_cb(
 void <IFACE_NAME>::<NAME>(<PARAMS>) {
-  if (port_ == nullptr) {
+  if (port_ == nullptr && (local_execution_.get() == nullptr || !local_execution_->IsConnected())) {
     _E("Not connected");
     throw NotConnectedSocketException();
   }
@@ -302,7 +331,12 @@ void <IFACE_NAME>::<NAME>(<PARAMS>) {
   map_.Serialize(parcel_);;
 
   std::lock_guard<std::recursive_mutex> lock(mutex_);
-  int ret_ = rpc_port_parcel_send(parcel_, port_);
+  int ret_;
+  if (local_execution_.get() != nullptr && local_execution_->IsConnected())
+    ret_ = local_execution_->Send(parcel_, nullptr);
+  else
+    ret_ = rpc_port_parcel_send(parcel_, port_);
+
   rpc_port_parcel_destroy(parcel_);
   if (ret_ != RPC_PORT_ERROR_NONE) {
     _E("Failed to send parcel. error(%d)", ret_);
@@ -323,7 +357,7 @@ void <IFACE_NAME>::<NAME>(<PARAMS>) {
 constexpr const char CB_INTERFACE_METHOD_BASE[] =
 R"__cpp_cb(
 <RETURN_TYPE> <IFACE_NAME>::<NAME>(<PARAMS>) {
-  if (port_ == nullptr) {
+  if (port_ == nullptr && (local_execution_.get() == nullptr || !local_execution_->IsConnected())) {
     _E("Not connected");
     throw NotConnectedSocketException();
   }
@@ -344,7 +378,13 @@ R"__cpp_cb(
   map_.Serialize(parcel_);
 
   std::lock_guard<std::recursive_mutex> lock(mutex_);
-  int ret_ = rpc_port_parcel_send(parcel_, port_);
+  int ret_;
+  rpc_port_parcel_h result_parcel_ = nullptr;
+  if (local_execution_.get() != nullptr && local_execution_->IsConnected())
+    ret_ = local_execution_->Send(parcel_, &result_parcel_);
+  else
+    ret_ = rpc_port_parcel_send(parcel_, port_);
+
   rpc_port_parcel_destroy(parcel_);
   if (ret_ != RPC_PORT_ERROR_NONE) {
     _E("Failed to send parcel. error(%d)", ret_);
@@ -353,7 +393,13 @@ R"__cpp_cb(
 
   <RETURN_TYPE> result_<SET_INIT_VALUE>;
   UnitMap received_map_;
-  ConsumeCommand(port_, seq_num_, received_map_);
+  if (local_execution_.get() != nullptr && local_execution_->IsConnected()) {
+    received_map_.Deserialize(result_parcel_);
+    rpc_port_parcel_destroy(result_parcel_);
+  } else {
+    ConsumeCommand(port_, seq_num_, received_map_);
+  }
+
   if (received_map_.GetSize() == 0) {
     _E("received map size is zero");
   }
@@ -395,6 +441,253 @@ R"__cpp_cb(
 received_map_.Read("<NAME>", <NAME>);
 )__cpp_cb";
 
+constexpr const char CB_LEM_ANONYMOUS_NAMESPACE[] =
+R"__cpp_cb(
+namespace {
+
+std::atomic<unsigned int> seq_ { 0 };
+std::string appid_;
+
+const std::string& GetAppId() {
+  if (getuid() < 5000)
+    return appid_;
+
+  if (appid_.empty()) {
+    char* id = nullptr;
+    app_get_id(&id);
+    if (id == nullptr) {
+      _E("Failed to get app id");
+      return appid_;
+    }
+
+    appid_ = std::string(id);
+    free(id);
+  }
+
+  return appid_;
+}
+
+rpc_port_parcel_h Clone(rpc_port_parcel_h parcel) {
+  void* raw = nullptr;
+  unsigned int size = 0;
+  if (rpc_port_parcel_get_raw(parcel, &raw, &size) != RPC_PORT_ERROR_NONE) {
+    _E("Failed to get raw");
+    return nullptr;
+  }
+
+  rpc_port_parcel_h handle = nullptr;
+  rpc_port_parcel_create_from_raw(&handle, raw, size);
+  return handle;
+}
+
+}  // namespace
+)__cpp_cb";
+
+/**
+ * <INPUT_FILE> The input file name.
+ */
+constexpr const char CB_LEM_BASE[] =
+R"__cpp_cb(
+LocalExecution::LocalExecution(std::string port_name, LocalExecution::IEvent* listener) : port_name_(std::move(port_name)), listener_(listener) {
+  instance_ = GetAppId() + "::" + std::to_string(seq_++);
+}
+
+LocalExecution::~LocalExecution() {
+  while (!result_queue_.empty()) {
+    auto parcel = result_queue_.front();
+    result_queue_.pop();
+    rpc_port_parcel_destroy(parcel);
+  }
+
+  while (!request_queue_.empty()) {
+    auto parcel = request_queue_.front();
+    request_queue_.pop();
+    rpc_port_parcel_destroy(parcel);
+  }
+}
+
+bool LocalExecution::Connect() {
+  if (connect_func_) {
+    if (connect_func_(this, GetAppId().c_str(), instance_.c_str()) != RPC_PORT_ERROR_NONE)
+      return false;
+  }
+
+  return true;
+}
+
+void LocalExecution::Disconnect() {
+  if (disconnect_func_)
+    disconnect_func_(this, GetAppId().c_str(), instance_.c_str());
+}
+
+int LocalExecution::Send(rpc_port_parcel_h request, rpc_port_parcel_h* result) {
+  if (send_func_) {
+    int ret = send_func_(this, request);
+    if (result != nullptr) {
+      int count = 0;
+      while (ResultQueueEmpty() && count++ < 100)
+        usleep(100 * 1000);
+
+      if (ResultQueueEmpty()) {
+        _E("Failed to get result from server");
+        return RPC_PORT_ERROR_IO_ERROR;
+      }
+
+      *result = ResultQueuePop();
+    }
+
+    return ret;
+  }
+
+  return RPC_PORT_ERROR_NONE;
+}
+
+void LocalExecution::OnConnected() {
+  connected_ = true;
+  if (listener_ != nullptr)
+    listener_->OnLocalConnected();
+}
+
+void LocalExecution::OnDisconnected() {
+  connected_ = false;
+  if (listener_ != nullptr)
+    listener_->OnLocalDisconnected();
+}
+
+void LocalExecution::OnReceived(rpc_port_parcel_h parcel) {
+  if (listener_ != nullptr)
+    listener_->OnLocalReceived(parcel);
+}
+
+bool LocalExecution::LoadSymbols() {
+  if (loaded_)
+    return true;
+
+  if (connect_func_ == nullptr) {
+    std::string symbol = "rpc_port_stub_<INPUT_FILE>_lem_" + port_name_ + "_connect";
+    connect_func_ = reinterpret_cast<StubConnectFunc>(dlsym(RTLD_DEFAULT, symbol.c_str()));
+    if (connect_func_ == nullptr) {
+      _E("Failed to find symbol(%s)", symbol.c_str());
+      return false;
+    }
+  }
+
+  if (disconnect_func_ == nullptr) {
+    std::string symbol = "rpc_port_stub_<INPUT_FILE>_lem_" + port_name_ + "_disconnect";
+    disconnect_func_ = reinterpret_cast<StubDisconnectFunc>(dlsym(RTLD_DEFAULT, symbol.c_str()));
+    if (disconnect_func_ == nullptr) {
+      _E("Failed to find symbol(%s)", symbol.c_str());
+      return false;
+    }
+  }
+
+  if (send_func_ == nullptr) {
+    std::string symbol = "rpc_port_stub_<INPUT_FILE>_lem_" + port_name_ + "_send";
+    send_func_ = reinterpret_cast<StubSendFunc>(dlsym(RTLD_DEFAULT, symbol.c_str()));
+    if (send_func_ == nullptr) {
+      _E("Failed to find symbol(%s)", symbol.c_str());
+      return false;
+    }
+  }
+
+  loaded_ = true;
+  return true;
+}
+
+void LocalExecution::ResultQueuePush(rpc_port_parcel_h parcel) {
+  std::lock_guard<std::recursive_mutex> lock(mutex_);
+  result_queue_.push(parcel);
+}
+
+rpc_port_parcel_h LocalExecution::ResultQueuePop() {
+  std::lock_guard<std::recursive_mutex> lock(mutex_);
+  auto parcel = result_queue_.front();
+  result_queue_.pop();
+  return parcel;
+}
+
+bool LocalExecution::ResultQueueEmpty() const {
+  std::lock_guard<std::recursive_mutex> lock(mutex_);
+  return result_queue_.empty();
+}
+
+void LocalExecution::RequestQueuePush(rpc_port_parcel_h parcel) {
+  std::lock_guard<std::recursive_mutex> lock(mutex_);
+  request_queue_.push(parcel);
+}
+
+rpc_port_parcel_h LocalExecution::RequestQueuePop() {
+  std::lock_guard<std::recursive_mutex> lock(mutex_);
+  auto parcel = request_queue_.front();
+  request_queue_.pop();
+  return parcel;
+}
+)__cpp_cb";
+
+/**
+ * <CLS_NAME> The interface name.
+ * <INPUT_FILE> The input file name.
+ * <FILE_NAMESPACE> The file namespace.
+ */
+constexpr const char CB_LEM_API[] =
+R"__cpp_cb(
+EXPORT_API int rpc_port_proxy_<INPUT_FILE>_lem_<CLS_NAME>_connect(void* h) {
+  auto* handle = static_cast<rpc_port::<FILE_NAMESPACE>::LocalExecution*>(h);
+  auto* ptr = new std::weak_ptr<rpc_port::<FILE_NAMESPACE>::LocalExecution>(handle->shared_from_this());
+  g_idle_add([](gpointer user_data) {
+        auto* wp = static_cast<std::weak_ptr<rpc_port::<FILE_NAMESPACE>::LocalExecution>*>(user_data);
+        auto p = wp->lock();
+        if (p != nullptr)
+          p->OnConnected();
+
+        delete wp;
+        return G_SOURCE_REMOVE;
+      }, ptr);
+  return RPC_PORT_ERROR_NONE;
+}
+
+EXPORT_API int rpc_port_proxy_<INPUT_FILE>_lem_<CLS_NAME>_disconnect(void* h) {
+  auto* handle = static_cast<rpc_port::<FILE_NAMESPACE>::LocalExecution*>(h);
+  auto* ptr = new std::weak_ptr<rpc_port::<FILE_NAMESPACE>::LocalExecution>(handle->shared_from_this());
+  g_idle_add([](gpointer user_data) {
+        auto* wp = static_cast<std::weak_ptr<rpc_port::<FILE_NAMESPACE>::LocalExecution>*>(user_data);
+        auto p = wp->lock();
+        if (p != nullptr)
+          p->OnDisconnected();
+
+        delete wp;
+        return G_SOURCE_REMOVE;
+      }, ptr);
+  return RPC_PORT_ERROR_NONE;
+}
+
+EXPORT_API int rpc_port_proxy_<INPUT_FILE>_lem_<CLS_NAME>_invoke_callback(void* h, rpc_port_parcel_h parcel) {
+  auto* handle = static_cast<rpc_port::<FILE_NAMESPACE>::LocalExecution*>(h);
+  auto* ptr = new std::weak_ptr<rpc_port::<FILE_NAMESPACE>::LocalExecution>(handle->shared_from_this());
+  rpc_port_parcel_h cloned_parcel = ::Clone(parcel);
+  handle->RequestQueuePush(cloned_parcel);
+  g_idle_add([](gpointer user_data) {
+        auto* wp = static_cast<std::weak_ptr<rpc_port::<FILE_NAMESPACE>::LocalExecution>*>(user_data);
+        auto p = wp->lock();
+        if (p != nullptr) {
+          rpc_port_parcel_h request = p->RequestQueuePop();
+          p->OnReceived(request);
+          rpc_port_parcel_destroy(request);
+        }
+
+        delete wp;
+        return G_SOURCE_REMOVE;
+      }, ptr);
+  return RPC_PORT_ERROR_NONE;
+}
+
+EXPORT_API int rpc_port_proxy_<INPUT_FILE>_lem_<CLS_NAME>_send_result(void* h, rpc_port_parcel_h parcel) {
+  auto* handle = static_cast<rpc_port::<FILE_NAMESPACE>::LocalExecution*>(h);
+  rpc_port_parcel_h cloned_parcel = ::Clone(parcel);
+  handle->ResultQueuePush(cloned_parcel);
+  return RPC_PORT_ERROR_NONE;
+}
+)__cpp_cb";
 
 }  // namespace version2
 }  // namespace tidl
index b715871..ce81dac 100644 (file)
@@ -24,8 +24,9 @@
 namespace tidl {
 namespace version2 {
 
-CppProxyHeaderGenerator::CppProxyHeaderGenerator(std::shared_ptr<Document> doc)
-    : CppGeneratorBase(std::move(doc)) {}
+CppProxyHeaderGenerator::CppProxyHeaderGenerator(
+    std::shared_ptr<Document> doc, std::shared_ptr<Options> options)
+    : CppGeneratorBase(std::move(doc)), options_(std::move(options)) {}
 
 void CppProxyHeaderGenerator::OnInitGen(std::ofstream& stream) {
   GenVersion(stream);
@@ -38,13 +39,20 @@ void CppProxyHeaderGenerator::OnFiniGen(std::ofstream& stream) {}
 void CppProxyHeaderGenerator::GenNamespace(std::ofstream& stream) {
   ReplaceAll(CB_NAMESPACE_PROXY)
       .ChangeToLower("<FILE_NAMESPACE>", GetFileNamespace())
-      .Change("<STRUCTURES>", GenStructuresForHeader())
+      .Change("<STRUCTURES>", GenLemBaseWithStructures())
       .Change("<BASE_IMPL>", GenBaseImpl())
       .Change("<INTERFACES>", GenInterfaces())
       .Transform([&](std::string str) { return SmartIndent(str); })
       .Out(stream);
 }
 
+std::string CppProxyHeaderGenerator::GenLemBaseWithStructures() {
+  std::string code = CB_LEM_BASE;
+  code += NLine(1);
+  code += GenStructuresForHeader();
+  return code;
+}
+
 std::string CppProxyHeaderGenerator::GenBaseImpl() {
   std::string code = GenExceptions();
   code += GenRemoteExceptionForHeader();
@@ -78,16 +86,13 @@ std::string CppProxyHeaderGenerator::GenInterface(const Interface& iface) {
 std::string CppProxyHeaderGenerator::GenInterfaceCallbacks(
     const Interface& iface) {
   std::string code;
+  code += ReplaceAll(CB_INTERFACE_CALLBACK_BASE)
+              .Change("<IFACE_NAME>", iface.GetID());
+  code += NLine(1);
   for (const auto& decl : iface.GetDeclarations()) {
     if (decl->GetMethodType() != Declaration::MethodType::DELEGATE)
       continue;
 
-    if (code.empty()) {
-      code += ReplaceAll(CB_INTERFACE_CALLBACK_BASE)
-          .Change("<IFACE_NAME>", iface.GetID());
-      code += NLine(1);
-    }
-
     code += ReplaceAll(CB_INTERFACE_CALLBACK)
         .Change("<CLS_NAME>", decl->GetID())
         .Change("<PARAMS>", GetParameters(decl->GetParameters()));
index 72ba768..13b147e 100644 (file)
 #include <string>
 
 #include "idlc/gen/version2/cpp_generator_base.hh"
+#include "idlc/options.h"
 
 namespace tidl {
 namespace version2 {
 
 class CppProxyHeaderGenerator : public CppGeneratorBase {
  public:
-  explicit CppProxyHeaderGenerator(std::shared_ptr<Document> doc);
+  explicit CppProxyHeaderGenerator(std::shared_ptr<Document> doc,
+                                   std::shared_ptr<Options> options);
   virtual ~CppProxyHeaderGenerator() = default;
 
   void OnInitGen(std::ofstream& stream) override;
@@ -35,11 +37,15 @@ class CppProxyHeaderGenerator : public CppGeneratorBase {
 
  private:
   void GenNamespace(std::ofstream& stream);
+  std::string GenLemBaseWithStructures();
   std::string GenBaseImpl();
   std::string GenInterfaces();
   std::string GenInterface(const Interface& iface);
   std::string GenInterfaceCallbacks(const Interface& iface);
   std::string GenInterfaceMethods(const Interface& iface);
+
+ private:
+  std::shared_ptr<Options> options_;
 };
 
 }  // namespace version2
index 6c3953f..c02b013 100644 (file)
@@ -77,7 +77,7 @@ class <CLS_NAME> : public CallbackBase {
  */
 constexpr const char CB_INTERFACE_BASE[] =
 R"__cpp_cb(
-class <CLS_NAME> {
+class <CLS_NAME> : public LocalExecution::IEvent {
  public:
   <ENUMS>
   <CALLBACKS>
@@ -155,6 +155,10 @@ class <CLS_NAME> {
   static void OnRejectedCb(const char* endpoint, const char* port_name, void* user_data);
   static void OnReceivedCb(const char* endpoint, const char* port_name, void* user_data);
 
+  void OnLocalConnected() override;
+  void OnLocalDisconnected() override;
+  void OnLocalReceived(rpc_port_parcel_h parcel) override;
+
  private:
   rpc_port_h port_ = nullptr;
   rpc_port_h callback_port_ = nullptr;
@@ -163,6 +167,7 @@ class <CLS_NAME> {
   std::recursive_mutex mutex_;
   std::list<std::unique_ptr<CallbackBase>> delegate_list_;
   std::string target_appid_;
+  std::shared_ptr<LocalExecution> local_execution_;
 };
 )__cpp_cb";
 
@@ -176,6 +181,61 @@ R"__cpp_cb(
 <RETURN_TYPE> <NAME>(<PARAMS>);
 )__cpp_cb";
 
+constexpr const char CB_LEM_BASE[] =
+R"__cpp_cb(
+class LocalExecution : public std::enable_shared_from_this<LocalExecution> {
+ public:
+  class IEvent {
+   public:
+    virtual ~IEvent() = default;
+    virtual void OnLocalConnected() = 0;
+    virtual void OnLocalDisconnected() = 0;
+    virtual void OnLocalReceived(rpc_port_parcel_h parcel) = 0;
+  };
+
+  LocalExecution(std::string port_name, IEvent* listener);
+  virtual ~LocalExecution();
+
+  bool Connect();
+  void Disconnect();
+  int Send(rpc_port_parcel_h request, rpc_port_parcel_h* result);
+
+  bool IsConnected() const { return connected_; }
+
+  void OnConnected();
+  void OnDisconnected();
+  void OnReceived(rpc_port_parcel_h parcel);
+
+  bool LoadSymbols();
+
+  void ResultQueuePush(rpc_port_parcel_h parcel);
+  rpc_port_parcel_h ResultQueuePop();
+  bool ResultQueueEmpty() const;
+
+  void RequestQueuePush(rpc_port_parcel_h parcel);
+  rpc_port_parcel_h RequestQueuePop();
+
+
+ private:
+  using StubConnectFunc = int (*)(void*, const char*, const char*);
+  using StubDisconnectFunc = void (*)(void*, const char*, const char*);
+  using StubSendFunc = int (*)(void*, rpc_port_parcel_h);
+
+ private:
+  std::string port_name_;
+  IEvent* listener_;
+  std::string instance_;
+  bool connected_ = false;
+  bool loaded_ = false;
+  StubConnectFunc connect_func_ = nullptr;
+  StubDisconnectFunc disconnect_func_ = nullptr;
+  StubSendFunc send_func_ = nullptr;
+  std::queue<rpc_port_parcel_h> result_queue_;
+  std::queue<rpc_port_parcel_h> request_queue_;
+  mutable std::recursive_mutex mutex_;
+};
+)__cpp_cb";
+
 }  // namespace version2
 }  // namespace tidl
 
index 78de08d..255fbb8 100644 (file)
@@ -16,6 +16,8 @@
 
 #include "idlc/gen/version2/cpp_stub_body_generator.hh"
 
+#include <libgen.h>
+
 #include <utility>
 
 #include "idlc/gen/version2/cpp_generator_base_cb.hh"
@@ -35,7 +37,10 @@ void CppStubBodyGenerator::OnInitGen(std::ofstream& stream) {
   GenLogTag(stream, "RPC_PORT_STUB");
   GenLogDefinition(stream);
   GenVersionDefinition(stream);
+  GenExportAPI(stream);
+  GenLemAnonymousNamespace(stream);
   GenNamespace(stream);
+  GenLemAPI(stream);
 }
 
 void CppStubBodyGenerator::OnFiniGen(std::ofstream& stream) {}
@@ -56,13 +61,63 @@ void CppStubBodyGenerator::GenIncludeStubBodyHeader(std::ofstream& stream) {
 void CppStubBodyGenerator::GenNamespace(std::ofstream& stream) {
   ReplaceAll(CB_NAMESPACE_STUB)
       .ChangeToLower("<FILE_NAMESPACE>", GetFileNamespace())
-      .Change("<STRUCTURES>", GenStructures())
+      .Change("<STRUCTURES>", GenLemBaseWithStructures())
       .Change("<BASE_IMPL>", GenBaseImpl())
       .Change("<INTERFACES>", GenInterfaces())
       .Transform([&](std::string str) { return SmartIndent(str); })
       .Out(stream);
 }
 
+void CppStubBodyGenerator::GenLemAnonymousNamespace(std::ofstream& stream) {
+  ReplaceAll(CB_LEM_ANONYMOUS_NAMESPACE)
+      .Change("<LEM_CONTEXT>", GenLemContext())
+      .Transform([&](std::string code) { return SmartIndent(code); })
+      .Out(stream);
+}
+
+std::string CppStubBodyGenerator::GenLemContext() {
+  std::string code;
+  for (const auto& block : GetDocument().GetBlocks()) {
+    if (block->GetType() != Block::TYPE_INTERFACE)
+      continue;
+
+    auto& iface = static_cast<Interface&>(*block);
+    code += ReplaceAll(CB_LEM_CONTEXT)
+        .Change("<IFACE_NAME>", iface.GetID())
+        .ChangeToLower("<FILE_NAMESPACE>", GetFileNamespace());
+  }
+
+  return RemoveLine(code);
+}
+
+void CppStubBodyGenerator::GenLemAPI(std::ofstream& stream) {
+  std::string input = basename(const_cast<char*>(options_->GetInput().c_str()));
+  input = input.substr(0, input.find_last_of("."));
+  std::string code = NLine(1);
+  for (const auto& block : GetDocument().GetBlocks()) {
+    if (block->GetType() != Block::TYPE_INTERFACE)
+      continue;
+
+    auto& iface = static_cast<Interface&>(*block);
+    code += ReplaceAll(CB_LEM_API)
+        .Change("<CLS_NAME>", iface.GetID())
+        .ChangeToLower("<INPUT_FILE>", input);
+    code += NLine(1);
+  }
+
+  stream << SmartIndent(code);
+}
+
+std::string CppStubBodyGenerator::GenLemBaseWithStructures() {
+  std::string input = basename(const_cast<char*>(options_->GetInput().c_str()));
+  input = input.substr(0, input.find_last_of("."));
+  std::string code;
+  code += ReplaceAll(CB_LEM_BASE).ChangeToLower("<INPUT_FILE>", input);
+  code += NLine(1);
+  code += GenStructures();
+  return code;
+}
+
 std::string CppStubBodyGenerator::GenBaseImpl() {
   std::string code = GenRemoteException();
   code += GenUnitMap();
@@ -102,16 +157,13 @@ std::string CppStubBodyGenerator::GenInterface(const Interface& iface) {
 std::string CppStubBodyGenerator::GenInterfaceCallbacks(
     const Interface& iface) {
   std::string code;
+  code += ReplaceAll(CB_INTERFACE_CALKBACBASE_BASE)
+              .Change("<IFACE_NAME>", iface.GetID());
+  code += NLine(1);
   for (const auto& decl : iface.GetDeclarations()) {
     if (decl->GetMethodType() != Declaration::MethodType::DELEGATE)
       continue;
 
-    if (code.empty()) {
-      code += ReplaceAll(CB_INTERFACE_CALKBACBASE_BASE)
-          .Change("<IFACE_NAME>", iface.GetID());
-      code += NLine(1);
-    }
-
     code += ReplaceAll(CB_INTERFACE_CALLBACK)
         .Change("<IFACE_NAME>", iface.GetID())
         .Change("<CLS_NAME>", decl->GetID())
index ba3a54e..90a7353 100644 (file)
@@ -37,7 +37,11 @@ class CppStubBodyGenerator : public CppGeneratorBase {
 
  private:
   void GenIncludeStubBodyHeader(std::ofstream& stream);
+  void GenLemAnonymousNamespace(std::ofstream& stream);
+  std::string GenLemContext();
+  void GenLemAPI(std::ofstream& stream);
   void GenNamespace(std::ofstream& stream);
+  std::string GenLemBaseWithStructures();
   std::string GenBaseImpl();
   std::string GenInterfaces();
   std::string GenInterface(const Interface& iface);
index b0c375b..7571959 100644 (file)
@@ -72,6 +72,14 @@ void <IFACE_NAME>::CallbackBase::SetOnce(bool once) {
 std::string <IFACE_NAME>::CallbackBase::GetTag() const {
   return std::to_string(id_) + "::" + std::to_string(seq_id_);
 }
+
+void <IFACE_NAME>::CallbackBase::SetContext(void* context) {
+  context_ = context;
+}
+
+void* <IFACE_NAME>::CallbackBase::GetContext() const {
+  return context_;
+}
 )__cpp_cb";
 
 /**
@@ -82,7 +90,7 @@ std::string <IFACE_NAME>::CallbackBase::GetTag() const {
 constexpr const char CB_INTERFACE_CALLBACK[] =
 R"__cpp_cb(
 void <IFACE_NAME>::<CLS_NAME>::Invoke(<PARAMS>) {
-  if (callback_port_ == nullptr)
+  if (callback_port_ == nullptr && GetContext() == nullptr)
       throw NotConnectedSocketException();
 
   if (service_.lock().get() == nullptr)
@@ -100,7 +108,13 @@ void <IFACE_NAME>::<CLS_NAME>::Invoke(<PARAMS>) {
   rpc_port_parcel_create(&parcel_);
   unit_map_.Serialize(parcel_);
 
-  set_last_result(rpc_port_parcel_send(parcel_, callback_port_));
+  if (GetContext() != nullptr) {
+    <IFACE_NAME>_context_->InvokeCallback(GetContext(), parcel_);
+    set_last_result(RPC_PORT_ERROR_NONE);
+  } else {
+    set_last_result(rpc_port_parcel_send(parcel_, callback_port_));
+  }
+
   rpc_port_parcel_destroy(parcel_);
   valid_ = false;
 }
@@ -254,6 +268,14 @@ bool <CLS_NAME>::ServiceBase::CheckPrivileges(int method_id) {
 
 <IMPL_SERVICE_BASE_DISPATCH_FUNCS>
 
+void <CLS_NAME>::ServiceBase::SetContext(void* context) {
+  context_ = context;
+}
+
+void* <CLS_NAME>::ServiceBase::GetContext() const {
+  return context_;
+}
+
 <CLS_NAME>::<CLS_NAME>() {
   _W("<CLS_NAME> ctor");
   int ret = rpc_port_stub_create(&stub_, "<CLS_NAME>");
@@ -265,10 +287,13 @@ bool <CLS_NAME>::ServiceBase::CheckPrivileges(int method_id) {
   rpc_port_stub_add_connected_event_cb(stub_, OnConnectedCb, this);
   rpc_port_stub_add_disconnected_event_cb(stub_, OnDisconnectedCb, this);
   rpc_port_stub_add_received_event_cb(stub_, OnReceivedCb, this);
+
+  <CLS_NAME>_context_ = std::make_unique<LocalExecution>("<CLS_NAME>", this);
 }
 
 <CLS_NAME>::~<CLS_NAME>() {
   _W("<CLS_NAME> dtor");
+  <CLS_NAME>_context_.reset();
   for (auto& service : services_)
     service->OnTerminate();
 
@@ -284,6 +309,8 @@ void <CLS_NAME>::Listen(std::shared_ptr<<CLS_NAME>::ServiceBase::Factory> servic
     if (ret == RPC_PORT_ERROR_INVALID_PARAMETER || ret == RPC_PORT_ERROR_IO_ERROR)
       throw InvalidIOException();
   }
+
+  <CLS_NAME>_context_->SetListening(true);
 }
 
 void <CLS_NAME>::OnConnectedCb(const char* sender, const char* instance, void* user_data) {
@@ -348,6 +375,47 @@ int <CLS_NAME>::OnReceivedCb(const char* sender, const char* instance, rpc_port_
   service->Dispatch(port, callback_port, parcel, service);
   return ret;
 }
+
+void <CLS_NAME>::OnLocalConnected(void* context, const std::string& sender, const std::string& instance) {
+  auto service = service_factory_->CreateService(sender, instance);
+  service->SetContext(context);
+  service->OnCreate();
+  services_.emplace_back(std::move(service));
+  <CLS_NAME>_context_->Connect(context);
+}
+
+void <CLS_NAME>::OnLocalDisconnected(void* context, const std::string& sender, const std::string& instance) {
+  auto iter = services_.begin();
+  while (iter != services_.end()) {
+    if ((*iter)->GetInstance() == instance) {
+      (*iter)->OnTerminate();
+      iter = services_.erase(iter);
+      break;
+    }
+
+    iter++;
+  }
+
+  <CLS_NAME>_context_->Disconnect(context);
+}
+
+void <CLS_NAME>::OnLocalReceived(void* context, rpc_port_parcel_h parcel) {
+  std::shared_ptr<ServiceBase> service;
+  for (auto& iter : services_) {
+    if (iter->GetContext() == context) {
+      service = iter;
+      break;
+    }
+  }
+
+  if (service.get() == nullptr) {
+    _E("Failed to find <CLS_NAME> context. context(%p)", context);
+    return;
+  }
+
+  rpc_port_parcel_h p = Clone(parcel);
+  service->Dispatch(nullptr, nullptr, p, service);
+}
 )__cpp_cb";
 
 /**
@@ -431,7 +499,10 @@ void <IFACE_NAME>::ServiceBase::Dispatch<NAME>(rpc_port_h port, rpc_port_h callb
   rpc_port_parcel_header_set_seq_num(header_, seq_num);
 
   map_.Serialize(parcel_);
-  rpc_port_parcel_send(parcel_, port);
+  if (GetContext() != nullptr)
+    <IFACE_NAME>_context_->SendResult(GetContext(), parcel_);
+  else
+    rpc_port_parcel_send(parcel_, port);
   rpc_port_parcel_destroy(parcel_);
 }
 )__cpp_cb";
@@ -461,6 +532,7 @@ R"__cpp_cb(
 constexpr const char CB_INTERFACE_SERVICE_BASE_PARAM_DELEGATE[] =
 R"__cpp_cb(
 <TYPE> <NAME>(new <TYPE_NAME>(callback_port, std::weak_ptr<ServiceBase>(this->shared_from_this())));
+<NAME>->SetContext(GetContext());
 )__cpp_cb";
 
 /**
@@ -485,6 +557,163 @@ R"__cpp_cb(
 }
 )__cpp_cb";
 
+/**
+ * <LEM_CONTEXT> The context of the local execution of the interface.
+ */
+constexpr const char CB_LEM_ANONYMOUS_NAMESPACE[] =
+R"__cpp_cb(
+namespace {
+
+rpc_port_parcel_h Clone(rpc_port_parcel_h parcel) {
+  void* raw = nullptr;
+  unsigned int size = 0;
+  rpc_port_parcel_get_raw(parcel, &raw, &size);
+
+  rpc_port_parcel_h handle = nullptr;
+  rpc_port_parcel_create_from_raw(&handle, raw, size);
+  return handle;
+}
+
+<LEM_CONTEXT>
+
+}  // namespace
+)__cpp_cb";
+
+/**
+ * <FILE_NAMESPACE> The file namespace.
+ * <IFACE_NAME> The interface name.
+ */
+constexpr const char CB_LEM_CONTEXT[] =
+R"__cpp_cb(
+std::shared_ptr<rpc_port::<FILE_NAMESPACE>::LocalExecution> <IFACE_NAME>_context_;
+)__cpp_cb";
+
+/**
+ * <INPUT_FILE> The file namespace.
+ */
+constexpr const char CB_LEM_BASE[] =
+R"__cpp_cb(
+LocalExecution::LocalExecution(std::string port_name, LocalExecution::IEvent* listener) : port_name_(std::move(port_name)), listener_(listener) {
+  LoadSymbols();
+}
+
+void LocalExecution::Connect(void* context) {
+  if (connect_func_ != nullptr)
+    connect_func_(context);
+}
+
+void LocalExecution::Disconnect(void* context) {
+  if (disconnect_func_ != nullptr)
+    disconnect_func_(context);
+}
+
+void LocalExecution::SendResult(void* context, rpc_port_parcel_h parcel) {
+  if (send_result_func_ != nullptr)
+    send_result_func_(context, parcel);
+}
+
+void LocalExecution::InvokeCallback(void* context, rpc_port_parcel_h parcel) {
+  if (invoke_callback_func_ != nullptr)
+    invoke_callback_func_(context, parcel);
+}
+
+void LocalExecution::OnConnected(void* context, const std::string& sender, const std::string& instance) {
+  if (listener_ != nullptr)
+    listener_->OnLocalConnected(context, sender, instance);
+}
+
+void LocalExecution::OnDisconnected(void* context, const std::string& sender, const std::string& instance) {
+  if (listener_ != nullptr)
+    listener_->OnLocalDisconnected(context, sender, instance);
+}
+
+void LocalExecution::OnReceived(void* context, rpc_port_parcel_h parcel) {
+  if (listener_ != nullptr)
+    listener_->OnLocalReceived(context, parcel);
+}
+
+bool LocalExecution::LoadSymbols() {
+  if (loaded_)
+    return true;
+
+  std::string symbol = "rpc_port_proxy_<INPUT_FILE>_lem_" + port_name_ + "_connect";
+  connect_func_ = reinterpret_cast<ProxyConnectFunc>(dlsym(RTLD_DEFAULT, symbol.c_str()));
+  if (connect_func_ == nullptr) {
+    _E("Failed to find symbol");
+    return false;
+  }
+
+  symbol = "rpc_port_proxy_<INPUT_FILE>_lem_" + port_name_ + "_disconnect";
+  disconnect_func_ = reinterpret_cast<ProxyDisconnectFunc>(dlsym(RTLD_DEFAULT, symbol.c_str()));
+  if (disconnect_func_ == nullptr) {
+    _E("Failed to find symbol");
+    return false;
+  }
+
+  symbol = "rpc_port_proxy_<INPUT_FILE>_lem_" + port_name_ + "_send_result";
+  send_result_func_ = reinterpret_cast<ProxySendResultFunc>(dlsym(RTLD_DEFAULT, symbol.c_str()));
+  if (send_result_func_ == nullptr) {
+    _E("Failed to find symbol");
+    return false;
+  }
+
+  symbol = "rpc_port_proxy_<INPUT_FILE>_lem_" + port_name_ + "_invoke_callback";
+  invoke_callback_func_ = reinterpret_cast<ProxyInvokeCallbackFunc>(dlsym(RTLD_DEFAULT, symbol.c_str()));
+  if (invoke_callback_func_ == nullptr) {
+    _E("Failed to find symbol");
+    return false;
+  }
+
+  loaded_ = true;
+  return true;
+}
+
+void LocalExecution::SetListening(bool listening) {
+  listening_ = listening;
+}
+
+bool LocalExecution::IsListening() const {
+  return listening_;
+}
+)__cpp_cb";
+
+/**
+ * <INPUT_FILE> The input file name.
+ * <CLS_NAME> The interface name.
+ */
+constexpr const char CB_LEM_API[] =
+R"__cpp_cb(
+EXPORT_API int rpc_port_stub_<INPUT_FILE>_lem_<CLS_NAME>_connect(void* context, const char* sender, const char* instance) {
+  if (<CLS_NAME>_context_.get() == nullptr || !<CLS_NAME>_context_->IsListening()) {
+    _E("Server is not ready");
+    return RPC_PORT_ERROR_IO_ERROR;
+  }
+
+  <CLS_NAME>_context_->OnConnected(context, sender, instance);
+  return RPC_PORT_ERROR_NONE;
+}
+
+EXPORT_API int rpc_port_stub_<INPUT_FILE>_lem_<CLS_NAME>_disconnect(void* context, const char* sender, const char* instance) {
+  if (<CLS_NAME>_context_.get() == nullptr || !<CLS_NAME>_context_->IsListening()) {
+    _E("Server is not ready");
+    return RPC_PORT_ERROR_IO_ERROR;
+  }
+
+  <CLS_NAME>_context_->OnDisconnected(context, sender, instance);
+  return RPC_PORT_ERROR_NONE;
+}
+
+EXPORT_API int rpc_port_stub_<INPUT_FILE>_lem_<CLS_NAME>_send(void* context, rpc_port_parcel_h parcel) {
+  if (<CLS_NAME>_context_.get() == nullptr || !<CLS_NAME>_context_->IsListening()) {
+    _E("Server is not ready");
+    return RPC_PORT_ERROR_IO_ERROR;
+  }
+
+  <CLS_NAME>_context_->OnReceived(context, parcel);
+  return RPC_PORT_ERROR_NONE;
+}
+)__cpp_cb";
+
 }  // namespace version2
 }  // namespace tidl
 
index 4ba607a..9453b42 100644 (file)
@@ -39,13 +39,20 @@ void CppStubHeaderGenerator::OnFiniGen(std::ofstream& stream) {}
 void CppStubHeaderGenerator::GenNamespace(std::ofstream& stream) {
   ReplaceAll(CB_NAMESPACE_STUB)
       .ChangeToLower("<FILE_NAMESPACE>", GetFileNamespace())
-      .Change("<STRUCTURES>", GenStructuresForHeader())
+      .Change("<STRUCTURES>", GenLemBaseWithStructures())
       .Change("<BASE_IMPL>", GenBaseImpl())
       .Change("<INTERFACES>", GenInterfaces())
       .Transform([&](std::string str) { return SmartIndent(str); })
       .Out(stream);
 }
 
+std::string CppStubHeaderGenerator::GenLemBaseWithStructures() {
+  std::string code = CB_LEM_BASE;
+  code += NLine(1);
+  code += GenStructuresForHeader();
+  return code;
+}
+
 std::string CppStubHeaderGenerator::GenBaseImpl() {
   std::string code = GenExceptions();
   code += GenRemoteExceptionForHeader();
@@ -87,16 +94,13 @@ std::string CppStubHeaderGenerator::GenInterface(const Interface& iface) {
 std::string CppStubHeaderGenerator::GenInterfaceCallbacks(
     const Interface& iface) {
   std::string code;
+  code += ReplaceAll(CB_INTERFACE_CALLBACK_BASE)
+              .Change("<IFACE_NAME>", iface.GetID());
+  code += NLine(1);
   for (const auto& decl : iface.GetDeclarations()) {
     if (decl->GetMethodType() != Declaration::MethodType::DELEGATE)
       continue;
 
-    if (code.empty()) {
-      code += ReplaceAll(CB_INTERFACE_CALLBACK_BASE)
-          .Change("<IFACE_NAME>", iface.GetID());
-      code += NLine(1);
-    }
-
     code += ReplaceAll(CB_INTERFACE_CALLBACK)
         .Change("<CLS_NAME>", decl->GetID())
         .Change("<PARAMS>", GetParameters(decl->GetParameters()));
index 46935b1..e124fc7 100644 (file)
@@ -37,6 +37,7 @@ class CppStubHeaderGenerator : public CppGeneratorBase {
 
  private:
   void GenNamespace(std::ofstream& stream);
+  std::string GenLemBaseWithStructures();
   std::string GenBaseImpl();
   std::string GenInterfaces();
   std::string GenInterface(const Interface& iface);
index ee4b63b..51db84f 100644 (file)
@@ -183,11 +183,15 @@ class CallbackBase {
 
   std::string GetTag() const;
 
+  void SetContext(void* context);
+  void* GetContext() const;
+
  private:
   static std::atomic<int> seq_num_;
   int id_ = 0;
   int seq_id_ = 0;
   bool once_ = false;
+  void* context_ = nullptr;
 };
 )__cpp_cb";
 
@@ -240,7 +244,7 @@ class PendingJob : public Job, Job::IEvent {
  */
 constexpr const char CB_INTERFACE_BASE[] =
 R"__cpp_cb(
-class <CLS_NAME> {
+class <CLS_NAME> : public LocalExecution::IEvent {
  public:
   <ENUMS>
   <CALLBACKS>
@@ -298,6 +302,8 @@ class <CLS_NAME> {
     /// </summary>
     virtual void OnTerminate() = 0;
 
+    void SetContext(void* context);
+    void* GetContext() const;
     void Dispatch(rpc_port_h port, rpc_port_h callback_port, rpc_port_parcel_h parcel, std::shared_ptr<ServiceBase> service);
     void Dispatch(rpc_port_h port, rpc_port_h callback_port, rpc_port_parcel_h parcel);
 
@@ -324,6 +330,7 @@ class <CLS_NAME> {
     std::unordered_map<int, DispatchFunc> dispatch_funcs_;
     std::unordered_map<int, std::vector<std::string>> privilege_map_;
     std::unordered_set<std::string> privileges_;
+    void* context_ = nullptr;
   };
 
   <CLS_NAME>();
@@ -354,6 +361,10 @@ class <CLS_NAME> {
   static void OnDisconnectedCb(const char* sender, const char* instance, void* user_data);
   static int OnReceivedCb(const char* sender, const char* instance, rpc_port_h port, void* user_data);
 
+  void OnLocalConnected(void* context, const std::string& sender, const std::string& instance) override;
+  void OnLocalDisconnected(void* context, const std::string& sender, const std::string& instance) override;
+  void OnLocalReceived(void* context, rpc_port_parcel_h parcel) override;
+
  private:
   rpc_port_stub_h stub_ = nullptr;
   std::shared_ptr<ServiceBase::Factory> service_factory_;
@@ -384,6 +395,53 @@ R"__cpp_cb(
 std::unique_ptr<ActiveObject> active_object_;
 )__cpp_cb";
 
+constexpr const char CB_LEM_BASE[] =
+R"__cpp_cb(
+class LocalExecution {
+ public:
+  class IEvent {
+   public:
+    virtual ~IEvent() = default;
+    virtual void OnLocalConnected(void* context, const std::string& sender, const std::string& instance) = 0;
+    virtual void OnLocalDisconnected(void* context, const std::string& sender, const std::string& instance) = 0;
+    virtual void OnLocalReceived(void* context, rpc_port_parcel_h parcel) = 0;
+  };
+
+  LocalExecution(std::string port_name, IEvent* listener);
+  virtual ~LocalExecution() = default;
+
+  void Connect(void* context);
+  void Disconnect(void* context);
+  void SendResult(void* context, rpc_port_parcel_h parcel);
+  void InvokeCallback(void* context, rpc_port_parcel_h parcel);
+
+  void OnConnected(void* context, const std::string& sender, const std::string& instance);
+  void OnDisconnected(void* context, const std::string& sender, const std::string& instance);
+  void OnReceived(void* context, rpc_port_parcel_h parcel);
+
+  void SetListening(bool listening);
+  bool IsListening() const;
+
+  bool LoadSymbols();
+
+ private:
+  using ProxyConnectFunc = int (*)(void*);
+  using ProxyDisconnectFunc = int (*)(void*);
+  using ProxySendResultFunc = int (*)(void*, rpc_port_parcel_h);
+  using ProxyInvokeCallbackFunc = int (*)(void*, rpc_port_parcel_h);
+
+ private:
+  std::string port_name_;
+  IEvent* listener_;
+  bool listening_ = false;
+  bool loaded_ = false;
+  ProxyConnectFunc connect_func_ = nullptr;
+  ProxyDisconnectFunc disconnect_func_ = nullptr;
+  ProxySendResultFunc send_result_func_ = nullptr;
+  ProxyInvokeCallbackFunc invoke_callback_func_ = nullptr;
+};
+)__cpp_cb";
+
 }  // namespace version2
 }  // namespace tidl
 
index af5e199..2c52c58 100644 (file)
@@ -137,10 +137,10 @@ void DefaultGenerator::GenCProxyCode(std::shared_ptr<Options> options,
 
 void DefaultGenerator::GenCppProxyCode(std::shared_ptr<Options> options,
                                        const Parser& ps) {
-  CppProxyHeaderGenerator proxy_header(ps.GetDoc());
+  CppProxyHeaderGenerator proxy_header(ps.GetDoc(), options);
   proxy_header.Run(options->GetOutput() + ".h");
 
-  CppProxyBodyGenerator proxy_body(ps.GetDoc());
+  CppProxyBodyGenerator proxy_body(ps.GetDoc(), options);
   proxy_body.Run(options->GetOutput() + ".cc");
 }
 
index 58899b4..8d9fe6a 100644 (file)
@@ -97,8 +97,6 @@ SET(TIDL_GEN_SRCS
   FooPubsubCionGroupC.c
   Message_v2ProxyC.c
   Message_v2StubC.c
-  Message_v2testProxyCpp.cc
-  Message_v2testStubCpp.cc
   Buffer_v2ProxyC.c
   Buffer_v2StubC.c
   Ex_v2ProxyC.c
@@ -109,6 +107,18 @@ SET(TIDL_GEN_SRCS
   Foo_v2StubC.c
   Import_v2ProxyC.c
   Import_v2StubC.c
+  Message_v2Proxy.cc
+  Message_v2Stub.cc
+  Buffer_v2Proxy.cc
+  Buffer_v2Stub.cc
+  Ex_v2Proxy.cc
+  Ex_v2Stub.cc
+  DataPort_v2Proxy.cc
+  DataPort_v2Stub.cc
+  Foo_v2Proxy.cc
+  Foo_v2Stub.cc
+  Import_v2Proxy.cc
+  Import_v2Stub.cc
 )
 
 ADD_CUSTOM_COMMAND(OUTPUT ${TIDL_GEN_SRCS} PRE_BUILD
index 76e2476..4ad11e4 100755 (executable)
@@ -58,15 +58,14 @@ GenerateTIDL() {
 
     OUTPUT="${FILES_V2[index]}StubC"
     ${TIDLC} -s -n -l C -i ${SCRIPT_DIR}/tidl/${INPUT} -o ${TARGET_DIR}/${OUTPUT}
-  done
 
-  INPUT="${FILES_V2[0]}test.tidl"
+    OUTPUT="${FILES_V2[index]}Proxy"
+    ${TIDLC} -p -n -l C++ -i ${SCRIPT_DIR}/tidl/${INPUT} -o ${TARGET_DIR}/${OUTPUT}
 
-  OUTPUT="${FILES_V2[0]}testProxyCpp"
-  ${TIDLC} -p -n -l C++ -i ${SCRIPT_DIR}/tidl/${INPUT} -o ${TARGET_DIR}/${OUTPUT}
+    OUTPUT="${FILES_V2[index]}Stub"
+    ${TIDLC} -s -n -l C++ -i ${SCRIPT_DIR}/tidl/${INPUT} -o ${TARGET_DIR}/${OUTPUT}
 
-  OUTPUT="${FILES_V2[0]}testStubCpp"
-  ${TIDLC} -s -n -l C++ -i ${SCRIPT_DIR}/tidl/${INPUT} -o ${TARGET_DIR}/${OUTPUT}
+  done
 
   for index in ${!FILES_FOR_GROUP[*]}; do
     echo "Generate ${FILES_FOR_GROUP[index]}"