On Thu, Oct 8, 2026 at 7:28 AM Pierrick Bouvier
<[email protected]> wrote:
>
> On 10/7/2026 4:02 PM, Yonggang Luo wrote:
> > On Thu, Oct 8, 2026 at 6:31 AM Pierrick Bouvier
> > <[email protected]> wrote:
> >>
> >> On 10/7/2026 1:50 PM, Yonggang Luo wrote:
> >>> On Thu, Oct 8, 2026 at 4:29 AM Pierrick Bouvier
> >>> <[email protected]> wrote:
> >>>>
> >>>> On 10/7/2026 4:48 AM, Yonggang Luo wrote:
> >>>>> Register target definitions through constructors instead of
> >>>>> MODULE_INIT_TARGET_INFO, making target_info_list() and target_info()
> >>>>> available on entry to main(), without explicit initialization or a
> >>>>> call to module_call_init(MODULE_INIT_QOM).
> >>>>>
> >>>>> Keep the target list sorted by target_arch and default to its first
> >>>>> entry. Provide an unknown TargetInfo fallback for target-independent
> >>>>> tools such as qemu-img and unit tests that link no target-info-def.c
> >>>>> objects.
> >>>>>
> >>>>> Remove the obsolete QOM target-info registration infrastructure and
> >>>>> update the multi-target test to inspect target information before
> >>>>> initializing QOM.
> >>>>>
> >>>>> Signed-off-by: Yonggang Luo <[email protected]>
> >>>>> ---
> >>>>>  include/qemu/module.h           |  1 -
> >>>>>  include/qemu/target-info-def.h  | 56 +++++++++++++++++++++++++++---
> >>>>>  include/qemu/target-info-init.h | 53 ----------------------------
> >>>>>  include/qemu/target-info-qom.h  | 31 -----------------
> >>>>>  include/qemu/target-info.h      |  9 +++++
> >>>>>  meson.build                     |  6 ++--
> >>>>>  system/vl.c                     |  4 ---
> >>>>>  target-info-def.c               |  1 -
> >>>>>  target-info-qom.c               | 60 --------------------------------
> >>>>>  target-info.c                   | 61 ++++++++++++++++++++++++++++++++-
> >>>>>  tests/qtest/fuzz/fuzz.c         |  3 --
> >>>>>  tests/unit/test-multi-target.c  | 12 +++----
> >>>>>  12 files changed, 129 insertions(+), 168 deletions(-)
> >>>>>  delete mode 100644 include/qemu/target-info-init.h
> >>>>>  delete mode 100644 include/qemu/target-info-qom.h
> >>>>>  delete mode 100644 target-info-qom.c
> >>>>>
> >>>>
> >>>> This approach (custom list based) was considered before implementing
> >>>> things with QOM Types. The rationale I followed was that if everything
> >>>> is in QOM, we might better follow that for consistency sake.
> >>>> Yes, the compromise if that we need an extra init step, but it was not a
> >>>> problem to add it.
> >>> I have issue to add the init step for unit-tests, and hard to write the 
> >>> -target
> >>> parse procedure and get it right. Not means this won't work. but for
> >>> me, too much
> >>> coupled.
> >>>
> >>
> >> We already have such a test upstream:
> >> https://gitlab.com/qemu-project/qemu/-/blob/master/tests/unit/test-multi-target.c#L35
> >>
> >> The init sequence is quite straightforward:
> >>
> >> ```
> >> /* initialize target types, and only them */
> >> module_call_init(MODULE_INIT_TARGET_INFO);
> >>
> >> /* we can get the list if we want, for -target or any other purpose */
> >> g_autoptr(GSList) targets = object_class_get_list(TYPE_TARGET_INFO, false);
> >>
> >> /* set the global target info from any element in this list */
> >> TargetInfo* ti = ...;
> >> target_info_qom_set_target_info(ti);
> >>
> >> /* register rest of QOM types */
> >> module_call_init(MODULE_INIT_QOM);
> >> ```
> >>
> >> It works fine to implement -target (if we would like to do it), since I
> >> implemented it myself. That was also my initial motivation by the way.
> >>
> >> Also, I appreciate that target-info is NULL by default, it crashes
> >> loudly when it has not been set, and make it easy to find who depends on 
> >> it.
> >>
> >>> If we treat target_info as a QOM, but QOM needs target_info to set
> >>> up(is_avaible). That makes
> >>> the init sequence too much of a burden.
> >>>
> >>
> >> See sequence above, the solution is to initialize TARGET_INFO first,
> >> before the rest of QOM. You end up with the same result than with a
> >> statically initialized list.
> >>
> >>>
> >>> is_available is depends on target_arch
> >>> And before this patch, target_arch depends on QOM, pulls user/softmmu 
> >>> because
> >>> target_info_init. By moving target-info to be a custom list based, we
> >>> can decouple
> >>> target-info from qom/softmmu/user. and target-info will always
> >>> available once "main(argv, argc)" is entered. We also have the
> >>> advantage of doing all sorts
> >>> of tests against it.
> >>>
> >>
> >> Which kind of tests are you trying to add?
> >>
> >> For now, the exact list of places where we need to do this initialize
> >> target dance are:
> >> - system/vl.c:    module_call_init(MODULE_INIT_TARGET_INFO);
> >> - tests/qtest/fuzz/fuzz.c:    module_call_init(MODULE_INIT_TARGET_INFO);
> >> - tests/unit/test-multi-target.c:
> >
> > # Multi targets test
> > if multi_target_objects != []
> >   test('test-multi-target',
> >        executable('test-multi-target',
> >                   sources: [multi_target_crates, 
> > files('test-multi-target.c')],
> >                   dependencies: multi_target_deps,
> >                   objects: multi_target_objects,
> >                   link_depends: [block_syms, qemu_syms],
> >                   link_args: multi_target_link_args),
> >        suite: ['unit'])
> > endif
> >
> > I see this test, I am trying to add tests that do not pull so many
> > multi_target_objects, as it would be huge.
>
> Agree, we should not add more binary.
> If you need truly multi targets test, this existing binary is a good
> place to start: just add a second test in it.
>
> > Just pull qom only.  And I am trying to call target_info() in
> > object.c, as inspect machines with
> > qemu-system is rejected, so maybe that's not an issue anymore
> >
>
> Seems like a good candidate for the multi-target.c test.
>
> >
> > I means Subject: [PATCH v3 00/10] machine: uniquify virt QOM names
> > https://lore.kernel.org/qemu-devel/[email protected]/#r
> >
> > So the current design always rejects types that do not belong to the
> > current target. Listing them
> > all is not an option at all. With this restriction, then these are
> > indeed not needed.
> > So I'll wait for your work first, otherwise it's always conflicting.
> >
> >
> >> module_call_init(MODULE_INIT_TARGET_INFO);
> >>
> >> If we want more tests, I'm totally ok to move this init code to
> >> target-info.c, and replace call sites if needed.
> >>
> >>>
> >>> Tools such as qemu-img and unit tests may link target-info.c without any
> >>> target-info-def.c objects. Their target list remains empty, so use this
> >>> fallback.
> >>>
> >>
> >> Why should this tool get access to target list? qemu-img deals with disk
> >> images, and is unrelated to targets.
> >>
> >>>
> >>> static TypeImpl *type_register_internal(const TypeInfo *info)
> >>> {
> >>>     TypeImpl *ti;
> >>>
> >>>     if (!type_name_is_valid(info->name)) {
> >>>         fprintf(stderr, "Registering '%s' with illegal type name\n",
> >>> info->name);
> >>>         abort();
> >>>     }
> >>>
> >>>     if (info->is_available && !info->is_available()) {
> >>>         return NULL;
> >>>     }
> >>>
> >>>     ti = type_new(info);
> >>>
> >>>     type_table_add(ti);
> >>>     return ti;
> >>> }
> >>>
> >>>>
> >>>> Is there another good value this list approach brings compared to what
> >>>> exists?
> >>>>
> >>>> Regards,
> >>>> Pierrick
> >>>
> >>>
> >>>
> >>
> >
> >
>


Hi, the cycle dependencies issue happened again, deal with it's a bit
nasty, there is workaround, but I think
the constructor list is the best, here is the rationale:


# Target discovery during QOM registration

## Problem

Machine registration needs the list of targets compiled into the binary.
Currently, it obtains that list through:

```c
object_class_get_list(TYPE_TARGET_INFO, false);
```

Despite the filter, QOM initializes every registered type before checking
whether it implements the requested type.

During `MODULE_INIT_QOM`, registration is only partially complete. A device
may already be registered while its parent's registration callback has not
run, causing failures such as:

```text
Type 'sys-bus-device' is missing its parent 'device'
```

The parent is linked into the binary. The problem is premature
initialization, not a missing library.

## Option 1: cache target-info QOM classes

Enumerate target-info classes once, before device registration starts.
Machine registration then reads the cache instead of enumerating QOM.

### Demo

Declare shared helpers:

```c
void target_info_qom_init(void);
const GSList *target_info_qom_get_targets(void);
```

Implement the cache:

```c
static GSList *target_info_classes;
static bool target_info_initialized;

void target_info_qom_init(void)
{
    if (target_info_initialized) {
        return;
    }

    module_call_init(MODULE_INIT_TARGET_INFO);
    target_info_classes = object_class_get_list(TYPE_TARGET_INFO, false);
    target_info_initialized = true;
}

const GSList *target_info_qom_get_targets(void)
{
    assert(target_info_initialized);
    return target_info_classes;
}
```

Initialize it before other QOM registration:

```c
target_info_qom_init();
module_call_init(MODULE_INIT_QOM);
```

Machine registration uses the borrowed cache:

```c
for (const GSList *l = target_info_qom_get_targets(); l; l = l->next) {
    const TargetInfo *ti = TARGET_INFO_CLASS(l->data)->target_info;

    machine_register_virt_type_for_target(info, name_suffix, arch_mask,
                                         latest, ti);
}
```

`target_info_qom_set_target()` should also use the cached list instead of
enumerating QOM again.

### Advantages

- Preserves the existing QOM-based representation.
- Avoids enumeration during incomplete device registration.
- Requires relatively small changes.

### Disadvantages

- Every relevant executable and test must initialize the cache before
  starting QOM registration.
- `object_class_get_list()` allocates list nodes.
- Callers borrow the list, so it cannot be freed while they are using it.
- Cleanup is possible after all consumers finish, but requires an explicit
  lifecycle policy. Keeping the cache until process exit is a lifetime
  allocation, not inherently an unreachable memory leak.
- Target-info types registered after cache creation are not included.
- Target discovery remains coupled to QOM class initialization.

## Option 2: constructor-populated TargetInfo registry

Each target registers its immutable `TargetInfo` pointer directly.
Machine registration later iterates the registry without querying QOM.

Use a statically allocated node per target so registration requires no
heap allocation.

### Demo

Define a registration node and accessors:

```c
typedef struct TargetInfoRegistration {
    const TargetInfo *info;
    struct TargetInfoRegistration *next;
} TargetInfoRegistration;

void target_info_register(TargetInfoRegistration *entry);
const TargetInfoRegistration *target_info_get_targets(void);
```

Implement the registry in shared code:

```c
static TargetInfoRegistration *target_info_targets;

void target_info_register(TargetInfoRegistration *entry)
{
    entry->next = target_info_targets;
    target_info_targets = entry;
}

const TargetInfoRegistration *target_info_get_targets(void)
{
    return target_info_targets;
}
```

Each target's translation unit provides its own static node and
constructor. For example:

```c
static TargetInfoRegistration target_info_registration = {
    .info = &target_info_stub,
};

static void __attribute__((constructor)) register_target_info(void)
{
    target_info_register(&target_info_registration);
}
```

The constructor must run exactly once per node. The existing target-info
initialization macro can generate this registration code alongside the
QOM registration code; user-mode target-info behavior should remain
unchanged.

Machine registration consumes the completed registry:

```c
for (const TargetInfoRegistration *entry = target_info_get_targets();
     entry;
     entry = entry->next) {
    machine_register_virt_type_for_target(info, name_suffix, arch_mask,
                                         latest, entry->info);
}
```

The sequence is:

```text
Target constructors register static metadata pointers
    ↓
Startup constructors finish
    ↓
Machine registration iterates the completed registry
```

QOM target-info classes can remain available for introspection.

### Advantages

- Makes target discovery independent of QOM initialization.
- Removes the explicit cache-initialization step from executables and tests.
- Avoids premature initialization of unrelated device types.
- Uses static storage: no allocated list nodes and no registry cleanup.
- Does not require ordering between target constructors.

### Constraints

- Constructors must only register metadata, not enumerate or initialize
  QOM classes.
- Consumers must run after startup constructors have completed.
- Each registration node must be inserted exactly once.
- Registry order must not be treated as a meaningful target ordering.
- This simple design assumes compiled-in targets; runtime loading or
  unloading would require additional lifecycle handling.

## Comparison

| Aspect | QOM class cache | Static constructor registry |
|---|---|---|
| Discovery mechanism | QOM enumeration | Direct metadata registration |
| Explicit startup initialization | Required | Not required |
| Heap allocation for list nodes | Yes | No |
| Cleanup policy | Required if releasing the cache | No registry cleanup |
| Dependency on QOM initialization | Yes | No |
| Registration-order sensitivity | Avoided through explicit sequencing
| Avoided by consuming after constructors |
| Late target registration | Cache needs updating | Requires a defined
runtime registration policy |

## Recommendation

Prefer the constructor-populated registry with statically allocated nodes.

`TargetInfo` describes the binary's compiled-in capabilities. Accessing
that metadata should not require initializing the device model or
maintaining an allocated cache of QOM classes.

The QOM cache fixes the immediate failure, but introduces an additional
startup contract and ownership policy. A static constructor registry
removes the underlying dependency and avoids heap allocation for the
registry itself.



-- 
         此致
礼
罗勇刚
Yours
    sincerely,
Yonggang Luo

Reply via email to