diff options
author | Patrick Ohly <patrick.ohly@intel.com> | 2012-09-11 15:28:07 +0200 |
---|---|---|
committer | Patrick Ohly <patrick.ohly@intel.com> | 2012-10-25 16:43:45 +0200 |
commit | cec68658987d99da8db3fdde4ad61b2fb44a310b (patch) | |
tree | 33c41f5a9f3de46f39fac9ee04b784a7d981bbfe | |
parent | 3004545b0ccee6657cce3f38d0bc5bae2a8d66b6 (diff) |
GDBus GIO: revamped name owning
Remove global variables and allow addditional names to be owned via
DBusConnectionPtr::ownName().
g_bus_own_name_on_connection() is given shared access to a ref-counted
OwnNameAsyncData (instead of full ownership) because that way it is
guaranteed that the instance is still around while waiting for name
acquisition in undelay().
-rw-r--r-- | src/gdbusxx/gdbus-cxx-bridge.cpp | 118 | ||||
-rw-r--r-- | src/gdbusxx/gdbus-cxx-bridge.h | 24 |
2 files changed, 102 insertions, 40 deletions
diff --git a/src/gdbusxx/gdbus-cxx-bridge.cpp b/src/gdbusxx/gdbus-cxx-bridge.cpp index ea6aaefe..8dee2c8d 100644 --- a/src/gdbusxx/gdbus-cxx-bridge.cpp +++ b/src/gdbusxx/gdbus-cxx-bridge.cpp @@ -33,65 +33,103 @@ namespace GDBusCXX { MethodHandler::MethodMap MethodHandler::m_methodMap; boost::function<void (void)> MethodHandler::m_callback; -// It should be okay to use global variables here because they are -// only used inside the main thread while it waits in undelay() for a -// positive or negative result to g_bus_own_name_on_connection(). -// Once acquired, the name can only get lost again when the -// D-Bus daemon dies (no name owership alloed), in which case the -// process dies anyway. -static bool nameError; -static bool nameAcquired; -static void BusNameAcquired(GDBusConnection *connection, +struct OwnNameAsyncData +{ + enum State { + OWN_NAME_WAITING, + OWN_NAME_OBTAINED, + OWN_NAME_LOST + }; + + OwnNameAsyncData(const std::string &name, + const boost::function<void (bool)> &obtainedCB) : + m_name(name), + m_obtainedCB(obtainedCB), + m_state(OWN_NAME_WAITING) + {} + + static void busNameAcquired(GDBusConnection *connection, + const gchar *name, + gpointer userData) throw () + { + boost::shared_ptr<OwnNameAsyncData> *data = static_cast< boost::shared_ptr<OwnNameAsyncData> *>(userData); + (*data)->m_state = OWN_NAME_OBTAINED; + try { + g_debug("got D-Bus name %s", name); + if ((*data)->m_obtainedCB) { + (*data)->m_obtainedCB(true); + } + } catch (...) { + (*data)->m_state = OWN_NAME_LOST; + } + } + + static void busNameLost(GDBusConnection *connection, const gchar *name, gpointer userData) throw () -{ - try { - g_debug("got D-Bus name %s", name); - nameAcquired = true; - } catch (...) { - nameError = true; + { + boost::shared_ptr<OwnNameAsyncData> *data = static_cast< boost::shared_ptr<OwnNameAsyncData> *>(userData); + (*data)->m_state = OWN_NAME_LOST; + try { + g_debug("lost %s %s", + connection ? "D-Bus connection for name" : + "D-Bus name", + name); + if ((*data)->m_obtainedCB) { + (*data)->m_obtainedCB(false); + } + } catch (...) { + } } -} -static void BusNameLost(GDBusConnection *connection, - const gchar *name, - gpointer userData) throw () -{ - try { - g_debug("lost %s %s", - connection ? "D-Bus connection for name" : - "D-Bus name", - name); - } catch (...) { + static void freeData(gpointer userData) throw () + { + delete static_cast< boost::shared_ptr<OwnNameAsyncData> *>(userData); + } + + static boost::shared_ptr<OwnNameAsyncData> ownName(GDBusConnection *conn, + const std::string &name, + boost::function<void (bool)> obtainedCB = + boost::function<void (bool)>()) { + boost::shared_ptr<OwnNameAsyncData> data(new OwnNameAsyncData(name, obtainedCB)); + g_bus_own_name_on_connection(conn, + data->m_name.c_str(), + G_BUS_NAME_OWNER_FLAGS_NONE, + OwnNameAsyncData::busNameAcquired, + OwnNameAsyncData::busNameLost, + new boost::shared_ptr<OwnNameAsyncData>(data), + OwnNameAsyncData::freeData); + return data; } - nameError = true; -} + + const std::string m_name; + const boost::function<void (bool)> m_obtainedCB; + State m_state; +}; void DBusConnectionPtr::undelay() const { if (!m_name.empty()) { g_debug("starting to acquire D-Bus name %s", m_name.c_str()); - nameAcquired = false; - nameError = false; - char *copy = g_strdup(m_name.c_str()); - g_bus_own_name_on_connection(get(), - copy, - G_BUS_NAME_OWNER_FLAGS_NONE, - BusNameAcquired, - BusNameLost, - copy, - g_free); - while (!nameAcquired && !nameError) { + boost::shared_ptr<OwnNameAsyncData> data = OwnNameAsyncData::ownName(get(), + m_name); + while (data->m_state == OwnNameAsyncData::OWN_NAME_WAITING) { g_main_context_iteration(NULL, true); } g_debug("done with acquisition of %s", m_name.c_str()); - if (nameError) { + if (data->m_state == OwnNameAsyncData::OWN_NAME_LOST) { throw std::runtime_error("could not obtain D-Bus name - already running?"); } } g_dbus_connection_start_message_processing(get()); } +void DBusConnectionPtr::ownNameAsync(const std::string &name, + const boost::function<void (bool)> &obtainedCB) const +{ + OwnNameAsyncData::ownName(get(), name, obtainedCB); +} + DBusConnectionPtr dbus_get_bus_connection(const char *busType, const char *name, bool unshared, diff --git a/src/gdbusxx/gdbus-cxx-bridge.h b/src/gdbusxx/gdbus-cxx-bridge.h index e5bccee2..07a4ad3f 100644 --- a/src/gdbusxx/gdbus-cxx-bridge.h +++ b/src/gdbusxx/gdbus-cxx-bridge.h @@ -186,8 +186,32 @@ class DBusConnectionPtr : public boost::intrusive_ptr<GDBusConnection> void setDisconnect(const Disconnect_t &func); // #define GDBUS_CXX_HAVE_DISCONNECT 1 + /** + * Starts processing of messages, + * claims the bus name set with addName() or + * when creating the connection (legacy API, + * done that way for compatibility with GDBus for libdbus). + */ void undelay() const; void addName(const std::string &name) { m_name = name; } + + /** + * Claims another name on the connection. + * + * The callback will be invoked with true as + * parameter once the name was successfully + * claimed. If that fails, false will be passed. + * + * The caller should be prepared to get called + * again later on, when loosing an already obtained + * name. Currently this shouldn't happen, though, + * because name transfer is not enabled when + * registering the name. + * + * The callback is allowed to be empty. + */ + void ownNameAsync(const std::string &name, + const boost::function<void (bool)> &obtainedCB) const; }; class DBusMessagePtr : public boost::intrusive_ptr<GDBusMessage> |