Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qobject_p_p.h
Go to the documentation of this file.
1// Copyright (C) 2019 The Qt Company Ltd.
2// Copyright (C) 2013 Olivier Goffart <ogoffart@woboq.com>
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#ifndef QOBJECT_P_P_H
6#define QOBJECT_P_P_H
7
8//
9// W A R N I N G
10// -------------
11//
12// This file is not part of the Qt API. It exists for the convenience
13// of qobject.cpp. This header file may change from version to version
14// without notice, or even be removed.
15//
16// We mean it.
17//
18
19// Even though this file is only used by qobject.cpp, the only reason this
20// code lives here is that some special apps/libraries for e.g., QtJambi,
21// Gammaray need access to the structs in this file.
22
23#include <QtCore/qobject.h>
24#include <QtCore/private/qobject_p.h>
25
27
28// ConnectionList is a singly-linked list
30{
31 QAtomicPointer<Connection> first;
32 QAtomicPointer<Connection> last;
33};
34static_assert(std::is_trivially_destructible_v<QObjectPrivate::ConnectionList>);
36
38{
40
41 TaggedSignalVector() = default;
42 TaggedSignalVector(std::nullptr_t) noexcept : c(0) {}
43 TaggedSignalVector(Connection *v) noexcept : c(reinterpret_cast<quintptr>(v)) { Q_ASSERT(v && (reinterpret_cast<quintptr>(v) & 0x1) == 0); }
44 TaggedSignalVector(SignalVector *v) noexcept : c(reinterpret_cast<quintptr>(v) | quintptr(1u)) { Q_ASSERT(v); }
45 explicit operator SignalVector *() const noexcept
46 {
47 if (c & 0x1)
48 return reinterpret_cast<SignalVector *>(c & ~quintptr(1u));
49 return nullptr;
50 }
51 explicit operator Connection *() const noexcept
52 {
53 return reinterpret_cast<Connection *>(c);
54 }
55 operator uintptr_t() const noexcept { return c; }
56};
57
59{
60 union {
61 // linked list of orphaned connections that need cleaning up
63 // linked list of connections connected to slots in this object
65 };
66};
67static_assert(std::is_trivial_v<QObjectPrivate::ConnectionOrSignalVector>);
68
70{
71 // linked list of connections connected to slots in this object, next is in base class
73 // linked list of connections connected to signals in this object
74 QAtomicPointer<Connection> nextConnectionList;
76
78 QAtomicPointer<QObject> receiver;
79 QAtomicPointer<QThreadData> receiverThreadData;
80 union {
83 };
84 QAtomicPointer<const int> argumentTypes;
86 2
87 }; // ref_ is 2 for the use in the internal lists, and for the use in QMetaObject::Connection
88 uint id = 0;
91 signed int signal_index : 27; // In signal range (see QObjectPrivate::signalIndex())
92 ushort connectionType : 2; // 0 == auto, 1 == direct, 2 == queued, 3 == blocking
98 int method() const
99 {
102 }
103 void ref() { ref_.ref(); }
105 {
106 if (isSlotObject) {
108 isSlotObject = false;
109 }
110 }
111 void deref()
112 {
113 if (!ref_.deref()) {
116 delete this;
117 }
118 }
119};
121
123{
125 // ConnectionList signals[]
126 ConnectionList &at(int i) { return reinterpret_cast<ConnectionList *>(this + 1)[i + 1]; }
127 const ConnectionList &at(int i) const
128 {
129 return reinterpret_cast<const ConnectionList *>(this + 1)[i + 1];
130 }
131 int count() const { return static_cast<int>(allocated); }
132};
133static_assert(
134 std::is_trivial_v<QObjectPrivate::SignalVector>); // it doesn't need to be, but it helps
135
137{
138 // the id below is used to avoid activating new connections. When the object gets
139 // deleted it's set to 0, so that signal emission stops
140 QAtomicInteger<uint> currentConnectionId;
142 QAtomicPointer<SignalVector> signalVector;
143 Connection *senders = nullptr;
144 Sender *currentSender = nullptr; // object currently activating the object
145 std::atomic<TaggedSignalVector> orphaned = {};
146
148 {
149 Q_ASSERT(ref.loadRelaxed() == 0);
150 TaggedSignalVector c = orphaned.exchange(nullptr, std::memory_order_relaxed);
151 if (c)
153 SignalVector *v = signalVector.loadRelaxed();
154 if (v) {
155 v->~SignalVector();
156 free(v);
157 }
158 }
159
160 // must be called on the senders connection data
161 // assumes the senders and receivers lock are held
165 // Beware that we need to temporarily release the lock
166 // and thus calling code must carefully consider whether
167 // invariants still hold.
169 };
171 {
172 if (orphaned.load(std::memory_order_relaxed) && ref.loadAcquire() == 1)
173 cleanOrphanedConnectionsImpl(sender, lockPolicy);
174 }
175 void cleanOrphanedConnectionsImpl(QObject *sender, LockPolicy lockPolicy);
176
178 {
179 return signalVector.loadRelaxed()->at(signal);
180 }
181
183 {
184 SignalVector *vector = this->signalVector.loadRelaxed();
185 if (vector && vector->allocated > size)
186 return;
187 size = (size + 7) & ~7;
188 void *ptr = malloc(sizeof(SignalVector) + (size + 1) * sizeof(ConnectionList));
189 auto newVector = new (ptr) SignalVector;
190
191 int start = -1;
192 if (vector) {
193 // not (yet) existing trait:
194 // static_assert(std::is_relocatable_v<SignalVector>);
195 // static_assert(std::is_relocatable_v<ConnectionList>);
196 memcpy(newVector, vector,
197 sizeof(SignalVector) + (vector->allocated + 1) * sizeof(ConnectionList));
198 start = vector->count();
199 }
200 for (int i = start; i < int(size); ++i)
201 new (&newVector->at(i)) ConnectionList();
202 newVector->next = nullptr;
203 newVector->allocated = size;
204
205 signalVector.storeRelaxed(newVector);
206 if (vector) {
207 TaggedSignalVector o = nullptr;
208 /* No ABA issue here: When adding a node, we only care about the list head, it doesn't
209 * matter if the tail changes.
210 */
211 o = orphaned.load(std::memory_order_acquire);
212 do {
213 vector->nextInOrphanList = o;
214 } while (!orphaned.compare_exchange_strong(o, TaggedSignalVector(vector), std::memory_order_release));
215 }
216 }
218 {
219 return signalVector.loadAcquire() ? signalVector.loadRelaxed()->count() : -1;
220 }
221
223};
224
226{
229 {
230 if (receiverConnections) {
231 previous = receiverConnections->currentSender;
232 receiverConnections->currentSender = this;
233 }
234 }
236 {
237 if (receiver)
238 receiver->d_func()->connections.loadAcquire()->currentSender = previous;
239 }
241 {
242 Sender *s = this;
243 while (s) {
244 s->receiver = nullptr;
245 s = s->previous;
246 }
247 }
248 Sender *previous = nullptr;
252};
254
256
257#endif
\inmodule QtCore
Definition qatomic.h:112
bool ref() noexcept
bool deref() noexcept
Type loadRelaxed() const noexcept
qsizetype count() const noexcept
Definition qlist.h:398
void(* StaticMetaCallFunction)(QObject *, QMetaObject::Call, int, void **)
Definition qobject_p.h:108
\inmodule QtCore
Definition qobject.h:103
auto signal
Combined button and popup list for selecting options.
static ControlElement< T > * ptr(QWidget *widget)
GLsizei const GLfloat * v
[13]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint start
GLint ref
GLdouble s
[6]
Definition qopenglext.h:235
const GLubyte * c
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
@ Q_RELOCATABLE_TYPE
Definition qtypeinfo.h:158
#define Q_DECLARE_TYPEINFO(TYPE, FLAGS)
Definition qtypeinfo.h:180
size_t quintptr
Definition qtypes.h:167
unsigned int uint
Definition qtypes.h:34
unsigned short ushort
Definition qtypes.h:33
QList< int > vector
[14]
std::atomic< TaggedSignalVector > orphaned
QAtomicInteger< uint > currentConnectionId
ConnectionList & connectionsForSignal(int signal)
void removeConnection(Connection *c)
Definition qobject.cpp:301
void resizeSignalVector(uint size)
static void deleteOrphaned(TaggedSignalVector o)
Definition qobject.cpp:395
void cleanOrphanedConnections(QObject *sender, LockPolicy lockPolicy=NeedToLock)
void cleanOrphanedConnectionsImpl(QObject *sender, LockPolicy lockPolicy)
Definition qobject.cpp:367
QAtomicPointer< SignalVector > signalVector
QAtomicPointer< Connection > last
Definition qobject_p_p.h:32
QAtomicPointer< Connection > first
Definition qobject_p_p.h:31
QAtomicPointer< const int > argumentTypes
Definition qobject_p_p.h:84
QAtomicPointer< QThreadData > receiverThreadData
Definition qobject_p_p.h:79
QAtomicPointer< Connection > nextConnectionList
Definition qobject_p_p.h:74
QAtomicPointer< QObject > receiver
Definition qobject_p_p.h:78
Connection * prevConnectionList
Definition qobject_p_p.h:75
QtPrivate::QSlotObjectBase * slotObj
Definition qobject_p_p.h:82
StaticMetaCallFunction callFunction
Definition qobject_p_p.h:81
Sender(QObject *receiver, QObject *sender, int signal, ConnectionData *receiverConnections)
ConnectionList & at(int i)
const ConnectionList & at(int i) const
TaggedSignalVector(std::nullptr_t) noexcept
Definition qobject_p_p.h:42
TaggedSignalVector(Connection *v) noexcept
Definition qobject_p_p.h:43
TaggedSignalVector(SignalVector *v) noexcept
Definition qobject_p_p.h:44