summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qobject_p.h
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2019-01-09 22:17:51 +0100
committerLars Knoll <lars.knoll@qt.io>2019-03-29 13:46:29 +0000
commit13ab090977439cf432c7b99dbdd2b1263b4d8cd4 (patch)
tree41b5dd0a4ee4eeb91b7fcfc2395137c3c81eaa7c /src/corelib/kernel/qobject_p.h
parent999c26dd83ad37fcd7a2b2fc62c0281f38c8e6e0 (diff)
Add safe way to resize the signalVector
Change-Id: Ib55da020f22e981bc379af3b4cf3431bf0fa0c20 Reviewed-by: Olivier Goffart (Woboq GmbH) <ogoffart@woboq.com>
Diffstat (limited to 'src/corelib/kernel/qobject_p.h')
-rw-r--r--src/corelib/kernel/qobject_p.h85
1 files changed, 70 insertions, 15 deletions
diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h
index da3d035087..f01b709faa 100644
--- a/src/corelib/kernel/qobject_p.h
+++ b/src/corelib/kernel/qobject_p.h
@@ -124,14 +124,30 @@ public:
};
typedef void (*StaticMetaCallFunction)(QObject *, QMetaObject::Call, int, void **);
- struct Connection
- {
+ struct Connection;
+ struct SignalVector;
+
+ struct ConnectionOrSignalVector {
union {
// linked list of orphaned connections that need cleaning up
- Connection *nextInOrphanList;
+ ConnectionOrSignalVector *nextInOrphanList;
// linked list of connections connected to slots in this object
Connection *next;
};
+
+ static SignalVector *asSignalVector(ConnectionOrSignalVector *c) {
+ if (reinterpret_cast<quintptr>(c) & 1)
+ return reinterpret_cast<SignalVector *>(reinterpret_cast<quintptr>(c) & ~quintptr(1u));
+ return nullptr;
+ }
+ static Connection *fromSignalVector(SignalVector *v) {
+ return reinterpret_cast<Connection *>(reinterpret_cast<quintptr>(v) | quintptr(1u));
+ }
+ };
+
+ struct Connection : public ConnectionOrSignalVector
+ {
+ // linked list of connections connected to slots in this object, next is in base class
Connection **prev;
// linked list of connections connected to signals in this object
Connection *nextConnectionList;
@@ -210,6 +226,22 @@ public:
int signal;
};
+ struct SignalVector : public ConnectionOrSignalVector {
+ quintptr allocated;
+ // ConnectionList signals[]
+ ConnectionList &at(int i)
+ {
+ return reinterpret_cast<ConnectionList *>(this + 1)[i + 1];
+ }
+ const ConnectionList &at(int i) const
+ {
+ return reinterpret_cast<const ConnectionList *>(this + 1)[i + 1];
+ }
+ int count() { return static_cast<int>(allocated); }
+ };
+
+
+
/*
This contains the all connections from and to an object.
@@ -236,22 +268,16 @@ public:
};
Ref ref;
- ConnectionList allsignals;
- QVector<ConnectionList> signalVector;
+ SignalVector *signalVector = nullptr;
Connection *senders = nullptr;
Sender *currentSender = nullptr; // object currently activating the object
QAtomicPointer<Connection> orphaned;
~ConnectionData()
{
- Connection *c = orphaned.load();
- while (c) {
- Q_ASSERT(!c->receiver);
- QObjectPrivate::Connection *next = c->nextInOrphanList;
- c->freeSlotObject();
- c->deref();
- c = next;
- }
+ deleteOrphaned(orphaned.load());
+ if (signalVector)
+ free(signalVector);
}
// must be called on the senders connection data
@@ -259,7 +285,7 @@ public:
void removeConnection(Connection *c)
{
Q_ASSERT(c->receiver);
- ConnectionList &connections = connectionsForSignal(c->signal_index);
+ ConnectionList &connections = signalVector->at(c->signal_index);
c->receiver = nullptr;
#ifndef QT_NO_DEBUG
@@ -283,6 +309,8 @@ public:
connections.first = c->nextConnectionList;
if (connections.last == c)
connections.last = c->prevConnectionList;
+ Q_ASSERT(signalVector->at(c->signal_index).first != c);
+ Q_ASSERT(signalVector->at(c->signal_index).last != c);
// keep c->nextConnectionList intact, as it might still get accessed by activate
if (c->nextConnectionList)
@@ -317,8 +345,35 @@ public:
ConnectionList &connectionsForSignal(int signal)
{
- return signal < 0 ? allsignals : signalVector[signal];
+ return signalVector->at(signal);
}
+
+ void resizeSignalVector(uint size) {
+ if (signalVector && signalVector->allocated > size)
+ return;
+ size = (size + 7) & ~7;
+ SignalVector *v = reinterpret_cast<SignalVector *>(malloc(sizeof(SignalVector) + (size + 1) * sizeof(ConnectionList)));
+ int start = -1;
+ if (signalVector) {
+ memcpy(v, signalVector, sizeof(SignalVector) + (signalVector->allocated + 1) * sizeof(ConnectionList));
+ start = signalVector->count();
+ }
+ for (int i = start; i < int(size); ++i)
+ v->at(i) = ConnectionList();
+ v->next = nullptr;
+ v->allocated = size;
+
+ qSwap(v, signalVector);
+ if (v) {
+ v->next = orphaned.load();
+ orphaned.store(ConnectionOrSignalVector::fromSignalVector(v));
+ }
+ }
+ int signalVectorCount() const {
+ return signalVector ? signalVector->count() : -1;
+ }
+
+ static void deleteOrphaned(ConnectionOrSignalVector *c);
};
QObjectPrivate(int version = QObjectPrivateVersion);