QObject-Internals: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
No edit summary
 
No edit summary
Line 1: Line 1:
=QObject Internals=
[[Category:Developing_Qt::Qt_Internals]]


==How Signals and Slots Works.==
= QObject Internals =
 
== How Signals and Slots Works. ==


See http://woboq.com/blog/how-qt-signals-slots-work.html
See http://woboq.com/blog/how-qt-signals-slots-work.html


==moc==
== moc ==


The moc is there to generate the QMetaObject contents.<br /> It parses the headers and generate source code that contains the metaobject and the code of the signals.
The moc is there to generate the QMetaObject contents.<br />It parses the headers and generate source code that contains the metaobject and the code of the signals.


===Cloned Method===
=== Cloned Method ===


If you have a signal or a slot with default arguments, the signature are duplicated as if there was overload with and without those argument argument.
If you have a signal or a slot with default arguments, the signature are duplicated as if there was overload with and without those argument argument.


First is the “original” one, with the full number of argument. <br /> Then follow all the clones: they have the flag MethodFlags::MethodCloned in the QMetaObject method flags
First is the &quot;original&amp;quot; one, with the full number of argument.<br />Then follow all the clones: they have the flag MethodFlags::MethodCloned in the QMetaObject method flags


==methodIndex and signalIndex==
== methodIndex and signalIndex ==


In each QMetaObject, the slots, signals, and other invokable methods of that object<br /> have an index starting from 0. They are ordered such that the signals comes first, then the slot, then the other method.
In each QMetaObject, the slots, signals, and other invokable methods of that object<br />have an index starting from 0. They are ordered such that the signals comes first, then the slot, then the other method.


This index is called the relativeIndex in the code, and can be obtained by QMetaObjectPrivate::indexOf{Signal,Slot}Relative. This function returns the index, but also via its baseObject argument, the QMetaObject in which that slot belogs.
This index is called the relativeIndex in the code, and can be obtained by QMetaObjectPrivate::indexOf{Signal,Slot}Relative. This function returns the index, but also via its baseObject argument, the QMetaObject in which that slot belogs.
Line 23: Line 25:
The IndexOfMethod call of the QObject::qt_static_metacall function also returns that relativeIndex
The IndexOfMethod call of the QObject::qt_static_metacall function also returns that relativeIndex


Then there is the method index: it is the index returned by the public <span class="caps">API</span> QMetaObject::indexOf{Signal,Slot,Method}<br /> That is basically the relativeIndex + QMetaObject::methodOffset()<br /> This is the only index avaliable from the public <span class="caps">API</span>
Then there is the method index: it is the index returned by the public API QMetaObject::indexOf{Signal,Slot,Method}<br />That is basically the relativeIndex + QMetaObject::methodOffset()<br />This is the only index avaliable from the public API
 
The signalIndex is used from Qt 4.6 in the connectionLists. It was introduced because the connectionList only care about signals, and not the slots, and that there might be a lot of slots wasting space in that vector. It is only used internaly, and not avaliable through the public <span class="caps">API</span>.<br /> The main difference is that it does not contains the slots. So the signalIndex is usually less than the methodIndex for a given signal (and it only exist for signal)<br /> The second difference is that for cloned signal, we use the original instead. (Hence the call to QMetaObjectPrivate::originalClone)
 
==connectionLists Data Structure==
 
connectionLists is a vector of lists of connections.<br /> The index is the signalIndex, and lists are single linked list of connections represented with QObjectPrivate::Connection.
 
The vector contains a pointer to the first Connection for that signal, and because we want the connection to be O(1), we store also the last connection. This last connection also helps to stop before the connection that would have been added after the signal has been emitted while emitting that signal. The linked list works by following the QObjectPrivate::Connection::nextConnectionList.


The Connection’s are part of another linked list: the object sender’s list. This list is used to be able to remove the connections when the object is destroyed. The starts of the list is QObjectPrivate::senders. And it is a (semi-) double linked list. We can get to the next element of that list using QObjectPrivate::Connection::next. But QObjectPrivate::Connection::prev is a pointer to the Connection::next of the previous element, or the the QObjectPrivate::senders if it is the first. It is like that because we only need to iterate that list one way, but we need to quickly O(1) remove connection from that list while we disconnect (or if the sender get detroyed)
The signalIndex is used from Qt 4.6 in the connectionLists. It was introduced because the connectionList only care about signals, and not the slots, and that there might be a lot of slots wasting space in that vector. It is only used internaly, and not avaliable through the public API.<br />The main difference is that it does not contains the slots. So the signalIndex is usually less than the methodIndex for a given signal (and it only exist for signal)<br />The second difference is that for cloned signal, we use the original instead. (Hence the call to QMetaObjectPrivate::originalClone)


When an Object is destroyed:
== connectionLists Data Structure ==


* That QObjectPrivate::senders list will be iterated when the object is destroyed, and all the Connection::receiver will be set to 0, also Connection::receiver-&gt;connectionLists-&gt;dirty will be set to true. That way removing a connection is O(1) and destroying an object is O(n), n is the number of slot of this object connected to a signal (possibly in another object)
connectionLists is a vector of lists of connections.<br />The index is the signalIndex, and lists are single linked list of connections represented with QObjectPrivate::Connection.
* each of the QObjectPrivate::connectionLists are also iterated to remove the Connection in the senders lists.


The lists are protected by the signalSlotMutex(QObject *)<br /> The connectionLists by the mutex of the sender, and the senders by the mutex of the receiver.<br /> So to modify a Connection, you need to lock the two mutex, but if you only access them, locking one mutex is enough.
The vector contains a pointer to the first Connection for that signal, and because we want the connection to be O (1), we store also the last connection. This last connection also helps to stop before the connection that would have been added after the signal has been emitted while emitting that signal. The linked list works by following the QObjectPrivate::Connection::nextConnectionList.


===History===
The Connection's are part of another linked list: the object sender's list. This list is used to be able to remove the connections when the object is destroyed. The starts of the list is QObjectPrivate::senders. And it is a (semi-) double linked list. We can get to the next element of that list using QObjectPrivate::Connection::next. But QObjectPrivate::Connection::prev is a pointer to the Connection::next of the previous element, or the the QObjectPrivate::senders if it is the first. It is like that because we only need to iterate that list one way, but we need to quickly O (1) remove connection from that list while we disconnect (or if the sender get detroyed)


That data structure has changed a lot in Qt4 history<br /> In Qt 4.0 it was a global, mutex protected, big list of connection, indexed with a QHash.
When an Object is destroyed:<br />* That QObjectPrivate::senders list will be iterated when the object is destroyed, and all the Connection::receiver will be set to 0, also Connection::receiver-&gt;connectionLists-&gt;dirty will be set to true. That way removing a connection is O (1) and destroying an object is O (n), n is the number of slot of this object connected to a signal (possibly in another object)<br />* each of the QObjectPrivate::connectionLists are also iterated to remove the Connection in the senders lists.


In Qt 4.4 it was changed to a QVector&lt;QList&lt;QObjectPrivate::Connection&gt;&gt; connectionLists and QList&lt;QObjectPRivate::Sender&gt; senders in order to optimize QMetaObject;;activate
The lists are protected by the signalSlotMutex(QObject *)<br />The connectionLists by the mutex of the sender, and the senders by the mutex of the receiver.<br />So to modify a Connection, you need to lock the two mutex, but if you only access them, locking one mutex is enough.


But as ~QObject was still too slow it was changed to the current linked list based data structure in Qt 4.6 (a66525c2e4c760f8ceda344cd7252431ed263654 and improved further with time)
=== History ===


===Categories:===
That data structure has changed a lot in Qt4 history<br />In Qt 4.0 it was a global, mutex protected, big list of connection, indexed with a QHash.


* [[:Category:Developing Qt|Developing_Qt]]
In Qt 4.4 it was changed to a QVector&amp;lt;QList&amp;lt;QObjectPrivate::Connection&amp;gt;&gt; connectionLists and QList&amp;lt;QObjectPRivate::Sender&amp;gt; senders in order to optimize QMetaObject;;activate
** [[:Category:Developing Qt::Qt Internals|Qt_Internals]]

Revision as of 10:09, 24 February 2015


QObject Internals

How Signals and Slots Works.

See http://woboq.com/blog/how-qt-signals-slots-work.html

moc

The moc is there to generate the QMetaObject contents.
It parses the headers and generate source code that contains the metaobject and the code of the signals.

Cloned Method

If you have a signal or a slot with default arguments, the signature are duplicated as if there was overload with and without those argument argument.

First is the "original&quot; one, with the full number of argument.
Then follow all the clones: they have the flag MethodFlags::MethodCloned in the QMetaObject method flags

methodIndex and signalIndex

In each QMetaObject, the slots, signals, and other invokable methods of that object
have an index starting from 0. They are ordered such that the signals comes first, then the slot, then the other method.

This index is called the relativeIndex in the code, and can be obtained by QMetaObjectPrivate::indexOf{Signal,Slot}Relative. This function returns the index, but also via its baseObject argument, the QMetaObject in which that slot belogs.

The IndexOfMethod call of the QObject::qt_static_metacall function also returns that relativeIndex

Then there is the method index: it is the index returned by the public API QMetaObject::indexOf{Signal,Slot,Method}
That is basically the relativeIndex + QMetaObject::methodOffset()
This is the only index avaliable from the public API

The signalIndex is used from Qt 4.6 in the connectionLists. It was introduced because the connectionList only care about signals, and not the slots, and that there might be a lot of slots wasting space in that vector. It is only used internaly, and not avaliable through the public API.
The main difference is that it does not contains the slots. So the signalIndex is usually less than the methodIndex for a given signal (and it only exist for signal)
The second difference is that for cloned signal, we use the original instead. (Hence the call to QMetaObjectPrivate::originalClone)

connectionLists Data Structure

connectionLists is a vector of lists of connections.
The index is the signalIndex, and lists are single linked list of connections represented with QObjectPrivate::Connection.

The vector contains a pointer to the first Connection for that signal, and because we want the connection to be O (1), we store also the last connection. This last connection also helps to stop before the connection that would have been added after the signal has been emitted while emitting that signal. The linked list works by following the QObjectPrivate::Connection::nextConnectionList.

The Connection's are part of another linked list: the object sender's list. This list is used to be able to remove the connections when the object is destroyed. The starts of the list is QObjectPrivate::senders. And it is a (semi-) double linked list. We can get to the next element of that list using QObjectPrivate::Connection::next. But QObjectPrivate::Connection::prev is a pointer to the Connection::next of the previous element, or the the QObjectPrivate::senders if it is the first. It is like that because we only need to iterate that list one way, but we need to quickly O (1) remove connection from that list while we disconnect (or if the sender get detroyed)

When an Object is destroyed:
* That QObjectPrivate::senders list will be iterated when the object is destroyed, and all the Connection::receiver will be set to 0, also Connection::receiver->connectionLists->dirty will be set to true. That way removing a connection is O (1) and destroying an object is O (n), n is the number of slot of this object connected to a signal (possibly in another object)
* each of the QObjectPrivate::connectionLists are also iterated to remove the Connection in the senders lists.

The lists are protected by the signalSlotMutex(QObject *)
The connectionLists by the mutex of the sender, and the senders by the mutex of the receiver.
So to modify a Connection, you need to lock the two mutex, but if you only access them, locking one mutex is enough.

History

That data structure has changed a lot in Qt4 history
In Qt 4.0 it was a global, mutex protected, big list of connection, indexed with a QHash.

In Qt 4.4 it was changed to a QVector&lt;QList&lt;QObjectPrivate::Connection&gt;> connectionLists and QList&lt;QObjectPRivate::Sender&gt; senders in order to optimize QMetaObject;;activate