3

D-Bus サーバー (g_bus_own_name() 経由) とクライアント (g_dbus_proxy_new() を使用) を同じプロセスで作成し、g_dbus_proxy_call_sync() を呼び出すと、戻りません。ただし、サーバーとクライアントが別々のプロセスにある場合は、すべて問題ありません。

次のコードは私の問題を示しています (ここでは giomm C++ バインディングを使用しています)。

ファイル main.cc:

#include <giomm.h>
#include <thread>

int server_main();
int client_main();

int main() {
    Gio::init();
    std::thread thr_server([](){ server_main(); });
    sleep(1);  // give some time to server to register
    std::thread thr_client([](){ client_main(); });
    sleep(10);  // wait for the client to finish
}

ファイル server.cc:

#include <giomm.h>
#include <iostream>

namespace {
static Glib::RefPtr<Gio::DBus::NodeInfo> introspection_data;

static Glib::ustring introspection_xml =
  "<node name='/org/glibmm/DBusExample'>"
  "  <interface name='org.glibmm.DBusExample'>"
  "    <method name='Method'>"
  "    </method>"
  "  </interface>"
  "</node>";

guint registered_id = 0;
}

static void on_method_call(const Glib::RefPtr<Gio::DBus::Connection>& /* connection */,
  const Glib::ustring& /* sender */, const Glib::ustring& /* object_path */,
  const Glib::ustring& /* interface_name */, const Glib::ustring& method_name,
  const Glib::VariantContainerBase& parameters,
  const Glib::RefPtr<Gio::DBus::MethodInvocation>& invocation)
{
  if(method_name == "Method") {
    std::cout << "Method was called\n";
  }      
}

const Gio::DBus::InterfaceVTable interface_vtable(sigc::ptr_fun(&on_method_call));

void on_bus_acquired(const Glib::RefPtr<Gio::DBus::Connection>& connection, const Glib::ustring& /* name */)
{
  std::cout << "on_bus_acquired\n";      
  try {
    registered_id = connection->register_object("/org/glibmm/DBusExample",
      introspection_data->lookup_interface(),
      interface_vtable);
  }
  catch(const Glib::Error& ex) {
    std::cerr << "Registration of object failed." << std::endl;
  }

  return;
}

void on_name_acquired(const Glib::RefPtr<Gio::DBus::Connection>& /* connection */, const Glib::ustring& /* name */)
{}

void on_name_lost(const Glib::RefPtr<Gio::DBus::Connection>& connection, const Glib::ustring& /* name */) {
  connection->unregister_object(registered_id);
}

int server_main()
{
  try {
    introspection_data = Gio::DBus::NodeInfo::create_for_xml(introspection_xml);
  }
  catch(const Glib::Error& ex) {
    std::cerr << "Unable to create introspection data: " << ex.what() <<
      "." << std::endl;
    return 1;
  }

  const guint id = Gio::DBus::own_name(Gio::DBus::BUS_TYPE_SESSION,
    "org.glibmm.DBusExample",
    sigc::ptr_fun(&on_bus_acquired),
    sigc::ptr_fun(&on_name_acquired),
    sigc::ptr_fun(&on_name_lost));

  //Keep the service running
  auto loop = Glib::MainLoop::create();
  loop->run();

  Gio::DBus::unown_name(id);

  return EXIT_SUCCESS;
}

ファイル client.cc:

#include <giomm.h>
#include <iostream>

Glib::RefPtr<Glib::MainLoop> loop;

// A main loop idle callback to quit when the main loop is idle.
bool on_main_loop_idle() {
  std::cout << "loop_idle\n";
  loop->quit();
  return false;
}

void on_dbus_proxy_available(Glib::RefPtr<Gio::AsyncResult>& result)
{
  auto proxy = Gio::DBus::Proxy::create_finish(result);

  if(!proxy) {
    std::cerr << "The proxy to the user's session bus was not successfully "
      "created." << std::endl;
    loop->quit();
    return;
  }

  try {
    std::cout << "Calling...\n";

    proxy->call_sync("Method");

    std::cout << "It works!\n";
  }
  catch(const Glib::Error& error) {
    std::cerr << "Got an error: '" << error.what() << "'." << std::endl;
  }

  // Connect an idle callback to the main loop to quit when the main loop is
  // idle now that the method call is finished.
  Glib::signal_idle().connect(sigc::ptr_fun(&on_main_loop_idle));
}

int client_main() {    
  loop = Glib::MainLoop::create();

  auto connection =
    Gio::DBus::Connection::get_sync(Gio::DBus::BUS_TYPE_SESSION);

  if(!connection) {
    std::cerr << "The user's session bus is not available." << std::endl;
    return 1;
  }

  // Create the proxy to the bus asynchronously.
  Gio::DBus::Proxy::create(connection, "org.glibmm.DBusExample",
    "/org/glibmm/DBusExample", "org.glibmm.DBusExample",
    sigc::ptr_fun(&on_dbus_proxy_available));

  loop->run();

  return EXIT_SUCCESS;
}

テストをコンパイルしg++ -O2 -std=c++0x main.cc server.cc client.cc -o test $(pkg-config --cflags --libs giomm-2.4)て実行します:

./test
on_bus_acquired
Calling...
<it hangs>

ただし、main.cc を変更すると:

    #include <giomm.h>

    int server_main();
    int client_main();

    int main() {
      Gio::init();
      auto childid = fork();
      if (childid == 0) {
        server_main();
      } else {
        sleep(1);
        client_main();
      }
    }

私は得る:

./test
on_bus_acquired
Calling...
Method was called
It works!

したがって、call_sync() は正常に戻ります。

サーバーとクライアントからループを除外し、シングルスレッドの main.cc を使用しようとしました。

#include <giomm.h>
#include <thread>

int server_main();
int client_main();

int main() {
    Gio::init();
    server_main();
    client_main();
    auto loop = Glib::MainLoop::create();
    loop->run();
}

何も役に立ちません。問題は、私が間違っていることは何ですか? d-bus サーバーとクライアントを 1 つのプロセスで使用したいと考えています。

4

1 に答える 1

0

私はそれを理解しました、トリックは実行することです

Glib::VariantContainerBase result;
invocation->return_value(result);

on_method_call の最後に。

于 2012-09-05T11:41:15.953 に答える