[RFC PATCH v2 136/137] docs/devel/qom: Document the composition-tree parenting contract

Alexander Graf <[email protected]>
Newsgroups org.nongnu.qemu-arm,org.nongnu.qemu-devel,org.nongnu.qemu-riscv
Message-ID <[email protected]>
Add a section to the QOM developer documentation explaining that
every object must have a composition-tree parent before use, how
to pick the parent (creator owns lifetime), how to name children,
the reference-count contract for parented creators, and where the
contract is enforced (device_set_realized, memory_region_do_init,
qdev_connect_gpio_out_named).

AI-used-for: code (refactoring)
Signed-off-by: Alexander Graf <[email protected]>
---
 docs/devel/qom.rst | 96 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 96 insertions(+)

diff --git a/docs/devel/qom.rst b/docs/devel/qom.rst
index 935bb1004a..ffcb3333b5 100644
--- a/docs/devel/qom.rst
+++ b/docs/devel/qom.rst
@@ -27,6 +27,102 @@ that make up a QEMU "machine". You can view this tree by running
 objects created by the machine itself as well those created due to
 user configuration.
 
+Composition-tree parenting contract
+====================================
+
+Every QOM object that participates in the running system must have a
+composition-tree parent before it is used.  The parent gives the object
+a stable, canonical path such as ``/machine/soc/uart[0]`` that is
+visible in ``info qom-tree`` and addressable via ``qom-get`` and
+``qom-set``.  Objects that reach ``realize`` (for devices), that are
+wired to another object (for IRQ lines), or that are given a name (for
+memory regions) without a parent are programming errors.
+
+Creating parented objects
+-------------------------
+
+The standard creation helpers all take the composition-tree parent and
+the child name as their first two arguments:
+
+.. code-block:: c
+
+    Object      *object_new_child(Object *parent, const char *id,
+                                  const char *typename);
+    DeviceState *qdev_new(Object *parent, const char *id,
+                          const char *typename);
+    DeviceState *sysbus_create_simple(Object *parent, const char *id,
+                                      const char *type, hwaddr, qemu_irq);
+    PCIDevice   *pci_new(Object *parent, const char *id, ...);
+    ISADevice   *isa_new(Object *parent, const char *id, ...);
+    /* i2c_slave_new(), ssi_create_peripheral(), usb_new(),
+       cpu_create() etc. follow the same pattern. */
+
+``object_new()`` remains available as the primitive allocator for
+transient introspection objects and for ``qdev_device_add()``, which
+parents the device via ``qdev_set_id()``.  All other callers should use
+one of the parented helpers above, or ``object_initialize_child()`` for
+objects that are embedded by value in the parent's instance struct.
+
+Choosing the parent
+-------------------
+
+The QOM parent is the object that owns the child's lifetime.  In
+practice this is the object whose code is creating the child:
+
+* Board code (``MachineClass.init``) parents onboard devices to the
+  machine: ``OBJECT(machine)``.
+* A composite device's ``DeviceClass.realize`` parents the sub-devices
+  it creates to itself: ``OBJECT(dev)``.
+* An SoC container likewise parents the devices it creates to the SoC
+  object.
+
+The bus a device is plugged into is *not* its composition-tree parent.
+A device may sit on a bus owned by ``B`` without being a child of
+``B``; the bus relationship is expressed through the ``parent_bus``
+link, not the ``child<>`` property.
+
+Choosing the child name
+-----------------------
+
+* A single instance takes a bare noun: ``"uart"``, ``"gic"``, ``"rtc"``.
+* A fixed number of identical instances take an explicit index:
+  ``"uart[0]"``, ``"uart[1]"``.
+* When the caller does not care about the index, ``"uart[*]"`` lets
+  QOM allocate the next free slot in the ``uart[]`` array.
+* Address-based names such as ``"eth@0x30000000"`` should only be used
+  when the address is genuinely the identity of the device.
+
+Child names share the parent's property namespace, so avoid names that
+collide with class-defined properties of the parent (in particular,
+machine class properties visible on ``/machine``).
+
+Reference-count contract
+------------------------
+
+``object_new_child()``, ``qdev_new()`` and the per-bus creators return
+with the object's single reference held by the parent's ``child<>``
+property.  The caller does *not* hold a reference of its own and must
+therefore pair creation with plain ``qdev_realize()`` rather than
+``qdev_realize_and_unref()``.  The object is finalized when the parent
+drops its ``child<>`` property, typically via ``object_unparent()``.
+
+Enforcement
+-----------
+
+The parenting contract is enforced at the points where an unparented
+object would first become visible or entangled with another object:
+
+* ``device_set_realized()`` fails with an ``Error`` if the device has
+  no composition-tree parent.
+* ``memory_region_do_init()`` asserts that a memory region given a
+  non-empty name also has an owner.
+* ``qdev_connect_gpio_out_named()`` asserts that the outbound IRQ
+  line being connected already has a composition-tree parent.
+
+There is no ``/machine/unattached`` fallback container; an object that
+would previously have landed there now triggers one of the errors
+above instead.
+
 Creating a QOM class
 ====================
 
-- 
2.47.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.