summaryrefslogtreecommitdiffstats
path: root/src/dbus
diff options
context:
space:
mode:
Diffstat (limited to 'src/dbus')
-rw-r--r--src/dbus/qdbusconnection.cpp47
-rw-r--r--src/dbus/qdbusconnection_p.h8
-rw-r--r--src/dbus/qdbusintegrator.cpp97
3 files changed, 92 insertions, 60 deletions
diff --git a/src/dbus/qdbusconnection.cpp b/src/dbus/qdbusconnection.cpp
index a4c241941f..7e56ea9fbd 100644
--- a/src/dbus/qdbusconnection.cpp
+++ b/src/dbus/qdbusconnection.cpp
@@ -803,13 +803,8 @@ bool QDBusConnection::registerObject(const QString &path, QObject *object, Regis
return false;
if (options & QDBusConnectionPrivate::VirtualObject) {
- // technically the check for children needs to go even deeper
- if (options & SubPath) {
- foreach (const QDBusConnectionPrivate::ObjectTreeNode &child, node->children) {
- if (child.obj)
- return false;
- }
- }
+ if (options & SubPath && node->activeChildren)
+ return false;
} else {
if ((options & ExportChildObjects && !node->children.isEmpty()))
return false;
@@ -825,8 +820,8 @@ bool QDBusConnection::registerObject(const QString &path, QObject *object, Regis
// if a virtual object occupies this path, return false
if (node->obj && (node->flags & QDBusConnectionPrivate::VirtualObject) && (node->flags & QDBusConnection::SubPath)) {
- qDebug("Cannot register object at %s because QDBusVirtualObject handles all sub-paths.",
- qPrintable(path));
+ //qDebug("Cannot register object at %s because QDBusVirtualObject handles all sub-paths.",
+ // qPrintable(path));
return false;
}
@@ -840,12 +835,13 @@ bool QDBusConnection::registerObject(const QString &path, QObject *object, Regis
// are we allowed to go deeper?
if (node->flags & ExportChildObjects) {
// we're not
- qDebug("Cannot register object at %s because %s exports its own child objects",
- qPrintable(path), qPrintable(pathComponents.at(i)));
+ //qDebug("Cannot register object at %s because %s exports its own child objects",
+ // qPrintable(path), qPrintable(pathComponents.at(i)));
return false;
}
} else {
// add entry
+ ++node->activeChildren;
node = node->children.insert(it, pathComponents.at(i));
}
@@ -883,35 +879,8 @@ void QDBusConnection::unregisterObject(const QString &path, UnregisterMode mode)
if (!d || !d->connection || !QDBusUtil::isValidObjectPath(path))
return;
- QStringList pathComponents = path.split(QLatin1Char('/'));
QDBusWriteLocker locker(UnregisterObjectAction, d);
- QDBusConnectionPrivate::ObjectTreeNode *node = &d->rootNode;
- int i = 1;
-
- // find the object
- while (node) {
- if (pathComponents.count() == i || !path.compare(QLatin1String("/"))) {
- // found it
- node->obj = 0;
- node->flags = 0;
-
- if (mode == UnregisterTree) {
- // clear the sub-tree as well
- node->children.clear(); // can't disconnect the objects because we really don't know if they can
- // be found somewhere else in the path too
- }
-
- return;
- }
-
- QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator it =
- std::lower_bound(node->children.begin(), node->children.end(), pathComponents.at(i));
- if (it == node->children.end() || it->name != pathComponents.at(i))
- break; // node not found
-
- node = it;
- ++i;
- }
+ d->unregisterObject(path, mode);
}
/*!
diff --git a/src/dbus/qdbusconnection_p.h b/src/dbus/qdbusconnection_p.h
index 2c3ddefc50..bef0b88f78 100644
--- a/src/dbus/qdbusconnection_p.h
+++ b/src/dbus/qdbusconnection_p.h
@@ -140,14 +140,16 @@ public:
{
typedef QVector<ObjectTreeNode> DataList;
- inline ObjectTreeNode() : obj(0), flags(0) { }
+ inline ObjectTreeNode() : obj(0), flags(0), activeChildren(0) { }
inline ObjectTreeNode(const QString &n) // intentionally implicit
- : name(n), obj(0), flags(0) { }
+ : name(n), obj(0), flags(0), activeChildren(0) { }
inline ~ObjectTreeNode() { }
inline bool operator<(const QString &other) const
{ return name < other; }
inline bool operator<(const QStringRef &other) const
{ return QStringRef(&name) < other; }
+ inline bool isActive() const
+ { return obj || activeChildren; }
QString name;
union {
@@ -155,6 +157,7 @@ public:
QDBusVirtualObject *treeNode;
};
int flags;
+ int activeChildren;
DataList children;
};
@@ -208,6 +211,7 @@ public:
const QString &name, const QStringList &argumentMatch, const QString &signature,
QObject *receiver, const char *slot);
void registerObject(const ObjectTreeNode *node);
+ void unregisterObject(const QString &path, QDBusConnection::UnregisterMode mode);
void connectRelay(const QString &service,
const QString &path, const QString &interface,
QDBusAbstractInterface *receiver, const QMetaMethod &signal);
diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp
index bc49d6816e..4326ee1fa0 100644
--- a/src/dbus/qdbusintegrator.cpp
+++ b/src/dbus/qdbusintegrator.cpp
@@ -587,17 +587,76 @@ bool QDBusConnectionPrivate::handleMessage(const QDBusMessage &amsg)
return false;
}
+static void garbageCollectChildren(QDBusConnectionPrivate::ObjectTreeNode &node)
+{
+ int size = node.children.count();
+ if (node.activeChildren == 0) {
+ // easy case
+ node.children.clear();
+ } else if (size > node.activeChildren * 3 || (size > 20 && size * 2 > node.activeChildren * 3)) {
+ // rewrite the vector, keeping only the active children
+ // if the vector is large (> 20 items) and has one third of inactives
+ // or if the vector is small and has two thirds of inactives.
+ QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator end = node.children.end();
+ QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator it = node.children.begin();
+ QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator tgt = it;
+ for ( ; it != end; ++it) {
+ if (it->isActive())
+ *tgt++ = qMove(*it);
+ }
+ ++tgt;
+ node.children.erase(tgt, end);
+ }
+}
+
static void huntAndDestroy(QObject *needle, QDBusConnectionPrivate::ObjectTreeNode &haystack)
{
QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator it = haystack.children.begin();
QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator end = haystack.children.end();
- for ( ; it != end; ++it)
+ for ( ; it != end; ++it) {
+ if (!it->isActive())
+ continue;
huntAndDestroy(needle, *it);
+ if (!it->isActive())
+ --haystack.activeChildren;
+ }
if (needle == haystack.obj) {
haystack.obj = 0;
haystack.flags = 0;
}
+
+ garbageCollectChildren(haystack);
+}
+
+static void huntAndUnregister(const QStringList &pathComponents, int i, QDBusConnection::UnregisterMode mode,
+ QDBusConnectionPrivate::ObjectTreeNode *node)
+{
+ if (pathComponents.count() == i) {
+ // found it
+ node->obj = 0;
+ node->flags = 0;
+
+ if (mode == QDBusConnection::UnregisterTree) {
+ // clear the sub-tree as well
+ node->activeChildren = 0;
+ node->children.clear(); // can't disconnect the objects because we really don't know if they can
+ // be found somewhere else in the path too
+ }
+ } else {
+ // keep going
+ QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator end = node->children.end();
+ QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator it =
+ std::lower_bound(node->children.begin(), end, pathComponents.at(i));
+ if (it == end || it->name != pathComponents.at(i) || !it->isActive())
+ return; // node not found
+
+ huntAndUnregister(pathComponents, i + 1, mode, it);
+ if (!it->isActive())
+ --node->activeChildren;
+
+ garbageCollectChildren(*node);
+ }
}
static void huntAndEmit(DBusConnection *connection, DBusMessage *msg,
@@ -606,8 +665,10 @@ static void huntAndEmit(DBusConnection *connection, DBusMessage *msg,
{
QDBusConnectionPrivate::ObjectTreeNode::DataList::ConstIterator it = haystack.children.constBegin();
QDBusConnectionPrivate::ObjectTreeNode::DataList::ConstIterator end = haystack.children.constEnd();
- for ( ; it != end; ++it)
- huntAndEmit(connection, msg, needle, *it, isScriptable, isAdaptor, path + QLatin1Char('/') + it->name);
+ for ( ; it != end; ++it) {
+ if (it->isActive())
+ huntAndEmit(connection, msg, needle, *it, isScriptable, isAdaptor, path + QLatin1Char('/') + it->name);
+ }
if (needle == haystack.obj) {
// is this a signal we should relay?
@@ -2224,19 +2285,6 @@ QDBusConnectionPrivate::disconnectSignal(SignalHookHash::Iterator &it)
return signalHooks.erase(it);
}
-
-static void cleanupDeletedNodes(QDBusConnectionPrivate::ObjectTreeNode &parent)
-{
- QMutableVectorIterator<QDBusConnectionPrivate::ObjectTreeNode> it(parent.children);
- while (it.hasNext()) {
- QDBusConnectionPrivate::ObjectTreeNode& node = it.next();
- if (node.obj == 0 && node.children.isEmpty())
- it.remove();
- else
- cleanupDeletedNodes(node);
- }
-}
-
void QDBusConnectionPrivate::registerObject(const ObjectTreeNode *node)
{
connect(node->obj, SIGNAL(destroyed(QObject*)), SLOT(objectDestroyed(QObject*)),
@@ -2260,10 +2308,21 @@ void QDBusConnectionPrivate::registerObject(const ObjectTreeNode *node)
this, SLOT(relaySignal(QObject*,const QMetaObject*,int,QVariantList)),
Qt::DirectConnection);
}
+}
+
+void QDBusConnectionPrivate::unregisterObject(const QString &path, QDBusConnection::UnregisterMode mode)
+{
+ QDBusConnectionPrivate::ObjectTreeNode *node = &rootNode;
+ QStringList pathComponents;
+ int i;
+ if (path == QLatin1String("/")) {
+ i = 0;
+ } else {
+ pathComponents = path.split(QLatin1Char('/'));
+ i = 1;
+ }
- static int counter = 0;
- if ((++counter % 20) == 0)
- cleanupDeletedNodes(rootNode);
+ huntAndUnregister(pathComponents, i, mode, node);
}
void QDBusConnectionPrivate::connectRelay(const QString &service,